未验证 提交 1c9231cb 编写于 作者: O openeuler-ci-bot 提交者: Gitee

!1621 fix three CVEs by backport mainline patchs

Merge Pull Request from: @ci-robot 
 
PR sync from: ZhaoLong Wang <wangzhaolong1@huawei.com>
https://mailweb.openeuler.org/hyperkitty/list/kernel@openeuler.org/message/6ETLQBKJNMKNALJRDIYCV27MJA2XG66X/ 
mainline patch f5c779b7("ksmbd: fix racy issue from session setup and
logoff") It fixes three CVEs:

 CVE-2023-32250
 CVE-2023-32252
 CVE-2023-32257

In order to successfully apply the patch, we chose to incorporate the
related pre-installed bugfix patch.

Colin Ian King (1):
  ksmbd: Fix spelling mistake "excceed" -> "exceeded"

Dawei Li (1):
  ksmbd: Implements sess->ksmbd_chann_list as xarray

Namjae Jeon (2):
  ksmbd: limit pdu length size according to connection status
  ksmbd: fix racy issue from session setup and logoff


-- 
2.34.3
 
https://gitee.com/src-openeuler/kernel/issues/I7BG0L
https://gitee.com/openeuler/kernel/issues/I7CETC 
 
Link:https://gitee.com/openeuler/kernel/pulls/1621 

Reviewed-by: Jialin Zhang <zhangjialin11@huawei.com> 
Signed-off-by: Jialin Zhang <zhangjialin11@huawei.com> 
...@@ -56,7 +56,7 @@ struct ksmbd_conn *ksmbd_conn_alloc(void) ...@@ -56,7 +56,7 @@ struct ksmbd_conn *ksmbd_conn_alloc(void)
return NULL; return NULL;
conn->need_neg = true; conn->need_neg = true;
conn->status = KSMBD_SESS_NEW; ksmbd_conn_set_new(conn);
conn->local_nls = load_nls("utf8"); conn->local_nls = load_nls("utf8");
if (!conn->local_nls) if (!conn->local_nls)
conn->local_nls = load_nls_default(); conn->local_nls = load_nls_default();
...@@ -143,12 +143,12 @@ int ksmbd_conn_try_dequeue_request(struct ksmbd_work *work) ...@@ -143,12 +143,12 @@ int ksmbd_conn_try_dequeue_request(struct ksmbd_work *work)
return ret; return ret;
} }
static void ksmbd_conn_lock(struct ksmbd_conn *conn) void ksmbd_conn_lock(struct ksmbd_conn *conn)
{ {
mutex_lock(&conn->srv_mutex); mutex_lock(&conn->srv_mutex);
} }
static void ksmbd_conn_unlock(struct ksmbd_conn *conn) void ksmbd_conn_unlock(struct ksmbd_conn *conn)
{ {
mutex_unlock(&conn->srv_mutex); mutex_unlock(&conn->srv_mutex);
} }
...@@ -239,7 +239,7 @@ bool ksmbd_conn_alive(struct ksmbd_conn *conn) ...@@ -239,7 +239,7 @@ bool ksmbd_conn_alive(struct ksmbd_conn *conn)
if (!ksmbd_server_running()) if (!ksmbd_server_running())
return false; return false;
if (conn->status == KSMBD_SESS_EXITING) if (ksmbd_conn_exiting(conn))
return false; return false;
if (kthread_should_stop()) if (kthread_should_stop())
...@@ -274,7 +274,7 @@ int ksmbd_conn_handler_loop(void *p) ...@@ -274,7 +274,7 @@ int ksmbd_conn_handler_loop(void *p)
{ {
struct ksmbd_conn *conn = (struct ksmbd_conn *)p; struct ksmbd_conn *conn = (struct ksmbd_conn *)p;
struct ksmbd_transport *t = conn->transport; struct ksmbd_transport *t = conn->transport;
unsigned int pdu_size; unsigned int pdu_size, max_allowed_pdu_size;
char hdr_buf[4] = {0,}; char hdr_buf[4] = {0,};
int size; int size;
...@@ -299,13 +299,26 @@ int ksmbd_conn_handler_loop(void *p) ...@@ -299,13 +299,26 @@ int ksmbd_conn_handler_loop(void *p)
pdu_size = get_rfc1002_len(hdr_buf); pdu_size = get_rfc1002_len(hdr_buf);
ksmbd_debug(CONN, "RFC1002 header %u bytes\n", pdu_size); ksmbd_debug(CONN, "RFC1002 header %u bytes\n", pdu_size);
if (ksmbd_conn_good(conn))
max_allowed_pdu_size =
SMB3_MAX_MSGSIZE + conn->vals->max_write_size;
else
max_allowed_pdu_size = SMB3_MAX_MSGSIZE;
if (pdu_size > max_allowed_pdu_size) {
pr_err_ratelimited("PDU length(%u) exceeded maximum allowed pdu size(%u) on connection(%d)\n",
pdu_size, max_allowed_pdu_size,
READ_ONCE(conn->status));
break;
}
/* /*
* Check if pdu size is valid (min : smb header size, * Check if pdu size is valid (min : smb header size,
* max : 0x00FFFFFF). * max : 0x00FFFFFF).
*/ */
if (pdu_size < __SMB2_HEADER_STRUCTURE_SIZE || if (pdu_size < __SMB2_HEADER_STRUCTURE_SIZE ||
pdu_size > MAX_STREAM_PROT_LEN) { pdu_size > MAX_STREAM_PROT_LEN) {
continue; break;
} }
/* 4 for rfc1002 length field */ /* 4 for rfc1002 length field */
...@@ -400,7 +413,7 @@ static void stop_sessions(void) ...@@ -400,7 +413,7 @@ static void stop_sessions(void)
if (task) if (task)
ksmbd_debug(CONN, "Stop session handler %s/%d\n", ksmbd_debug(CONN, "Stop session handler %s/%d\n",
task->comm, task_pid_nr(task)); task->comm, task_pid_nr(task));
conn->status = KSMBD_SESS_EXITING; ksmbd_conn_set_exiting(conn);
if (t->ops->shutdown) { if (t->ops->shutdown) {
read_unlock(&conn_list_lock); read_unlock(&conn_list_lock);
t->ops->shutdown(t); t->ops->shutdown(t);
......
...@@ -154,6 +154,8 @@ void ksmbd_conn_init_server_callbacks(struct ksmbd_conn_ops *ops); ...@@ -154,6 +154,8 @@ void ksmbd_conn_init_server_callbacks(struct ksmbd_conn_ops *ops);
int ksmbd_conn_handler_loop(void *p); int ksmbd_conn_handler_loop(void *p);
int ksmbd_conn_transport_init(void); int ksmbd_conn_transport_init(void);
void ksmbd_conn_transport_destroy(void); void ksmbd_conn_transport_destroy(void);
void ksmbd_conn_lock(struct ksmbd_conn *conn);
void ksmbd_conn_unlock(struct ksmbd_conn *conn);
/* /*
* WARNING * WARNING
...@@ -161,43 +163,48 @@ void ksmbd_conn_transport_destroy(void); ...@@ -161,43 +163,48 @@ void ksmbd_conn_transport_destroy(void);
* This is a hack. We will move status to a proper place once we land * This is a hack. We will move status to a proper place once we land
* a multi-sessions support. * a multi-sessions support.
*/ */
static inline bool ksmbd_conn_good(struct ksmbd_work *work) static inline bool ksmbd_conn_good(struct ksmbd_conn *conn)
{ {
return work->conn->status == KSMBD_SESS_GOOD; return READ_ONCE(conn->status) == KSMBD_SESS_GOOD;
} }
static inline bool ksmbd_conn_need_negotiate(struct ksmbd_work *work) static inline bool ksmbd_conn_need_negotiate(struct ksmbd_conn *conn)
{ {
return work->conn->status == KSMBD_SESS_NEED_NEGOTIATE; return READ_ONCE(conn->status) == KSMBD_SESS_NEED_NEGOTIATE;
} }
static inline bool ksmbd_conn_need_reconnect(struct ksmbd_work *work) static inline bool ksmbd_conn_need_reconnect(struct ksmbd_conn *conn)
{ {
return work->conn->status == KSMBD_SESS_NEED_RECONNECT; return READ_ONCE(conn->status) == KSMBD_SESS_NEED_RECONNECT;
} }
static inline bool ksmbd_conn_exiting(struct ksmbd_work *work) static inline bool ksmbd_conn_exiting(struct ksmbd_conn *conn)
{ {
return work->conn->status == KSMBD_SESS_EXITING; return READ_ONCE(conn->status) == KSMBD_SESS_EXITING;
} }
static inline void ksmbd_conn_set_good(struct ksmbd_work *work) static inline void ksmbd_conn_set_new(struct ksmbd_conn *conn)
{ {
work->conn->status = KSMBD_SESS_GOOD; WRITE_ONCE(conn->status, KSMBD_SESS_NEW);
} }
static inline void ksmbd_conn_set_need_negotiate(struct ksmbd_work *work) static inline void ksmbd_conn_set_good(struct ksmbd_conn *conn)
{ {
work->conn->status = KSMBD_SESS_NEED_NEGOTIATE; WRITE_ONCE(conn->status, KSMBD_SESS_GOOD);
} }
static inline void ksmbd_conn_set_need_reconnect(struct ksmbd_work *work) static inline void ksmbd_conn_set_need_negotiate(struct ksmbd_conn *conn)
{ {
work->conn->status = KSMBD_SESS_NEED_RECONNECT; WRITE_ONCE(conn->status, KSMBD_SESS_NEED_NEGOTIATE);
} }
static inline void ksmbd_conn_set_exiting(struct ksmbd_work *work) static inline void ksmbd_conn_set_need_reconnect(struct ksmbd_conn *conn)
{ {
work->conn->status = KSMBD_SESS_EXITING; WRITE_ONCE(conn->status, KSMBD_SESS_NEED_RECONNECT);
}
static inline void ksmbd_conn_set_exiting(struct ksmbd_conn *conn)
{
WRITE_ONCE(conn->status, KSMBD_SESS_EXITING);
} }
#endif /* __CONNECTION_H__ */ #endif /* __CONNECTION_H__ */
...@@ -30,15 +30,15 @@ struct ksmbd_session_rpc { ...@@ -30,15 +30,15 @@ struct ksmbd_session_rpc {
static void free_channel_list(struct ksmbd_session *sess) static void free_channel_list(struct ksmbd_session *sess)
{ {
struct channel *chann, *tmp; struct channel *chann;
unsigned long index;
write_lock(&sess->chann_lock); xa_for_each(&sess->ksmbd_chann_list, index, chann) {
list_for_each_entry_safe(chann, tmp, &sess->ksmbd_chann_list, xa_erase(&sess->ksmbd_chann_list, index);
chann_list) {
list_del(&chann->chann_list);
kfree(chann); kfree(chann);
} }
write_unlock(&sess->chann_lock);
xa_destroy(&sess->ksmbd_chann_list);
} }
static void __session_rpc_close(struct ksmbd_session *sess, static void __session_rpc_close(struct ksmbd_session *sess,
...@@ -188,21 +188,15 @@ int ksmbd_session_register(struct ksmbd_conn *conn, ...@@ -188,21 +188,15 @@ int ksmbd_session_register(struct ksmbd_conn *conn,
static int ksmbd_chann_del(struct ksmbd_conn *conn, struct ksmbd_session *sess) static int ksmbd_chann_del(struct ksmbd_conn *conn, struct ksmbd_session *sess)
{ {
struct channel *chann, *tmp; struct channel *chann;
write_lock(&sess->chann_lock); chann = xa_erase(&sess->ksmbd_chann_list, (long)conn);
list_for_each_entry_safe(chann, tmp, &sess->ksmbd_chann_list, if (!chann)
chann_list) { return -ENOENT;
if (chann->conn == conn) {
list_del(&chann->chann_list);
kfree(chann);
write_unlock(&sess->chann_lock);
return 0;
}
}
write_unlock(&sess->chann_lock);
return -ENOENT; kfree(chann);
return 0;
} }
void ksmbd_sessions_deregister(struct ksmbd_conn *conn) void ksmbd_sessions_deregister(struct ksmbd_conn *conn)
...@@ -232,7 +226,7 @@ void ksmbd_sessions_deregister(struct ksmbd_conn *conn) ...@@ -232,7 +226,7 @@ void ksmbd_sessions_deregister(struct ksmbd_conn *conn)
return; return;
sess_destroy: sess_destroy:
if (list_empty(&sess->ksmbd_chann_list)) { if (xa_empty(&sess->ksmbd_chann_list)) {
xa_erase(&conn->sessions, sess->id); xa_erase(&conn->sessions, sess->id);
ksmbd_session_destroy(sess); ksmbd_session_destroy(sess);
} }
...@@ -318,6 +312,9 @@ static struct ksmbd_session *__session_create(int protocol) ...@@ -318,6 +312,9 @@ static struct ksmbd_session *__session_create(int protocol)
struct ksmbd_session *sess; struct ksmbd_session *sess;
int ret; int ret;
if (protocol != CIFDS_SESSION_FLAG_SMB2)
return NULL;
sess = kzalloc(sizeof(struct ksmbd_session), GFP_KERNEL); sess = kzalloc(sizeof(struct ksmbd_session), GFP_KERNEL);
if (!sess) if (!sess)
return NULL; return NULL;
...@@ -325,32 +322,23 @@ static struct ksmbd_session *__session_create(int protocol) ...@@ -325,32 +322,23 @@ static struct ksmbd_session *__session_create(int protocol)
if (ksmbd_init_file_table(&sess->file_table)) if (ksmbd_init_file_table(&sess->file_table))
goto error; goto error;
sess->state = SMB2_SESSION_IN_PROGRESS;
set_session_flag(sess, protocol); set_session_flag(sess, protocol);
xa_init(&sess->tree_conns); xa_init(&sess->tree_conns);
INIT_LIST_HEAD(&sess->ksmbd_chann_list); xa_init(&sess->ksmbd_chann_list);
INIT_LIST_HEAD(&sess->rpc_handle_list); INIT_LIST_HEAD(&sess->rpc_handle_list);
sess->sequence_number = 1; sess->sequence_number = 1;
rwlock_init(&sess->chann_lock);
switch (protocol) {
case CIFDS_SESSION_FLAG_SMB2:
ret = __init_smb2_session(sess);
break;
default:
ret = -EINVAL;
break;
}
ret = __init_smb2_session(sess);
if (ret) if (ret)
goto error; goto error;
ida_init(&sess->tree_conn_ida); ida_init(&sess->tree_conn_ida);
if (protocol == CIFDS_SESSION_FLAG_SMB2) { down_write(&sessions_table_lock);
down_write(&sessions_table_lock); hash_add(sessions_table, &sess->hlist, sess->id);
hash_add(sessions_table, &sess->hlist, sess->id); up_write(&sessions_table_lock);
up_write(&sessions_table_lock);
}
return sess; return sess;
error: error:
......
...@@ -21,7 +21,6 @@ struct ksmbd_file_table; ...@@ -21,7 +21,6 @@ struct ksmbd_file_table;
struct channel { struct channel {
__u8 smb3signingkey[SMB3_SIGN_KEY_SIZE]; __u8 smb3signingkey[SMB3_SIGN_KEY_SIZE];
struct ksmbd_conn *conn; struct ksmbd_conn *conn;
struct list_head chann_list;
}; };
struct preauth_session { struct preauth_session {
...@@ -50,8 +49,7 @@ struct ksmbd_session { ...@@ -50,8 +49,7 @@ struct ksmbd_session {
char sess_key[CIFS_KEY_SIZE]; char sess_key[CIFS_KEY_SIZE];
struct hlist_node hlist; struct hlist_node hlist;
rwlock_t chann_lock; struct xarray ksmbd_chann_list;
struct list_head ksmbd_chann_list;
struct xarray tree_conns; struct xarray tree_conns;
struct ida tree_conn_ida; struct ida tree_conn_ida;
struct list_head rpc_handle_list; struct list_head rpc_handle_list;
......
...@@ -93,7 +93,8 @@ static inline int check_conn_state(struct ksmbd_work *work) ...@@ -93,7 +93,8 @@ static inline int check_conn_state(struct ksmbd_work *work)
{ {
struct smb_hdr *rsp_hdr; struct smb_hdr *rsp_hdr;
if (ksmbd_conn_exiting(work) || ksmbd_conn_need_reconnect(work)) { if (ksmbd_conn_exiting(work->conn) ||
ksmbd_conn_need_reconnect(work->conn)) {
rsp_hdr = work->response_buf; rsp_hdr = work->response_buf;
rsp_hdr->Status.CifsError = STATUS_CONNECTION_DISCONNECTED; rsp_hdr->Status.CifsError = STATUS_CONNECTION_DISCONNECTED;
return 1; return 1;
......
...@@ -74,14 +74,7 @@ static inline bool check_session_id(struct ksmbd_conn *conn, u64 id) ...@@ -74,14 +74,7 @@ static inline bool check_session_id(struct ksmbd_conn *conn, u64 id)
struct channel *lookup_chann_list(struct ksmbd_session *sess, struct ksmbd_conn *conn) struct channel *lookup_chann_list(struct ksmbd_session *sess, struct ksmbd_conn *conn)
{ {
struct channel *chann; return xa_load(&sess->ksmbd_chann_list, (long)conn);
list_for_each_entry(chann, &sess->ksmbd_chann_list, chann_list) {
if (chann->conn == conn)
return chann;
}
return NULL;
} }
/** /**
...@@ -257,7 +250,7 @@ int init_smb2_neg_rsp(struct ksmbd_work *work) ...@@ -257,7 +250,7 @@ int init_smb2_neg_rsp(struct ksmbd_work *work)
rsp = smb2_get_msg(work->response_buf); rsp = smb2_get_msg(work->response_buf);
WARN_ON(ksmbd_conn_good(work)); WARN_ON(ksmbd_conn_good(conn));
rsp->StructureSize = cpu_to_le16(65); rsp->StructureSize = cpu_to_le16(65);
ksmbd_debug(SMB, "conn->dialect 0x%x\n", conn->dialect); ksmbd_debug(SMB, "conn->dialect 0x%x\n", conn->dialect);
...@@ -287,7 +280,7 @@ int init_smb2_neg_rsp(struct ksmbd_work *work) ...@@ -287,7 +280,7 @@ int init_smb2_neg_rsp(struct ksmbd_work *work)
rsp->SecurityMode |= SMB2_NEGOTIATE_SIGNING_REQUIRED_LE; rsp->SecurityMode |= SMB2_NEGOTIATE_SIGNING_REQUIRED_LE;
conn->use_spnego = true; conn->use_spnego = true;
ksmbd_conn_set_need_negotiate(work); ksmbd_conn_set_need_negotiate(conn);
return 0; return 0;
} }
...@@ -581,7 +574,7 @@ int smb2_check_user_session(struct ksmbd_work *work) ...@@ -581,7 +574,7 @@ int smb2_check_user_session(struct ksmbd_work *work)
cmd == SMB2_SESSION_SETUP_HE) cmd == SMB2_SESSION_SETUP_HE)
return 0; return 0;
if (!ksmbd_conn_good(work)) if (!ksmbd_conn_good(conn))
return -EINVAL; return -EINVAL;
sess_id = le64_to_cpu(req_hdr->SessionId); sess_id = le64_to_cpu(req_hdr->SessionId);
...@@ -599,6 +592,7 @@ static void destroy_previous_session(struct ksmbd_conn *conn, ...@@ -599,6 +592,7 @@ static void destroy_previous_session(struct ksmbd_conn *conn,
struct ksmbd_session *prev_sess = ksmbd_session_lookup_slowpath(id); struct ksmbd_session *prev_sess = ksmbd_session_lookup_slowpath(id);
struct ksmbd_user *prev_user; struct ksmbd_user *prev_user;
struct channel *chann; struct channel *chann;
long index;
if (!prev_sess) if (!prev_sess)
return; return;
...@@ -612,10 +606,8 @@ static void destroy_previous_session(struct ksmbd_conn *conn, ...@@ -612,10 +606,8 @@ static void destroy_previous_session(struct ksmbd_conn *conn,
return; return;
prev_sess->state = SMB2_SESSION_EXPIRED; prev_sess->state = SMB2_SESSION_EXPIRED;
write_lock(&prev_sess->chann_lock); xa_for_each(&prev_sess->ksmbd_chann_list, index, chann)
list_for_each_entry(chann, &prev_sess->ksmbd_chann_list, chann_list) ksmbd_conn_set_exiting(chann->conn);
chann->conn->status = KSMBD_SESS_EXITING;
write_unlock(&prev_sess->chann_lock);
} }
/** /**
...@@ -1077,7 +1069,7 @@ int smb2_handle_negotiate(struct ksmbd_work *work) ...@@ -1077,7 +1069,7 @@ int smb2_handle_negotiate(struct ksmbd_work *work)
ksmbd_debug(SMB, "Received negotiate request\n"); ksmbd_debug(SMB, "Received negotiate request\n");
conn->need_neg = false; conn->need_neg = false;
if (ksmbd_conn_good(work)) { if (ksmbd_conn_good(conn)) {
pr_err("conn->tcp_status is already in CifsGood State\n"); pr_err("conn->tcp_status is already in CifsGood State\n");
work->send_no_response = 1; work->send_no_response = 1;
return rc; return rc;
...@@ -1232,7 +1224,7 @@ int smb2_handle_negotiate(struct ksmbd_work *work) ...@@ -1232,7 +1224,7 @@ int smb2_handle_negotiate(struct ksmbd_work *work)
} }
conn->srv_sec_mode = le16_to_cpu(rsp->SecurityMode); conn->srv_sec_mode = le16_to_cpu(rsp->SecurityMode);
ksmbd_conn_set_need_negotiate(work); ksmbd_conn_set_need_negotiate(conn);
err_out: err_out:
if (rc < 0) if (rc < 0)
...@@ -1521,19 +1513,14 @@ static int ntlm_authenticate(struct ksmbd_work *work) ...@@ -1521,19 +1513,14 @@ static int ntlm_authenticate(struct ksmbd_work *work)
binding_session: binding_session:
if (conn->dialect >= SMB30_PROT_ID) { if (conn->dialect >= SMB30_PROT_ID) {
read_lock(&sess->chann_lock);
chann = lookup_chann_list(sess, conn); chann = lookup_chann_list(sess, conn);
read_unlock(&sess->chann_lock);
if (!chann) { if (!chann) {
chann = kmalloc(sizeof(struct channel), GFP_KERNEL); chann = kmalloc(sizeof(struct channel), GFP_KERNEL);
if (!chann) if (!chann)
return -ENOMEM; return -ENOMEM;
chann->conn = conn; chann->conn = conn;
INIT_LIST_HEAD(&chann->chann_list); xa_store(&sess->ksmbd_chann_list, (long)conn, chann, GFP_KERNEL);
write_lock(&sess->chann_lock);
list_add(&chann->chann_list, &sess->ksmbd_chann_list);
write_unlock(&sess->chann_lock);
} }
} }
...@@ -1607,19 +1594,14 @@ static int krb5_authenticate(struct ksmbd_work *work) ...@@ -1607,19 +1594,14 @@ static int krb5_authenticate(struct ksmbd_work *work)
} }
if (conn->dialect >= SMB30_PROT_ID) { if (conn->dialect >= SMB30_PROT_ID) {
read_lock(&sess->chann_lock);
chann = lookup_chann_list(sess, conn); chann = lookup_chann_list(sess, conn);
read_unlock(&sess->chann_lock);
if (!chann) { if (!chann) {
chann = kmalloc(sizeof(struct channel), GFP_KERNEL); chann = kmalloc(sizeof(struct channel), GFP_KERNEL);
if (!chann) if (!chann)
return -ENOMEM; return -ENOMEM;
chann->conn = conn; chann->conn = conn;
INIT_LIST_HEAD(&chann->chann_list); xa_store(&sess->ksmbd_chann_list, (long)conn, chann, GFP_KERNEL);
write_lock(&sess->chann_lock);
list_add(&chann->chann_list, &sess->ksmbd_chann_list);
write_unlock(&sess->chann_lock);
} }
} }
...@@ -1662,6 +1644,7 @@ int smb2_sess_setup(struct ksmbd_work *work) ...@@ -1662,6 +1644,7 @@ int smb2_sess_setup(struct ksmbd_work *work)
rsp->SecurityBufferLength = 0; rsp->SecurityBufferLength = 0;
inc_rfc1001_len(work->response_buf, 9); inc_rfc1001_len(work->response_buf, 9);
ksmbd_conn_lock(conn);
if (!req->hdr.SessionId) { if (!req->hdr.SessionId) {
sess = ksmbd_smb2_session_create(); sess = ksmbd_smb2_session_create();
if (!sess) { if (!sess) {
...@@ -1709,6 +1692,12 @@ int smb2_sess_setup(struct ksmbd_work *work) ...@@ -1709,6 +1692,12 @@ int smb2_sess_setup(struct ksmbd_work *work)
goto out_err; goto out_err;
} }
if (ksmbd_conn_need_reconnect(conn)) {
rc = -EFAULT;
sess = NULL;
goto out_err;
}
if (ksmbd_session_lookup(conn, sess_id)) { if (ksmbd_session_lookup(conn, sess_id)) {
rc = -EACCES; rc = -EACCES;
goto out_err; goto out_err;
...@@ -1728,12 +1717,20 @@ int smb2_sess_setup(struct ksmbd_work *work) ...@@ -1728,12 +1717,20 @@ int smb2_sess_setup(struct ksmbd_work *work)
rc = -ENOENT; rc = -ENOENT;
goto out_err; goto out_err;
} }
if (sess->state == SMB2_SESSION_EXPIRED) {
rc = -EFAULT;
goto out_err;
}
if (ksmbd_conn_need_reconnect(conn)) {
rc = -EFAULT;
sess = NULL;
goto out_err;
}
} }
work->sess = sess; work->sess = sess;
if (sess->state == SMB2_SESSION_EXPIRED)
sess->state = SMB2_SESSION_IN_PROGRESS;
negblob_off = le16_to_cpu(req->SecurityBufferOffset); negblob_off = le16_to_cpu(req->SecurityBufferOffset);
negblob_len = le16_to_cpu(req->SecurityBufferLength); negblob_len = le16_to_cpu(req->SecurityBufferLength);
if (negblob_off < offsetof(struct smb2_sess_setup_req, Buffer) || if (negblob_off < offsetof(struct smb2_sess_setup_req, Buffer) ||
...@@ -1763,8 +1760,10 @@ int smb2_sess_setup(struct ksmbd_work *work) ...@@ -1763,8 +1760,10 @@ int smb2_sess_setup(struct ksmbd_work *work)
goto out_err; goto out_err;
} }
ksmbd_conn_set_good(work); if (!ksmbd_conn_need_reconnect(conn)) {
sess->state = SMB2_SESSION_VALID; ksmbd_conn_set_good(conn);
sess->state = SMB2_SESSION_VALID;
}
kfree(sess->Preauth_HashValue); kfree(sess->Preauth_HashValue);
sess->Preauth_HashValue = NULL; sess->Preauth_HashValue = NULL;
} else if (conn->preferred_auth_mech == KSMBD_AUTH_NTLMSSP) { } else if (conn->preferred_auth_mech == KSMBD_AUTH_NTLMSSP) {
...@@ -1786,8 +1785,10 @@ int smb2_sess_setup(struct ksmbd_work *work) ...@@ -1786,8 +1785,10 @@ int smb2_sess_setup(struct ksmbd_work *work)
if (rc) if (rc)
goto out_err; goto out_err;
ksmbd_conn_set_good(work); if (!ksmbd_conn_need_reconnect(conn)) {
sess->state = SMB2_SESSION_VALID; ksmbd_conn_set_good(conn);
sess->state = SMB2_SESSION_VALID;
}
if (conn->binding) { if (conn->binding) {
struct preauth_session *preauth_sess; struct preauth_session *preauth_sess;
...@@ -1853,14 +1854,13 @@ int smb2_sess_setup(struct ksmbd_work *work) ...@@ -1853,14 +1854,13 @@ int smb2_sess_setup(struct ksmbd_work *work)
if (sess->user && sess->user->flags & KSMBD_USER_FLAG_DELAY_SESSION) if (sess->user && sess->user->flags & KSMBD_USER_FLAG_DELAY_SESSION)
try_delay = true; try_delay = true;
xa_erase(&conn->sessions, sess->id); sess->state = SMB2_SESSION_EXPIRED;
ksmbd_session_destroy(sess);
work->sess = NULL;
if (try_delay) if (try_delay)
ssleep(5); ssleep(5);
} }
} }
ksmbd_conn_unlock(conn);
return rc; return rc;
} }
...@@ -2080,21 +2080,24 @@ int smb2_session_logoff(struct ksmbd_work *work) ...@@ -2080,21 +2080,24 @@ int smb2_session_logoff(struct ksmbd_work *work)
{ {
struct ksmbd_conn *conn = work->conn; struct ksmbd_conn *conn = work->conn;
struct smb2_logoff_rsp *rsp = smb2_get_msg(work->response_buf); struct smb2_logoff_rsp *rsp = smb2_get_msg(work->response_buf);
struct ksmbd_session *sess = work->sess; struct ksmbd_session *sess;
struct smb2_logoff_req *req = smb2_get_msg(work->request_buf);
rsp->StructureSize = cpu_to_le16(4); rsp->StructureSize = cpu_to_le16(4);
inc_rfc1001_len(work->response_buf, 4); inc_rfc1001_len(work->response_buf, 4);
ksmbd_debug(SMB, "request\n"); ksmbd_debug(SMB, "request\n");
/* setting CifsExiting here may race with start_tcp_sess */ ksmbd_conn_set_need_reconnect(conn);
ksmbd_conn_set_need_reconnect(work);
ksmbd_close_session_fds(work); ksmbd_close_session_fds(work);
ksmbd_conn_wait_idle(conn); ksmbd_conn_wait_idle(conn);
/*
* Re-lookup session to validate if session is deleted
* while waiting request complete
*/
sess = ksmbd_session_lookup(conn, le64_to_cpu(req->hdr.SessionId));
if (ksmbd_tree_conn_session_logoff(sess)) { if (ksmbd_tree_conn_session_logoff(sess)) {
struct smb2_logoff_req *req = smb2_get_msg(work->request_buf);
ksmbd_debug(SMB, "Invalid tid %d\n", req->hdr.Id.SyncId.TreeId); ksmbd_debug(SMB, "Invalid tid %d\n", req->hdr.Id.SyncId.TreeId);
rsp->hdr.Status = STATUS_NETWORK_NAME_DELETED; rsp->hdr.Status = STATUS_NETWORK_NAME_DELETED;
smb2_set_err_rsp(work); smb2_set_err_rsp(work);
...@@ -2106,9 +2109,7 @@ int smb2_session_logoff(struct ksmbd_work *work) ...@@ -2106,9 +2109,7 @@ int smb2_session_logoff(struct ksmbd_work *work)
ksmbd_free_user(sess->user); ksmbd_free_user(sess->user);
sess->user = NULL; sess->user = NULL;
ksmbd_conn_set_need_negotiate(conn);
/* let start_tcp_sess free connection info now */
ksmbd_conn_set_need_negotiate(work);
return 0; return 0;
} }
...@@ -8348,14 +8349,11 @@ int smb3_check_sign_req(struct ksmbd_work *work) ...@@ -8348,14 +8349,11 @@ int smb3_check_sign_req(struct ksmbd_work *work)
if (le16_to_cpu(hdr->Command) == SMB2_SESSION_SETUP_HE) { if (le16_to_cpu(hdr->Command) == SMB2_SESSION_SETUP_HE) {
signing_key = work->sess->smb3signingkey; signing_key = work->sess->smb3signingkey;
} else { } else {
read_lock(&work->sess->chann_lock);
chann = lookup_chann_list(work->sess, conn); chann = lookup_chann_list(work->sess, conn);
if (!chann) { if (!chann) {
read_unlock(&work->sess->chann_lock);
return 0; return 0;
} }
signing_key = chann->smb3signingkey; signing_key = chann->smb3signingkey;
read_unlock(&work->sess->chann_lock);
} }
if (!signing_key) { if (!signing_key) {
...@@ -8415,14 +8413,11 @@ void smb3_set_sign_rsp(struct ksmbd_work *work) ...@@ -8415,14 +8413,11 @@ void smb3_set_sign_rsp(struct ksmbd_work *work)
le16_to_cpu(hdr->Command) == SMB2_SESSION_SETUP_HE) { le16_to_cpu(hdr->Command) == SMB2_SESSION_SETUP_HE) {
signing_key = work->sess->smb3signingkey; signing_key = work->sess->smb3signingkey;
} else { } else {
read_lock(&work->sess->chann_lock);
chann = lookup_chann_list(work->sess, work->conn); chann = lookup_chann_list(work->sess, work->conn);
if (!chann) { if (!chann) {
read_unlock(&work->sess->chann_lock);
return; return;
} }
signing_key = chann->smb3signingkey; signing_key = chann->smb3signingkey;
read_unlock(&work->sess->chann_lock);
} }
if (!signing_key) if (!signing_key)
......
...@@ -113,8 +113,9 @@ ...@@ -113,8 +113,9 @@
#define SMB21_DEFAULT_IOSIZE (1024 * 1024) #define SMB21_DEFAULT_IOSIZE (1024 * 1024)
#define SMB3_DEFAULT_IOSIZE (4 * 1024 * 1024) #define SMB3_DEFAULT_IOSIZE (4 * 1024 * 1024)
#define SMB3_DEFAULT_TRANS_SIZE (1024 * 1024) #define SMB3_DEFAULT_TRANS_SIZE (1024 * 1024)
#define SMB3_MIN_IOSIZE (64 * 1024) #define SMB3_MIN_IOSIZE (64 * 1024)
#define SMB3_MAX_IOSIZE (8 * 1024 * 1024) #define SMB3_MAX_IOSIZE (8 * 1024 * 1024)
#define SMB3_MAX_MSGSIZE (4 * 4096)
/* /*
* SMB2 Header Definition * SMB2 Header Definition
......
...@@ -318,7 +318,7 @@ static int ksmbd_tcp_readv(struct tcp_transport *t, struct kvec *iov_orig, ...@@ -318,7 +318,7 @@ static int ksmbd_tcp_readv(struct tcp_transport *t, struct kvec *iov_orig,
if (length == -EINTR) { if (length == -EINTR) {
total_read = -ESHUTDOWN; total_read = -ESHUTDOWN;
break; break;
} else if (conn->status == KSMBD_SESS_NEED_RECONNECT) { } else if (ksmbd_conn_need_reconnect(conn)) {
total_read = -EAGAIN; total_read = -EAGAIN;
break; break;
} else if (length == -ERESTARTSYS || length == -EAGAIN) { } else if (length == -ERESTARTSYS || length == -EAGAIN) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册