mirror of
https://github.com/torvalds/linux.git
synced 2026-09-23 05:04:02 +02:00
- 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:
commit
c3d85c669d
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
enum {
|
||||
KSMBD_COUNTER_SESSIONS = 0,
|
||||
KSMBD_COUNTER_SESSION_TIMEOUTS,
|
||||
KSMBD_COUNTER_TREE_CONNS,
|
||||
KSMBD_COUNTER_REQUESTS,
|
||||
KSMBD_COUNTER_STATUS_SUCCESS,
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user