From 1d9c4172110e645b383ff13eee759728d74f1a5d Mon Sep 17 00:00:00 2001 From: Dawei Li Date: Sun, 15 Jan 2023 18:32:04 +0800 Subject: ksmbd: Implements sess->ksmbd_chann_list as xarray For some ops on channel: 1. lookup_chann_list(), possibly on high frequency. 2. ksmbd_chann_del(). Connection is used as indexing key to lookup channel, in that case, linear search based on list may suffer a bit for performance. Implements sess->ksmbd_chann_list as xarray. Signed-off-by: Dawei Li Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/ksmbd/mgmt/user_session.c | 61 +++++++++++++++++--------------------------- fs/ksmbd/mgmt/user_session.h | 4 +-- fs/ksmbd/smb2pdu.c | 34 ++++-------------------- 3 files changed, 30 insertions(+), 69 deletions(-) (limited to 'fs') diff --git a/fs/ksmbd/mgmt/user_session.c b/fs/ksmbd/mgmt/user_session.c index 92b1603b5abe..a2b128dedcfc 100644 --- a/fs/ksmbd/mgmt/user_session.c +++ b/fs/ksmbd/mgmt/user_session.c @@ -30,15 +30,15 @@ struct ksmbd_session_rpc { static void free_channel_list(struct ksmbd_session *sess) { - struct channel *chann, *tmp; + struct channel *chann; + unsigned long index; - write_lock(&sess->chann_lock); - list_for_each_entry_safe(chann, tmp, &sess->ksmbd_chann_list, - chann_list) { - list_del(&chann->chann_list); + xa_for_each(&sess->ksmbd_chann_list, index, chann) { + xa_erase(&sess->ksmbd_chann_list, index); kfree(chann); } - write_unlock(&sess->chann_lock); + + xa_destroy(&sess->ksmbd_chann_list); } static void __session_rpc_close(struct ksmbd_session *sess, @@ -190,21 +190,15 @@ int ksmbd_session_register(struct ksmbd_conn *conn, static int ksmbd_chann_del(struct ksmbd_conn *conn, struct ksmbd_session *sess) { - struct channel *chann, *tmp; - - write_lock(&sess->chann_lock); - list_for_each_entry_safe(chann, tmp, &sess->ksmbd_chann_list, - chann_list) { - if (chann->conn == conn) { - list_del(&chann->chann_list); - kfree(chann); - write_unlock(&sess->chann_lock); - return 0; - } - } - write_unlock(&sess->chann_lock); + struct channel *chann; + + chann = xa_erase(&sess->ksmbd_chann_list, (long)conn); + if (!chann) + return -ENOENT; - return -ENOENT; + kfree(chann); + + return 0; } void ksmbd_sessions_deregister(struct ksmbd_conn *conn) @@ -234,7 +228,7 @@ void ksmbd_sessions_deregister(struct ksmbd_conn *conn) return; sess_destroy: - if (list_empty(&sess->ksmbd_chann_list)) { + if (xa_empty(&sess->ksmbd_chann_list)) { xa_erase(&conn->sessions, sess->id); ksmbd_session_destroy(sess); } @@ -320,6 +314,9 @@ static struct ksmbd_session *__session_create(int protocol) struct ksmbd_session *sess; int ret; + if (protocol != CIFDS_SESSION_FLAG_SMB2) + return NULL; + sess = kzalloc(sizeof(struct ksmbd_session), GFP_KERNEL); if (!sess) return NULL; @@ -329,30 +326,20 @@ static struct ksmbd_session *__session_create(int protocol) set_session_flag(sess, protocol); 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); 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) goto error; ida_init(&sess->tree_conn_ida); - if (protocol == CIFDS_SESSION_FLAG_SMB2) { - down_write(&sessions_table_lock); - hash_add(sessions_table, &sess->hlist, sess->id); - up_write(&sessions_table_lock); - } + down_write(&sessions_table_lock); + hash_add(sessions_table, &sess->hlist, sess->id); + up_write(&sessions_table_lock); + return sess; error: diff --git a/fs/ksmbd/mgmt/user_session.h b/fs/ksmbd/mgmt/user_session.h index 8934b8ee275b..44a3c67b2bd9 100644 --- a/fs/ksmbd/mgmt/user_session.h +++ b/fs/ksmbd/mgmt/user_session.h @@ -21,7 +21,6 @@ struct ksmbd_file_table; struct channel { __u8 smb3signingkey[SMB3_SIGN_KEY_SIZE]; struct ksmbd_conn *conn; - struct list_head chann_list; }; struct preauth_session { @@ -50,8 +49,7 @@ struct ksmbd_session { char sess_key[CIFS_KEY_SIZE]; struct hlist_node hlist; - rwlock_t chann_lock; - struct list_head ksmbd_chann_list; + struct xarray ksmbd_chann_list; struct xarray tree_conns; struct ida tree_conn_ida; struct list_head rpc_handle_list; diff --git a/fs/ksmbd/smb2pdu.c b/fs/ksmbd/smb2pdu.c index d681f91947d9..886e7ad42af0 100644 --- a/fs/ksmbd/smb2pdu.c +++ b/fs/ksmbd/smb2pdu.c @@ -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 *chann; - - list_for_each_entry(chann, &sess->ksmbd_chann_list, chann_list) { - if (chann->conn == conn) - return chann; - } - - return NULL; + return xa_load(&sess->ksmbd_chann_list, (long)conn); } /** @@ -595,6 +588,7 @@ static void destroy_previous_session(struct ksmbd_conn *conn, struct ksmbd_session *prev_sess = ksmbd_session_lookup_slowpath(id); struct ksmbd_user *prev_user; struct channel *chann; + long index; if (!prev_sess) return; @@ -608,10 +602,8 @@ static void destroy_previous_session(struct ksmbd_conn *conn, return; prev_sess->state = SMB2_SESSION_EXPIRED; - write_lock(&prev_sess->chann_lock); - list_for_each_entry(chann, &prev_sess->ksmbd_chann_list, chann_list) + xa_for_each(&prev_sess->ksmbd_chann_list, index, chann) chann->conn->status = KSMBD_SESS_EXITING; - write_unlock(&prev_sess->chann_lock); } /** @@ -1519,19 +1511,14 @@ static int ntlm_authenticate(struct ksmbd_work *work) binding_session: if (conn->dialect >= SMB30_PROT_ID) { - read_lock(&sess->chann_lock); chann = lookup_chann_list(sess, conn); - read_unlock(&sess->chann_lock); if (!chann) { chann = kmalloc(sizeof(struct channel), GFP_KERNEL); if (!chann) return -ENOMEM; chann->conn = conn; - INIT_LIST_HEAD(&chann->chann_list); - write_lock(&sess->chann_lock); - list_add(&chann->chann_list, &sess->ksmbd_chann_list); - write_unlock(&sess->chann_lock); + xa_store(&sess->ksmbd_chann_list, (long)conn, chann, GFP_KERNEL); } } @@ -1606,19 +1593,14 @@ static int krb5_authenticate(struct ksmbd_work *work) } if (conn->dialect >= SMB30_PROT_ID) { - read_lock(&sess->chann_lock); chann = lookup_chann_list(sess, conn); - read_unlock(&sess->chann_lock); if (!chann) { chann = kmalloc(sizeof(struct channel), GFP_KERNEL); if (!chann) return -ENOMEM; chann->conn = conn; - INIT_LIST_HEAD(&chann->chann_list); - write_lock(&sess->chann_lock); - list_add(&chann->chann_list, &sess->ksmbd_chann_list); - write_unlock(&sess->chann_lock); + xa_store(&sess->ksmbd_chann_list, (long)conn, chann, GFP_KERNEL); } } @@ -8409,14 +8391,11 @@ int smb3_check_sign_req(struct ksmbd_work *work) if (le16_to_cpu(hdr->Command) == SMB2_SESSION_SETUP_HE) { signing_key = work->sess->smb3signingkey; } else { - read_lock(&work->sess->chann_lock); chann = lookup_chann_list(work->sess, conn); if (!chann) { - read_unlock(&work->sess->chann_lock); return 0; } signing_key = chann->smb3signingkey; - read_unlock(&work->sess->chann_lock); } if (!signing_key) { @@ -8476,14 +8455,11 @@ void smb3_set_sign_rsp(struct ksmbd_work *work) le16_to_cpu(hdr->Command) == SMB2_SESSION_SETUP_HE) { signing_key = work->sess->smb3signingkey; } else { - read_lock(&work->sess->chann_lock); chann = lookup_chann_list(work->sess, work->conn); if (!chann) { - read_unlock(&work->sess->chann_lock); return; } signing_key = chann->smb3signingkey; - read_unlock(&work->sess->chann_lock); } if (!signing_key) -- cgit v1.2.3 From b685757c7b08d5073046fb379be965fd6c06aafc Mon Sep 17 00:00:00 2001 From: Dawei Li Date: Sun, 15 Jan 2023 18:32:05 +0800 Subject: ksmbd: Implements sess->rpc_handle_list as xarray For some ops on rpc handle: 1. ksmbd_session_rpc_method(), possibly on high frequency. 2. ksmbd_session_rpc_close(). id is used as indexing key to lookup channel, in that case, linear search based on list may suffer a bit for performance. Implements sess->rpc_handle_list as xarray. Signed-off-by: Dawei Li Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/ksmbd/mgmt/user_session.c | 37 ++++++++++++++----------------------- fs/ksmbd/mgmt/user_session.h | 2 +- 2 files changed, 15 insertions(+), 24 deletions(-) (limited to 'fs') diff --git a/fs/ksmbd/mgmt/user_session.c b/fs/ksmbd/mgmt/user_session.c index a2b128dedcfc..1ca2aae4c299 100644 --- a/fs/ksmbd/mgmt/user_session.c +++ b/fs/ksmbd/mgmt/user_session.c @@ -25,7 +25,6 @@ static DECLARE_RWSEM(sessions_table_lock); struct ksmbd_session_rpc { int id; unsigned int method; - struct list_head list; }; static void free_channel_list(struct ksmbd_session *sess) @@ -58,15 +57,14 @@ static void __session_rpc_close(struct ksmbd_session *sess, static void ksmbd_session_rpc_clear_list(struct ksmbd_session *sess) { struct ksmbd_session_rpc *entry; + long index; - while (!list_empty(&sess->rpc_handle_list)) { - entry = list_entry(sess->rpc_handle_list.next, - struct ksmbd_session_rpc, - list); - - list_del(&entry->list); + xa_for_each(&sess->rpc_handle_list, index, entry) { + xa_erase(&sess->rpc_handle_list, index); __session_rpc_close(sess, entry); } + + xa_destroy(&sess->rpc_handle_list); } static int __rpc_method(char *rpc_name) @@ -102,13 +100,13 @@ int ksmbd_session_rpc_open(struct ksmbd_session *sess, char *rpc_name) entry = kzalloc(sizeof(struct ksmbd_session_rpc), GFP_KERNEL); if (!entry) - return -EINVAL; + return -ENOMEM; - list_add(&entry->list, &sess->rpc_handle_list); entry->method = method; entry->id = ksmbd_ipc_id_alloc(); if (entry->id < 0) goto free_entry; + xa_store(&sess->rpc_handle_list, entry->id, entry, GFP_KERNEL); resp = ksmbd_rpc_open(sess, entry->id); if (!resp) @@ -117,9 +115,9 @@ int ksmbd_session_rpc_open(struct ksmbd_session *sess, char *rpc_name) kvfree(resp); return entry->id; free_id: + xa_erase(&sess->rpc_handle_list, entry->id); ksmbd_rpc_id_free(entry->id); free_entry: - list_del(&entry->list); kfree(entry); return -EINVAL; } @@ -128,24 +126,17 @@ void ksmbd_session_rpc_close(struct ksmbd_session *sess, int id) { struct ksmbd_session_rpc *entry; - list_for_each_entry(entry, &sess->rpc_handle_list, list) { - if (entry->id == id) { - list_del(&entry->list); - __session_rpc_close(sess, entry); - break; - } - } + entry = xa_erase(&sess->rpc_handle_list, id); + if (entry) + __session_rpc_close(sess, entry); } int ksmbd_session_rpc_method(struct ksmbd_session *sess, int id) { struct ksmbd_session_rpc *entry; - list_for_each_entry(entry, &sess->rpc_handle_list, list) { - if (entry->id == id) - return entry->method; - } - return 0; + entry = xa_load(&sess->rpc_handle_list, id); + return entry ? entry->method : 0; } void ksmbd_session_destroy(struct ksmbd_session *sess) @@ -327,7 +318,7 @@ static struct ksmbd_session *__session_create(int protocol) set_session_flag(sess, protocol); xa_init(&sess->tree_conns); xa_init(&sess->ksmbd_chann_list); - INIT_LIST_HEAD(&sess->rpc_handle_list); + xa_init(&sess->rpc_handle_list); sess->sequence_number = 1; ret = __init_smb2_session(sess); diff --git a/fs/ksmbd/mgmt/user_session.h b/fs/ksmbd/mgmt/user_session.h index 44a3c67b2bd9..b6a9e7a6aae4 100644 --- a/fs/ksmbd/mgmt/user_session.h +++ b/fs/ksmbd/mgmt/user_session.h @@ -52,7 +52,7 @@ struct ksmbd_session { struct xarray ksmbd_chann_list; struct xarray tree_conns; struct ida tree_conn_ida; - struct list_head rpc_handle_list; + struct xarray rpc_handle_list; __u8 smb3encryptionkey[SMB3_ENC_DEC_KEY_SIZE]; __u8 smb3decryptionkey[SMB3_ENC_DEC_KEY_SIZE]; -- cgit v1.2.3 From f8d6e7442aa716a233c7eba99dec628f8885e00b Mon Sep 17 00:00:00 2001 From: Dawei Li Date: Sun, 15 Jan 2023 18:32:09 +0800 Subject: ksmbd: fix typo, syncronous->synchronous syncronous->synchronous Signed-off-by: Dawei Li Acked-by: Namjae Jeon Reviewed-by: Sergey Senozhatsky Signed-off-by: Steve French --- fs/ksmbd/connection.c | 4 ++-- fs/ksmbd/ksmbd_work.h | 2 +- fs/ksmbd/smb2pdu.c | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'fs') diff --git a/fs/ksmbd/connection.c b/fs/ksmbd/connection.c index 56be077e5d8a..fc2479ec7b10 100644 --- a/fs/ksmbd/connection.c +++ b/fs/ksmbd/connection.c @@ -114,7 +114,7 @@ void ksmbd_conn_enqueue_request(struct ksmbd_work *work) if (conn->ops->get_cmd_val(work) != SMB2_CANCEL_HE) { requests_queue = &conn->requests; - work->syncronous = true; + work->synchronous = true; } if (requests_queue) { @@ -139,7 +139,7 @@ int ksmbd_conn_try_dequeue_request(struct ksmbd_work *work) spin_lock(&conn->request_lock); if (!work->multiRsp) { list_del_init(&work->request_entry); - if (work->syncronous == false) + if (!work->synchronous) list_del_init(&work->async_request_entry); ret = 0; } diff --git a/fs/ksmbd/ksmbd_work.h b/fs/ksmbd/ksmbd_work.h index 5ece58e40c97..3234f2cf6327 100644 --- a/fs/ksmbd/ksmbd_work.h +++ b/fs/ksmbd/ksmbd_work.h @@ -68,7 +68,7 @@ struct ksmbd_work { /* Request is encrypted */ bool encrypted:1; /* Is this SYNC or ASYNC ksmbd_work */ - bool syncronous:1; + bool synchronous:1; bool need_invalidate_rkey:1; unsigned int remote_key; diff --git a/fs/ksmbd/smb2pdu.c b/fs/ksmbd/smb2pdu.c index 886e7ad42af0..a225727d4bc1 100644 --- a/fs/ksmbd/smb2pdu.c +++ b/fs/ksmbd/smb2pdu.c @@ -498,7 +498,7 @@ int init_smb2_rsp_hdr(struct ksmbd_work *work) rsp_hdr->SessionId = rcv_hdr->SessionId; memcpy(rsp_hdr->Signature, rcv_hdr->Signature, 16); - work->syncronous = true; + work->synchronous = true; if (work->async_id) { ksmbd_release_id(&conn->async_ida, work->async_id); work->async_id = 0; @@ -644,7 +644,7 @@ int setup_async_work(struct ksmbd_work *work, void (*fn)(void **), void **arg) pr_err("Failed to alloc async message id\n"); return id; } - work->syncronous = false; + work->synchronous = false; work->async_id = id; rsp_hdr->Id.AsyncId = cpu_to_le64(id); -- cgit v1.2.3 From 7010357004096e54c884813e702d71147dc081f8 Mon Sep 17 00:00:00 2001 From: Dawei Li Date: Tue, 17 Jan 2023 23:29:19 +0900 Subject: ksmbd: Remove duplicated codes ksmbd_neg_token_init_mech_token() and ksmbd_neg_token_targ_resp_token() share same implementation, unify them. Signed-off-by: Dawei Li Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/ksmbd/asn1.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) (limited to 'fs') diff --git a/fs/ksmbd/asn1.c b/fs/ksmbd/asn1.c index c03eba090368..cc6384f79675 100644 --- a/fs/ksmbd/asn1.c +++ b/fs/ksmbd/asn1.c @@ -208,9 +208,9 @@ int ksmbd_neg_token_init_mech_type(void *context, size_t hdrlen, return 0; } -int ksmbd_neg_token_init_mech_token(void *context, size_t hdrlen, - unsigned char tag, const void *value, - size_t vlen) +static int ksmbd_neg_token_alloc(void *context, size_t hdrlen, + unsigned char tag, const void *value, + size_t vlen) { struct ksmbd_conn *conn = context; @@ -223,17 +223,16 @@ int ksmbd_neg_token_init_mech_token(void *context, size_t hdrlen, return 0; } -int ksmbd_neg_token_targ_resp_token(void *context, size_t hdrlen, +int ksmbd_neg_token_init_mech_token(void *context, size_t hdrlen, unsigned char tag, const void *value, size_t vlen) { - struct ksmbd_conn *conn = context; - - conn->mechToken = kmalloc(vlen + 1, GFP_KERNEL); - if (!conn->mechToken) - return -ENOMEM; + return ksmbd_neg_token_alloc(context, hdrlen, tag, value, vlen); +} - memcpy(conn->mechToken, value, vlen); - conn->mechToken[vlen] = '\0'; - return 0; +int ksmbd_neg_token_targ_resp_token(void *context, size_t hdrlen, + unsigned char tag, const void *value, + size_t vlen) +{ + return ksmbd_neg_token_alloc(context, hdrlen, tag, value, vlen); } -- cgit v1.2.3 From d280a958f8b2b62610c280ecdf35d780e7922620 Mon Sep 17 00:00:00 2001 From: Steve French Date: Sun, 29 Jan 2023 17:49:59 -0600 Subject: ksmbd: update Kconfig to note Kerberos support and fix indentation Fix indentation of server config options, and also since support for very old, less secure, NTLM authentication was removed (and quite a while ago), remove the mention of that in Kconfig, but do note Kerberos (not just NTLMv2) which are supported and much more secure. Acked-by: Namjae Jeon Acked-by: David Howells Signed-off-by: Steve French --- fs/ksmbd/Kconfig | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/ksmbd/Kconfig b/fs/ksmbd/Kconfig index e1fe17747ed6..7055cb5d2880 100644 --- a/fs/ksmbd/Kconfig +++ b/fs/ksmbd/Kconfig @@ -33,14 +33,16 @@ config SMB_SERVER in ksmbd-tools, available from https://github.com/cifsd-team/ksmbd-tools. More detail about how to run the ksmbd kernel server is - available via README file + available via the README file (https://github.com/cifsd-team/ksmbd-tools/blob/master/README). ksmbd kernel server includes support for auto-negotiation, Secure negotiate, Pre-authentication integrity, oplock/lease, compound requests, multi-credit, packet signing, RDMA(smbdirect), smb3 encryption, copy-offload, secure per-user session - establishment via NTLM or NTLMv2. + establishment via Kerberos or NTLMv2. + +if SMB_SERVER config SMB_SERVER_SMBDIRECT bool "Support for SMB Direct protocol" @@ -54,6 +56,8 @@ config SMB_SERVER_SMBDIRECT SMB Direct allows transferring SMB packets over RDMA. If unsure, say N. +endif + config SMB_SERVER_CHECK_CAP_NET_ADMIN bool "Enable check network administration capability" depends on SMB_SERVER -- cgit v1.2.3 From 7a17c61ee3b2683c40090179c273f4701fca9677 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 30 Jan 2023 09:23:57 +0000 Subject: ksmbd: Fix spelling mistake "excceed" -> "exceeded" There is a spelling mistake in an error message. Fix it. Signed-off-by: Colin Ian King Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/ksmbd/connection.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/ksmbd/connection.c b/fs/ksmbd/connection.c index fc2479ec7b10..5b10b03800c1 100644 --- a/fs/ksmbd/connection.c +++ b/fs/ksmbd/connection.c @@ -312,7 +312,7 @@ int ksmbd_conn_handler_loop(void *p) max_allowed_pdu_size = SMB3_MAX_MSGSIZE; if (pdu_size > max_allowed_pdu_size) { - pr_err_ratelimited("PDU length(%u) excceed maximum allowed pdu size(%u) on connection(%d)\n", + pr_err_ratelimited("PDU length(%u) exceeded maximum allowed pdu size(%u) on connection(%d)\n", pdu_size, max_allowed_pdu_size, conn->status); break; -- cgit v1.2.3 From 63f09a9986eb58578ed6ad0e27a6e2c54e49f797 Mon Sep 17 00:00:00 2001 From: Jiapeng Chong Date: Wed, 8 Feb 2023 09:30:30 +0900 Subject: ksmbd: Fix parameter name and comment mismatch fs/ksmbd/vfs.c:965: warning: Function parameter or member 'attr_value' not described in 'ksmbd_vfs_setxattr'. Reported-by: Abaci Robot Link: https://bugzilla.openanolis.cn/show_bug.cgi?id=3946 Signed-off-by: Jiapeng Chong Acked-by: Namjae Jeon Reviewed-by: Sergey Senozhatsky Signed-off-by: Steve French --- fs/ksmbd/vfs.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'fs') diff --git a/fs/ksmbd/vfs.c b/fs/ksmbd/vfs.c index ff0e7a4fcd4d..0f0d6158c88e 100644 --- a/fs/ksmbd/vfs.c +++ b/fs/ksmbd/vfs.c @@ -951,9 +951,9 @@ ssize_t ksmbd_vfs_getxattr(struct user_namespace *user_ns, * ksmbd_vfs_setxattr() - vfs helper for smb set extended attributes value * @user_ns: user namespace * @dentry: dentry to set XATTR at - * @name: xattr name for setxattr - * @value: xattr value to set - * @size: size of xattr value + * @attr_name: xattr name for setxattr + * @attr_value: xattr value to set + * @attr_size: size of xattr value * @flags: destination buffer length * * Return: 0 on success, otherwise error -- cgit v1.2.3 From 8f8c43b125882ac14372f8dca0c8e50a59e78d79 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Wed, 8 Feb 2023 09:50:46 +0900 Subject: ksmbd: fix wrong data area length for smb2 lock request When turning debug mode on, The following error message from ksmbd_smb2_check_message() is coming. ksmbd: cli req padded more than expected. Length 112 not 88 for cmd:10 mid:14 data area length calculation for smb2 lock request in smb2_get_data_area_len() is incorrect. Fixes: e2f34481b24d ("cifsd: add server-side procedures for SMB3") Cc: stable@vger.kernel.org Signed-off-by: Namjae Jeon Signed-off-by: Steve French --- fs/ksmbd/smb2misc.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'fs') diff --git a/fs/ksmbd/smb2misc.c b/fs/ksmbd/smb2misc.c index 6e25ace36568..a717aa9b4af8 100644 --- a/fs/ksmbd/smb2misc.c +++ b/fs/ksmbd/smb2misc.c @@ -149,15 +149,11 @@ static int smb2_get_data_area_len(unsigned int *off, unsigned int *len, break; case SMB2_LOCK: { - int lock_count; + unsigned short lock_count; - /* - * smb2_lock request size is 48 included single - * smb2_lock_element structure size. - */ - lock_count = le16_to_cpu(((struct smb2_lock_req *)hdr)->LockCount) - 1; + lock_count = le16_to_cpu(((struct smb2_lock_req *)hdr)->LockCount); if (lock_count > 0) { - *off = __SMB2_HEADER_STRUCTURE_SIZE + 48; + *off = offsetof(struct smb2_lock_req, locks); *len = sizeof(struct smb2_lock_element) * lock_count; } break; -- cgit v1.2.3 From fb533473d1595fe79ecb528fda1de33552b07178 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Sat, 11 Feb 2023 00:27:34 +0900 Subject: ksmbd: do not allow the actual frame length to be smaller than the rfc1002 length ksmbd allowed the actual frame length to be smaller than the rfc1002 length. If allowed, it is possible to allocates a large amount of memory that can be limited by credit management and can eventually cause memory exhaustion problem. This patch do not allow it except SMB2 Negotiate request which will be validated when message handling proceeds. Also, Allow a message that padded to 8byte boundary. Fixes: e2f34481b24d ("cifsd: add server-side procedures for SMB3") Cc: stable@vger.kernel.org Signed-off-by: Namjae Jeon Signed-off-by: Steve French --- fs/ksmbd/smb2misc.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) (limited to 'fs') diff --git a/fs/ksmbd/smb2misc.c b/fs/ksmbd/smb2misc.c index a717aa9b4af8..fbdde426dd01 100644 --- a/fs/ksmbd/smb2misc.c +++ b/fs/ksmbd/smb2misc.c @@ -408,20 +408,19 @@ int ksmbd_smb2_check_message(struct ksmbd_work *work) goto validate_credit; /* - * windows client also pad up to 8 bytes when compounding. - * If pad is longer than eight bytes, log the server behavior - * (once), since may indicate a problem but allow it and - * continue since the frame is parseable. + * SMB2 NEGOTIATE request will be validated when message + * handling proceeds. */ - if (clc_len < len) { - ksmbd_debug(SMB, - "cli req padded more than expected. Length %d not %d for cmd:%d mid:%llu\n", - len, clc_len, command, - le64_to_cpu(hdr->MessageId)); + if (command == SMB2_NEGOTIATE_HE) + goto validate_credit; + + /* + * Allow a message that padded to 8byte boundary. + */ + if (clc_len < len && (len - clc_len) < 8) goto validate_credit; - } - ksmbd_debug(SMB, + pr_err_ratelimited( "cli req too short, len %d not %d. cmd:%d mid:%llu\n", len, clc_len, command, le64_to_cpu(hdr->MessageId)); -- cgit v1.2.3 From d3ca9f7aeba793d74361d88a8800b2f205c9236b Mon Sep 17 00:00:00 2001 From: Hangyu Hua Date: Fri, 17 Feb 2023 22:29:34 +0900 Subject: ksmbd: fix possible memory leak in smb2_lock() argv needs to be free when setup_async_work fails or when the current process is woken up. Fixes: e2f34481b24d ("cifsd: add server-side procedures for SMB3") Cc: stable@vger.kernel.org Signed-off-by: Hangyu Hua Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/ksmbd/smb2pdu.c | 28 +++++++++++++--------------- fs/ksmbd/vfs_cache.c | 5 ++--- 2 files changed, 15 insertions(+), 18 deletions(-) (limited to 'fs') diff --git a/fs/ksmbd/smb2pdu.c b/fs/ksmbd/smb2pdu.c index a225727d4bc1..33cfc8d80c2c 100644 --- a/fs/ksmbd/smb2pdu.c +++ b/fs/ksmbd/smb2pdu.c @@ -6626,7 +6626,7 @@ int smb2_cancel(struct ksmbd_work *work) struct ksmbd_conn *conn = work->conn; struct smb2_hdr *hdr = smb2_get_msg(work->request_buf); struct smb2_hdr *chdr; - struct ksmbd_work *cancel_work = NULL, *iter; + struct ksmbd_work *iter; struct list_head *command_list; ksmbd_debug(SMB, "smb2 cancel called on mid %llu, async flags 0x%x\n", @@ -6648,7 +6648,9 @@ int smb2_cancel(struct ksmbd_work *work) "smb2 with AsyncId %llu cancelled command = 0x%x\n", le64_to_cpu(hdr->Id.AsyncId), le16_to_cpu(chdr->Command)); - cancel_work = iter; + iter->state = KSMBD_WORK_CANCELLED; + if (iter->cancel_fn) + iter->cancel_fn(iter->cancel_argv); break; } spin_unlock(&conn->request_lock); @@ -6667,18 +6669,12 @@ int smb2_cancel(struct ksmbd_work *work) "smb2 with mid %llu cancelled command = 0x%x\n", le64_to_cpu(hdr->MessageId), le16_to_cpu(chdr->Command)); - cancel_work = iter; + iter->state = KSMBD_WORK_CANCELLED; break; } spin_unlock(&conn->request_lock); } - if (cancel_work) { - cancel_work->state = KSMBD_WORK_CANCELLED; - if (cancel_work->cancel_fn) - cancel_work->cancel_fn(cancel_work->cancel_argv); - } - /* For SMB2_CANCEL command itself send no response*/ work->send_no_response = 1; return 0; @@ -7043,6 +7039,14 @@ skip: ksmbd_vfs_posix_lock_wait(flock); + spin_lock(&work->conn->request_lock); + spin_lock(&fp->f_lock); + list_del(&work->fp_entry); + work->cancel_fn = NULL; + kfree(argv); + spin_unlock(&fp->f_lock); + spin_unlock(&work->conn->request_lock); + if (work->state != KSMBD_WORK_ACTIVE) { list_del(&smb_lock->llist); spin_lock(&work->conn->llist_lock); @@ -7051,9 +7055,6 @@ skip: locks_free_lock(flock); if (work->state == KSMBD_WORK_CANCELLED) { - spin_lock(&fp->f_lock); - list_del(&work->fp_entry); - spin_unlock(&fp->f_lock); rsp->hdr.Status = STATUS_CANCELLED; kfree(smb_lock); @@ -7075,9 +7076,6 @@ skip: list_del(&smb_lock->clist); spin_unlock(&work->conn->llist_lock); - spin_lock(&fp->f_lock); - list_del(&work->fp_entry); - spin_unlock(&fp->f_lock); goto retry; } else if (!rc) { spin_lock(&work->conn->llist_lock); diff --git a/fs/ksmbd/vfs_cache.c b/fs/ksmbd/vfs_cache.c index da9163b00350..0ae5dd0829e9 100644 --- a/fs/ksmbd/vfs_cache.c +++ b/fs/ksmbd/vfs_cache.c @@ -364,12 +364,11 @@ static void __put_fd_final(struct ksmbd_work *work, struct ksmbd_file *fp) static void set_close_state_blocked_works(struct ksmbd_file *fp) { - struct ksmbd_work *cancel_work, *ctmp; + struct ksmbd_work *cancel_work; spin_lock(&fp->f_lock); - list_for_each_entry_safe(cancel_work, ctmp, &fp->blocked_works, + list_for_each_entry(cancel_work, &fp->blocked_works, fp_entry) { - list_del(&cancel_work->fp_entry); cancel_work->state = KSMBD_WORK_CLOSED; cancel_work->cancel_fn(cancel_work->cancel_argv); } -- cgit v1.2.3