- Fix session expiration so that valid sessions are no longer removed

after ten seconds of inactivity when a new session setup request is
    received. Sessions now expire only after credential expiration, while
    stale unauthenticated sessions are cleaned up after a 45-second timeout.
 
  - Keep earlier responses in compound requests when Query Info fails
    because the output buffer is too small. The error response is appended
    without truncating preceding responses.
 
  - Return STATUS_BUFFER_OVERFLOW for partial
    FILE_NORMALIZED_NAME_INFORMATION responses instead of incorrectly
    returning STATUS_INFO_LENGTH_MISMATCH.
 -----BEGIN PGP SIGNATURE-----
 
 iQJKBAABCgA0FiEE6NzKS6Uv/XAAGHgyZwv7A1FEIQgFAmqtTBMWHGxpbmtpbmpl
 b25Aa2VybmVsLm9yZwAKCRBnC/sDUUQhCD2GD/9OzkmZ+/kIMum8IQi9upOM5zUD
 +2nyFMebJ6qXmrhOuUgLn2ptUYxO3q1B9VvzTjKrM1Vun0VuvHmHQbGUp9a/3F7c
 VTncl7E3FEHqlPkLWQJFv2dS+TYYcOhjoc2TDAY9093xktcMHK5zjv4E/DV2o0bf
 NN/GcrrcWSxdJU8WI9JvY2kzmPQMDfM8uVbj2RqHSZ8m9mF5cajtDnzCCS0K6UOR
 qzMrekzewIskUtcQNqU8hJWl1sgiYdD+16LmKmwLd3uOZISc3Miy5Bg8VpNN+B1g
 XHhr49G4Fb8PkEYjncjxQH7zop1ID5UyC2xN63NuoH8+mkm4qn6uG2NrLhmVQO+f
 Z81Ov3g77/jK3Z2fw00H3A7VGSPs931BaRTNj+lPkHTVVq3PyP1XZsfXkPUoRu1Q
 xeaJydScGNYE+kaYbseXwN8haJGawd1Dd+Afn4W2zikUU5tKZxO9d2tBr4Fhl/Fm
 0OBcAssTArhrY7PX2fAOQ4sUwAC4nMXSEIfdWIvcgU2OoyuFltQ55ooCoM0uLs6+
 7R4rxZLipdZmKhuE2mlAWcFQJn8nS0EHXeyEDjO0u8KYsV6C8d+jDNpvtS+/5QVF
 bKE4/uUX/lV0IZ55nFSPT7XdI+gxeiUql3+8bqOVqkw7wR4VjaC0xIQybyEBTMYH
 IJEKfjx4tZcWGTzmdA==
 =9nNl
 -----END PGP SIGNATURE-----

Merge tag 'ksmbd-for-7.3-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/linkinjeon/smb

Pull smb server fixes from Namjae Jeon:

 - Fix session expiration so that valid sessions are no longer removed
   after ten seconds of inactivity when a new session setup request is
   received.

   Sessions now expire only after credential expiration, while stale
   unauthenticated sessions are cleaned up after a 45-second timeout.

 - Keep earlier responses in compound requests when Query Info fails
   because the output buffer is too small. The error response is
   appended without truncating preceding responses.

 - Return STATUS_BUFFER_OVERFLOW for partial
   FILE_NORMALIZED_NAME_INFORMATION responses instead of incorrectly
   returning STATUS_INFO_LENGTH_MISMATCH.

* tag 'ksmbd-for-7.3-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/linkinjeon/smb:
  ksmbd: keep compound responses on query info errors
  ksmbd: fix partial normalized name responses
  ksmbd: follow SMB2 session expiration semantics
This commit is contained in:
Linus Torvalds 2026-09-18 11:05:55 -07:00
commit c3d85c669d
9 changed files with 243 additions and 43 deletions

View File

@ -22,6 +22,8 @@
static DEFINE_MUTEX(init_lock);
static struct ksmbd_conn_ops default_conn_ops;
static struct delayed_work session_expiration_work;
static bool stopping_session_expiration_work;
DEFINE_HASHTABLE(conn_list, CONN_HASH_BITS);
DECLARE_RWSEM(conn_list_lock);
@ -158,18 +160,28 @@ static void delete_proc_clients(void) {}
static struct workqueue_struct *ksmbd_conn_wq;
static void ksmbd_session_expiration_worker(struct work_struct *work);
int ksmbd_conn_wq_init(void)
{
ksmbd_conn_wq = alloc_workqueue("ksmbd-conn-release",
WQ_UNBOUND | WQ_MEM_RECLAIM, 0);
if (!ksmbd_conn_wq)
return -ENOMEM;
WRITE_ONCE(stopping_session_expiration_work, false);
INIT_DELAYED_WORK(&session_expiration_work,
ksmbd_session_expiration_worker);
queue_delayed_work(ksmbd_conn_wq, &session_expiration_work,
KSMBD_SESSION_EXPIRATION_INTERVAL);
return 0;
}
void ksmbd_conn_wq_destroy(void)
{
if (ksmbd_conn_wq) {
WRITE_ONCE(stopping_session_expiration_work, true);
cancel_delayed_work_sync(&session_expiration_work);
destroy_workqueue(ksmbd_conn_wq);
ksmbd_conn_wq = NULL;
}
@ -279,6 +291,7 @@ struct ksmbd_conn *ksmbd_conn_alloc(void)
return NULL;
conn->need_neg = true;
conn->creation_time = jiffies;
ksmbd_conn_set_new(conn);
conn->local_nls = load_nls("utf8");
if (!conn->local_nls)
@ -588,6 +601,20 @@ bool ksmbd_conn_alive(struct ksmbd_conn *conn)
if (kthread_should_stop())
return false;
/*
* Stale connections that have not completed NEGOTIATE and SESSION_SETUP
* must be disconnected. Do not race a request that is currently
* completing authentication.
*/
if (!atomic_read(&conn->req_running) &&
time_after(jiffies, conn->creation_time +
KSMBD_UNAUTHENTICATED_CONN_TIMEOUT) &&
(READ_ONCE(conn->need_neg) ||
!ksmbd_conn_has_valid_or_expired_session(conn))) {
ksmbd_debug(CONN, "Connection setup timed out\n");
return false;
}
if (atomic_read(&conn->stats.open_files_count) > 0)
return true;
@ -605,6 +632,51 @@ bool ksmbd_conn_alive(struct ksmbd_conn *conn)
return true;
}
static void ksmbd_session_expiration_worker(struct work_struct *work)
{
struct ksmbd_conn *conn, *target;
int bkt;
if (!ksmbd_server_running())
goto reschedule;
ksmbd_expire_sessions();
/*
* An old connection without a Valid or Expired session must be
* disconnected. Process one connection at a time without holding
* conn_list_lock across transport shutdown.
*/
again:
target = NULL;
down_read(&conn_list_lock);
hash_for_each(conn_list, bkt, conn, hlist) {
if (ksmbd_conn_exiting(conn) || ksmbd_conn_releasing(conn) ||
atomic_read(&conn->req_running) ||
time_before_eq(jiffies, conn->creation_time +
KSMBD_UNAUTHENTICATED_CONN_TIMEOUT) ||
(!READ_ONCE(conn->need_neg) &&
ksmbd_conn_has_valid_or_expired_session(conn)))
continue;
target = ksmbd_conn_get(conn);
break;
}
up_read(&conn_list_lock);
if (target) {
ksmbd_debug(CONN, "Connection setup timed out\n");
ksmbd_conn_abort(target);
ksmbd_conn_put(target);
goto again;
}
reschedule:
if (!READ_ONCE(stopping_session_expiration_work))
queue_delayed_work(ksmbd_conn_wq, &session_expiration_work,
KSMBD_SESSION_EXPIRATION_INTERVAL);
}
/* "+2" for BCC field (ByteCount, 2 bytes) */
#define SMB1_MIN_SUPPORTED_PDU_SIZE (sizeof(struct smb_hdr) + 2)
#define SMB2_MIN_SUPPORTED_PDU_SIZE (sizeof(struct smb2_pdu))

View File

@ -77,6 +77,7 @@ struct ksmbd_conn {
struct rw_semaphore session_lock;
/* smb session 1 per user */
struct xarray sessions;
unsigned long creation_time;
unsigned long last_active;
/* How many request are running currently */
atomic_t req_running;
@ -192,6 +193,8 @@ struct ksmbd_transport {
#define KSMBD_TCP_RECV_TIMEOUT (7 * HZ)
#define KSMBD_TCP_SEND_TIMEOUT (5 * HZ)
#define KSMBD_SESSION_EXPIRATION_INTERVAL (5 * HZ)
#define KSMBD_UNAUTHENTICATED_CONN_TIMEOUT (45 * HZ)
#define KSMBD_TCP_PEER_SOCKADDR(c) ((struct sockaddr *)&((c)->peer_addr))
#define CONN_HASH_BITS 12

View File

@ -22,6 +22,7 @@
static DEFINE_IDA(session_ida);
#define SESSION_HASH_BITS 12
#define KSMBD_MAX_PENDING_SESSIONS 1
static DEFINE_HASHTABLE(sessions_table, SESSION_HASH_BITS);
static DECLARE_RWSEM(sessions_table_lock);
@ -432,26 +433,31 @@ struct ksmbd_session *__session_lookup(unsigned long long id)
return NULL;
}
static void ksmbd_expire_session(struct ksmbd_conn *conn)
static bool ksmbd_too_many_session_setups(struct ksmbd_conn *conn)
{
unsigned long id;
struct ksmbd_session *sess;
unsigned int pending = 0;
down_write(&sessions_table_lock);
down_write(&conn->session_lock);
xa_for_each(&conn->sessions, id, sess) {
if (READ_ONCE(sess->state) != SMB2_SESSION_IN_PROGRESS)
continue;
if (atomic_read(&sess->refcnt) <= 1 &&
(sess->state != SMB2_SESSION_VALID ||
time_after(jiffies,
sess->last_active + SMB2_SESSION_TIMEOUT))) {
time_after(jiffies, sess->last_active +
KSMBD_UNAUTHENTICATED_CONN_TIMEOUT)) {
xa_erase(&conn->sessions, sess->id);
ksmbd_session_remove_from_table(sess);
ksmbd_session_destroy(sess);
continue;
}
pending++;
}
up_write(&conn->session_lock);
up_write(&sessions_table_lock);
return pending >= KSMBD_MAX_PENDING_SESSIONS;
}
int ksmbd_session_register(struct ksmbd_conn *conn,
@ -461,9 +467,12 @@ int ksmbd_session_register(struct ksmbd_conn *conn,
sess->dialect = conn->dialect;
memcpy(sess->ClientGUID, conn->ClientGUID, SMB2_CLIENT_GUID_SIZE);
ksmbd_expire_session(conn);
ret = xa_err(xa_store(&conn->sessions, sess->id, sess,
KSMBD_DEFAULT_GFP));
/* Bound abandoned SessionId-zero authentication exchanges. */
if (ksmbd_too_many_session_setups(conn))
ret = -ENOSPC;
else
ret = xa_err(xa_store(&conn->sessions, sess->id, sess,
KSMBD_DEFAULT_GFP));
if (ret) {
down_write(&sessions_table_lock);
ksmbd_session_remove_from_table(sess);
@ -474,6 +483,105 @@ int ksmbd_session_register(struct ksmbd_conn *conn,
return ret;
}
void ksmbd_session_unregister(struct ksmbd_conn *conn,
struct ksmbd_session *sess)
{
struct ksmbd_conn *session_conns[KSMBD_MAX_CHANNELS];
struct channel *chann;
unsigned long index;
unsigned int nr_conns = 0, i;
bool removed = false;
down_write(&sessions_table_lock);
if (!hlist_unhashed(&sess->hlist)) {
/* Keep each channel connection stable under sessions_table_lock. */
down_read(&sess->chann_lock);
xa_for_each(&sess->ksmbd_chann_list, index, chann) {
if (nr_conns == ARRAY_SIZE(session_conns))
break;
session_conns[nr_conns++] = chann->conn;
}
up_read(&sess->chann_lock);
ksmbd_session_remove_from_table(sess);
removed = true;
}
down_write(&conn->session_lock);
if (xa_load(&conn->sessions, sess->id) == sess)
xa_erase(&conn->sessions, sess->id);
up_write(&conn->session_lock);
for (i = 0; i < nr_conns; i++) {
if (session_conns[i] == conn)
continue;
down_write(&session_conns[i]->session_lock);
if (xa_load(&session_conns[i]->sessions, sess->id) == sess)
xa_erase(&session_conns[i]->sessions, sess->id);
up_write(&session_conns[i]->session_lock);
}
up_write(&sessions_table_lock);
if (removed)
ksmbd_user_session_put(sess);
}
bool ksmbd_conn_has_valid_or_expired_session(struct ksmbd_conn *conn)
{
struct ksmbd_session *sess;
unsigned long id;
int state, bkt;
bool found = false;
down_read(&conn->session_lock);
xa_for_each(&conn->sessions, id, sess) {
state = READ_ONCE(sess->state);
if (state == SMB2_SESSION_VALID ||
state == SMB2_SESSION_EXPIRED) {
found = true;
break;
}
}
up_read(&conn->session_lock);
if (found)
return true;
/* A session bound through SMB3 multichannel is not in conn->sessions. */
down_read(&sessions_table_lock);
hash_for_each(sessions_table, bkt, sess, hlist) {
state = READ_ONCE(sess->state);
if (state != SMB2_SESSION_VALID &&
state != SMB2_SESSION_EXPIRED)
continue;
down_read(&sess->chann_lock);
found = xa_load(&sess->ksmbd_chann_list, (long)conn);
up_read(&sess->chann_lock);
if (found)
break;
}
up_read(&sessions_table_lock);
return found;
}
void ksmbd_expire_sessions(void)
{
struct ksmbd_session *sess;
u64 now = ktime_get_real_seconds();
int bkt;
down_read(&sessions_table_lock);
hash_for_each(sessions_table, bkt, sess, hlist) {
if (READ_ONCE(sess->state) != SMB2_SESSION_VALID ||
!sess->kerberos_expiry || now < sess->kerberos_expiry)
continue;
if (cmpxchg(&sess->state, SMB2_SESSION_VALID,
SMB2_SESSION_EXPIRED) == SMB2_SESSION_VALID)
ksmbd_counter_inc(KSMBD_COUNTER_SESSION_TIMEOUTS);
}
up_read(&sessions_table_lock);
}
static int ksmbd_chann_del(struct ksmbd_conn *conn, struct ksmbd_session *sess)
{
struct channel *chann;
@ -488,7 +596,7 @@ static int ksmbd_chann_del(struct ksmbd_conn *conn, struct ksmbd_session *sess)
return 0;
}
void ksmbd_sessions_deregister(struct ksmbd_conn *conn)
void ksmbd_conn_sessions_cleanup(struct ksmbd_conn *conn)
{
struct ksmbd_session *sess;
unsigned long id;

View File

@ -72,6 +72,8 @@ struct ksmbd_session {
struct rw_semaphore rpc_lock;
};
#define KSMBD_MAX_CHANNELS 32
static inline int test_session_flag(struct ksmbd_session *sess, int bit)
{
return sess->flags & bit;
@ -98,7 +100,11 @@ bool is_ksmbd_session_in_connection(struct ksmbd_conn *conn,
unsigned long long id);
int ksmbd_session_register(struct ksmbd_conn *conn,
struct ksmbd_session *sess);
void ksmbd_sessions_deregister(struct ksmbd_conn *conn);
void ksmbd_session_unregister(struct ksmbd_conn *conn,
struct ksmbd_session *sess);
void ksmbd_conn_sessions_cleanup(struct ksmbd_conn *conn);
bool ksmbd_conn_has_valid_or_expired_session(struct ksmbd_conn *conn);
void ksmbd_expire_sessions(void);
struct ksmbd_session *__session_lookup(unsigned long long id);
struct ksmbd_session *ksmbd_session_lookup_all(struct ksmbd_conn *conn,
unsigned long long id);

View File

@ -178,6 +178,8 @@ static int proc_show_ksmbd_stats(struct seq_file *m, void *v)
proc_show_runtime_totals(m);
seq_printf(m, "sessions:\t%lld\n",
ksmbd_counter_sum(KSMBD_COUNTER_SESSIONS));
seq_printf(m, "session_timeouts:\t%lld\n",
ksmbd_counter_sum(KSMBD_COUNTER_SESSION_TIMEOUTS));
seq_printf(m, "tree_connects:\t%lld\n",
ksmbd_counter_sum(KSMBD_COUNTER_TREE_CONNS));
seq_printf(m, "requests:\t%lld\n",

View File

@ -414,7 +414,7 @@ static int ksmbd_server_process_request(struct ksmbd_conn *conn)
static int ksmbd_server_terminate_conn(struct ksmbd_conn *conn)
{
ksmbd_sessions_deregister(conn);
ksmbd_conn_sessions_cleanup(conn);
destroy_lease_table(conn);
return 0;
}

View File

@ -85,8 +85,6 @@ struct channel *lookup_chann_list(struct ksmbd_session *sess, struct ksmbd_conn
return chann;
}
#define KSMBD_MAX_CHANNELS 32
static int register_session_channel(struct ksmbd_session *sess,
struct ksmbd_conn *conn,
const char *sess_key)
@ -933,8 +931,14 @@ static bool smb2_session_expired_cmd_allowed(struct ksmbd_work *work,
static bool smb2_session_kerberos_expired(struct ksmbd_session *sess)
{
return sess->kerberos_expiry &&
ktime_get_real_seconds() >= sess->kerberos_expiry;
if (!sess->kerberos_expiry ||
ktime_get_real_seconds() < sess->kerberos_expiry)
return false;
if (cmpxchg(&sess->state, SMB2_SESSION_VALID,
SMB2_SESSION_EXPIRED) == SMB2_SESSION_VALID)
ksmbd_counter_inc(KSMBD_COUNTER_SESSION_TIMEOUTS);
return true;
}
/**
@ -969,9 +973,8 @@ int smb2_check_user_session(struct ksmbd_work *work)
if (!work->next_smb2_rcv_hdr_off && sess_id)
work->sess = ksmbd_session_lookup_all_states(conn, sess_id);
if (work->sess) {
if (smb2_session_kerberos_expired(work->sess)) {
work->sess->state = SMB2_SESSION_EXPIRED;
} else if (work->sess->state != SMB2_SESSION_VALID) {
if (!smb2_session_kerberos_expired(work->sess) &&
work->sess->state != SMB2_SESSION_VALID) {
ksmbd_user_session_put(work->sess);
work->sess = NULL;
}
@ -996,8 +999,7 @@ int smb2_check_user_session(struct ksmbd_work *work)
sess_id, work->sess->id);
return -EINVAL;
}
if (smb2_session_kerberos_expired(work->sess))
work->sess->state = SMB2_SESSION_EXPIRED;
smb2_session_kerberos_expired(work->sess);
if (work->sess->state != SMB2_SESSION_VALID) {
pr_err("compound request on a non-valid session (state %d)\n",
work->sess->state);
@ -1014,7 +1016,6 @@ int smb2_check_user_session(struct ksmbd_work *work)
work->sess = ksmbd_session_lookup_all_states(conn, sess_id);
if (work->sess) {
if (smb2_session_kerberos_expired(work->sess)) {
work->sess->state = SMB2_SESSION_EXPIRED;
return smb2_session_expired_cmd_allowed(work, cmd) ?
1 : -EKEYEXPIRED;
}
@ -2436,7 +2437,7 @@ int smb2_sess_setup(struct ksmbd_work *work)
struct ksmbd_conn *conn = work->conn;
struct smb2_sess_setup_req *req;
struct smb2_sess_setup_rsp *rsp;
struct ksmbd_session *sess;
struct ksmbd_session *sess = NULL;
struct negotiate_message *negblob;
unsigned int negblob_len, negblob_off;
int rc = 0;
@ -2592,6 +2593,9 @@ int smb2_sess_setup(struct ksmbd_work *work)
goto out_err;
}
if (work->session_setup_reauth)
WRITE_ONCE(sess->state, SMB2_SESSION_IN_PROGRESS);
conn->binding = false;
}
work->sess = sess;
@ -2703,6 +2707,14 @@ int smb2_sess_setup(struct ksmbd_work *work)
}
if (rc < 0) {
bool setup_in_progress = sess &&
READ_ONCE(sess->state) == SMB2_SESSION_IN_PROGRESS &&
!(req->Flags & SMB2_SESSION_REQ_FLAG_BINDING);
/* Authentication errors must not leave the new session published. */
if (setup_in_progress)
ksmbd_session_unregister(conn, sess);
if (sess && conn->dialect == SMB311_PROT_ID &&
(req->Flags & SMB2_SESSION_REQ_FLAG_BINDING)) {
struct preauth_session *preauth_sess;
@ -2736,7 +2748,8 @@ int smb2_sess_setup(struct ksmbd_work *work)
* For binding requests, session belongs to another
* connection. Do not expire it.
*/
if (!(req->Flags & SMB2_SESSION_REQ_FLAG_BINDING)) {
if (!(req->Flags & SMB2_SESSION_REQ_FLAG_BINDING) &&
!setup_in_progress) {
sess->last_active = jiffies;
sess->kerberos_expiry = 0;
sess->state = SMB2_SESSION_EXPIRED;
@ -6262,21 +6275,18 @@ int smb2_query_dir(struct ksmbd_work *work)
* @reqOutputBufferLength: max buffer length expected in command response
* @fixed_len: minimum fixed response length
* @rsp: query info response buffer contains output buffer length
* @rsp_org: base response buffer pointer in case of chained response
*
* Return: 0 on success, otherwise error
*/
static int buffer_check_err(int reqOutputBufferLength,
unsigned int fixed_len,
struct smb2_query_info_rsp *rsp,
void *rsp_org)
struct smb2_query_info_rsp *rsp)
{
unsigned int output_len = le32_to_cpu(rsp->OutputBufferLength);
if (reqOutputBufferLength < fixed_len) {
pr_err("Invalid Buffer Size Requested\n");
rsp->hdr.Status = STATUS_INFO_LENGTH_MISMATCH;
*(__be32 *)rsp_org = cpu_to_be32(sizeof(struct smb2_hdr));
return -EINVAL;
}
@ -6287,8 +6297,7 @@ static int buffer_check_err(int reqOutputBufferLength,
return 0;
}
static void get_standard_info_pipe(struct smb2_query_info_rsp *rsp,
void *rsp_org)
static void get_standard_info_pipe(struct smb2_query_info_rsp *rsp)
{
struct smb2_file_standard_info *sinfo;
@ -6303,8 +6312,7 @@ static void get_standard_info_pipe(struct smb2_query_info_rsp *rsp,
cpu_to_le32(sizeof(struct smb2_file_standard_info));
}
static void get_internal_info_pipe(struct smb2_query_info_rsp *rsp, u64 num,
void *rsp_org)
static void get_internal_info_pipe(struct smb2_query_info_rsp *rsp, u64 num)
{
struct smb2_file_internal_info *file_info;
@ -6318,8 +6326,7 @@ static void get_internal_info_pipe(struct smb2_query_info_rsp *rsp, u64 num,
static int smb2_get_info_file_pipe(struct ksmbd_session *sess,
struct smb2_query_info_req *req,
struct smb2_query_info_rsp *rsp,
void *rsp_org)
struct smb2_query_info_rsp *rsp)
{
u64 id;
int rc;
@ -6344,16 +6351,16 @@ static int smb2_get_info_file_pipe(struct ksmbd_session *sess,
switch (req->FileInfoClass) {
case FILE_STANDARD_INFORMATION:
get_standard_info_pipe(rsp, rsp_org);
get_standard_info_pipe(rsp);
rc = buffer_check_err(le32_to_cpu(req->OutputBufferLength),
le32_to_cpu(rsp->OutputBufferLength),
rsp, rsp_org);
rsp);
break;
case FILE_INTERNAL_INFORMATION:
get_internal_info_pipe(rsp, id, rsp_org);
get_internal_info_pipe(rsp, id);
rc = buffer_check_err(le32_to_cpu(req->OutputBufferLength),
le32_to_cpu(rsp->OutputBufferLength),
rsp, rsp_org);
rsp);
break;
default:
ksmbd_debug(SMB, "smb2_info_file_pipe for %u not supported\n",
@ -7189,8 +7196,7 @@ static int smb2_get_info_file(struct ksmbd_work *work,
if (test_share_config_flag(work->tcon->share_conf,
KSMBD_SHARE_FLAG_PIPE)) {
/* smb2 info file called for pipe */
rc = smb2_get_info_file_pipe(work->sess, req, rsp,
work->response_buf);
rc = smb2_get_info_file_pipe(work->sess, req, rsp);
goto iov_pin_out;
}
@ -7299,13 +7305,16 @@ static int smb2_get_info_file(struct ksmbd_work *work,
case FILE_ALTERNATE_NAME_INFORMATION:
fixed_len = FILE_ALTERNATE_NAME_INFORMATION_SIZE;
break;
case FILE_NORMALIZED_NAME_INFORMATION:
fixed_len = FILE_NORMALIZED_NAME_INFORMATION_SIZE;
break;
case FILE_STREAM_INFORMATION:
fixed_len = FILE_STREAM_INFORMATION_SIZE;
break;
}
rc = buffer_check_err(le32_to_cpu(req->OutputBufferLength),
fixed_len,
rsp, work->response_buf);
rsp);
}
ksmbd_fd_put(work, fp);
@ -7576,7 +7585,7 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work,
}
rc = buffer_check_err(le32_to_cpu(req->OutputBufferLength),
fixed_len,
rsp, work->response_buf);
rsp);
path_put(&path);
if (!rc)
@ -7690,7 +7699,7 @@ static int smb2_get_info_sec(struct ksmbd_work *work,
rsp->OutputBufferLength = cpu_to_le32(secdesclen);
rc = buffer_check_err(le32_to_cpu(req->OutputBufferLength),
le32_to_cpu(rsp->OutputBufferLength),
rsp, work->response_buf);
rsp);
if (rc)
goto err_out;

View File

@ -61,8 +61,6 @@ struct preauth_integrity_info {
#define SMB2_SESSION_IN_PROGRESS BIT(0)
#define SMB2_SESSION_VALID BIT(1)
#define SMB2_SESSION_TIMEOUT (10 * HZ)
/* Apple Defined Contexts */
#define SMB2_CREATE_AAPL "AAPL"
@ -214,6 +212,7 @@ struct file_sparse {
#define FILE_ALLOCATION_INFORMATION_SIZE 19
#define FILE_END_OF_FILE_INFORMATION_SIZE 20
#define FILE_ALTERNATE_NAME_INFORMATION_SIZE 8
#define FILE_NORMALIZED_NAME_INFORMATION_SIZE 8
#define FILE_STREAM_INFORMATION_SIZE 32
#define FILE_PIPE_INFORMATION_SIZE 23
#define FILE_PIPE_LOCAL_INFORMATION_SIZE 24

View File

@ -15,6 +15,7 @@
enum {
KSMBD_COUNTER_SESSIONS = 0,
KSMBD_COUNTER_SESSION_TIMEOUTS,
KSMBD_COUNTER_TREE_CONNS,
KSMBD_COUNTER_REQUESTS,
KSMBD_COUNTER_STATUS_SUCCESS,