From: Greg Kroah-Hartman Date: Wed, 20 Dec 2023 14:31:11 +0000 (+0100) Subject: 5.15-stable patches X-Git-Tag: v4.14.334~1 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=423524a2dda0be21c04a0d83a4ede256d068e61b;p=thirdparty%2Fkernel%2Fstable-queue.git 5.15-stable patches added patches: fs-introduce-lock_rename_child-helper.patch ksmbd-add-missing-calling-smb2_set_err_rsp-on-error.patch ksmbd-add-missing-compound-request-handing-in-some-commands.patch ksmbd-add-mnt_want_write-to-ksmbd-vfs-functions.patch ksmbd-add-smb-direct-shutdown.patch ksmbd-add-support-for-key-exchange.patch ksmbd-add-support-for-read-compound.patch ksmbd-add-support-for-surrogate-pair-conversion.patch ksmbd-avoid-duplicate-negotiate-ctx-offset-increments.patch ksmbd-avoid-out-of-bounds-access-in-decode_preauth_ctxt.patch ksmbd-block-asynchronous-requests-when-making-a-delay-on-session-setup.patch ksmbd-call-ib_drain_qp-when-disconnected.patch ksmbd-call-putname-after-using-the-last-component.patch ksmbd-casefold-utf-8-share-names-and-fix-ascii-lowercase-conversion.patch ksmbd-change-leasekey-data-type-to-u8-array.patch ksmbd-change-security-id-to-the-one-samba-used-for-posix-extension.patch ksmbd-change-the-return-value-of-ksmbd_vfs_query_maximal_access-to-void.patch ksmbd-check-if-a-mount-point-is-crossed-during-path-lookup.patch ksmbd-check-iov-vector-index-in-ksmbd_conn_write.patch ksmbd-check-the-validation-of-pdu_size-in-ksmbd_conn_handler_loop.patch ksmbd-constify-struct-path.patch ksmbd-convert-to-use-sysfs_emit-sysfs_emit_at-apis.patch ksmbd-decrease-the-number-of-smb3-smbdirect-server-sges.patch ksmbd-delete-an-invalid-argument-description-in-smb2_populate_readdir_entry.patch ksmbd-delete-asynchronous-work-from-list.patch ksmbd-destroy-expired-sessions.patch ksmbd-don-t-open-code-file_path.patch ksmbd-don-t-open-code-pd.patch ksmbd-don-t-update-op_state-as-oplock_state_none-on-error.patch ksmbd-fill-sids-in-smb_find_file_posix_info-response.patch ksmbd-fix-buffer_check_err-kernel-doc-comment.patch ksmbd-fix-encryption-failure-issue-for-session-logoff-response.patch ksmbd-fix-force-create-mode-and-force-directory-mode.patch ksmbd-fix-kernel-doc-comment-of-ksmbd_vfs_kern_path_locked.patch ksmbd-fix-kernel-doc-comment-of-ksmbd_vfs_setxattr.patch ksmbd-fix-missing-rdma-capable-flag-for-ipoib-device-in-ksmbd_rdma_capable_netdev.patch ksmbd-fix-multiple-out-of-bounds-read-during-context-decoding.patch ksmbd-fix-null-pointer-dereferences-in-ksmbd_update_fstate.patch ksmbd-fix-one-kernel-doc-comment.patch ksmbd-fix-out-of-bound-read-in-deassemble_neg_contexts.patch ksmbd-fix-out-of-bound-read-in-parse_lease_state.patch ksmbd-fix-out-of-bounds-in-init_smb2_rsp_hdr.patch ksmbd-fix-out-of-bounds-read-in-smb2_sess_setup.patch ksmbd-fix-parameter-name-and-comment-mismatch.patch ksmbd-fix-passing-freed-memory-aux_payload_buf.patch ksmbd-fix-posix_acls-and-acls-dereferencing-possible-err_ptr.patch ksmbd-fix-possible-deadlock-in-smb2_open.patch ksmbd-fix-possible-memory-leak-in-smb2_lock.patch ksmbd-fix-potential-double-free-on-smb2_read_pipe-error-path.patch ksmbd-fix-race-condition-between-session-lookup-and-expire.patch ksmbd-fix-race-condition-between-tree-conn-lookup-and-disconnect.patch ksmbd-fix-race-condition-from-parallel-smb2-lock-requests.patch ksmbd-fix-race-condition-from-parallel-smb2-logoff-requests.patch ksmbd-fix-race-condition-with-fp.patch ksmbd-fix-racy-issue-from-session-setup-and-logoff.patch ksmbd-fix-racy-issue-from-smb2-close-and-logoff-with-multichannel.patch ksmbd-fix-racy-issue-from-using-d_parent-and-d_name.patch ksmbd-fix-racy-issue-under-cocurrent-smb2-tree-disconnect.patch ksmbd-fix-recursive-locking-in-vfs-helpers.patch ksmbd-fix-resource-leak-in-smb2_lock.patch ksmbd-fix-slab-out-of-bounds-in-init_smb2_rsp_hdr.patch ksmbd-fix-slub-overflow-in-ksmbd_decode_ntlmssp_auth_blob.patch ksmbd-fix-smb2_get_name-kernel-doc-comment.patch ksmbd-fix-smb2_set_info_file-kernel-doc-comment.patch ksmbd-fix-some-kernel-doc-comments.patch ksmbd-fix-spelling-mistake-excceed-exceeded.patch ksmbd-fix-typo-syncronous-synchronous.patch ksmbd-fix-uaf-issue-from-opinfo-conn.patch ksmbd-fix-uninitialized-pointer-read-in-ksmbd_vfs_rename.patch ksmbd-fix-uninitialized-pointer-read-in-smb2_create_link.patch ksmbd-fix-unsigned-expression-compared-with-zero.patch ksmbd-fix-wrong-error-response-status-by-using-set_smb2_rsp_status.patch ksmbd-fix-wrong-interim-response-on-compound.patch ksmbd-fix-wrong-signingkey-creation-when-encryption-is-aes256.patch ksmbd-fix-wrong-smbd-max-read-write-size-check.patch ksmbd-handle-malformed-smb1-message.patch ksmbd-hide-socket-error-message-when-ipv6-config-is-disable.patch ksmbd-implements-sess-ksmbd_chann_list-as-xarray.patch ksmbd-implements-sess-rpc_handle_list-as-xarray.patch ksmbd-make-utf-8-file-name-comparison-work-in-__caseless_lookup.patch ksmbd-move-oplock-handling-after-unlock-parent-dir.patch ksmbd-move-setting-smb2_flags_async_command-and-asyncid.patch ksmbd-no-need-to-wait-for-binded-connection-termination-at-logoff.patch ksmbd-prevent-memory-leak-on-error-return.patch ksmbd-reduce-descriptor-size-if-remaining-bytes-is-less-than-request-size.patch ksmbd-reduce-server-smbdirect-max-send-receive-segment-sizes.patch ksmbd-register-ksmbd-ib-client-with-ib_register_client.patch ksmbd-release-interim-response-after-sending-status-pending-response.patch ksmbd-remove-a-redundant-zeroing-of-memory.patch ksmbd-remove-duplicate-flag-set-in-smb2_write.patch ksmbd-remove-duplicated-codes.patch ksmbd-remove-experimental-warning.patch ksmbd-remove-filename-in-ksmbd_file.patch ksmbd-remove-generic_fillattr-use-in-smb2_open.patch ksmbd-remove-md4-leftovers.patch ksmbd-remove-redundant-flush_workqueue-calls.patch ksmbd-remove-smb2_buf_length-in-smb2_hdr.patch ksmbd-remove-smb2_buf_length-in-smb2_transform_hdr.patch ksmbd-remove-unnecessary-generic_fillattr-in-smb2_open.patch ksmbd-remove-unneeded-mark_inode_dirty-in-set_info_sec.patch ksmbd-remove-unused-compression-negotiate-ctx-packing.patch ksmbd-remove-unused-field-in-ksmbd_user-struct.patch ksmbd-remove-unused-fields-from-ksmbd_file-struct-definition.patch ksmbd-remove-unused-is_char_allowed-function.patch ksmbd-remove-unused-ksmbd_share_configs_cleanup-function.patch ksmbd-remove-unused-ksmbd_tree_conn_share-function.patch ksmbd-remove-unused-parameter-from-smb2_get_name.patch ksmbd-reorganize-ksmbd_iov_pin_rsp.patch ksmbd-replace-one-element-array-with-flexible-array-member.patch ksmbd-replace-one-element-arrays-with-flexible-array-members.patch ksmbd-replace-the-ternary-conditional-operator-with-min.patch ksmbd-replace-usage-of-found-with-dedicated-list-iterator-variable.patch ksmbd-request-update-to-stale-share-config.patch ksmbd-return-a-literal-instead-of-err-in-ksmbd_vfs_kern_path_locked.patch ksmbd-return-invalid-parameter-error-response-if-smb2-request-is-invalid.patch ksmbd-send-proper-error-response-in-smb2_tree_connect.patch ksmbd-separately-allocate-ci-per-dentry.patch ksmbd-set-445-port-to-smbdirect-port-by-default.patch ksmbd-set-both-ipv4-and-ipv6-in-fsctl_query_network_interface_info.patch ksmbd-set-file-permission-mode-to-match-samba-server-posix-extension-behavior.patch ksmbd-set-negotiatecontextcount-once-instead-of-every-inc.patch ksmbd-set-ntlmssp_negotiate_seal-flag-to-challenge-blob.patch ksmbd-set-smb2_session_flag_encrypt_data-when-enforcing-data-encryption-for-this-share.patch ksmbd-shorten-experimental-warning-on-loading-the-module.patch ksmbd-smbd-call-rdma_accept-under-cm-handler.patch ksmbd-smbd-change-prototypes-of-rdma-read-write-related-functions.patch ksmbd-smbd-change-the-default-maximum-read-write-receive-size.patch ksmbd-smbd-change-the-return-value-of-get_sg_list.patch ksmbd-smbd-create-mr-pool.patch ksmbd-smbd-fix-connection-dropped-issue.patch ksmbd-smbd-fix-missing-client-s-memory-region-invalidation.patch ksmbd-smbd-handle-multiple-buffer-descriptors.patch ksmbd-smbd-introduce-read-write-credits-for-rdma-read-write.patch ksmbd-smbd-relax-the-count-of-sges-required.patch ksmbd-smbd-remove-useless-license-text-when-spdx-license-identifier-is-already-used.patch ksmbd-smbd-simplify-tracking-pending-packets.patch ksmbd-smbd-validate-buffer-descriptor-structures.patch ksmbd-store-fids-as-opaque-u64-integers.patch ksmbd-switch-to-use-kmemdup_nul-helper.patch ksmbd-update-kconfig-to-note-kerberos-support-and-fix-indentation.patch ksmbd-use-f_setlk-when-unlocking-a-file.patch ksmbd-use-ksmbd_req_buf_next-in-ksmbd_verify_smb_message.patch ksmbd-use-kvzalloc-instead-of-kvmalloc.patch ksmbd-use-kzalloc-instead-of-__gfp_zero.patch ksmbd-use-netif_is_bridge_port.patch ksmbd-use-oid-registry-functions-to-decode-oids.patch ksmbd-use-struct_size-helper-in-ksmbd_negotiate_smb_dialect.patch ksmbd-use-wait_event-instead-of-schedule_timeout.patch ksmbd-validate-length-in-smb2_write.patch ksmbd-validate-session-id-and-tree-id-in-compound-request.patch ksmbd-validate-share-name-from-share-config-response.patch ksmbd-validate-smb-request-protocol-id.patch ksmdb-use-cmd-helper-variable-in-smb2_get_ksmbd_tcon.patch series smb3-fix-ksmbd-bigendian-bug-in-oplock-break-and-move-its-struct-to-smbfs_common.patch --- diff --git a/queue-5.15/fs-introduce-lock_rename_child-helper.patch b/queue-5.15/fs-introduce-lock_rename_child-helper.patch new file mode 100644 index 00000000000..f1e0d087738 --- /dev/null +++ b/queue-5.15/fs-introduce-lock_rename_child-helper.patch @@ -0,0 +1,127 @@ +From linkinjeon@gmail.com Mon Dec 18 16:39:57 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:33:46 +0900 +Subject: fs: introduce lock_rename_child() helper +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Al Viro , Namjae Jeon +Message-ID: <20231218153454.8090-87-linkinjeon@kernel.org> + +From: Al Viro + +[ Upstream commit 9bc37e04823b5280dd0f22b6680fc23fe81ca325 ] + +Pass the dentry of a source file and the dentry of a destination directory +to lock parent inodes for rename. As soon as this function returns, +->d_parent of the source file dentry is stable and inodes are properly +locked for calling vfs-rename. This helper is needed for ksmbd server. +rename request of SMB protocol has to rename an opened file, no matter +which directory it's in. + +Signed-off-by: Al Viro +Signed-off-by: Namjae Jeon +Signed-off-by: Al Viro +Signed-off-by: Greg Kroah-Hartman +--- + fs/namei.c | 68 +++++++++++++++++++++++++++++++++++++++++--------- + include/linux/namei.h | 1 + 2 files changed, 58 insertions(+), 11 deletions(-) + +--- a/fs/namei.c ++++ b/fs/namei.c +@@ -2956,20 +2956,10 @@ static inline int may_create(struct user + return inode_permission(mnt_userns, dir, MAY_WRITE | MAY_EXEC); + } + +-/* +- * p1 and p2 should be directories on the same fs. +- */ +-struct dentry *lock_rename(struct dentry *p1, struct dentry *p2) ++static struct dentry *lock_two_directories(struct dentry *p1, struct dentry *p2) + { + struct dentry *p; + +- if (p1 == p2) { +- inode_lock_nested(p1->d_inode, I_MUTEX_PARENT); +- return NULL; +- } +- +- mutex_lock(&p1->d_sb->s_vfs_rename_mutex); +- + p = d_ancestor(p2, p1); + if (p) { + inode_lock_nested(p2->d_inode, I_MUTEX_PARENT); +@@ -2988,8 +2978,64 @@ struct dentry *lock_rename(struct dentry + I_MUTEX_PARENT, I_MUTEX_PARENT2); + return NULL; + } ++ ++/* ++ * p1 and p2 should be directories on the same fs. ++ */ ++struct dentry *lock_rename(struct dentry *p1, struct dentry *p2) ++{ ++ if (p1 == p2) { ++ inode_lock_nested(p1->d_inode, I_MUTEX_PARENT); ++ return NULL; ++ } ++ ++ mutex_lock(&p1->d_sb->s_vfs_rename_mutex); ++ return lock_two_directories(p1, p2); ++} + EXPORT_SYMBOL(lock_rename); + ++/* ++ * c1 and p2 should be on the same fs. ++ */ ++struct dentry *lock_rename_child(struct dentry *c1, struct dentry *p2) ++{ ++ if (READ_ONCE(c1->d_parent) == p2) { ++ /* ++ * hopefully won't need to touch ->s_vfs_rename_mutex at all. ++ */ ++ inode_lock_nested(p2->d_inode, I_MUTEX_PARENT); ++ /* ++ * now that p2 is locked, nobody can move in or out of it, ++ * so the test below is safe. ++ */ ++ if (likely(c1->d_parent == p2)) ++ return NULL; ++ ++ /* ++ * c1 got moved out of p2 while we'd been taking locks; ++ * unlock and fall back to slow case. ++ */ ++ inode_unlock(p2->d_inode); ++ } ++ ++ mutex_lock(&c1->d_sb->s_vfs_rename_mutex); ++ /* ++ * nobody can move out of any directories on this fs. ++ */ ++ if (likely(c1->d_parent != p2)) ++ return lock_two_directories(c1->d_parent, p2); ++ ++ /* ++ * c1 got moved into p2 while we were taking locks; ++ * we need p2 locked and ->s_vfs_rename_mutex unlocked, ++ * for consistency with lock_rename(). ++ */ ++ inode_lock_nested(p2->d_inode, I_MUTEX_PARENT); ++ mutex_unlock(&c1->d_sb->s_vfs_rename_mutex); ++ return NULL; ++} ++EXPORT_SYMBOL(lock_rename_child); ++ + void unlock_rename(struct dentry *p1, struct dentry *p2) + { + inode_unlock(p1->d_inode); +--- a/include/linux/namei.h ++++ b/include/linux/namei.h +@@ -83,6 +83,7 @@ extern int follow_down(struct path *); + extern int follow_up(struct path *); + + extern struct dentry *lock_rename(struct dentry *, struct dentry *); ++extern struct dentry *lock_rename_child(struct dentry *, struct dentry *); + extern void unlock_rename(struct dentry *, struct dentry *); + + extern int __must_check nd_jump_link(struct path *path); diff --git a/queue-5.15/ksmbd-add-missing-calling-smb2_set_err_rsp-on-error.patch b/queue-5.15/ksmbd-add-missing-calling-smb2_set_err_rsp-on-error.patch new file mode 100644 index 00000000000..59a2c402b3e --- /dev/null +++ b/queue-5.15/ksmbd-add-missing-calling-smb2_set_err_rsp-on-error.patch @@ -0,0 +1,33 @@ +From linkinjeon@gmail.com Mon Dec 18 16:42:04 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:34:25 +0900 +Subject: ksmbd: add missing calling smb2_set_err_rsp() on error +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-126-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit 0e2378eaa2b3a663726cf740d4aaa8a801e2cb31 ] + +If some error happen on smb2_sess_setup(), Need to call +smb2_set_err_rsp() to set error response. +This patch add missing calling smb2_set_err_rsp() on error. + +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/smb2pdu.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -1904,6 +1904,7 @@ out_err: + ksmbd_conn_set_need_negotiate(conn); + } + } ++ smb2_set_err_rsp(work); + } else { + unsigned int iov_len; + diff --git a/queue-5.15/ksmbd-add-missing-compound-request-handing-in-some-commands.patch b/queue-5.15/ksmbd-add-missing-compound-request-handing-in-some-commands.patch new file mode 100644 index 00000000000..b913ce25e08 --- /dev/null +++ b/queue-5.15/ksmbd-add-missing-compound-request-handing-in-some-commands.patch @@ -0,0 +1,242 @@ +From linkinjeon@gmail.com Mon Dec 18 16:41:18 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:34:11 +0900 +Subject: ksmbd: add missing compound request handing in some commands +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-112-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit 7b7d709ef7cf285309157fb94c33f625dd22c5e1 ] + +This patch add the compound request handling to the some commands. +Existing clients do not send these commands as compound requests, +but ksmbd should consider that they may come. + +Cc: stable@vger.kernel.org +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/smb2pdu.c | 78 ++++++++++++++++++++++++++++++++++++----------------- + 1 file changed, 53 insertions(+), 25 deletions(-) + +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -1915,14 +1915,16 @@ out_err: + int smb2_tree_connect(struct ksmbd_work *work) + { + struct ksmbd_conn *conn = work->conn; +- struct smb2_tree_connect_req *req = smb2_get_msg(work->request_buf); +- struct smb2_tree_connect_rsp *rsp = smb2_get_msg(work->response_buf); ++ struct smb2_tree_connect_req *req; ++ struct smb2_tree_connect_rsp *rsp; + struct ksmbd_session *sess = work->sess; + char *treename = NULL, *name = NULL; + struct ksmbd_tree_conn_status status; + struct ksmbd_share_config *share; + int rc = -EINVAL; + ++ WORK_BUFFERS(work, req, rsp); ++ + treename = smb_strndup_from_utf16(req->Buffer, + le16_to_cpu(req->PathLength), true, + conn->local_nls); +@@ -2091,19 +2093,19 @@ static int smb2_create_open_flags(bool f + */ + int smb2_tree_disconnect(struct ksmbd_work *work) + { +- struct smb2_tree_disconnect_rsp *rsp = smb2_get_msg(work->response_buf); ++ struct smb2_tree_disconnect_rsp *rsp; ++ struct smb2_tree_disconnect_req *req; + struct ksmbd_session *sess = work->sess; + struct ksmbd_tree_connect *tcon = work->tcon; + ++ WORK_BUFFERS(work, req, rsp); ++ + rsp->StructureSize = cpu_to_le16(4); + inc_rfc1001_len(work->response_buf, 4); + + ksmbd_debug(SMB, "request\n"); + + if (!tcon || test_and_set_bit(TREE_CONN_EXPIRE, &tcon->status)) { +- struct smb2_tree_disconnect_req *req = +- smb2_get_msg(work->request_buf); +- + ksmbd_debug(SMB, "Invalid tid %d\n", req->hdr.Id.SyncId.TreeId); + + rsp->hdr.Status = STATUS_NETWORK_NAME_DELETED; +@@ -2126,10 +2128,14 @@ int smb2_tree_disconnect(struct ksmbd_wo + int smb2_session_logoff(struct ksmbd_work *work) + { + struct ksmbd_conn *conn = work->conn; +- struct smb2_logoff_rsp *rsp = smb2_get_msg(work->response_buf); ++ struct smb2_logoff_req *req; ++ struct smb2_logoff_rsp *rsp; + struct ksmbd_session *sess; +- struct smb2_logoff_req *req = smb2_get_msg(work->request_buf); +- u64 sess_id = le64_to_cpu(req->hdr.SessionId); ++ u64 sess_id; ++ ++ WORK_BUFFERS(work, req, rsp); ++ ++ sess_id = le64_to_cpu(req->hdr.SessionId); + + rsp->StructureSize = cpu_to_le16(4); + inc_rfc1001_len(work->response_buf, 4); +@@ -2169,12 +2175,14 @@ int smb2_session_logoff(struct ksmbd_wor + */ + static noinline int create_smb2_pipe(struct ksmbd_work *work) + { +- struct smb2_create_rsp *rsp = smb2_get_msg(work->response_buf); +- struct smb2_create_req *req = smb2_get_msg(work->request_buf); ++ struct smb2_create_rsp *rsp; ++ struct smb2_create_req *req; + int id; + int err; + char *name; + ++ WORK_BUFFERS(work, req, rsp); ++ + name = smb_strndup_from_utf16(req->Buffer, le16_to_cpu(req->NameLength), + 1, work->conn->local_nls); + if (IS_ERR(name)) { +@@ -5314,8 +5322,10 @@ int smb2_query_info(struct ksmbd_work *w + static noinline int smb2_close_pipe(struct ksmbd_work *work) + { + u64 id; +- struct smb2_close_req *req = smb2_get_msg(work->request_buf); +- struct smb2_close_rsp *rsp = smb2_get_msg(work->response_buf); ++ struct smb2_close_req *req; ++ struct smb2_close_rsp *rsp; ++ ++ WORK_BUFFERS(work, req, rsp); + + id = req->VolatileFileId; + ksmbd_session_rpc_close(work->sess, id); +@@ -5457,6 +5467,9 @@ int smb2_echo(struct ksmbd_work *work) + { + struct smb2_echo_rsp *rsp = smb2_get_msg(work->response_buf); + ++ if (work->next_smb2_rcv_hdr_off) ++ rsp = ksmbd_resp_buf_next(work); ++ + rsp->StructureSize = cpu_to_le16(4); + rsp->Reserved = 0; + inc_rfc1001_len(work->response_buf, 4); +@@ -6093,8 +6106,10 @@ static noinline int smb2_read_pipe(struc + int nbytes = 0, err; + u64 id; + struct ksmbd_rpc_command *rpc_resp; +- struct smb2_read_req *req = smb2_get_msg(work->request_buf); +- struct smb2_read_rsp *rsp = smb2_get_msg(work->response_buf); ++ struct smb2_read_req *req; ++ struct smb2_read_rsp *rsp; ++ ++ WORK_BUFFERS(work, req, rsp); + + id = req->VolatileFileId; + +@@ -6347,14 +6362,16 @@ out: + */ + static noinline int smb2_write_pipe(struct ksmbd_work *work) + { +- struct smb2_write_req *req = smb2_get_msg(work->request_buf); +- struct smb2_write_rsp *rsp = smb2_get_msg(work->response_buf); ++ struct smb2_write_req *req; ++ struct smb2_write_rsp *rsp; + struct ksmbd_rpc_command *rpc_resp; + u64 id = 0; + int err = 0, ret = 0; + char *data_buf; + size_t length; + ++ WORK_BUFFERS(work, req, rsp); ++ + length = le32_to_cpu(req->Length); + id = req->VolatileFileId; + +@@ -6623,6 +6640,9 @@ int smb2_cancel(struct ksmbd_work *work) + struct ksmbd_work *iter; + struct list_head *command_list; + ++ if (work->next_smb2_rcv_hdr_off) ++ hdr = ksmbd_resp_buf_next(work); ++ + ksmbd_debug(SMB, "smb2 cancel called on mid %llu, async flags 0x%x\n", + hdr->MessageId, hdr->Flags); + +@@ -6782,8 +6802,8 @@ static inline bool lock_defer_pending(st + */ + int smb2_lock(struct ksmbd_work *work) + { +- struct smb2_lock_req *req = smb2_get_msg(work->request_buf); +- struct smb2_lock_rsp *rsp = smb2_get_msg(work->response_buf); ++ struct smb2_lock_req *req; ++ struct smb2_lock_rsp *rsp; + struct smb2_lock_element *lock_ele; + struct ksmbd_file *fp = NULL; + struct file_lock *flock = NULL; +@@ -6800,6 +6820,8 @@ int smb2_lock(struct ksmbd_work *work) + LIST_HEAD(rollback_list); + int prior_lock = 0; + ++ WORK_BUFFERS(work, req, rsp); ++ + ksmbd_debug(SMB, "Received lock request\n"); + fp = ksmbd_lookup_fd_slow(work, req->VolatileFileId, req->PersistentFileId); + if (!fp) { +@@ -7914,8 +7936,8 @@ out: + */ + static void smb20_oplock_break_ack(struct ksmbd_work *work) + { +- struct smb2_oplock_break *req = smb2_get_msg(work->request_buf); +- struct smb2_oplock_break *rsp = smb2_get_msg(work->response_buf); ++ struct smb2_oplock_break *req; ++ struct smb2_oplock_break *rsp; + struct ksmbd_file *fp; + struct oplock_info *opinfo = NULL; + __le32 err = 0; +@@ -7924,6 +7946,8 @@ static void smb20_oplock_break_ack(struc + char req_oplevel = 0, rsp_oplevel = 0; + unsigned int oplock_change_type; + ++ WORK_BUFFERS(work, req, rsp); ++ + volatile_id = req->VolatileFid; + persistent_id = req->PersistentFid; + req_oplevel = req->OplockLevel; +@@ -8058,8 +8082,8 @@ static int check_lease_state(struct leas + static void smb21_lease_break_ack(struct ksmbd_work *work) + { + struct ksmbd_conn *conn = work->conn; +- struct smb2_lease_ack *req = smb2_get_msg(work->request_buf); +- struct smb2_lease_ack *rsp = smb2_get_msg(work->response_buf); ++ struct smb2_lease_ack *req; ++ struct smb2_lease_ack *rsp; + struct oplock_info *opinfo; + __le32 err = 0; + int ret = 0; +@@ -8067,6 +8091,8 @@ static void smb21_lease_break_ack(struct + __le32 lease_state; + struct lease *lease; + ++ WORK_BUFFERS(work, req, rsp); ++ + ksmbd_debug(OPLOCK, "smb21 lease break, lease state(0x%x)\n", + le32_to_cpu(req->LeaseState)); + opinfo = lookup_lease_in_table(conn, req->LeaseKey); +@@ -8192,8 +8218,10 @@ err_out: + */ + int smb2_oplock_break(struct ksmbd_work *work) + { +- struct smb2_oplock_break *req = smb2_get_msg(work->request_buf); +- struct smb2_oplock_break *rsp = smb2_get_msg(work->response_buf); ++ struct smb2_oplock_break *req; ++ struct smb2_oplock_break *rsp; ++ ++ WORK_BUFFERS(work, req, rsp); + + switch (le16_to_cpu(req->StructureSize)) { + case OP_BREAK_STRUCT_SIZE_20: diff --git a/queue-5.15/ksmbd-add-mnt_want_write-to-ksmbd-vfs-functions.patch b/queue-5.15/ksmbd-add-mnt_want_write-to-ksmbd-vfs-functions.patch new file mode 100644 index 00000000000..15a8e8cf0e5 --- /dev/null +++ b/queue-5.15/ksmbd-add-mnt_want_write-to-ksmbd-vfs-functions.patch @@ -0,0 +1,590 @@ +From stable+bounces-7732-greg=kroah.com@vger.kernel.org Mon Dec 18 16:45:42 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:34:03 +0900 +Subject: ksmbd: add mnt_want_write to ksmbd vfs functions +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , Amir Goldstein , Steve French +Message-ID: <20231218153454.8090-104-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit 40b268d384a22276dca1450549f53eed60e21deb ] + +ksmbd is doing write access using vfs helpers. There are the cases that +mnt_want_write() is not called in vfs helper. This patch add missing +mnt_want_write() to ksmbd vfs functions. + +Cc: stable@vger.kernel.org +Cc: Amir Goldstein +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/smb2pdu.c | 26 +++++------ + fs/ksmbd/smbacl.c | 10 +--- + fs/ksmbd/vfs.c | 112 ++++++++++++++++++++++++++++++++++++++++----------- + fs/ksmbd/vfs.h | 17 +++---- + fs/ksmbd/vfs_cache.c | 2 + 5 files changed, 112 insertions(+), 55 deletions(-) + +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -2284,7 +2284,7 @@ static int smb2_set_ea(struct smb2_ea_in + /* delete the EA only when it exits */ + if (rc > 0) { + rc = ksmbd_vfs_remove_xattr(user_ns, +- path->dentry, ++ path, + attr_name); + + if (rc < 0) { +@@ -2298,8 +2298,7 @@ static int smb2_set_ea(struct smb2_ea_in + /* if the EA doesn't exist, just do nothing. */ + rc = 0; + } else { +- rc = ksmbd_vfs_setxattr(user_ns, +- path->dentry, attr_name, value, ++ rc = ksmbd_vfs_setxattr(user_ns, path, attr_name, value, + le16_to_cpu(eabuf->EaValueLength), 0); + if (rc < 0) { + ksmbd_debug(SMB, +@@ -2363,8 +2362,7 @@ static noinline int smb2_set_stream_name + return -EBADF; + } + +- rc = ksmbd_vfs_setxattr(user_ns, path->dentry, +- xattr_stream_name, NULL, 0, 0); ++ rc = ksmbd_vfs_setxattr(user_ns, path, xattr_stream_name, NULL, 0, 0); + if (rc < 0) + pr_err("Failed to store XATTR stream name :%d\n", rc); + return 0; +@@ -2392,7 +2390,7 @@ static int smb2_remove_smb_xattrs(const + if (!strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN) && + !strncmp(&name[XATTR_USER_PREFIX_LEN], STREAM_PREFIX, + STREAM_PREFIX_LEN)) { +- err = ksmbd_vfs_remove_xattr(user_ns, path->dentry, ++ err = ksmbd_vfs_remove_xattr(user_ns, path, + name); + if (err) + ksmbd_debug(SMB, "remove xattr failed : %s\n", +@@ -2439,8 +2437,7 @@ static void smb2_new_xattrs(struct ksmbd + da.flags = XATTR_DOSINFO_ATTRIB | XATTR_DOSINFO_CREATE_TIME | + XATTR_DOSINFO_ITIME; + +- rc = ksmbd_vfs_set_dos_attrib_xattr(mnt_user_ns(path->mnt), +- path->dentry, &da); ++ rc = ksmbd_vfs_set_dos_attrib_xattr(mnt_user_ns(path->mnt), path, &da); + if (rc) + ksmbd_debug(SMB, "failed to store file attribute into xattr\n"); + } +@@ -3011,7 +3008,7 @@ int smb2_open(struct ksmbd_work *work) + struct inode *inode = d_inode(path.dentry); + + posix_acl_rc = ksmbd_vfs_inherit_posix_acl(user_ns, +- inode, ++ &path, + d_inode(path.dentry->d_parent)); + if (posix_acl_rc) + ksmbd_debug(SMB, "inherit posix acl failed : %d\n", posix_acl_rc); +@@ -3027,7 +3024,7 @@ int smb2_open(struct ksmbd_work *work) + if (rc) { + if (posix_acl_rc) + ksmbd_vfs_set_init_posix_acl(user_ns, +- inode); ++ &path); + + if (test_share_config_flag(work->tcon->share_conf, + KSMBD_SHARE_FLAG_ACL_XATTR)) { +@@ -3067,7 +3064,7 @@ int smb2_open(struct ksmbd_work *work) + + rc = ksmbd_vfs_set_sd_xattr(conn, + user_ns, +- path.dentry, ++ &path, + pntsd, + pntsd_size); + kfree(pntsd); +@@ -5506,7 +5503,7 @@ static int smb2_rename(struct ksmbd_work + goto out; + + rc = ksmbd_vfs_setxattr(file_mnt_user_ns(fp->filp), +- fp->filp->f_path.dentry, ++ &fp->filp->f_path, + xattr_stream_name, + NULL, 0, 0); + if (rc < 0) { +@@ -5671,8 +5668,7 @@ static int set_file_basic_info(struct ks + da.flags = XATTR_DOSINFO_ATTRIB | XATTR_DOSINFO_CREATE_TIME | + XATTR_DOSINFO_ITIME; + +- rc = ksmbd_vfs_set_dos_attrib_xattr(user_ns, +- filp->f_path.dentry, &da); ++ rc = ksmbd_vfs_set_dos_attrib_xattr(user_ns, &filp->f_path, &da); + if (rc) + ksmbd_debug(SMB, + "failed to restore file attribute in EA\n"); +@@ -7535,7 +7531,7 @@ static inline int fsctl_set_sparse(struc + + da.attr = le32_to_cpu(fp->f_ci->m_fattr); + ret = ksmbd_vfs_set_dos_attrib_xattr(user_ns, +- fp->filp->f_path.dentry, &da); ++ &fp->filp->f_path, &da); + if (ret) + fp->f_ci->m_fattr = old_fattr; + } +--- a/fs/ksmbd/smbacl.c ++++ b/fs/ksmbd/smbacl.c +@@ -1183,8 +1183,7 @@ pass: + pntsd_size += sizeof(struct smb_acl) + nt_size; + } + +- ksmbd_vfs_set_sd_xattr(conn, user_ns, +- path->dentry, pntsd, pntsd_size); ++ ksmbd_vfs_set_sd_xattr(conn, user_ns, path, pntsd, pntsd_size); + kfree(pntsd); + } + +@@ -1404,7 +1403,7 @@ int set_info_sec(struct ksmbd_conn *conn + newattrs.ia_valid |= ATTR_MODE; + newattrs.ia_mode = (inode->i_mode & ~0777) | (fattr.cf_mode & 0777); + +- ksmbd_vfs_remove_acl_xattrs(user_ns, path->dentry); ++ ksmbd_vfs_remove_acl_xattrs(user_ns, path); + /* Update posix acls */ + if (IS_ENABLED(CONFIG_FS_POSIX_ACL) && fattr.cf_dacls) { + rc = set_posix_acl(user_ns, inode, +@@ -1435,9 +1434,8 @@ int set_info_sec(struct ksmbd_conn *conn + + if (test_share_config_flag(tcon->share_conf, KSMBD_SHARE_FLAG_ACL_XATTR)) { + /* Update WinACL in xattr */ +- ksmbd_vfs_remove_sd_xattrs(user_ns, path->dentry); +- ksmbd_vfs_set_sd_xattr(conn, user_ns, +- path->dentry, pntsd, ntsd_len); ++ ksmbd_vfs_remove_sd_xattrs(user_ns, path); ++ ksmbd_vfs_set_sd_xattr(conn, user_ns, path, pntsd, ntsd_len); + } + + out: +--- a/fs/ksmbd/vfs.c ++++ b/fs/ksmbd/vfs.c +@@ -170,6 +170,10 @@ int ksmbd_vfs_create(struct ksmbd_work * + return err; + } + ++ err = mnt_want_write(path.mnt); ++ if (err) ++ goto out_err; ++ + mode |= S_IFREG; + err = vfs_create(mnt_user_ns(path.mnt), d_inode(path.dentry), + dentry, mode, true); +@@ -179,6 +183,9 @@ int ksmbd_vfs_create(struct ksmbd_work * + } else { + pr_err("File(%s): creation failed (err:%d)\n", name, err); + } ++ mnt_drop_write(path.mnt); ++ ++out_err: + done_path_create(&path, dentry); + return err; + } +@@ -209,30 +216,35 @@ int ksmbd_vfs_mkdir(struct ksmbd_work *w + return err; + } + ++ err = mnt_want_write(path.mnt); ++ if (err) ++ goto out_err2; ++ + user_ns = mnt_user_ns(path.mnt); + mode |= S_IFDIR; + err = vfs_mkdir(user_ns, d_inode(path.dentry), dentry, mode); +- if (err) { +- goto out; +- } else if (d_unhashed(dentry)) { ++ if (!err && d_unhashed(dentry)) { + struct dentry *d; + + d = lookup_one(user_ns, dentry->d_name.name, dentry->d_parent, + dentry->d_name.len); + if (IS_ERR(d)) { + err = PTR_ERR(d); +- goto out; ++ goto out_err1; + } + if (unlikely(d_is_negative(d))) { + dput(d); + err = -ENOENT; +- goto out; ++ goto out_err1; + } + + ksmbd_vfs_inherit_owner(work, d_inode(path.dentry), d_inode(d)); + dput(d); + } +-out: ++ ++out_err1: ++ mnt_drop_write(path.mnt); ++out_err2: + done_path_create(&path, dentry); + if (err) + pr_err("mkdir(%s): creation failed (err:%d)\n", name, err); +@@ -443,7 +455,7 @@ static int ksmbd_vfs_stream_write(struct + memcpy(&stream_buf[*pos], buf, count); + + err = ksmbd_vfs_setxattr(user_ns, +- fp->filp->f_path.dentry, ++ &fp->filp->f_path, + fp->stream.name, + (void *)stream_buf, + size, +@@ -589,6 +601,10 @@ int ksmbd_vfs_remove_file(struct ksmbd_w + goto out_err; + } + ++ err = mnt_want_write(path->mnt); ++ if (err) ++ goto out_err; ++ + user_ns = mnt_user_ns(path->mnt); + if (S_ISDIR(d_inode(path->dentry)->i_mode)) { + err = vfs_rmdir(user_ns, d_inode(parent), path->dentry); +@@ -599,6 +615,7 @@ int ksmbd_vfs_remove_file(struct ksmbd_w + if (err) + ksmbd_debug(VFS, "unlink failed, err %d\n", err); + } ++ mnt_drop_write(path->mnt); + + out_err: + ksmbd_revert_fsids(work); +@@ -644,11 +661,16 @@ int ksmbd_vfs_link(struct ksmbd_work *wo + goto out3; + } + ++ err = mnt_want_write(newpath.mnt); ++ if (err) ++ goto out3; ++ + err = vfs_link(oldpath.dentry, mnt_user_ns(newpath.mnt), + d_inode(newpath.dentry), + dentry, NULL); + if (err) + ksmbd_debug(VFS, "vfs_link failed err %d\n", err); ++ mnt_drop_write(newpath.mnt); + + out3: + done_path_create(&newpath, dentry); +@@ -694,6 +716,10 @@ retry: + goto out2; + } + ++ err = mnt_want_write(old_path->mnt); ++ if (err) ++ goto out2; ++ + trap = lock_rename_child(old_child, new_path.dentry); + + old_parent = dget(old_child->d_parent); +@@ -757,6 +783,7 @@ out4: + out3: + dput(old_parent); + unlock_rename(old_parent, new_path.dentry); ++ mnt_drop_write(old_path->mnt); + out2: + path_put(&new_path); + +@@ -897,19 +924,24 @@ ssize_t ksmbd_vfs_getxattr(struct user_n + * Return: 0 on success, otherwise error + */ + int ksmbd_vfs_setxattr(struct user_namespace *user_ns, +- struct dentry *dentry, const char *attr_name, ++ const struct path *path, const char *attr_name, + const void *attr_value, size_t attr_size, int flags) + { + int err; + ++ err = mnt_want_write(path->mnt); ++ if (err) ++ return err; ++ + err = vfs_setxattr(user_ns, +- dentry, ++ path->dentry, + attr_name, + attr_value, + attr_size, + flags); + if (err) + ksmbd_debug(VFS, "setxattr failed, err %d\n", err); ++ mnt_drop_write(path->mnt); + return err; + } + +@@ -1013,9 +1045,18 @@ int ksmbd_vfs_fqar_lseek(struct ksmbd_fi + } + + int ksmbd_vfs_remove_xattr(struct user_namespace *user_ns, +- struct dentry *dentry, char *attr_name) ++ const struct path *path, char *attr_name) + { +- return vfs_removexattr(user_ns, dentry, attr_name); ++ int err; ++ ++ err = mnt_want_write(path->mnt); ++ if (err) ++ return err; ++ ++ err = vfs_removexattr(user_ns, path->dentry, attr_name); ++ mnt_drop_write(path->mnt); ++ ++ return err; + } + + int ksmbd_vfs_unlink(struct file *filp) +@@ -1024,6 +1065,10 @@ int ksmbd_vfs_unlink(struct file *filp) + struct dentry *dir, *dentry = filp->f_path.dentry; + struct user_namespace *user_ns = file_mnt_user_ns(filp); + ++ err = mnt_want_write(filp->f_path.mnt); ++ if (err) ++ return err; ++ + dir = dget_parent(dentry); + err = ksmbd_vfs_lock_parent(dir, dentry); + if (err) +@@ -1041,6 +1086,7 @@ int ksmbd_vfs_unlink(struct file *filp) + ksmbd_debug(VFS, "failed to delete, err %d\n", err); + out: + dput(dir); ++ mnt_drop_write(filp->f_path.mnt); + + return err; + } +@@ -1246,13 +1292,13 @@ struct dentry *ksmbd_vfs_kern_path_creat + } + + int ksmbd_vfs_remove_acl_xattrs(struct user_namespace *user_ns, +- struct dentry *dentry) ++ const struct path *path) + { + char *name, *xattr_list = NULL; + ssize_t xattr_list_len; + int err = 0; + +- xattr_list_len = ksmbd_vfs_listxattr(dentry, &xattr_list); ++ xattr_list_len = ksmbd_vfs_listxattr(path->dentry, &xattr_list); + if (xattr_list_len < 0) { + goto out; + } else if (!xattr_list_len) { +@@ -1268,25 +1314,25 @@ int ksmbd_vfs_remove_acl_xattrs(struct u + sizeof(XATTR_NAME_POSIX_ACL_ACCESS) - 1) || + !strncmp(name, XATTR_NAME_POSIX_ACL_DEFAULT, + sizeof(XATTR_NAME_POSIX_ACL_DEFAULT) - 1)) { +- err = ksmbd_vfs_remove_xattr(user_ns, dentry, name); ++ err = ksmbd_vfs_remove_xattr(user_ns, path, name); + if (err) + ksmbd_debug(SMB, + "remove acl xattr failed : %s\n", name); + } + } ++ + out: + kvfree(xattr_list); + return err; + } + +-int ksmbd_vfs_remove_sd_xattrs(struct user_namespace *user_ns, +- struct dentry *dentry) ++int ksmbd_vfs_remove_sd_xattrs(struct user_namespace *user_ns, const struct path *path) + { + char *name, *xattr_list = NULL; + ssize_t xattr_list_len; + int err = 0; + +- xattr_list_len = ksmbd_vfs_listxattr(dentry, &xattr_list); ++ xattr_list_len = ksmbd_vfs_listxattr(path->dentry, &xattr_list); + if (xattr_list_len < 0) { + goto out; + } else if (!xattr_list_len) { +@@ -1299,7 +1345,7 @@ int ksmbd_vfs_remove_sd_xattrs(struct us + ksmbd_debug(SMB, "%s, len %zd\n", name, strlen(name)); + + if (!strncmp(name, XATTR_NAME_SD, XATTR_NAME_SD_LEN)) { +- err = ksmbd_vfs_remove_xattr(user_ns, dentry, name); ++ err = ksmbd_vfs_remove_xattr(user_ns, path, name); + if (err) + ksmbd_debug(SMB, "remove xattr failed : %s\n", name); + } +@@ -1376,13 +1422,14 @@ out: + + int ksmbd_vfs_set_sd_xattr(struct ksmbd_conn *conn, + struct user_namespace *user_ns, +- struct dentry *dentry, ++ const struct path *path, + struct smb_ntsd *pntsd, int len) + { + int rc; + struct ndr sd_ndr = {0}, acl_ndr = {0}; + struct xattr_ntacl acl = {0}; + struct xattr_smb_acl *smb_acl, *def_smb_acl = NULL; ++ struct dentry *dentry = path->dentry; + struct inode *inode = d_inode(dentry); + + acl.version = 4; +@@ -1434,7 +1481,7 @@ int ksmbd_vfs_set_sd_xattr(struct ksmbd_ + goto out; + } + +- rc = ksmbd_vfs_setxattr(user_ns, dentry, ++ rc = ksmbd_vfs_setxattr(user_ns, path, + XATTR_NAME_SD, sd_ndr.data, + sd_ndr.offset, 0); + if (rc < 0) +@@ -1524,7 +1571,7 @@ free_n_data: + } + + int ksmbd_vfs_set_dos_attrib_xattr(struct user_namespace *user_ns, +- struct dentry *dentry, ++ const struct path *path, + struct xattr_dos_attrib *da) + { + struct ndr n; +@@ -1534,7 +1581,7 @@ int ksmbd_vfs_set_dos_attrib_xattr(struc + if (err) + return err; + +- err = ksmbd_vfs_setxattr(user_ns, dentry, XATTR_NAME_DOS_ATTRIBUTE, ++ err = ksmbd_vfs_setxattr(user_ns, path, XATTR_NAME_DOS_ATTRIBUTE, + (void *)n.data, n.offset, 0); + if (err) + ksmbd_debug(SMB, "failed to store dos attribute in xattr\n"); +@@ -1771,10 +1818,11 @@ void ksmbd_vfs_posix_lock_unblock(struct + } + + int ksmbd_vfs_set_init_posix_acl(struct user_namespace *user_ns, +- struct inode *inode) ++ struct path *path) + { + struct posix_acl_state acl_state; + struct posix_acl *acls; ++ struct inode *inode = d_inode(path->dentry); + int rc; + + if (!IS_ENABLED(CONFIG_FS_POSIX_ACL)) +@@ -1803,6 +1851,11 @@ int ksmbd_vfs_set_init_posix_acl(struct + return -ENOMEM; + } + posix_state_to_acl(&acl_state, acls->a_entries); ++ ++ rc = mnt_want_write(path->mnt); ++ if (rc) ++ goto out_err; ++ + rc = set_posix_acl(user_ns, inode, ACL_TYPE_ACCESS, acls); + if (rc < 0) + ksmbd_debug(SMB, "Set posix acl(ACL_TYPE_ACCESS) failed, rc : %d\n", +@@ -1815,16 +1868,20 @@ int ksmbd_vfs_set_init_posix_acl(struct + ksmbd_debug(SMB, "Set posix acl(ACL_TYPE_DEFAULT) failed, rc : %d\n", + rc); + } ++ mnt_drop_write(path->mnt); ++ ++out_err: + free_acl_state(&acl_state); + posix_acl_release(acls); + return rc; + } + + int ksmbd_vfs_inherit_posix_acl(struct user_namespace *user_ns, +- struct inode *inode, struct inode *parent_inode) ++ struct path *path, struct inode *parent_inode) + { + struct posix_acl *acls; + struct posix_acl_entry *pace; ++ struct inode *inode = d_inode(path->dentry); + int rc, i; + + if (!IS_ENABLED(CONFIG_FS_POSIX_ACL)) +@@ -1842,6 +1899,10 @@ int ksmbd_vfs_inherit_posix_acl(struct u + } + } + ++ rc = mnt_want_write(path->mnt); ++ if (rc) ++ goto out_err; ++ + rc = set_posix_acl(user_ns, inode, ACL_TYPE_ACCESS, acls); + if (rc < 0) + ksmbd_debug(SMB, "Set posix acl(ACL_TYPE_ACCESS) failed, rc : %d\n", +@@ -1853,6 +1914,9 @@ int ksmbd_vfs_inherit_posix_acl(struct u + ksmbd_debug(SMB, "Set posix acl(ACL_TYPE_DEFAULT) failed, rc : %d\n", + rc); + } ++ mnt_drop_write(path->mnt); ++ ++out_err: + posix_acl_release(acls); + return rc; + } +--- a/fs/ksmbd/vfs.h ++++ b/fs/ksmbd/vfs.h +@@ -147,12 +147,12 @@ ssize_t ksmbd_vfs_casexattr_len(struct u + struct dentry *dentry, char *attr_name, + int attr_name_len); + int ksmbd_vfs_setxattr(struct user_namespace *user_ns, +- struct dentry *dentry, const char *attr_name, ++ const struct path *path, const char *attr_name, + const void *attr_value, size_t attr_size, int flags); + int ksmbd_vfs_xattr_stream_name(char *stream_name, char **xattr_stream_name, + size_t *xattr_stream_name_size, int s_type); + int ksmbd_vfs_remove_xattr(struct user_namespace *user_ns, +- struct dentry *dentry, char *attr_name); ++ const struct path *path, char *attr_name); + int ksmbd_vfs_kern_path_locked(struct ksmbd_work *work, char *name, + unsigned int flags, struct path *path, + bool caseless); +@@ -178,26 +178,25 @@ void ksmbd_vfs_posix_lock_wait(struct fi + int ksmbd_vfs_posix_lock_wait_timeout(struct file_lock *flock, long timeout); + void ksmbd_vfs_posix_lock_unblock(struct file_lock *flock); + int ksmbd_vfs_remove_acl_xattrs(struct user_namespace *user_ns, +- struct dentry *dentry); +-int ksmbd_vfs_remove_sd_xattrs(struct user_namespace *user_ns, +- struct dentry *dentry); ++ const struct path *path); ++int ksmbd_vfs_remove_sd_xattrs(struct user_namespace *user_ns, const struct path *path); + int ksmbd_vfs_set_sd_xattr(struct ksmbd_conn *conn, + struct user_namespace *user_ns, +- struct dentry *dentry, ++ const struct path *path, + struct smb_ntsd *pntsd, int len); + int ksmbd_vfs_get_sd_xattr(struct ksmbd_conn *conn, + struct user_namespace *user_ns, + struct dentry *dentry, + struct smb_ntsd **pntsd); + int ksmbd_vfs_set_dos_attrib_xattr(struct user_namespace *user_ns, +- struct dentry *dentry, ++ const struct path *path, + struct xattr_dos_attrib *da); + int ksmbd_vfs_get_dos_attrib_xattr(struct user_namespace *user_ns, + struct dentry *dentry, + struct xattr_dos_attrib *da); + int ksmbd_vfs_set_init_posix_acl(struct user_namespace *user_ns, +- struct inode *inode); ++ struct path *path); + int ksmbd_vfs_inherit_posix_acl(struct user_namespace *user_ns, +- struct inode *inode, ++ struct path *path, + struct inode *parent_inode); + #endif /* __KSMBD_VFS_H__ */ +--- a/fs/ksmbd/vfs_cache.c ++++ b/fs/ksmbd/vfs_cache.c +@@ -251,7 +251,7 @@ static void __ksmbd_inode_close(struct k + if (ksmbd_stream_fd(fp) && (ci->m_flags & S_DEL_ON_CLS_STREAM)) { + ci->m_flags &= ~S_DEL_ON_CLS_STREAM; + err = ksmbd_vfs_remove_xattr(file_mnt_user_ns(filp), +- filp->f_path.dentry, ++ &filp->f_path, + fp->stream.name); + if (err) + pr_err("remove xattr failed : %s\n", diff --git a/queue-5.15/ksmbd-add-smb-direct-shutdown.patch b/queue-5.15/ksmbd-add-smb-direct-shutdown.patch new file mode 100644 index 00000000000..bc64a5e4f5a --- /dev/null +++ b/queue-5.15/ksmbd-add-smb-direct-shutdown.patch @@ -0,0 +1,91 @@ +From stable+bounces-7650-greg=kroah.com@vger.kernel.org Mon Dec 18 16:39:41 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:32:41 +0900 +Subject: ksmbd: add smb-direct shutdown +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , Yufan Chen , Steve French +Message-ID: <20231218153454.8090-22-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit 136dff3a6b71dc16c30b35cc390feb0bfc32ed50 ] + +When killing ksmbd server after connecting rdma, ksmbd threads does not +terminate properly because the rdma connection is still alive. +This patch add shutdown operation to disconnect rdma connection while +ksmbd threads terminate. + +Signed-off-by: Yufan Chen +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/connection.c | 9 ++++++++- + fs/ksmbd/connection.h | 1 + + fs/ksmbd/transport_rdma.c | 10 ++++++++++ + 3 files changed, 19 insertions(+), 1 deletion(-) + +--- a/fs/ksmbd/connection.c ++++ b/fs/ksmbd/connection.c +@@ -399,17 +399,24 @@ out: + static void stop_sessions(void) + { + struct ksmbd_conn *conn; ++ struct ksmbd_transport *t; + + again: + read_lock(&conn_list_lock); + list_for_each_entry(conn, &conn_list, conns_list) { + struct task_struct *task; + +- task = conn->transport->handler; ++ t = conn->transport; ++ task = t->handler; + if (task) + ksmbd_debug(CONN, "Stop session handler %s/%d\n", + task->comm, task_pid_nr(task)); + conn->status = KSMBD_SESS_EXITING; ++ if (t->ops->shutdown) { ++ read_unlock(&conn_list_lock); ++ t->ops->shutdown(t); ++ read_lock(&conn_list_lock); ++ } + } + read_unlock(&conn_list_lock); + +--- a/fs/ksmbd/connection.h ++++ b/fs/ksmbd/connection.h +@@ -110,6 +110,7 @@ struct ksmbd_conn_ops { + struct ksmbd_transport_ops { + int (*prepare)(struct ksmbd_transport *t); + void (*disconnect)(struct ksmbd_transport *t); ++ void (*shutdown)(struct ksmbd_transport *t); + int (*read)(struct ksmbd_transport *t, char *buf, + unsigned int size, int max_retries); + int (*writev)(struct ksmbd_transport *t, struct kvec *iovs, int niov, +--- a/fs/ksmbd/transport_rdma.c ++++ b/fs/ksmbd/transport_rdma.c +@@ -1459,6 +1459,15 @@ static void smb_direct_disconnect(struct + free_transport(st); + } + ++static void smb_direct_shutdown(struct ksmbd_transport *t) ++{ ++ struct smb_direct_transport *st = smb_trans_direct_transfort(t); ++ ++ ksmbd_debug(RDMA, "smb-direct shutdown cm_id=%p\n", st->cm_id); ++ ++ smb_direct_disconnect_rdma_work(&st->disconnect_work); ++} ++ + static int smb_direct_cm_handler(struct rdma_cm_id *cm_id, + struct rdma_cm_event *event) + { +@@ -2207,6 +2216,7 @@ out: + static struct ksmbd_transport_ops ksmbd_smb_direct_transport_ops = { + .prepare = smb_direct_prepare, + .disconnect = smb_direct_disconnect, ++ .shutdown = smb_direct_shutdown, + .writev = smb_direct_writev, + .read = smb_direct_read, + .rdma_read = smb_direct_rdma_read, diff --git a/queue-5.15/ksmbd-add-support-for-key-exchange.patch b/queue-5.15/ksmbd-add-support-for-key-exchange.patch new file mode 100644 index 00000000000..d6ed007b443 --- /dev/null +++ b/queue-5.15/ksmbd-add-support-for-key-exchange.patch @@ -0,0 +1,79 @@ +From linkinjeon@gmail.com Mon Dec 18 16:36:39 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:32:44 +0900 +Subject: ksmbd: add support for key exchange +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-25-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit f9929ef6a2a55f03aac61248c6a3a987b8546f2a ] + +When mounting cifs client, can see the following warning message. + +CIFS: decode_ntlmssp_challenge: authentication has been weakened as server +does not support key exchange + +To remove this warning message, Add support for key exchange feature to +ksmbd. This patch decrypts 16-byte ciphertext value sent by the client +using RC4 with session key. The decrypted value is the recovered secondary +key that will use instead of the session key for signing and sealing. + +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/auth.c | 27 +++++++++++++++++++++++++++ + 1 file changed, 27 insertions(+) + +--- a/fs/ksmbd/auth.c ++++ b/fs/ksmbd/auth.c +@@ -29,6 +29,7 @@ + #include "mgmt/user_config.h" + #include "crypto_ctx.h" + #include "transport_ipc.h" ++#include "../smbfs_common/arc4.h" + + /* + * Fixed format data defining GSS header and fixed string +@@ -342,6 +343,29 @@ int ksmbd_decode_ntlmssp_auth_blob(struc + nt_len - CIFS_ENCPWD_SIZE, + domain_name, conn->ntlmssp.cryptkey); + kfree(domain_name); ++ ++ /* The recovered secondary session key */ ++ if (conn->ntlmssp.client_flags & NTLMSSP_NEGOTIATE_KEY_XCH) { ++ struct arc4_ctx *ctx_arc4; ++ unsigned int sess_key_off, sess_key_len; ++ ++ sess_key_off = le32_to_cpu(authblob->SessionKey.BufferOffset); ++ sess_key_len = le16_to_cpu(authblob->SessionKey.Length); ++ ++ if (blob_len < (u64)sess_key_off + sess_key_len) ++ return -EINVAL; ++ ++ ctx_arc4 = kmalloc(sizeof(*ctx_arc4), GFP_KERNEL); ++ if (!ctx_arc4) ++ return -ENOMEM; ++ ++ cifs_arc4_setkey(ctx_arc4, sess->sess_key, ++ SMB2_NTLMV2_SESSKEY_SIZE); ++ cifs_arc4_crypt(ctx_arc4, sess->sess_key, ++ (char *)authblob + sess_key_off, sess_key_len); ++ kfree_sensitive(ctx_arc4); ++ } ++ + return ret; + } + +@@ -414,6 +438,9 @@ ksmbd_build_ntlmssp_challenge_blob(struc + (cflags & NTLMSSP_NEGOTIATE_EXTENDED_SEC)) + flags |= NTLMSSP_NEGOTIATE_EXTENDED_SEC; + ++ if (cflags & NTLMSSP_NEGOTIATE_KEY_XCH) ++ flags |= NTLMSSP_NEGOTIATE_KEY_XCH; ++ + chgblob->NegotiateFlags = cpu_to_le32(flags); + len = strlen(ksmbd_netbios_name()); + name = kmalloc(2 + UNICODE_LEN(len), GFP_KERNEL); diff --git a/queue-5.15/ksmbd-add-support-for-read-compound.patch b/queue-5.15/ksmbd-add-support-for-read-compound.patch new file mode 100644 index 00000000000..7d0e7b9458d --- /dev/null +++ b/queue-5.15/ksmbd-add-support-for-read-compound.patch @@ -0,0 +1,1921 @@ +From linkinjeon@gmail.com Mon Dec 18 16:41:45 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:34:19 +0900 +Subject: ksmbd: add support for read compound +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-120-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit e2b76ab8b5c9327ab2dae6da05d0752eb2f4771d ] + +MacOS sends a compound request including read to the server +(e.g. open-read-close). So far, ksmbd has not handled read as +a compound request. For compatibility between ksmbd and an OS that +supports SMB, This patch provides compound support for read requests. + +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/auth.c | 11 + fs/ksmbd/connection.c | 55 +--- + fs/ksmbd/connection.h | 2 + fs/ksmbd/ksmbd_work.c | 91 ++++++++ + fs/ksmbd/ksmbd_work.h | 34 ++- + fs/ksmbd/oplock.c | 17 - + fs/ksmbd/server.c | 8 + fs/ksmbd/smb2pdu.c | 510 +++++++++++++++++++--------------------------- + fs/ksmbd/smb_common.c | 13 - + fs/ksmbd/transport_rdma.c | 4 + fs/ksmbd/vfs.c | 4 + fs/ksmbd/vfs.h | 4 + 12 files changed, 381 insertions(+), 372 deletions(-) + +--- a/fs/ksmbd/auth.c ++++ b/fs/ksmbd/auth.c +@@ -1029,11 +1029,15 @@ static struct scatterlist *ksmbd_init_sg + { + struct scatterlist *sg; + unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 20; +- int i, nr_entries[3] = {0}, total_entries = 0, sg_idx = 0; ++ int i, *nr_entries, total_entries = 0, sg_idx = 0; + + if (!nvec) + return NULL; + ++ nr_entries = kcalloc(nvec, sizeof(int), GFP_KERNEL); ++ if (!nr_entries) ++ return NULL; ++ + for (i = 0; i < nvec - 1; i++) { + unsigned long kaddr = (unsigned long)iov[i + 1].iov_base; + +@@ -1051,8 +1055,10 @@ static struct scatterlist *ksmbd_init_sg + total_entries += 2; + + sg = kmalloc_array(total_entries, sizeof(struct scatterlist), GFP_KERNEL); +- if (!sg) ++ if (!sg) { ++ kfree(nr_entries); + return NULL; ++ } + + sg_init_table(sg, total_entries); + smb2_sg_set_buf(&sg[sg_idx++], iov[0].iov_base + 24, assoc_data_len); +@@ -1086,6 +1092,7 @@ static struct scatterlist *ksmbd_init_sg + } + } + smb2_sg_set_buf(&sg[sg_idx], sign, SMB2_SIGNATURE_SIZE); ++ kfree(nr_entries); + return sg; + } + +--- a/fs/ksmbd/connection.c ++++ b/fs/ksmbd/connection.c +@@ -123,28 +123,22 @@ void ksmbd_conn_enqueue_request(struct k + } + } + +-int ksmbd_conn_try_dequeue_request(struct ksmbd_work *work) ++void ksmbd_conn_try_dequeue_request(struct ksmbd_work *work) + { + struct ksmbd_conn *conn = work->conn; +- int ret = 1; + + if (list_empty(&work->request_entry) && + list_empty(&work->async_request_entry)) +- return 0; ++ return; + +- if (!work->multiRsp) +- atomic_dec(&conn->req_running); +- if (!work->multiRsp) { +- spin_lock(&conn->request_lock); +- list_del_init(&work->request_entry); +- spin_unlock(&conn->request_lock); +- if (work->asynchronous) +- release_async_work(work); +- ret = 0; +- } ++ atomic_dec(&conn->req_running); ++ spin_lock(&conn->request_lock); ++ list_del_init(&work->request_entry); ++ spin_unlock(&conn->request_lock); ++ if (work->asynchronous) ++ release_async_work(work); + + wake_up_all(&conn->req_running_q); +- return ret; + } + + void ksmbd_conn_lock(struct ksmbd_conn *conn) +@@ -193,41 +187,22 @@ void ksmbd_conn_wait_idle(struct ksmbd_c + int ksmbd_conn_write(struct ksmbd_work *work) + { + struct ksmbd_conn *conn = work->conn; +- size_t len = 0; + int sent; +- struct kvec iov[3]; +- int iov_idx = 0; + + if (!work->response_buf) { + pr_err("NULL response header\n"); + return -EINVAL; + } + +- if (work->tr_buf) { +- iov[iov_idx] = (struct kvec) { work->tr_buf, +- sizeof(struct smb2_transform_hdr) + 4 }; +- len += iov[iov_idx++].iov_len; +- } +- +- if (work->aux_payload_sz) { +- iov[iov_idx] = (struct kvec) { work->response_buf, work->resp_hdr_sz }; +- len += iov[iov_idx++].iov_len; +- iov[iov_idx] = (struct kvec) { work->aux_payload_buf, work->aux_payload_sz }; +- len += iov[iov_idx++].iov_len; +- } else { +- if (work->tr_buf) +- iov[iov_idx].iov_len = work->resp_hdr_sz; +- else +- iov[iov_idx].iov_len = get_rfc1002_len(work->response_buf) + 4; +- iov[iov_idx].iov_base = work->response_buf; +- len += iov[iov_idx++].iov_len; +- } ++ if (work->send_no_response) ++ return 0; + + ksmbd_conn_lock(conn); +- sent = conn->transport->ops->writev(conn->transport, &iov[0], +- iov_idx, len, +- work->need_invalidate_rkey, +- work->remote_key); ++ sent = conn->transport->ops->writev(conn->transport, work->iov, ++ work->iov_cnt, ++ get_rfc1002_len(work->iov[0].iov_base) + 4, ++ work->need_invalidate_rkey, ++ work->remote_key); + ksmbd_conn_unlock(conn); + + if (sent < 0) { +--- a/fs/ksmbd/connection.h ++++ b/fs/ksmbd/connection.h +@@ -158,7 +158,7 @@ int ksmbd_conn_rdma_write(struct ksmbd_c + struct smb2_buffer_desc_v1 *desc, + unsigned int desc_len); + void ksmbd_conn_enqueue_request(struct ksmbd_work *work); +-int ksmbd_conn_try_dequeue_request(struct ksmbd_work *work); ++void ksmbd_conn_try_dequeue_request(struct ksmbd_work *work); + void ksmbd_conn_init_server_callbacks(struct ksmbd_conn_ops *ops); + int ksmbd_conn_handler_loop(void *p); + int ksmbd_conn_transport_init(void); +--- a/fs/ksmbd/ksmbd_work.c ++++ b/fs/ksmbd/ksmbd_work.c +@@ -27,18 +27,35 @@ struct ksmbd_work *ksmbd_alloc_work_stru + INIT_LIST_HEAD(&work->async_request_entry); + INIT_LIST_HEAD(&work->fp_entry); + INIT_LIST_HEAD(&work->interim_entry); ++ INIT_LIST_HEAD(&work->aux_read_list); ++ work->iov_alloc_cnt = 4; ++ work->iov = kcalloc(work->iov_alloc_cnt, sizeof(struct kvec), ++ GFP_KERNEL); ++ if (!work->iov) { ++ kmem_cache_free(work_cache, work); ++ work = NULL; ++ } + } + return work; + } + + void ksmbd_free_work_struct(struct ksmbd_work *work) + { ++ struct aux_read *ar, *tmp; ++ + WARN_ON(work->saved_cred != NULL); + + kvfree(work->response_buf); +- kvfree(work->aux_payload_buf); ++ ++ list_for_each_entry_safe(ar, tmp, &work->aux_read_list, entry) { ++ kvfree(ar->buf); ++ list_del(&ar->entry); ++ kfree(ar); ++ } ++ + kfree(work->tr_buf); + kvfree(work->request_buf); ++ kfree(work->iov); + if (work->async_id) + ksmbd_release_id(&work->conn->async_ida, work->async_id); + kmem_cache_free(work_cache, work); +@@ -77,3 +94,75 @@ bool ksmbd_queue_work(struct ksmbd_work + { + return queue_work(ksmbd_wq, &work->work); + } ++ ++static int ksmbd_realloc_iov_pin(struct ksmbd_work *work, void *ib, ++ unsigned int ib_len) ++{ ++ ++ if (work->iov_alloc_cnt <= work->iov_cnt) { ++ struct kvec *new; ++ ++ work->iov_alloc_cnt += 4; ++ new = krealloc(work->iov, ++ sizeof(struct kvec) * work->iov_alloc_cnt, ++ GFP_KERNEL | __GFP_ZERO); ++ if (!new) ++ return -ENOMEM; ++ work->iov = new; ++ } ++ ++ work->iov[++work->iov_idx].iov_base = ib; ++ work->iov[work->iov_idx].iov_len = ib_len; ++ work->iov_cnt++; ++ ++ return 0; ++} ++ ++static int __ksmbd_iov_pin_rsp(struct ksmbd_work *work, void *ib, int len, ++ void *aux_buf, unsigned int aux_size) ++{ ++ /* Plus rfc_length size on first iov */ ++ if (!work->iov_idx) { ++ work->iov[work->iov_idx].iov_base = work->response_buf; ++ *(__be32 *)work->iov[0].iov_base = 0; ++ work->iov[work->iov_idx].iov_len = 4; ++ work->iov_cnt++; ++ } ++ ++ ksmbd_realloc_iov_pin(work, ib, len); ++ inc_rfc1001_len(work->iov[0].iov_base, len); ++ ++ if (aux_size) { ++ struct aux_read *ar; ++ ++ ksmbd_realloc_iov_pin(work, aux_buf, aux_size); ++ inc_rfc1001_len(work->iov[0].iov_base, aux_size); ++ ++ ar = kmalloc(sizeof(struct aux_read), GFP_KERNEL); ++ if (!ar) ++ return -ENOMEM; ++ ++ ar->buf = aux_buf; ++ list_add(&ar->entry, &work->aux_read_list); ++ } ++ ++ return 0; ++} ++ ++int ksmbd_iov_pin_rsp(struct ksmbd_work *work, void *ib, int len) ++{ ++ return __ksmbd_iov_pin_rsp(work, ib, len, NULL, 0); ++} ++ ++int ksmbd_iov_pin_rsp_read(struct ksmbd_work *work, void *ib, int len, ++ void *aux_buf, unsigned int aux_size) ++{ ++ return __ksmbd_iov_pin_rsp(work, ib, len, aux_buf, aux_size); ++} ++ ++void ksmbd_iov_reset(struct ksmbd_work *work) ++{ ++ work->iov_idx = 0; ++ work->iov_cnt = 0; ++ *(__be32 *)work->iov[0].iov_base = 0; ++} +--- a/fs/ksmbd/ksmbd_work.h ++++ b/fs/ksmbd/ksmbd_work.h +@@ -19,6 +19,11 @@ enum { + KSMBD_WORK_CLOSED, + }; + ++struct aux_read { ++ void *buf; ++ struct list_head entry; ++}; ++ + /* one of these for every pending CIFS request at the connection */ + struct ksmbd_work { + /* Server corresponding to this mid */ +@@ -31,13 +36,19 @@ struct ksmbd_work { + /* Response buffer */ + void *response_buf; + +- /* Read data buffer */ +- void *aux_payload_buf; ++ struct list_head aux_read_list; ++ ++ struct kvec *iov; ++ int iov_alloc_cnt; ++ int iov_cnt; ++ int iov_idx; + + /* Next cmd hdr in compound req buf*/ + int next_smb2_rcv_hdr_off; + /* Next cmd hdr in compound rsp buf*/ + int next_smb2_rsp_hdr_off; ++ /* Current cmd hdr in compound rsp buf*/ ++ int curr_smb2_rsp_hdr_off; + + /* + * Current Local FID assigned compound response if SMB2 CREATE +@@ -53,16 +64,11 @@ struct ksmbd_work { + unsigned int credits_granted; + + /* response smb header size */ +- unsigned int resp_hdr_sz; + unsigned int response_sz; +- /* Read data count */ +- unsigned int aux_payload_sz; + + void *tr_buf; + + unsigned char state; +- /* Multiple responses for one request e.g. SMB ECHO */ +- bool multiRsp:1; + /* No response for cancelled request */ + bool send_no_response:1; + /* Request is encrypted */ +@@ -96,6 +102,15 @@ static inline void *ksmbd_resp_buf_next( + } + + /** ++ * ksmbd_resp_buf_curr - Get current buffer on compound response. ++ * @work: smb work containing response buffer ++ */ ++static inline void *ksmbd_resp_buf_curr(struct ksmbd_work *work) ++{ ++ return work->response_buf + work->curr_smb2_rsp_hdr_off + 4; ++} ++ ++/** + * ksmbd_req_buf_next - Get next buffer on compound request. + * @work: smb work containing response buffer + */ +@@ -113,5 +128,8 @@ int ksmbd_work_pool_init(void); + int ksmbd_workqueue_init(void); + void ksmbd_workqueue_destroy(void); + bool ksmbd_queue_work(struct ksmbd_work *work); +- ++int ksmbd_iov_pin_rsp_read(struct ksmbd_work *work, void *ib, int len, ++ void *aux_buf, unsigned int aux_size); ++int ksmbd_iov_pin_rsp(struct ksmbd_work *work, void *ib, int len); ++void ksmbd_iov_reset(struct ksmbd_work *work); + #endif /* __KSMBD_WORK_H__ */ +--- a/fs/ksmbd/oplock.c ++++ b/fs/ksmbd/oplock.c +@@ -639,7 +639,6 @@ static void __smb2_oplock_break_noti(str + { + struct smb2_oplock_break *rsp = NULL; + struct ksmbd_work *work = container_of(wk, struct ksmbd_work, work); +- struct ksmbd_conn *conn = work->conn; + struct oplock_break_info *br_info = work->request_buf; + struct smb2_hdr *rsp_hdr; + struct ksmbd_file *fp; +@@ -656,8 +655,6 @@ static void __smb2_oplock_break_noti(str + + rsp_hdr = smb2_get_msg(work->response_buf); + memset(rsp_hdr, 0, sizeof(struct smb2_hdr) + 2); +- *(__be32 *)work->response_buf = +- cpu_to_be32(conn->vals->header_size); + rsp_hdr->ProtocolId = SMB2_PROTO_NUMBER; + rsp_hdr->StructureSize = SMB2_HEADER_STRUCTURE_SIZE; + rsp_hdr->CreditRequest = cpu_to_le16(0); +@@ -684,13 +681,15 @@ static void __smb2_oplock_break_noti(str + rsp->PersistentFid = fp->persistent_id; + rsp->VolatileFid = fp->volatile_id; + +- inc_rfc1001_len(work->response_buf, 24); ++ ksmbd_fd_put(work, fp); ++ if (ksmbd_iov_pin_rsp(work, (void *)rsp, ++ sizeof(struct smb2_oplock_break))) ++ goto out; + + ksmbd_debug(OPLOCK, + "sending oplock break v_id %llu p_id = %llu lock level = %d\n", + rsp->VolatileFid, rsp->PersistentFid, rsp->OplockLevel); + +- ksmbd_fd_put(work, fp); + ksmbd_conn_write(work); + + out: +@@ -751,7 +750,6 @@ static void __smb2_lease_break_noti(stru + struct smb2_lease_break *rsp = NULL; + struct ksmbd_work *work = container_of(wk, struct ksmbd_work, work); + struct lease_break_info *br_info = work->request_buf; +- struct ksmbd_conn *conn = work->conn; + struct smb2_hdr *rsp_hdr; + + if (allocate_oplock_break_buf(work)) { +@@ -761,8 +759,6 @@ static void __smb2_lease_break_noti(stru + + rsp_hdr = smb2_get_msg(work->response_buf); + memset(rsp_hdr, 0, sizeof(struct smb2_hdr) + 2); +- *(__be32 *)work->response_buf = +- cpu_to_be32(conn->vals->header_size); + rsp_hdr->ProtocolId = SMB2_PROTO_NUMBER; + rsp_hdr->StructureSize = SMB2_HEADER_STRUCTURE_SIZE; + rsp_hdr->CreditRequest = cpu_to_le16(0); +@@ -791,7 +787,9 @@ static void __smb2_lease_break_noti(stru + rsp->AccessMaskHint = 0; + rsp->ShareMaskHint = 0; + +- inc_rfc1001_len(work->response_buf, 44); ++ if (ksmbd_iov_pin_rsp(work, (void *)rsp, ++ sizeof(struct smb2_lease_break))) ++ goto out; + + ksmbd_conn_write(work); + +@@ -845,6 +843,7 @@ static int smb2_lease_break_noti(struct + setup_async_work(in_work, NULL, NULL); + smb2_send_interim_resp(in_work, STATUS_PENDING); + list_del(&in_work->interim_entry); ++ ksmbd_iov_reset(in_work); + } + INIT_WORK(&work->work, __smb2_lease_break_noti); + ksmbd_queue_work(work); +--- a/fs/ksmbd/server.c ++++ b/fs/ksmbd/server.c +@@ -163,6 +163,7 @@ static void __handle_ksmbd_work(struct k + { + u16 command = 0; + int rc; ++ bool is_chained = false; + + if (conn->ops->allocate_rsp_buf(work)) + return; +@@ -229,14 +230,13 @@ static void __handle_ksmbd_work(struct k + } + } + ++ is_chained = is_chained_smb2_message(work); ++ + if (work->sess && + (work->sess->sign || smb3_11_final_sess_setup_resp(work) || + conn->ops->is_sign_req(work, command))) + conn->ops->set_sign_rsp(work); +- } while (is_chained_smb2_message(work)); +- +- if (work->send_no_response) +- return; ++ } while (is_chained == true); + + send: + smb3_preauth_hash_rsp(work); +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -145,12 +145,18 @@ void smb2_set_err_rsp(struct ksmbd_work + err_rsp = smb2_get_msg(work->response_buf); + + if (err_rsp->hdr.Status != STATUS_STOPPED_ON_SYMLINK) { ++ int err; ++ + err_rsp->StructureSize = SMB2_ERROR_STRUCTURE_SIZE2_LE; + err_rsp->ErrorContextCount = 0; + err_rsp->Reserved = 0; + err_rsp->ByteCount = 0; + err_rsp->ErrorData[0] = 0; +- inc_rfc1001_len(work->response_buf, SMB2_ERROR_STRUCTURE_SIZE2); ++ err = ksmbd_iov_pin_rsp(work, (void *)err_rsp, ++ work->conn->vals->header_size + ++ SMB2_ERROR_STRUCTURE_SIZE2); ++ if (err) ++ work->send_no_response = 1; + } + } + +@@ -245,9 +251,7 @@ int init_smb2_neg_rsp(struct ksmbd_work + struct smb2_hdr *rsp_hdr; + struct smb2_negotiate_rsp *rsp; + struct ksmbd_conn *conn = work->conn; +- +- *(__be32 *)work->response_buf = +- cpu_to_be32(conn->vals->header_size); ++ int err; + + rsp_hdr = smb2_get_msg(work->response_buf); + memset(rsp_hdr, 0, sizeof(struct smb2_hdr) + 2); +@@ -286,13 +290,14 @@ int init_smb2_neg_rsp(struct ksmbd_work + rsp->SecurityBufferLength = cpu_to_le16(AUTH_GSS_LENGTH); + ksmbd_copy_gss_neg_header((char *)(&rsp->hdr) + + le16_to_cpu(rsp->SecurityBufferOffset)); +- inc_rfc1001_len(work->response_buf, +- sizeof(struct smb2_negotiate_rsp) - +- sizeof(struct smb2_hdr) - sizeof(rsp->Buffer) + +- AUTH_GSS_LENGTH); + rsp->SecurityMode = SMB2_NEGOTIATE_SIGNING_ENABLED_LE; + if (server_conf.signing == KSMBD_CONFIG_OPT_MANDATORY) + rsp->SecurityMode |= SMB2_NEGOTIATE_SIGNING_REQUIRED_LE; ++ err = ksmbd_iov_pin_rsp(work, rsp, ++ sizeof(struct smb2_negotiate_rsp) - ++ sizeof(rsp->Buffer) + AUTH_GSS_LENGTH); ++ if (err) ++ return err; + conn->use_spnego = true; + + ksmbd_conn_set_need_negotiate(conn); +@@ -391,11 +396,12 @@ static void init_chained_smb2_rsp(struct + next_hdr_offset = le32_to_cpu(req->NextCommand); + + new_len = ALIGN(len, 8); +- inc_rfc1001_len(work->response_buf, +- sizeof(struct smb2_hdr) + new_len - len); ++ work->iov[work->iov_idx].iov_len += (new_len - len); ++ inc_rfc1001_len(work->response_buf, new_len - len); + rsp->NextCommand = cpu_to_le32(new_len); + + work->next_smb2_rcv_hdr_off += next_hdr_offset; ++ work->curr_smb2_rsp_hdr_off = work->next_smb2_rsp_hdr_off; + work->next_smb2_rsp_hdr_off += new_len; + ksmbd_debug(SMB, + "Compound req new_len = %d rcv off = %d rsp off = %d\n", +@@ -471,10 +477,10 @@ bool is_chained_smb2_message(struct ksmb + len = len - get_rfc1002_len(work->response_buf); + if (len) { + ksmbd_debug(SMB, "padding len %u\n", len); ++ work->iov[work->iov_idx].iov_len += len; + inc_rfc1001_len(work->response_buf, len); +- if (work->aux_payload_sz) +- work->aux_payload_sz += len; + } ++ work->curr_smb2_rsp_hdr_off = work->next_smb2_rsp_hdr_off; + } + return false; + } +@@ -489,11 +495,8 @@ int init_smb2_rsp_hdr(struct ksmbd_work + { + struct smb2_hdr *rsp_hdr = smb2_get_msg(work->response_buf); + struct smb2_hdr *rcv_hdr = smb2_get_msg(work->request_buf); +- struct ksmbd_conn *conn = work->conn; + + memset(rsp_hdr, 0, sizeof(struct smb2_hdr) + 2); +- *(__be32 *)work->response_buf = +- cpu_to_be32(conn->vals->header_size); + rsp_hdr->ProtocolId = rcv_hdr->ProtocolId; + rsp_hdr->StructureSize = SMB2_HEADER_STRUCTURE_SIZE; + rsp_hdr->Command = rcv_hdr->Command; +@@ -658,7 +661,7 @@ int setup_async_work(struct ksmbd_work * + struct ksmbd_conn *conn = work->conn; + int id; + +- rsp_hdr = smb2_get_msg(work->response_buf); ++ rsp_hdr = ksmbd_resp_buf_next(work); + rsp_hdr->Flags |= SMB2_FLAGS_ASYNC_COMMAND; + + id = ksmbd_acquire_async_msg_id(&conn->async_ida); +@@ -708,14 +711,12 @@ void smb2_send_interim_resp(struct ksmbd + { + struct smb2_hdr *rsp_hdr; + +- rsp_hdr = smb2_get_msg(work->response_buf); ++ rsp_hdr = ksmbd_resp_buf_next(work); + smb2_set_err_rsp(work); + rsp_hdr->Status = status; + +- work->multiRsp = 1; + ksmbd_conn_write(work); + rsp_hdr->Status = 0; +- work->multiRsp = 0; + } + + static __le32 smb2_get_reparse_tag_special_file(umode_t mode) +@@ -822,9 +823,8 @@ static void build_posix_ctxt(struct smb2 + pneg_ctxt->Name[15] = 0x7C; + } + +-static void assemble_neg_contexts(struct ksmbd_conn *conn, +- struct smb2_negotiate_rsp *rsp, +- void *smb2_buf_len) ++static unsigned int assemble_neg_contexts(struct ksmbd_conn *conn, ++ struct smb2_negotiate_rsp *rsp) + { + char * const pneg_ctxt = (char *)rsp + + le32_to_cpu(rsp->NegotiateContextOffset); +@@ -835,7 +835,6 @@ static void assemble_neg_contexts(struct + "assemble SMB2_PREAUTH_INTEGRITY_CAPABILITIES context\n"); + build_preauth_ctxt((struct smb2_preauth_neg_context *)pneg_ctxt, + conn->preauth_info->Preauth_HashId); +- inc_rfc1001_len(smb2_buf_len, AUTH_GSS_PADDING); + ctxt_size = sizeof(struct smb2_preauth_neg_context); + + if (conn->cipher_type) { +@@ -874,7 +873,7 @@ static void assemble_neg_contexts(struct + } + + rsp->NegotiateContextCount = cpu_to_le16(neg_ctxt_cnt); +- inc_rfc1001_len(smb2_buf_len, ctxt_size); ++ return ctxt_size + AUTH_GSS_PADDING; + } + + static __le32 decode_preauth_ctxt(struct ksmbd_conn *conn, +@@ -1090,7 +1089,7 @@ int smb2_handle_negotiate(struct ksmbd_w + struct smb2_negotiate_req *req = smb2_get_msg(work->request_buf); + struct smb2_negotiate_rsp *rsp = smb2_get_msg(work->response_buf); + int rc = 0; +- unsigned int smb2_buf_len, smb2_neg_size; ++ unsigned int smb2_buf_len, smb2_neg_size, neg_ctxt_len = 0; + __le32 status; + + ksmbd_debug(SMB, "Received negotiate request\n"); +@@ -1183,7 +1182,7 @@ int smb2_handle_negotiate(struct ksmbd_w + conn->preauth_info->Preauth_HashValue); + rsp->NegotiateContextOffset = + cpu_to_le32(OFFSET_OF_NEG_CONTEXT); +- assemble_neg_contexts(conn, rsp, work->response_buf); ++ neg_ctxt_len = assemble_neg_contexts(conn, rsp); + break; + case SMB302_PROT_ID: + init_smb3_02_server(conn); +@@ -1233,9 +1232,6 @@ int smb2_handle_negotiate(struct ksmbd_w + rsp->SecurityBufferLength = cpu_to_le16(AUTH_GSS_LENGTH); + ksmbd_copy_gss_neg_header((char *)(&rsp->hdr) + + le16_to_cpu(rsp->SecurityBufferOffset)); +- inc_rfc1001_len(work->response_buf, sizeof(struct smb2_negotiate_rsp) - +- sizeof(struct smb2_hdr) - sizeof(rsp->Buffer) + +- AUTH_GSS_LENGTH); + rsp->SecurityMode = SMB2_NEGOTIATE_SIGNING_ENABLED_LE; + conn->use_spnego = true; + +@@ -1253,9 +1249,16 @@ int smb2_handle_negotiate(struct ksmbd_w + ksmbd_conn_set_need_negotiate(conn); + + err_out: ++ if (rc) ++ rsp->hdr.Status = STATUS_INSUFFICIENT_RESOURCES; ++ ++ if (!rc) ++ rc = ksmbd_iov_pin_rsp(work, rsp, ++ sizeof(struct smb2_negotiate_rsp) - ++ sizeof(rsp->Buffer) + ++ AUTH_GSS_LENGTH + neg_ctxt_len); + if (rc < 0) + smb2_set_err_rsp(work); +- + return rc; + } + +@@ -1455,7 +1458,6 @@ static int ntlm_authenticate(struct ksmb + memcpy((char *)&rsp->hdr.ProtocolId + sz, spnego_blob, spnego_blob_len); + rsp->SecurityBufferLength = cpu_to_le16(spnego_blob_len); + kfree(spnego_blob); +- inc_rfc1001_len(work->response_buf, spnego_blob_len - 1); + } + + user = session_user(conn, req); +@@ -1601,7 +1603,6 @@ static int krb5_authenticate(struct ksmb + return -EINVAL; + } + rsp->SecurityBufferLength = cpu_to_le16(out_len); +- inc_rfc1001_len(work->response_buf, out_len - 1); + + if ((conn->sign || server_conf.enforced_signing) || + (req->SecurityMode & SMB2_NEGOTIATE_SIGNING_REQUIRED)) +@@ -1673,7 +1674,6 @@ int smb2_sess_setup(struct ksmbd_work *w + rsp->SessionFlags = 0; + rsp->SecurityBufferOffset = cpu_to_le16(72); + rsp->SecurityBufferLength = 0; +- inc_rfc1001_len(work->response_buf, 9); + + ksmbd_conn_lock(conn); + if (!req->hdr.SessionId) { +@@ -1809,13 +1809,6 @@ int smb2_sess_setup(struct ksmbd_work *w + goto out_err; + rsp->hdr.Status = + STATUS_MORE_PROCESSING_REQUIRED; +- /* +- * Note: here total size -1 is done as an +- * adjustment for 0 size blob +- */ +- inc_rfc1001_len(work->response_buf, +- le16_to_cpu(rsp->SecurityBufferLength) - 1); +- + } else if (negblob->MessageType == NtLmAuthenticate) { + rc = ntlm_authenticate(work, req, rsp); + if (rc) +@@ -1900,6 +1893,17 @@ out_err: + ksmbd_conn_set_need_negotiate(conn); + } + } ++ } else { ++ unsigned int iov_len; ++ ++ if (rsp->SecurityBufferLength) ++ iov_len = offsetof(struct smb2_sess_setup_rsp, Buffer) + ++ le16_to_cpu(rsp->SecurityBufferLength); ++ else ++ iov_len = sizeof(struct smb2_sess_setup_rsp); ++ rc = ksmbd_iov_pin_rsp(work, rsp, iov_len); ++ if (rc) ++ rsp->hdr.Status = STATUS_INSUFFICIENT_RESOURCES; + } + + ksmbd_conn_unlock(conn); +@@ -1978,13 +1982,16 @@ int smb2_tree_connect(struct ksmbd_work + status.tree_conn->posix_extensions = true; + + rsp->StructureSize = cpu_to_le16(16); +- inc_rfc1001_len(work->response_buf, 16); + out_err1: + rsp->Capabilities = 0; + rsp->Reserved = 0; + /* default manual caching */ + rsp->ShareFlags = SMB2_SHAREFLAG_MANUAL_CACHING; + ++ rc = ksmbd_iov_pin_rsp(work, rsp, sizeof(struct smb2_tree_connect_rsp)); ++ if (rc) ++ status.ret = KSMBD_TREE_CONN_STATUS_NOMEM; ++ + if (!IS_ERR(treename)) + kfree(treename); + if (!IS_ERR(name)) +@@ -2097,20 +2104,27 @@ int smb2_tree_disconnect(struct ksmbd_wo + struct smb2_tree_disconnect_req *req; + struct ksmbd_session *sess = work->sess; + struct ksmbd_tree_connect *tcon = work->tcon; ++ int err; + + WORK_BUFFERS(work, req, rsp); + +- rsp->StructureSize = cpu_to_le16(4); +- inc_rfc1001_len(work->response_buf, 4); +- + ksmbd_debug(SMB, "request\n"); + ++ rsp->StructureSize = cpu_to_le16(4); ++ err = ksmbd_iov_pin_rsp(work, rsp, ++ sizeof(struct smb2_tree_disconnect_rsp)); ++ if (err) { ++ rsp->hdr.Status = STATUS_INSUFFICIENT_RESOURCES; ++ smb2_set_err_rsp(work); ++ return err; ++ } ++ + if (!tcon || test_and_set_bit(TREE_CONN_EXPIRE, &tcon->status)) { + ksmbd_debug(SMB, "Invalid tid %d\n", req->hdr.Id.SyncId.TreeId); + + rsp->hdr.Status = STATUS_NETWORK_NAME_DELETED; + smb2_set_err_rsp(work); +- return 0; ++ return -ENOENT; + } + + ksmbd_close_tree_conn_fds(work); +@@ -2132,15 +2146,21 @@ int smb2_session_logoff(struct ksmbd_wor + struct smb2_logoff_rsp *rsp; + struct ksmbd_session *sess; + u64 sess_id; ++ int err; + + WORK_BUFFERS(work, req, rsp); + ++ ksmbd_debug(SMB, "request\n"); ++ + sess_id = le64_to_cpu(req->hdr.SessionId); + + rsp->StructureSize = cpu_to_le16(4); +- inc_rfc1001_len(work->response_buf, 4); +- +- ksmbd_debug(SMB, "request\n"); ++ err = ksmbd_iov_pin_rsp(work, rsp, sizeof(struct smb2_logoff_rsp)); ++ if (err) { ++ rsp->hdr.Status = STATUS_INSUFFICIENT_RESOURCES; ++ smb2_set_err_rsp(work); ++ return err; ++ } + + ksmbd_all_conn_set_status(sess_id, KSMBD_SESS_NEED_RECONNECT); + ksmbd_close_session_fds(work); +@@ -2155,7 +2175,7 @@ int smb2_session_logoff(struct ksmbd_wor + ksmbd_debug(SMB, "Invalid tid %d\n", req->hdr.Id.SyncId.TreeId); + rsp->hdr.Status = STATUS_NETWORK_NAME_DELETED; + smb2_set_err_rsp(work); +- return 0; ++ return -ENOENT; + } + + ksmbd_destroy_file_table(&sess->file_table); +@@ -2216,7 +2236,10 @@ static noinline int create_smb2_pipe(str + rsp->CreateContextsOffset = 0; + rsp->CreateContextsLength = 0; + +- inc_rfc1001_len(work->response_buf, 88); /* StructureSize - 1*/ ++ err = ksmbd_iov_pin_rsp(work, rsp, offsetof(struct smb2_create_rsp, Buffer)); ++ if (err) ++ goto out; ++ + kfree(name); + return 0; + +@@ -2595,6 +2618,7 @@ int smb2_open(struct ksmbd_work *work) + u64 time; + umode_t posix_mode = 0; + __le32 daccess, maximal_access = 0; ++ int iov_len = 0; + + WORK_BUFFERS(work, req, rsp); + +@@ -3246,7 +3270,7 @@ int smb2_open(struct ksmbd_work *work) + + rsp->CreateContextsOffset = 0; + rsp->CreateContextsLength = 0; +- inc_rfc1001_len(work->response_buf, 88); /* StructureSize - 1*/ ++ iov_len = offsetof(struct smb2_create_rsp, Buffer); + + /* If lease is request send lease context response */ + if (opinfo && opinfo->is_lease) { +@@ -3261,8 +3285,7 @@ int smb2_open(struct ksmbd_work *work) + create_lease_buf(rsp->Buffer, opinfo->o_lease); + le32_add_cpu(&rsp->CreateContextsLength, + conn->vals->create_lease_size); +- inc_rfc1001_len(work->response_buf, +- conn->vals->create_lease_size); ++ iov_len += conn->vals->create_lease_size; + next_ptr = &lease_ccontext->Next; + next_off = conn->vals->create_lease_size; + } +@@ -3282,8 +3305,7 @@ int smb2_open(struct ksmbd_work *work) + le32_to_cpu(maximal_access)); + le32_add_cpu(&rsp->CreateContextsLength, + conn->vals->create_mxac_size); +- inc_rfc1001_len(work->response_buf, +- conn->vals->create_mxac_size); ++ iov_len += conn->vals->create_mxac_size; + if (next_ptr) + *next_ptr = cpu_to_le32(next_off); + next_ptr = &mxac_ccontext->Next; +@@ -3301,8 +3323,7 @@ int smb2_open(struct ksmbd_work *work) + stat.ino, tcon->id); + le32_add_cpu(&rsp->CreateContextsLength, + conn->vals->create_disk_id_size); +- inc_rfc1001_len(work->response_buf, +- conn->vals->create_disk_id_size); ++ iov_len += conn->vals->create_disk_id_size; + if (next_ptr) + *next_ptr = cpu_to_le32(next_off); + next_ptr = &disk_id_ccontext->Next; +@@ -3316,8 +3337,7 @@ int smb2_open(struct ksmbd_work *work) + fp); + le32_add_cpu(&rsp->CreateContextsLength, + conn->vals->create_posix_size); +- inc_rfc1001_len(work->response_buf, +- conn->vals->create_posix_size); ++ iov_len += conn->vals->create_posix_size; + if (next_ptr) + *next_ptr = cpu_to_le32(next_off); + } +@@ -3335,7 +3355,8 @@ err_out: + } + ksmbd_revert_fsids(work); + err_out1: +- ++ if (!rc) ++ rc = ksmbd_iov_pin_rsp(work, (void *)rsp, iov_len); + if (rc) { + if (rc == -EINVAL) + rsp->hdr.Status = STATUS_INVALID_PARAMETER; +@@ -4062,7 +4083,10 @@ int smb2_query_dir(struct ksmbd_work *wo + rsp->OutputBufferOffset = cpu_to_le16(0); + rsp->OutputBufferLength = cpu_to_le32(0); + rsp->Buffer[0] = 0; +- inc_rfc1001_len(work->response_buf, 9); ++ rc = ksmbd_iov_pin_rsp(work, (void *)rsp, ++ sizeof(struct smb2_query_directory_rsp)); ++ if (rc) ++ goto err_out; + } else { + no_buf_len: + ((struct file_directory_info *) +@@ -4074,7 +4098,11 @@ no_buf_len: + rsp->StructureSize = cpu_to_le16(9); + rsp->OutputBufferOffset = cpu_to_le16(72); + rsp->OutputBufferLength = cpu_to_le32(d_info.data_count); +- inc_rfc1001_len(work->response_buf, 8 + d_info.data_count); ++ rc = ksmbd_iov_pin_rsp(work, (void *)rsp, ++ offsetof(struct smb2_query_directory_rsp, Buffer) + ++ d_info.data_count); ++ if (rc) ++ goto err_out; + } + + kfree(srch_ptr); +@@ -4121,21 +4149,13 @@ err_out2: + */ + static int buffer_check_err(int reqOutputBufferLength, + struct smb2_query_info_rsp *rsp, +- void *rsp_org, int infoclass_size) ++ void *rsp_org) + { + if (reqOutputBufferLength < le32_to_cpu(rsp->OutputBufferLength)) { +- if (reqOutputBufferLength < infoclass_size) { +- 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; +- } +- +- ksmbd_debug(SMB, "Buffer Overflow\n"); +- rsp->hdr.Status = STATUS_BUFFER_OVERFLOW; +- *(__be32 *)rsp_org = cpu_to_be32(sizeof(struct smb2_hdr) + +- reqOutputBufferLength); +- rsp->OutputBufferLength = cpu_to_le32(reqOutputBufferLength); ++ 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; + } + return 0; + } +@@ -4154,7 +4174,6 @@ static void get_standard_info_pipe(struc + sinfo->Directory = 0; + rsp->OutputBufferLength = + cpu_to_le32(sizeof(struct smb2_file_standard_info)); +- inc_rfc1001_len(rsp_org, sizeof(struct smb2_file_standard_info)); + } + + static void get_internal_info_pipe(struct smb2_query_info_rsp *rsp, u64 num, +@@ -4168,7 +4187,6 @@ static void get_internal_info_pipe(struc + file_info->IndexNumber = cpu_to_le64(num | (1ULL << 63)); + rsp->OutputBufferLength = + cpu_to_le32(sizeof(struct smb2_file_internal_info)); +- inc_rfc1001_len(rsp_org, sizeof(struct smb2_file_internal_info)); + } + + static int smb2_get_info_file_pipe(struct ksmbd_session *sess, +@@ -4194,14 +4212,12 @@ static int smb2_get_info_file_pipe(struc + case FILE_STANDARD_INFORMATION: + get_standard_info_pipe(rsp, rsp_org); + rc = buffer_check_err(le32_to_cpu(req->OutputBufferLength), +- rsp, rsp_org, +- FILE_STANDARD_INFORMATION_SIZE); ++ rsp, rsp_org); + break; + case FILE_INTERNAL_INFORMATION: + get_internal_info_pipe(rsp, id, rsp_org); + rc = buffer_check_err(le32_to_cpu(req->OutputBufferLength), +- rsp, rsp_org, +- FILE_INTERNAL_INFORMATION_SIZE); ++ rsp, rsp_org); + break; + default: + ksmbd_debug(SMB, "smb2_info_file_pipe for %u not supported\n", +@@ -4369,7 +4385,6 @@ done: + if (rsp_data_cnt == 0) + rsp->hdr.Status = STATUS_NO_EAS_ON_FILE; + rsp->OutputBufferLength = cpu_to_le32(rsp_data_cnt); +- inc_rfc1001_len(rsp_org, rsp_data_cnt); + out: + kvfree(xattr_list); + return rc; +@@ -4384,7 +4399,6 @@ static void get_file_access_info(struct + file_info->AccessFlags = fp->daccess; + rsp->OutputBufferLength = + cpu_to_le32(sizeof(struct smb2_file_access_info)); +- inc_rfc1001_len(rsp_org, sizeof(struct smb2_file_access_info)); + } + + static int get_file_basic_info(struct smb2_query_info_rsp *rsp, +@@ -4414,7 +4428,6 @@ static int get_file_basic_info(struct sm + basic_info->Pad1 = 0; + rsp->OutputBufferLength = + cpu_to_le32(sizeof(struct smb2_file_basic_info)); +- inc_rfc1001_len(rsp_org, sizeof(struct smb2_file_basic_info)); + return 0; + } + +@@ -4439,8 +4452,6 @@ static void get_file_standard_info(struc + sinfo->Directory = S_ISDIR(stat.mode) ? 1 : 0; + rsp->OutputBufferLength = + cpu_to_le32(sizeof(struct smb2_file_standard_info)); +- inc_rfc1001_len(rsp_org, +- sizeof(struct smb2_file_standard_info)); + } + + static void get_file_alignment_info(struct smb2_query_info_rsp *rsp, +@@ -4452,8 +4463,6 @@ static void get_file_alignment_info(stru + file_info->AlignmentRequirement = 0; + rsp->OutputBufferLength = + cpu_to_le32(sizeof(struct smb2_file_alignment_info)); +- inc_rfc1001_len(rsp_org, +- sizeof(struct smb2_file_alignment_info)); + } + + static int get_file_all_info(struct ksmbd_work *work, +@@ -4517,7 +4526,6 @@ static int get_file_all_info(struct ksmb + rsp->OutputBufferLength = + cpu_to_le32(sizeof(struct smb2_file_all_info) + conv_len - 1); + kfree(filename); +- inc_rfc1001_len(rsp_org, le32_to_cpu(rsp->OutputBufferLength)); + return 0; + } + +@@ -4540,7 +4548,6 @@ static void get_file_alternate_info(stru + file_info->FileNameLength = cpu_to_le32(conv_len); + rsp->OutputBufferLength = + cpu_to_le32(sizeof(struct smb2_file_alt_name_info) + conv_len); +- inc_rfc1001_len(rsp_org, le32_to_cpu(rsp->OutputBufferLength)); + } + + static void get_file_stream_info(struct ksmbd_work *work, +@@ -4640,7 +4647,6 @@ out: + kvfree(xattr_list); + + rsp->OutputBufferLength = cpu_to_le32(nbytes); +- inc_rfc1001_len(rsp_org, nbytes); + } + + static void get_file_internal_info(struct smb2_query_info_rsp *rsp, +@@ -4655,7 +4661,6 @@ static void get_file_internal_info(struc + file_info->IndexNumber = cpu_to_le64(stat.ino); + rsp->OutputBufferLength = + cpu_to_le32(sizeof(struct smb2_file_internal_info)); +- inc_rfc1001_len(rsp_org, sizeof(struct smb2_file_internal_info)); + } + + static int get_file_network_open_info(struct smb2_query_info_rsp *rsp, +@@ -4691,7 +4696,6 @@ static int get_file_network_open_info(st + file_info->Reserved = cpu_to_le32(0); + rsp->OutputBufferLength = + cpu_to_le32(sizeof(struct smb2_file_ntwrk_info)); +- inc_rfc1001_len(rsp_org, sizeof(struct smb2_file_ntwrk_info)); + return 0; + } + +@@ -4703,7 +4707,6 @@ static void get_file_ea_info(struct smb2 + file_info->EASize = 0; + rsp->OutputBufferLength = + cpu_to_le32(sizeof(struct smb2_file_ea_info)); +- inc_rfc1001_len(rsp_org, sizeof(struct smb2_file_ea_info)); + } + + static void get_file_position_info(struct smb2_query_info_rsp *rsp, +@@ -4715,7 +4718,6 @@ static void get_file_position_info(struc + file_info->CurrentByteOffset = cpu_to_le64(fp->filp->f_pos); + rsp->OutputBufferLength = + cpu_to_le32(sizeof(struct smb2_file_pos_info)); +- inc_rfc1001_len(rsp_org, sizeof(struct smb2_file_pos_info)); + } + + static void get_file_mode_info(struct smb2_query_info_rsp *rsp, +@@ -4727,7 +4729,6 @@ static void get_file_mode_info(struct sm + file_info->Mode = fp->coption & FILE_MODE_INFO_MASK; + rsp->OutputBufferLength = + cpu_to_le32(sizeof(struct smb2_file_mode_info)); +- inc_rfc1001_len(rsp_org, sizeof(struct smb2_file_mode_info)); + } + + static void get_file_compression_info(struct smb2_query_info_rsp *rsp, +@@ -4749,7 +4750,6 @@ static void get_file_compression_info(st + + rsp->OutputBufferLength = + cpu_to_le32(sizeof(struct smb2_file_comp_info)); +- inc_rfc1001_len(rsp_org, sizeof(struct smb2_file_comp_info)); + } + + static int get_file_attribute_tag_info(struct smb2_query_info_rsp *rsp, +@@ -4768,11 +4768,10 @@ static int get_file_attribute_tag_info(s + file_info->ReparseTag = 0; + rsp->OutputBufferLength = + cpu_to_le32(sizeof(struct smb2_file_attr_tag_info)); +- inc_rfc1001_len(rsp_org, sizeof(struct smb2_file_attr_tag_info)); + return 0; + } + +-static int find_file_posix_info(struct smb2_query_info_rsp *rsp, ++static void find_file_posix_info(struct smb2_query_info_rsp *rsp, + struct ksmbd_file *fp, void *rsp_org) + { + struct smb311_posix_qinfo *file_info; +@@ -4812,8 +4811,6 @@ static int find_file_posix_info(struct s + (struct smb_sid *)&file_info->Sids[16]); + + rsp->OutputBufferLength = cpu_to_le32(out_buf_len); +- inc_rfc1001_len(rsp_org, out_buf_len); +- return out_buf_len; + } + + static int smb2_get_info_file(struct ksmbd_work *work, +@@ -4823,7 +4820,6 @@ static int smb2_get_info_file(struct ksm + struct ksmbd_file *fp; + int fileinfoclass = 0; + int rc = 0; +- int file_infoclass_size; + unsigned int id = KSMBD_NO_FID, pid = KSMBD_NO_FID; + + if (test_share_config_flag(work->tcon->share_conf, +@@ -4856,85 +4852,69 @@ static int smb2_get_info_file(struct ksm + switch (fileinfoclass) { + case FILE_ACCESS_INFORMATION: + get_file_access_info(rsp, fp, work->response_buf); +- file_infoclass_size = FILE_ACCESS_INFORMATION_SIZE; + break; + + case FILE_BASIC_INFORMATION: + rc = get_file_basic_info(rsp, fp, work->response_buf); +- file_infoclass_size = FILE_BASIC_INFORMATION_SIZE; + break; + + case FILE_STANDARD_INFORMATION: + get_file_standard_info(rsp, fp, work->response_buf); +- file_infoclass_size = FILE_STANDARD_INFORMATION_SIZE; + break; + + case FILE_ALIGNMENT_INFORMATION: + get_file_alignment_info(rsp, work->response_buf); +- file_infoclass_size = FILE_ALIGNMENT_INFORMATION_SIZE; + break; + + case FILE_ALL_INFORMATION: + rc = get_file_all_info(work, rsp, fp, work->response_buf); +- file_infoclass_size = FILE_ALL_INFORMATION_SIZE; + break; + + case FILE_ALTERNATE_NAME_INFORMATION: + get_file_alternate_info(work, rsp, fp, work->response_buf); +- file_infoclass_size = FILE_ALTERNATE_NAME_INFORMATION_SIZE; + break; + + case FILE_STREAM_INFORMATION: + get_file_stream_info(work, rsp, fp, work->response_buf); +- file_infoclass_size = FILE_STREAM_INFORMATION_SIZE; + break; + + case FILE_INTERNAL_INFORMATION: + get_file_internal_info(rsp, fp, work->response_buf); +- file_infoclass_size = FILE_INTERNAL_INFORMATION_SIZE; + break; + + case FILE_NETWORK_OPEN_INFORMATION: + rc = get_file_network_open_info(rsp, fp, work->response_buf); +- file_infoclass_size = FILE_NETWORK_OPEN_INFORMATION_SIZE; + break; + + case FILE_EA_INFORMATION: + get_file_ea_info(rsp, work->response_buf); +- file_infoclass_size = FILE_EA_INFORMATION_SIZE; + break; + + case FILE_FULL_EA_INFORMATION: + rc = smb2_get_ea(work, fp, req, rsp, work->response_buf); +- file_infoclass_size = FILE_FULL_EA_INFORMATION_SIZE; + break; + + case FILE_POSITION_INFORMATION: + get_file_position_info(rsp, fp, work->response_buf); +- file_infoclass_size = FILE_POSITION_INFORMATION_SIZE; + break; + + case FILE_MODE_INFORMATION: + get_file_mode_info(rsp, fp, work->response_buf); +- file_infoclass_size = FILE_MODE_INFORMATION_SIZE; + break; + + case FILE_COMPRESSION_INFORMATION: + get_file_compression_info(rsp, fp, work->response_buf); +- file_infoclass_size = FILE_COMPRESSION_INFORMATION_SIZE; + break; + + case FILE_ATTRIBUTE_TAG_INFORMATION: + rc = get_file_attribute_tag_info(rsp, fp, work->response_buf); +- file_infoclass_size = FILE_ATTRIBUTE_TAG_INFORMATION_SIZE; + break; + case SMB_FIND_FILE_POSIX_INFO: + if (!work->tcon->posix_extensions) { + pr_err("client doesn't negotiate with SMB3.1.1 POSIX Extensions\n"); + rc = -EOPNOTSUPP; + } else { +- file_infoclass_size = find_file_posix_info(rsp, fp, +- work->response_buf); ++ find_file_posix_info(rsp, fp, work->response_buf); + } + break; + default: +@@ -4944,8 +4924,7 @@ static int smb2_get_info_file(struct ksm + } + if (!rc) + rc = buffer_check_err(le32_to_cpu(req->OutputBufferLength), +- rsp, work->response_buf, +- file_infoclass_size); ++ rsp, work->response_buf); + ksmbd_fd_put(work, fp); + return rc; + } +@@ -4961,7 +4940,6 @@ static int smb2_get_info_filesystem(stru + struct kstatfs stfs; + struct path path; + int rc = 0, len; +- int fs_infoclass_size = 0; + + if (!share->path) + return -EIO; +@@ -4991,8 +4969,6 @@ static int smb2_get_info_filesystem(stru + info->DeviceType = cpu_to_le32(stfs.f_type); + info->DeviceCharacteristics = cpu_to_le32(0x00000020); + rsp->OutputBufferLength = cpu_to_le32(8); +- inc_rfc1001_len(work->response_buf, 8); +- fs_infoclass_size = FS_DEVICE_INFORMATION_SIZE; + break; + } + case FS_ATTRIBUTE_INFORMATION: +@@ -5021,8 +4997,6 @@ static int smb2_get_info_filesystem(stru + info->FileSystemNameLen = cpu_to_le32(len); + sz = sizeof(struct filesystem_attribute_info) - 2 + len; + rsp->OutputBufferLength = cpu_to_le32(sz); +- inc_rfc1001_len(work->response_buf, sz); +- fs_infoclass_size = FS_ATTRIBUTE_INFORMATION_SIZE; + break; + } + case FS_VOLUME_INFORMATION: +@@ -5049,8 +5023,6 @@ static int smb2_get_info_filesystem(stru + info->Reserved = 0; + sz = sizeof(struct filesystem_vol_info) - 2 + len; + rsp->OutputBufferLength = cpu_to_le32(sz); +- inc_rfc1001_len(work->response_buf, sz); +- fs_infoclass_size = FS_VOLUME_INFORMATION_SIZE; + break; + } + case FS_SIZE_INFORMATION: +@@ -5063,8 +5035,6 @@ static int smb2_get_info_filesystem(stru + info->SectorsPerAllocationUnit = cpu_to_le32(1); + info->BytesPerSector = cpu_to_le32(stfs.f_bsize); + rsp->OutputBufferLength = cpu_to_le32(24); +- inc_rfc1001_len(work->response_buf, 24); +- fs_infoclass_size = FS_SIZE_INFORMATION_SIZE; + break; + } + case FS_FULL_SIZE_INFORMATION: +@@ -5080,8 +5050,6 @@ static int smb2_get_info_filesystem(stru + info->SectorsPerAllocationUnit = cpu_to_le32(1); + info->BytesPerSector = cpu_to_le32(stfs.f_bsize); + rsp->OutputBufferLength = cpu_to_le32(32); +- inc_rfc1001_len(work->response_buf, 32); +- fs_infoclass_size = FS_FULL_SIZE_INFORMATION_SIZE; + break; + } + case FS_OBJECT_ID_INFORMATION: +@@ -5101,8 +5069,6 @@ static int smb2_get_info_filesystem(stru + info->extended_info.rel_date = 0; + memcpy(info->extended_info.version_string, "1.1.0", strlen("1.1.0")); + rsp->OutputBufferLength = cpu_to_le32(64); +- inc_rfc1001_len(work->response_buf, 64); +- fs_infoclass_size = FS_OBJECT_ID_INFORMATION_SIZE; + break; + } + case FS_SECTOR_SIZE_INFORMATION: +@@ -5124,8 +5090,6 @@ static int smb2_get_info_filesystem(stru + info->ByteOffsetForSectorAlignment = 0; + info->ByteOffsetForPartitionAlignment = 0; + rsp->OutputBufferLength = cpu_to_le32(28); +- inc_rfc1001_len(work->response_buf, 28); +- fs_infoclass_size = FS_SECTOR_SIZE_INFORMATION_SIZE; + break; + } + case FS_CONTROL_INFORMATION: +@@ -5146,8 +5110,6 @@ static int smb2_get_info_filesystem(stru + info->DefaultQuotaLimit = cpu_to_le64(SMB2_NO_FID); + info->Padding = 0; + rsp->OutputBufferLength = cpu_to_le32(48); +- inc_rfc1001_len(work->response_buf, 48); +- fs_infoclass_size = FS_CONTROL_INFORMATION_SIZE; + break; + } + case FS_POSIX_INFORMATION: +@@ -5167,8 +5129,6 @@ static int smb2_get_info_filesystem(stru + info->TotalFileNodes = cpu_to_le64(stfs.f_files); + info->FreeFileNodes = cpu_to_le64(stfs.f_ffree); + rsp->OutputBufferLength = cpu_to_le32(56); +- inc_rfc1001_len(work->response_buf, 56); +- fs_infoclass_size = FS_POSIX_INFORMATION_SIZE; + } + break; + } +@@ -5177,8 +5137,7 @@ static int smb2_get_info_filesystem(stru + return -EOPNOTSUPP; + } + rc = buffer_check_err(le32_to_cpu(req->OutputBufferLength), +- rsp, work->response_buf, +- fs_infoclass_size); ++ rsp, work->response_buf); + path_put(&path); + return rc; + } +@@ -5212,7 +5171,6 @@ static int smb2_get_info_sec(struct ksmb + + secdesclen = sizeof(struct smb_ntsd); + rsp->OutputBufferLength = cpu_to_le32(secdesclen); +- inc_rfc1001_len(work->response_buf, secdesclen); + + return 0; + } +@@ -5257,7 +5215,6 @@ static int smb2_get_info_sec(struct ksmb + return rc; + + rsp->OutputBufferLength = cpu_to_le32(secdesclen); +- inc_rfc1001_len(work->response_buf, secdesclen); + return 0; + } + +@@ -5296,6 +5253,14 @@ int smb2_query_info(struct ksmbd_work *w + rc = -EOPNOTSUPP; + } + ++ if (!rc) { ++ rsp->StructureSize = cpu_to_le16(9); ++ rsp->OutputBufferOffset = cpu_to_le16(72); ++ rc = ksmbd_iov_pin_rsp(work, (void *)rsp, ++ offsetof(struct smb2_query_info_rsp, Buffer) + ++ le32_to_cpu(rsp->OutputBufferLength)); ++ } ++ + if (rc < 0) { + if (rc == -EACCES) + rsp->hdr.Status = STATUS_ACCESS_DENIED; +@@ -5303,6 +5268,8 @@ int smb2_query_info(struct ksmbd_work *w + rsp->hdr.Status = STATUS_FILE_CLOSED; + else if (rc == -EIO) + rsp->hdr.Status = STATUS_UNEXPECTED_IO_ERROR; ++ else if (rc == -ENOMEM) ++ rsp->hdr.Status = STATUS_INSUFFICIENT_RESOURCES; + else if (rc == -EOPNOTSUPP || rsp->hdr.Status == 0) + rsp->hdr.Status = STATUS_INVALID_INFO_CLASS; + smb2_set_err_rsp(work); +@@ -5311,9 +5278,6 @@ int smb2_query_info(struct ksmbd_work *w + rc); + return rc; + } +- rsp->StructureSize = cpu_to_le16(9); +- rsp->OutputBufferOffset = cpu_to_le16(72); +- inc_rfc1001_len(work->response_buf, 8); + return 0; + } + +@@ -5344,8 +5308,9 @@ static noinline int smb2_close_pipe(stru + rsp->AllocationSize = 0; + rsp->EndOfFile = 0; + rsp->Attributes = 0; +- inc_rfc1001_len(work->response_buf, 60); +- return 0; ++ ++ return ksmbd_iov_pin_rsp(work, (void *)rsp, ++ sizeof(struct smb2_close_rsp)); + } + + /** +@@ -5450,15 +5415,17 @@ int smb2_close(struct ksmbd_work *work) + + err = ksmbd_close_fd(work, volatile_id); + out: ++ if (!err) ++ err = ksmbd_iov_pin_rsp(work, (void *)rsp, ++ sizeof(struct smb2_close_rsp)); ++ + if (err) { + if (rsp->hdr.Status == 0) + rsp->hdr.Status = STATUS_FILE_CLOSED; + smb2_set_err_rsp(work); +- } else { +- inc_rfc1001_len(work->response_buf, 60); + } + +- return 0; ++ return err; + } + + /** +@@ -5476,8 +5443,7 @@ int smb2_echo(struct ksmbd_work *work) + + rsp->StructureSize = cpu_to_le16(4); + rsp->Reserved = 0; +- inc_rfc1001_len(work->response_buf, 4); +- return 0; ++ return ksmbd_iov_pin_rsp(work, rsp, sizeof(struct smb2_echo_rsp)); + } + + static int smb2_rename(struct ksmbd_work *work, +@@ -6071,7 +6037,10 @@ int smb2_set_info(struct ksmbd_work *wor + goto err_out; + + rsp->StructureSize = cpu_to_le16(2); +- inc_rfc1001_len(work->response_buf, 2); ++ rc = ksmbd_iov_pin_rsp(work, (void *)rsp, ++ sizeof(struct smb2_set_info_rsp)); ++ if (rc) ++ goto err_out; + ksmbd_fd_put(work, fp); + return 0; + +@@ -6118,28 +6087,36 @@ static noinline int smb2_read_pipe(struc + + id = req->VolatileFileId; + +- inc_rfc1001_len(work->response_buf, 16); + rpc_resp = ksmbd_rpc_read(work->sess, id); + if (rpc_resp) { ++ void *aux_payload_buf; ++ + if (rpc_resp->flags != KSMBD_RPC_OK) { + err = -EINVAL; + goto out; + } + +- work->aux_payload_buf = ++ aux_payload_buf = + kvmalloc(rpc_resp->payload_sz, GFP_KERNEL); +- if (!work->aux_payload_buf) { ++ if (!aux_payload_buf) { + err = -ENOMEM; + goto out; + } + +- memcpy(work->aux_payload_buf, rpc_resp->payload, +- rpc_resp->payload_sz); ++ memcpy(aux_payload_buf, rpc_resp->payload, rpc_resp->payload_sz); + + nbytes = rpc_resp->payload_sz; +- work->resp_hdr_sz = get_rfc1002_len(work->response_buf) + 4; +- work->aux_payload_sz = nbytes; + kvfree(rpc_resp); ++ err = ksmbd_iov_pin_rsp_read(work, (void *)rsp, ++ offsetof(struct smb2_read_rsp, Buffer), ++ aux_payload_buf, nbytes); ++ if (err) ++ goto out; ++ } else { ++ err = ksmbd_iov_pin_rsp(work, (void *)rsp, ++ offsetof(struct smb2_read_rsp, Buffer)); ++ if (err) ++ goto out; + } + + rsp->StructureSize = cpu_to_le16(17); +@@ -6148,7 +6125,6 @@ static noinline int smb2_read_pipe(struc + rsp->DataLength = cpu_to_le32(nbytes); + rsp->DataRemaining = 0; + rsp->Reserved2 = 0; +- inc_rfc1001_len(work->response_buf, nbytes); + return 0; + + out: +@@ -6222,13 +6198,8 @@ int smb2_read(struct ksmbd_work *work) + int err = 0; + bool is_rdma_channel = false; + unsigned int max_read_size = conn->vals->max_read_size; +- +- WORK_BUFFERS(work, req, rsp); +- if (work->next_smb2_rcv_hdr_off) { +- work->send_no_response = 1; +- err = -EOPNOTSUPP; +- goto out; +- } ++ unsigned int id = KSMBD_NO_FID, pid = KSMBD_NO_FID; ++ void *aux_payload_buf; + + if (test_share_config_flag(work->tcon->share_conf, + KSMBD_SHARE_FLAG_PIPE)) { +@@ -6236,6 +6207,25 @@ int smb2_read(struct ksmbd_work *work) + return smb2_read_pipe(work); + } + ++ if (work->next_smb2_rcv_hdr_off) { ++ req = ksmbd_req_buf_next(work); ++ rsp = ksmbd_resp_buf_next(work); ++ if (!has_file_id(req->VolatileFileId)) { ++ ksmbd_debug(SMB, "Compound request set FID = %llu\n", ++ work->compound_fid); ++ id = work->compound_fid; ++ pid = work->compound_pfid; ++ } ++ } else { ++ req = smb2_get_msg(work->request_buf); ++ rsp = smb2_get_msg(work->response_buf); ++ } ++ ++ if (!has_file_id(id)) { ++ id = req->VolatileFileId; ++ pid = req->PersistentFileId; ++ } ++ + if (req->Channel == SMB2_CHANNEL_RDMA_V1_INVALIDATE || + req->Channel == SMB2_CHANNEL_RDMA_V1) { + is_rdma_channel = true; +@@ -6258,7 +6248,7 @@ int smb2_read(struct ksmbd_work *work) + goto out; + } + +- fp = ksmbd_lookup_fd_slow(work, req->VolatileFileId, req->PersistentFileId); ++ fp = ksmbd_lookup_fd_slow(work, id, pid); + if (!fp) { + err = -ENOENT; + goto out; +@@ -6284,21 +6274,20 @@ int smb2_read(struct ksmbd_work *work) + ksmbd_debug(SMB, "filename %pD, offset %lld, len %zu\n", + fp->filp, offset, length); + +- work->aux_payload_buf = kvzalloc(length, GFP_KERNEL); +- if (!work->aux_payload_buf) { ++ aux_payload_buf = kvzalloc(length, GFP_KERNEL); ++ if (!aux_payload_buf) { + err = -ENOMEM; + goto out; + } + +- nbytes = ksmbd_vfs_read(work, fp, length, &offset); ++ nbytes = ksmbd_vfs_read(work, fp, length, &offset, aux_payload_buf); + if (nbytes < 0) { + err = nbytes; + goto out; + } + + if ((nbytes == 0 && length != 0) || nbytes < mincount) { +- kvfree(work->aux_payload_buf); +- work->aux_payload_buf = NULL; ++ kvfree(aux_payload_buf); + rsp->hdr.Status = STATUS_END_OF_FILE; + smb2_set_err_rsp(work); + ksmbd_fd_put(work, fp); +@@ -6311,10 +6300,9 @@ int smb2_read(struct ksmbd_work *work) + if (is_rdma_channel == true) { + /* write data to the client using rdma channel */ + remain_bytes = smb2_read_rdma_channel(work, req, +- work->aux_payload_buf, ++ aux_payload_buf, + nbytes); +- kvfree(work->aux_payload_buf); +- work->aux_payload_buf = NULL; ++ kvfree(aux_payload_buf); + + nbytes = 0; + if (remain_bytes < 0) { +@@ -6329,10 +6317,11 @@ int smb2_read(struct ksmbd_work *work) + rsp->DataLength = cpu_to_le32(nbytes); + rsp->DataRemaining = cpu_to_le32(remain_bytes); + rsp->Reserved2 = 0; +- inc_rfc1001_len(work->response_buf, 16); +- work->resp_hdr_sz = get_rfc1002_len(work->response_buf) + 4; +- work->aux_payload_sz = nbytes; +- inc_rfc1001_len(work->response_buf, nbytes); ++ err = ksmbd_iov_pin_rsp_read(work, (void *)rsp, ++ offsetof(struct smb2_read_rsp, Buffer), ++ aux_payload_buf, nbytes); ++ if (err) ++ goto out; + ksmbd_fd_put(work, fp); + return 0; + +@@ -6415,8 +6404,8 @@ static noinline int smb2_write_pipe(stru + rsp->DataLength = cpu_to_le32(length); + rsp->DataRemaining = 0; + rsp->Reserved2 = 0; +- inc_rfc1001_len(work->response_buf, 16); +- return 0; ++ err = ksmbd_iov_pin_rsp(work, (void *)rsp, ++ offsetof(struct smb2_write_rsp, Buffer)); + out: + if (err) { + rsp->hdr.Status = STATUS_INVALID_HANDLE; +@@ -6572,7 +6561,9 @@ int smb2_write(struct ksmbd_work *work) + rsp->DataLength = cpu_to_le32(nbytes); + rsp->DataRemaining = 0; + rsp->Reserved2 = 0; +- inc_rfc1001_len(work->response_buf, 16); ++ err = ksmbd_iov_pin_rsp(work, rsp, offsetof(struct smb2_write_rsp, Buffer)); ++ if (err) ++ goto out; + ksmbd_fd_put(work, fp); + return 0; + +@@ -6619,15 +6610,11 @@ int smb2_flush(struct ksmbd_work *work) + + rsp->StructureSize = cpu_to_le16(4); + rsp->Reserved = 0; +- inc_rfc1001_len(work->response_buf, 4); +- return 0; ++ return ksmbd_iov_pin_rsp(work, rsp, sizeof(struct smb2_flush_rsp)); + + out: +- if (err) { +- rsp->hdr.Status = STATUS_INVALID_HANDLE; +- smb2_set_err_rsp(work); +- } +- ++ rsp->hdr.Status = STATUS_INVALID_HANDLE; ++ smb2_set_err_rsp(work); + return err; + } + +@@ -7065,6 +7052,8 @@ skip: + list_del(&work->fp_entry); + spin_unlock(&fp->f_lock); + ++ ksmbd_iov_reset(work); ++ + if (work->state != KSMBD_WORK_ACTIVE) { + list_del(&smb_lock->llist); + spin_lock(&work->conn->llist_lock); +@@ -7083,7 +7072,6 @@ skip: + } + + init_smb2_rsp_hdr(work); +- smb2_set_err_rsp(work); + rsp->hdr.Status = + STATUS_RANGE_NOT_LOCKED; + kfree(smb_lock); +@@ -7118,7 +7106,10 @@ skip: + ksmbd_debug(SMB, "successful in taking lock\n"); + rsp->hdr.Status = STATUS_SUCCESS; + rsp->Reserved = 0; +- inc_rfc1001_len(work->response_buf, 4); ++ err = ksmbd_iov_pin_rsp(work, rsp, sizeof(struct smb2_lock_rsp)); ++ if (err) ++ goto out; ++ + ksmbd_fd_put(work, fp); + return 0; + +@@ -7914,9 +7905,9 @@ dup_ext_out: + rsp->Reserved = cpu_to_le16(0); + rsp->Flags = cpu_to_le32(0); + rsp->Reserved2 = cpu_to_le32(0); +- inc_rfc1001_len(work->response_buf, 48 + nbytes); +- +- return 0; ++ ret = ksmbd_iov_pin_rsp(work, rsp, sizeof(struct smb2_ioctl_rsp) + nbytes); ++ if (!ret) ++ return ret; + + out: + if (ret == -EACCES) +@@ -8051,8 +8042,9 @@ static void smb20_oplock_break_ack(struc + rsp->Reserved2 = 0; + rsp->VolatileFid = volatile_id; + rsp->PersistentFid = persistent_id; +- inc_rfc1001_len(work->response_buf, 24); +- return; ++ ret = ksmbd_iov_pin_rsp(work, rsp, sizeof(struct smb2_oplock_break)); ++ if (!ret) ++ return; + + err_out: + opinfo->op_state = OPLOCK_STATE_NONE; +@@ -8202,8 +8194,9 @@ static void smb21_lease_break_ack(struct + memcpy(rsp->LeaseKey, req->LeaseKey, 16); + rsp->LeaseState = lease_state; + rsp->LeaseDuration = 0; +- inc_rfc1001_len(work->response_buf, 36); +- return; ++ ret = ksmbd_iov_pin_rsp(work, rsp, sizeof(struct smb2_lease_ack)); ++ if (!ret) ++ return; + + err_out: + opinfo->op_state = OPLOCK_STATE_NONE; +@@ -8341,43 +8334,19 @@ int smb2_check_sign_req(struct ksmbd_wor + void smb2_set_sign_rsp(struct ksmbd_work *work) + { + struct smb2_hdr *hdr; +- struct smb2_hdr *req_hdr; + char signature[SMB2_HMACSHA256_SIZE]; +- struct kvec iov[2]; +- size_t len; ++ struct kvec *iov; + int n_vec = 1; + +- hdr = smb2_get_msg(work->response_buf); +- if (work->next_smb2_rsp_hdr_off) +- hdr = ksmbd_resp_buf_next(work); +- +- req_hdr = ksmbd_req_buf_next(work); +- +- if (!work->next_smb2_rsp_hdr_off) { +- len = get_rfc1002_len(work->response_buf); +- if (req_hdr->NextCommand) +- len = ALIGN(len, 8); +- } else { +- len = get_rfc1002_len(work->response_buf) - +- work->next_smb2_rsp_hdr_off; +- len = ALIGN(len, 8); +- } +- +- if (req_hdr->NextCommand) +- hdr->NextCommand = cpu_to_le32(len); +- ++ hdr = ksmbd_resp_buf_curr(work); + hdr->Flags |= SMB2_FLAGS_SIGNED; + memset(hdr->Signature, 0, SMB2_SIGNATURE_SIZE); + +- iov[0].iov_base = (char *)&hdr->ProtocolId; +- iov[0].iov_len = len; +- +- if (work->aux_payload_sz) { +- iov[0].iov_len -= work->aux_payload_sz; +- +- iov[1].iov_base = work->aux_payload_buf; +- iov[1].iov_len = work->aux_payload_sz; ++ if (hdr->Command == SMB2_READ) { ++ iov = &work->iov[work->iov_idx - 1]; + n_vec++; ++ } else { ++ iov = &work->iov[work->iov_idx]; + } + + if (!ksmbd_sign_smb2_pdu(work->conn, work->sess->sess_key, iov, n_vec, +@@ -8453,29 +8422,14 @@ int smb3_check_sign_req(struct ksmbd_wor + void smb3_set_sign_rsp(struct ksmbd_work *work) + { + struct ksmbd_conn *conn = work->conn; +- struct smb2_hdr *req_hdr, *hdr; ++ struct smb2_hdr *hdr; + struct channel *chann; + char signature[SMB2_CMACAES_SIZE]; +- struct kvec iov[2]; ++ struct kvec *iov; + int n_vec = 1; +- size_t len; + char *signing_key; + +- hdr = smb2_get_msg(work->response_buf); +- if (work->next_smb2_rsp_hdr_off) +- hdr = ksmbd_resp_buf_next(work); +- +- req_hdr = ksmbd_req_buf_next(work); +- +- if (!work->next_smb2_rsp_hdr_off) { +- len = get_rfc1002_len(work->response_buf); +- if (req_hdr->NextCommand) +- len = ALIGN(len, 8); +- } else { +- len = get_rfc1002_len(work->response_buf) - +- work->next_smb2_rsp_hdr_off; +- len = ALIGN(len, 8); +- } ++ hdr = ksmbd_resp_buf_curr(work); + + if (conn->binding == false && + le16_to_cpu(hdr->Command) == SMB2_SESSION_SETUP_HE) { +@@ -8491,21 +8445,18 @@ void smb3_set_sign_rsp(struct ksmbd_work + if (!signing_key) + return; + +- if (req_hdr->NextCommand) +- hdr->NextCommand = cpu_to_le32(len); +- + hdr->Flags |= SMB2_FLAGS_SIGNED; + memset(hdr->Signature, 0, SMB2_SIGNATURE_SIZE); +- iov[0].iov_base = (char *)&hdr->ProtocolId; +- iov[0].iov_len = len; +- if (work->aux_payload_sz) { +- iov[0].iov_len -= work->aux_payload_sz; +- iov[1].iov_base = work->aux_payload_buf; +- iov[1].iov_len = work->aux_payload_sz; ++ ++ if (hdr->Command == SMB2_READ) { ++ iov = &work->iov[work->iov_idx - 1]; + n_vec++; ++ } else { ++ iov = &work->iov[work->iov_idx]; + } + +- if (!ksmbd_sign_smb3_pdu(conn, signing_key, iov, n_vec, signature)) ++ if (!ksmbd_sign_smb3_pdu(conn, signing_key, iov, n_vec, ++ signature)) + memcpy(hdr->Signature, signature, SMB2_SIGNATURE_SIZE); + } + +@@ -8572,45 +8523,22 @@ static void fill_transform_hdr(void *tr_ + + int smb3_encrypt_resp(struct ksmbd_work *work) + { +- char *buf = work->response_buf; +- struct kvec iov[3]; ++ struct kvec *iov = work->iov; + int rc = -ENOMEM; +- int buf_size = 0, rq_nvec = 2 + (work->aux_payload_sz ? 1 : 0); ++ void *tr_buf; + +- if (ARRAY_SIZE(iov) < rq_nvec) +- return -ENOMEM; +- +- work->tr_buf = kzalloc(sizeof(struct smb2_transform_hdr) + 4, GFP_KERNEL); +- if (!work->tr_buf) ++ tr_buf = kzalloc(sizeof(struct smb2_transform_hdr) + 4, GFP_KERNEL); ++ if (!tr_buf) + return rc; + + /* fill transform header */ +- fill_transform_hdr(work->tr_buf, buf, work->conn->cipher_type); ++ fill_transform_hdr(tr_buf, work->response_buf, work->conn->cipher_type); + +- iov[0].iov_base = work->tr_buf; ++ iov[0].iov_base = tr_buf; + iov[0].iov_len = sizeof(struct smb2_transform_hdr) + 4; +- buf_size += iov[0].iov_len - 4; +- +- iov[1].iov_base = buf + 4; +- iov[1].iov_len = get_rfc1002_len(buf); +- if (work->aux_payload_sz) { +- iov[1].iov_len = work->resp_hdr_sz - 4; +- +- iov[2].iov_base = work->aux_payload_buf; +- iov[2].iov_len = work->aux_payload_sz; +- buf_size += iov[2].iov_len; +- } +- buf_size += iov[1].iov_len; +- work->resp_hdr_sz = iov[1].iov_len; ++ work->tr_buf = tr_buf; + +- rc = ksmbd_crypt_message(work, iov, rq_nvec, 1); +- if (rc) +- return rc; +- +- memmove(buf, iov[1].iov_base, iov[1].iov_len); +- *(__be32 *)work->tr_buf = cpu_to_be32(buf_size); +- +- return rc; ++ return ksmbd_crypt_message(work, iov, work->iov_idx + 1, 1); + } + + bool smb3_is_transform_hdr(void *buf) +--- a/fs/ksmbd/smb_common.c ++++ b/fs/ksmbd/smb_common.c +@@ -319,12 +319,6 @@ static int init_smb1_rsp_hdr(struct ksmb + struct smb_hdr *rsp_hdr = (struct smb_hdr *)work->response_buf; + struct smb_hdr *rcv_hdr = (struct smb_hdr *)work->request_buf; + +- /* +- * Remove 4 byte direct TCP header. +- */ +- *(__be32 *)work->response_buf = +- cpu_to_be32(sizeof(struct smb_hdr) - 4); +- + rsp_hdr->Command = SMB_COM_NEGOTIATE; + *(__le32 *)rsp_hdr->Protocol = SMB1_PROTO_NUMBER; + rsp_hdr->Flags = SMBFLG_RESPONSE; +@@ -560,10 +554,11 @@ static int smb_handle_negotiate(struct k + + ksmbd_debug(SMB, "Unsupported SMB1 protocol\n"); + +- /* Add 2 byte bcc and 2 byte DialectIndex. */ +- inc_rfc1001_len(work->response_buf, 4); +- neg_rsp->hdr.Status.CifsError = STATUS_SUCCESS; ++ if (ksmbd_iov_pin_rsp(work, (void *)neg_rsp, ++ sizeof(struct smb_negotiate_rsp) - 4)) ++ return -ENOMEM; + ++ neg_rsp->hdr.Status.CifsError = STATUS_SUCCESS; + neg_rsp->hdr.WordCount = 1; + neg_rsp->DialectIndex = cpu_to_le16(work->conn->dialect); + neg_rsp->ByteCount = 0; +--- a/fs/ksmbd/transport_rdma.c ++++ b/fs/ksmbd/transport_rdma.c +@@ -1241,14 +1241,12 @@ static int smb_direct_writev(struct ksmb + + //FIXME: skip RFC1002 header.. + buflen -= 4; +- iov[0].iov_base += 4; +- iov[0].iov_len -= 4; + + remaining_data_length = buflen; + ksmbd_debug(RDMA, "Sending smb (RDMA): smb_len=%u\n", buflen); + + smb_direct_send_ctx_init(st, &send_ctx, need_invalidate, remote_key); +- start = i = 0; ++ start = i = 1; + buflen = 0; + while (true) { + buflen += iov[i].iov_len; +--- a/fs/ksmbd/vfs.c ++++ b/fs/ksmbd/vfs.c +@@ -367,15 +367,15 @@ out: + * @fid: file id of open file + * @count: read byte count + * @pos: file pos ++ * @rbuf: read data buffer + * + * Return: number of read bytes on success, otherwise error + */ + int ksmbd_vfs_read(struct ksmbd_work *work, struct ksmbd_file *fp, size_t count, +- loff_t *pos) ++ loff_t *pos, char *rbuf) + { + struct file *filp = fp->filp; + ssize_t nbytes = 0; +- char *rbuf = work->aux_payload_buf; + struct inode *inode = file_inode(filp); + + if (S_ISDIR(inode->i_mode)) +--- a/fs/ksmbd/vfs.h ++++ b/fs/ksmbd/vfs.h +@@ -115,8 +115,8 @@ void ksmbd_vfs_query_maximal_access(stru + struct dentry *dentry, __le32 *daccess); + int ksmbd_vfs_create(struct ksmbd_work *work, const char *name, umode_t mode); + int ksmbd_vfs_mkdir(struct ksmbd_work *work, const char *name, umode_t mode); +-int ksmbd_vfs_read(struct ksmbd_work *work, struct ksmbd_file *fp, +- size_t count, loff_t *pos); ++int ksmbd_vfs_read(struct ksmbd_work *work, struct ksmbd_file *fp, size_t count, ++ loff_t *pos, char *rbuf); + int ksmbd_vfs_write(struct ksmbd_work *work, struct ksmbd_file *fp, + char *buf, size_t count, loff_t *pos, bool sync, + ssize_t *written); diff --git a/queue-5.15/ksmbd-add-support-for-surrogate-pair-conversion.patch b/queue-5.15/ksmbd-add-support-for-surrogate-pair-conversion.patch new file mode 100644 index 00000000000..ae83ec8709b --- /dev/null +++ b/queue-5.15/ksmbd-add-support-for-surrogate-pair-conversion.patch @@ -0,0 +1,294 @@ +From linkinjeon@gmail.com Mon Dec 18 16:43:07 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:34:44 +0900 +Subject: ksmbd: add support for surrogate pair conversion +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , Marios Makassikis , Steve French +Message-ID: <20231218153454.8090-145-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit 0c180317c654a494fe429adbf7bc9b0793caf9e2 ] + +ksmbd is missing supporting to convert filename included surrogate pair +characters. It triggers a "file or folder does not exist" error in +Windows client. + +[Steps to Reproduce for bug] +1. Create surrogate pair file + touch $(echo -e '\xf0\x9d\x9f\xa3') + touch $(echo -e '\xf0\x9d\x9f\xa4') + +2. Try to open these files in ksmbd share through Windows client. + +This patch update unicode functions not to consider about surrogate pair +(and IVS). + +Reviewed-by: Marios Makassikis +Tested-by: Marios Makassikis +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/unicode.c | 187 +++++++++++++++++++++++++++++++++++++++-------------- + 1 file changed, 138 insertions(+), 49 deletions(-) + +--- a/fs/ksmbd/unicode.c ++++ b/fs/ksmbd/unicode.c +@@ -15,45 +15,9 @@ + #include "smb_common.h" + + /* +- * smb_utf16_bytes() - how long will a string be after conversion? +- * @from: pointer to input string +- * @maxbytes: don't go past this many bytes of input string +- * @codepage: destination codepage +- * +- * Walk a utf16le string and return the number of bytes that the string will +- * be after being converted to the given charset, not including any null +- * termination required. Don't walk past maxbytes in the source buffer. +- * +- * Return: string length after conversion +- */ +-static int smb_utf16_bytes(const __le16 *from, int maxbytes, +- const struct nls_table *codepage) +-{ +- int i; +- int charlen, outlen = 0; +- int maxwords = maxbytes / 2; +- char tmp[NLS_MAX_CHARSET_SIZE]; +- __u16 ftmp; +- +- for (i = 0; i < maxwords; i++) { +- ftmp = get_unaligned_le16(&from[i]); +- if (ftmp == 0) +- break; +- +- charlen = codepage->uni2char(ftmp, tmp, NLS_MAX_CHARSET_SIZE); +- if (charlen > 0) +- outlen += charlen; +- else +- outlen++; +- } +- +- return outlen; +-} +- +-/* + * cifs_mapchar() - convert a host-endian char to proper char in codepage + * @target: where converted character should be copied +- * @src_char: 2 byte host-endian source character ++ * @from: host-endian source string + * @cp: codepage to which character should be converted + * @mapchar: should character be mapped according to mapchars mount option? + * +@@ -64,10 +28,13 @@ static int smb_utf16_bytes(const __le16 + * Return: string length after conversion + */ + static int +-cifs_mapchar(char *target, const __u16 src_char, const struct nls_table *cp, ++cifs_mapchar(char *target, const __u16 *from, const struct nls_table *cp, + bool mapchar) + { + int len = 1; ++ __u16 src_char; ++ ++ src_char = *from; + + if (!mapchar) + goto cp_convert; +@@ -105,12 +72,66 @@ out: + + cp_convert: + len = cp->uni2char(src_char, target, NLS_MAX_CHARSET_SIZE); +- if (len <= 0) { +- *target = '?'; +- len = 1; +- } ++ if (len <= 0) ++ goto surrogate_pair; + + goto out; ++ ++surrogate_pair: ++ /* convert SURROGATE_PAIR and IVS */ ++ if (strcmp(cp->charset, "utf8")) ++ goto unknown; ++ len = utf16s_to_utf8s(from, 3, UTF16_LITTLE_ENDIAN, target, 6); ++ if (len <= 0) ++ goto unknown; ++ return len; ++ ++unknown: ++ *target = '?'; ++ len = 1; ++ goto out; ++} ++ ++/* ++ * smb_utf16_bytes() - compute converted string length ++ * @from: pointer to input string ++ * @maxbytes: input string length ++ * @codepage: destination codepage ++ * ++ * Walk a utf16le string and return the number of bytes that the string will ++ * be after being converted to the given charset, not including any null ++ * termination required. Don't walk past maxbytes in the source buffer. ++ * ++ * Return: string length after conversion ++ */ ++static int smb_utf16_bytes(const __le16 *from, int maxbytes, ++ const struct nls_table *codepage) ++{ ++ int i, j; ++ int charlen, outlen = 0; ++ int maxwords = maxbytes / 2; ++ char tmp[NLS_MAX_CHARSET_SIZE]; ++ __u16 ftmp[3]; ++ ++ for (i = 0; i < maxwords; i++) { ++ ftmp[0] = get_unaligned_le16(&from[i]); ++ if (ftmp[0] == 0) ++ break; ++ for (j = 1; j <= 2; j++) { ++ if (i + j < maxwords) ++ ftmp[j] = get_unaligned_le16(&from[i + j]); ++ else ++ ftmp[j] = 0; ++ } ++ ++ charlen = cifs_mapchar(tmp, ftmp, codepage, 0); ++ if (charlen > 0) ++ outlen += charlen; ++ else ++ outlen++; ++ } ++ ++ return outlen; + } + + /* +@@ -140,12 +161,12 @@ cp_convert: + static int smb_from_utf16(char *to, const __le16 *from, int tolen, int fromlen, + const struct nls_table *codepage, bool mapchar) + { +- int i, charlen, safelen; ++ int i, j, charlen, safelen; + int outlen = 0; + int nullsize = nls_nullsize(codepage); + int fromwords = fromlen / 2; + char tmp[NLS_MAX_CHARSET_SIZE]; +- __u16 ftmp; ++ __u16 ftmp[3]; /* ftmp[3] = 3array x 2bytes = 6bytes UTF-16 */ + + /* + * because the chars can be of varying widths, we need to take care +@@ -156,9 +177,15 @@ static int smb_from_utf16(char *to, cons + safelen = tolen - (NLS_MAX_CHARSET_SIZE + nullsize); + + for (i = 0; i < fromwords; i++) { +- ftmp = get_unaligned_le16(&from[i]); +- if (ftmp == 0) ++ ftmp[0] = get_unaligned_le16(&from[i]); ++ if (ftmp[0] == 0) + break; ++ for (j = 1; j <= 2; j++) { ++ if (i + j < fromwords) ++ ftmp[j] = get_unaligned_le16(&from[i + j]); ++ else ++ ftmp[j] = 0; ++ } + + /* + * check to see if converting this character might make the +@@ -173,6 +200,19 @@ static int smb_from_utf16(char *to, cons + /* put converted char into 'to' buffer */ + charlen = cifs_mapchar(&to[outlen], ftmp, codepage, mapchar); + outlen += charlen; ++ ++ /* ++ * charlen (=bytes of UTF-8 for 1 character) ++ * 4bytes UTF-8(surrogate pair) is charlen=4 ++ * (4bytes UTF-16 code) ++ * 7-8bytes UTF-8(IVS) is charlen=3+4 or 4+4 ++ * (2 UTF-8 pairs divided to 2 UTF-16 pairs) ++ */ ++ if (charlen == 4) ++ i++; ++ else if (charlen >= 5) ++ /* 5-6bytes UTF-8 */ ++ i += 2; + } + + /* properly null-terminate string */ +@@ -307,6 +347,9 @@ int smbConvertToUTF16(__le16 *target, co + char src_char; + __le16 dst_char; + wchar_t tmp; ++ wchar_t wchar_to[6]; /* UTF-16 */ ++ int ret; ++ unicode_t u; + + if (!mapchars) + return smb_strtoUTF16(target, source, srclen, cp); +@@ -349,11 +392,57 @@ int smbConvertToUTF16(__le16 *target, co + * if no match, use question mark, which at least in + * some cases serves as wild card + */ +- if (charlen < 1) { +- dst_char = cpu_to_le16(0x003f); +- charlen = 1; ++ if (charlen > 0) ++ goto ctoUTF16; ++ ++ /* convert SURROGATE_PAIR */ ++ if (strcmp(cp->charset, "utf8")) ++ goto unknown; ++ if (*(source + i) & 0x80) { ++ charlen = utf8_to_utf32(source + i, 6, &u); ++ if (charlen < 0) ++ goto unknown; ++ } else ++ goto unknown; ++ ret = utf8s_to_utf16s(source + i, charlen, ++ UTF16_LITTLE_ENDIAN, ++ wchar_to, 6); ++ if (ret < 0) ++ goto unknown; ++ ++ i += charlen; ++ dst_char = cpu_to_le16(*wchar_to); ++ if (charlen <= 3) ++ /* 1-3bytes UTF-8 to 2bytes UTF-16 */ ++ put_unaligned(dst_char, &target[j]); ++ else if (charlen == 4) { ++ /* ++ * 4bytes UTF-8(surrogate pair) to 4bytes UTF-16 ++ * 7-8bytes UTF-8(IVS) divided to 2 UTF-16 ++ * (charlen=3+4 or 4+4) ++ */ ++ put_unaligned(dst_char, &target[j]); ++ dst_char = cpu_to_le16(*(wchar_to + 1)); ++ j++; ++ put_unaligned(dst_char, &target[j]); ++ } else if (charlen >= 5) { ++ /* 5-6bytes UTF-8 to 6bytes UTF-16 */ ++ put_unaligned(dst_char, &target[j]); ++ dst_char = cpu_to_le16(*(wchar_to + 1)); ++ j++; ++ put_unaligned(dst_char, &target[j]); ++ dst_char = cpu_to_le16(*(wchar_to + 2)); ++ j++; ++ put_unaligned(dst_char, &target[j]); + } ++ continue; ++ ++unknown: ++ dst_char = cpu_to_le16(0x003f); ++ charlen = 1; + } ++ ++ctoUTF16: + /* + * character may take more than one byte in the source string, + * but will take exactly two bytes in the target string diff --git a/queue-5.15/ksmbd-avoid-duplicate-negotiate-ctx-offset-increments.patch b/queue-5.15/ksmbd-avoid-duplicate-negotiate-ctx-offset-increments.patch new file mode 100644 index 00000000000..48062fa91ee --- /dev/null +++ b/queue-5.15/ksmbd-avoid-duplicate-negotiate-ctx-offset-increments.patch @@ -0,0 +1,108 @@ +From linkinjeon@gmail.com Mon Dec 18 16:39:51 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:33:44 +0900 +Subject: ksmbd: avoid duplicate negotiate ctx offset increments +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, David Disseldorp , Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-85-linkinjeon@kernel.org> + +From: David Disseldorp + +[ Upstream commit a12a07a85aff72e19520328f78b1c64d2281a1ec ] + +Both pneg_ctxt and ctxt_size change in unison, with each adding the +length of the previously added context, rounded up to an eight byte +boundary. +Drop pneg_ctxt increments and instead use the ctxt_size offset when +passing output pointers to per-context helper functions. This slightly +simplifies offset tracking and shaves off a few text bytes. +Before (x86-64 gcc 7.5): + text data bss dec hex filename + 213234 8677 672 222583 36577 ksmbd.ko + +After: + text data bss dec hex filename + 213218 8677 672 222567 36567 ksmbd.ko + +Signed-off-by: David Disseldorp +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/smb2pdu.c | 26 ++++++++++---------------- + 1 file changed, 10 insertions(+), 16 deletions(-) + +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -839,7 +839,7 @@ static void assemble_neg_contexts(struct + struct smb2_negotiate_rsp *rsp, + void *smb2_buf_len) + { +- char *pneg_ctxt = (char *)rsp + ++ char * const pneg_ctxt = (char *)rsp + + le32_to_cpu(rsp->NegotiateContextOffset); + int neg_ctxt_cnt = 1; + int ctxt_size; +@@ -850,21 +850,17 @@ static void assemble_neg_contexts(struct + conn->preauth_info->Preauth_HashId); + inc_rfc1001_len(smb2_buf_len, AUTH_GSS_PADDING); + ctxt_size = sizeof(struct smb2_preauth_neg_context); +- /* Round to 8 byte boundary */ +- pneg_ctxt += round_up(sizeof(struct smb2_preauth_neg_context), 8); + + if (conn->cipher_type) { ++ /* Round to 8 byte boundary */ + ctxt_size = round_up(ctxt_size, 8); + ksmbd_debug(SMB, + "assemble SMB2_ENCRYPTION_CAPABILITIES context\n"); +- build_encrypt_ctxt((struct smb2_encryption_neg_context *)pneg_ctxt, ++ build_encrypt_ctxt((struct smb2_encryption_neg_context *) ++ (pneg_ctxt + ctxt_size), + conn->cipher_type); + neg_ctxt_cnt++; + ctxt_size += sizeof(struct smb2_encryption_neg_context) + 2; +- /* Round to 8 byte boundary */ +- pneg_ctxt += +- round_up(sizeof(struct smb2_encryption_neg_context) + 2, +- 8); + } + + if (conn->compress_algorithm) { +@@ -872,31 +868,29 @@ static void assemble_neg_contexts(struct + ksmbd_debug(SMB, + "assemble SMB2_COMPRESSION_CAPABILITIES context\n"); + /* Temporarily set to SMB3_COMPRESS_NONE */ +- build_compression_ctxt((struct smb2_compression_ctx *)pneg_ctxt, ++ build_compression_ctxt((struct smb2_compression_ctx *) ++ (pneg_ctxt + ctxt_size), + conn->compress_algorithm); + neg_ctxt_cnt++; + ctxt_size += sizeof(struct smb2_compression_ctx) + 2; +- /* Round to 8 byte boundary */ +- pneg_ctxt += round_up(sizeof(struct smb2_compression_ctx) + 2, +- 8); + } + + if (conn->posix_ext_supported) { + ctxt_size = round_up(ctxt_size, 8); + ksmbd_debug(SMB, + "assemble SMB2_POSIX_EXTENSIONS_AVAILABLE context\n"); +- build_posix_ctxt((struct smb2_posix_neg_context *)pneg_ctxt); ++ build_posix_ctxt((struct smb2_posix_neg_context *) ++ (pneg_ctxt + ctxt_size)); + neg_ctxt_cnt++; + ctxt_size += sizeof(struct smb2_posix_neg_context); +- /* Round to 8 byte boundary */ +- pneg_ctxt += round_up(sizeof(struct smb2_posix_neg_context), 8); + } + + if (conn->signing_negotiated) { + ctxt_size = round_up(ctxt_size, 8); + ksmbd_debug(SMB, + "assemble SMB2_SIGNING_CAPABILITIES context\n"); +- build_sign_cap_ctxt((struct smb2_signing_capabilities *)pneg_ctxt, ++ build_sign_cap_ctxt((struct smb2_signing_capabilities *) ++ (pneg_ctxt + ctxt_size), + conn->signing_algorithm); + neg_ctxt_cnt++; + ctxt_size += sizeof(struct smb2_signing_capabilities) + 2; diff --git a/queue-5.15/ksmbd-avoid-out-of-bounds-access-in-decode_preauth_ctxt.patch b/queue-5.15/ksmbd-avoid-out-of-bounds-access-in-decode_preauth_ctxt.patch new file mode 100644 index 00000000000..b1a9bc98157 --- /dev/null +++ b/queue-5.15/ksmbd-avoid-out-of-bounds-access-in-decode_preauth_ctxt.patch @@ -0,0 +1,71 @@ +From linkinjeon@gmail.com Mon Dec 18 16:39:45 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:33:42 +0900 +Subject: ksmbd: avoid out of bounds access in decode_preauth_ctxt() +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, David Disseldorp , Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-83-linkinjeon@kernel.org> + +From: David Disseldorp + +[ Upstream commit e7067a446264a7514fa1cfaa4052cdb6803bc6a2 ] + +Confirm that the accessed pneg_ctxt->HashAlgorithms address sits within +the SMB request boundary; deassemble_neg_contexts() only checks that the +eight byte smb2_neg_context header + (client controlled) DataLength are +within the packet boundary, which is insufficient. + +Checking for sizeof(struct smb2_preauth_neg_context) is overkill given +that the type currently assumes SMB311_SALT_SIZE bytes of trailing Salt. + +Signed-off-by: David Disseldorp +Acked-by: Namjae Jeon +Cc: +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/smb2pdu.c | 23 ++++++++++++++--------- + 1 file changed, 14 insertions(+), 9 deletions(-) + +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -907,17 +907,21 @@ static void assemble_neg_contexts(struct + } + + static __le32 decode_preauth_ctxt(struct ksmbd_conn *conn, +- struct smb2_preauth_neg_context *pneg_ctxt) ++ struct smb2_preauth_neg_context *pneg_ctxt, ++ int len_of_ctxts) + { +- __le32 err = STATUS_NO_PREAUTH_INTEGRITY_HASH_OVERLAP; ++ /* ++ * sizeof(smb2_preauth_neg_context) assumes SMB311_SALT_SIZE Salt, ++ * which may not be present. Only check for used HashAlgorithms[1]. ++ */ ++ if (len_of_ctxts < 6) ++ return STATUS_INVALID_PARAMETER; + +- if (pneg_ctxt->HashAlgorithms == SMB2_PREAUTH_INTEGRITY_SHA512) { +- conn->preauth_info->Preauth_HashId = +- SMB2_PREAUTH_INTEGRITY_SHA512; +- err = STATUS_SUCCESS; +- } ++ if (pneg_ctxt->HashAlgorithms != SMB2_PREAUTH_INTEGRITY_SHA512) ++ return STATUS_NO_PREAUTH_INTEGRITY_HASH_OVERLAP; + +- return err; ++ conn->preauth_info->Preauth_HashId = SMB2_PREAUTH_INTEGRITY_SHA512; ++ return STATUS_SUCCESS; + } + + static void decode_encrypt_ctxt(struct ksmbd_conn *conn, +@@ -1045,7 +1049,8 @@ static __le32 deassemble_neg_contexts(st + break; + + status = decode_preauth_ctxt(conn, +- (struct smb2_preauth_neg_context *)pctx); ++ (struct smb2_preauth_neg_context *)pctx, ++ len_of_ctxts); + if (status != STATUS_SUCCESS) + break; + } else if (pctx->ContextType == SMB2_ENCRYPTION_CAPABILITIES) { diff --git a/queue-5.15/ksmbd-block-asynchronous-requests-when-making-a-delay-on-session-setup.patch b/queue-5.15/ksmbd-block-asynchronous-requests-when-making-a-delay-on-session-setup.patch new file mode 100644 index 00000000000..f1a3faec232 --- /dev/null +++ b/queue-5.15/ksmbd-block-asynchronous-requests-when-making-a-delay-on-session-setup.patch @@ -0,0 +1,41 @@ +From linkinjeon@gmail.com Mon Dec 18 16:40:11 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:33:50 +0900 +Subject: ksmbd: block asynchronous requests when making a delay on session setup +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , zdi-disclosures@trendmicro.com, Steve French +Message-ID: <20231218153454.8090-91-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit b096d97f47326b1e2dbdef1c91fab69ffda54d17 ] + +ksmbd make a delay of 5 seconds on session setup to avoid dictionary +attacks. But the 5 seconds delay can be bypassed by using asynchronous +requests. This patch block all requests on current connection when +making a delay on sesstion setup failure. + +Cc: stable@vger.kernel.org +Reported-by: zdi-disclosures@trendmicro.com # ZDI-CAN-20482 +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/smb2pdu.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -1877,8 +1877,11 @@ out_err: + + sess->last_active = jiffies; + sess->state = SMB2_SESSION_EXPIRED; +- if (try_delay) ++ if (try_delay) { ++ ksmbd_conn_set_need_reconnect(conn); + ssleep(5); ++ ksmbd_conn_set_need_negotiate(conn); ++ } + } + } + diff --git a/queue-5.15/ksmbd-call-ib_drain_qp-when-disconnected.patch b/queue-5.15/ksmbd-call-ib_drain_qp-when-disconnected.patch new file mode 100644 index 00000000000..d188902ff9f --- /dev/null +++ b/queue-5.15/ksmbd-call-ib_drain_qp-when-disconnected.patch @@ -0,0 +1,36 @@ +From linkinjeon@gmail.com Mon Dec 18 16:38:43 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:33:22 +0900 +Subject: ksmbd: call ib_drain_qp when disconnected +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , Hyunchul Lee , Tom Talpey , Steve French +Message-ID: <20231218153454.8090-63-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit 141fa9824c0fc11d44b2d5bb1266a33e95fa67fd ] + +When disconnected, call ib_drain_qp to cancel all pending work requests +and prevent ksmbd_conn_handler_loop from waiting for a long time +for those work requests to compelete. + +Signed-off-by: Hyunchul Lee +Signed-off-by: Namjae Jeon +Reviewed-by: Tom Talpey +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/transport_rdma.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/fs/ksmbd/transport_rdma.c ++++ b/fs/ksmbd/transport_rdma.c +@@ -1527,6 +1527,8 @@ static int smb_direct_cm_handler(struct + } + case RDMA_CM_EVENT_DEVICE_REMOVAL: + case RDMA_CM_EVENT_DISCONNECTED: { ++ ib_drain_qp(t->qp); ++ + t->status = SMB_DIRECT_CS_DISCONNECTED; + wake_up_interruptible(&t->wait_status); + wake_up_interruptible(&t->wait_reassembly_queue); diff --git a/queue-5.15/ksmbd-call-putname-after-using-the-last-component.patch b/queue-5.15/ksmbd-call-putname-after-using-the-last-component.patch new file mode 100644 index 00000000000..5d61f1304e8 --- /dev/null +++ b/queue-5.15/ksmbd-call-putname-after-using-the-last-component.patch @@ -0,0 +1,60 @@ +From linkinjeon@gmail.com Mon Dec 18 16:40:33 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:33:57 +0900 +Subject: ksmbd: call putname after using the last component +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-98-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit 6fe55c2799bc29624770c26f98ba7b06214f43e0 ] + +last component point filename struct. Currently putname is called after +vfs_path_parent_lookup(). And then last component is used for +lookup_one_qstr_excl(). name in last component is freed by previous +calling putname(). And It cause file lookup failure when testing +generic/464 test of xfstest. + +Fixes: 74d7970febf7 ("ksmbd: fix racy issue from using ->d_parent and ->d_name") +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/vfs.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +--- a/fs/ksmbd/vfs.c ++++ b/fs/ksmbd/vfs.c +@@ -86,12 +86,14 @@ static int ksmbd_vfs_path_lookup_locked( + err = vfs_path_parent_lookup(filename, flags, + &parent_path, &last, &type, + root_share_path); +- putname(filename); +- if (err) ++ if (err) { ++ putname(filename); + return err; ++ } + + if (unlikely(type != LAST_NORM)) { + path_put(&parent_path); ++ putname(filename); + return -ENOENT; + } + +@@ -108,12 +110,14 @@ static int ksmbd_vfs_path_lookup_locked( + path->dentry = d; + path->mnt = share_conf->vfs_path.mnt; + path_put(&parent_path); ++ putname(filename); + + return 0; + + err_out: + inode_unlock(parent_path.dentry->d_inode); + path_put(&parent_path); ++ putname(filename); + return -ENOENT; + } + diff --git a/queue-5.15/ksmbd-casefold-utf-8-share-names-and-fix-ascii-lowercase-conversion.patch b/queue-5.15/ksmbd-casefold-utf-8-share-names-and-fix-ascii-lowercase-conversion.patch new file mode 100644 index 00000000000..0cdc64094ac --- /dev/null +++ b/queue-5.15/ksmbd-casefold-utf-8-share-names-and-fix-ascii-lowercase-conversion.patch @@ -0,0 +1,270 @@ +From linkinjeon@gmail.com Mon Dec 18 16:38:13 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:33:12 +0900 +Subject: ksmbd: casefold utf-8 share names and fix ascii lowercase conversion +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, "Atte Heikkilä" , "Namjae Jeon" , "Steve French" +Message-ID: <20231218153454.8090-53-linkinjeon@kernel.org> + +From: Atte Heikkilä + +[ Upstream commit 16b5f54e30c1ddec36bdf946a299b3254aace477 ] + +strtolower() corrupts all UTF-8 share names that have a byte in the C0 +(À ISO8859-1) to DE (Þ ISO8859-1) range, since the non-ASCII part of +ISO8859-1 is incompatible with UTF-8. Prevent this by checking that a +byte is in the ASCII range with isascii(), before the conversion to +lowercase with tolower(). Properly handle case-insensitivity of UTF-8 +share names by casefolding them, but fallback to ASCII lowercase +conversion on failure or if CONFIG_UNICODE is not set. Refactor to move +the share name casefolding immediately after the share name extraction. +Also, make the associated constness corrections. + +Signed-off-by: Atte Heikkilä +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/connection.c | 8 +++++++ + fs/ksmbd/connection.h | 1 + fs/ksmbd/mgmt/share_config.c | 18 +++-------------- + fs/ksmbd/mgmt/share_config.h | 2 - + fs/ksmbd/mgmt/tree_connect.c | 2 - + fs/ksmbd/mgmt/tree_connect.h | 2 - + fs/ksmbd/misc.c | 44 +++++++++++++++++++++++++++++++++++-------- + fs/ksmbd/misc.h | 2 - + fs/ksmbd/smb2pdu.c | 2 - + fs/ksmbd/unicode.h | 3 +- + 10 files changed, 56 insertions(+), 28 deletions(-) + +--- a/fs/ksmbd/connection.c ++++ b/fs/ksmbd/connection.c +@@ -60,6 +60,12 @@ struct ksmbd_conn *ksmbd_conn_alloc(void + conn->local_nls = load_nls("utf8"); + if (!conn->local_nls) + conn->local_nls = load_nls_default(); ++ if (IS_ENABLED(CONFIG_UNICODE)) ++ conn->um = utf8_load("12.1.0"); ++ else ++ conn->um = ERR_PTR(-EOPNOTSUPP); ++ if (IS_ERR(conn->um)) ++ conn->um = NULL; + atomic_set(&conn->req_running, 0); + atomic_set(&conn->r_count, 0); + conn->total_credits = 1; +@@ -361,6 +367,8 @@ out: + wait_event(conn->r_count_q, atomic_read(&conn->r_count) == 0); + + ++ if (IS_ENABLED(CONFIG_UNICODE)) ++ utf8_unload(conn->um); + unload_nls(conn->local_nls); + if (default_conn_ops.terminate_fn) + default_conn_ops.terminate_fn(conn); +--- a/fs/ksmbd/connection.h ++++ b/fs/ksmbd/connection.h +@@ -46,6 +46,7 @@ struct ksmbd_conn { + char *request_buf; + struct ksmbd_transport *transport; + struct nls_table *local_nls; ++ struct unicode_map *um; + struct list_head conns_list; + /* smb session 1 per user */ + struct xarray sessions; +--- a/fs/ksmbd/mgmt/share_config.c ++++ b/fs/ksmbd/mgmt/share_config.c +@@ -26,7 +26,7 @@ struct ksmbd_veto_pattern { + struct list_head list; + }; + +-static unsigned int share_name_hash(char *name) ++static unsigned int share_name_hash(const char *name) + { + return jhash(name, strlen(name), 0); + } +@@ -72,7 +72,7 @@ __get_share_config(struct ksmbd_share_co + return share; + } + +-static struct ksmbd_share_config *__share_lookup(char *name) ++static struct ksmbd_share_config *__share_lookup(const char *name) + { + struct ksmbd_share_config *share; + unsigned int key = share_name_hash(name); +@@ -119,7 +119,7 @@ static int parse_veto_list(struct ksmbd_ + return 0; + } + +-static struct ksmbd_share_config *share_config_request(char *name) ++static struct ksmbd_share_config *share_config_request(const char *name) + { + struct ksmbd_share_config_response *resp; + struct ksmbd_share_config *share = NULL; +@@ -190,20 +190,10 @@ out: + return share; + } + +-static void strtolower(char *share_name) +-{ +- while (*share_name) { +- *share_name = tolower(*share_name); +- share_name++; +- } +-} +- +-struct ksmbd_share_config *ksmbd_share_config_get(char *name) ++struct ksmbd_share_config *ksmbd_share_config_get(const char *name) + { + struct ksmbd_share_config *share; + +- strtolower(name); +- + down_read(&shares_table_lock); + share = __share_lookup(name); + if (share) +--- a/fs/ksmbd/mgmt/share_config.h ++++ b/fs/ksmbd/mgmt/share_config.h +@@ -74,7 +74,7 @@ static inline void ksmbd_share_config_pu + __ksmbd_share_config_put(share); + } + +-struct ksmbd_share_config *ksmbd_share_config_get(char *name); ++struct ksmbd_share_config *ksmbd_share_config_get(const char *name); + bool ksmbd_share_veto_filename(struct ksmbd_share_config *share, + const char *filename); + #endif /* __SHARE_CONFIG_MANAGEMENT_H__ */ +--- a/fs/ksmbd/mgmt/tree_connect.c ++++ b/fs/ksmbd/mgmt/tree_connect.c +@@ -17,7 +17,7 @@ + + struct ksmbd_tree_conn_status + ksmbd_tree_conn_connect(struct ksmbd_conn *conn, struct ksmbd_session *sess, +- char *share_name) ++ const char *share_name) + { + struct ksmbd_tree_conn_status status = {-ENOENT, NULL}; + struct ksmbd_tree_connect_response *resp = NULL; +--- a/fs/ksmbd/mgmt/tree_connect.h ++++ b/fs/ksmbd/mgmt/tree_connect.h +@@ -42,7 +42,7 @@ struct ksmbd_session; + + struct ksmbd_tree_conn_status + ksmbd_tree_conn_connect(struct ksmbd_conn *conn, struct ksmbd_session *sess, +- char *share_name); ++ const char *share_name); + + int ksmbd_tree_conn_disconnect(struct ksmbd_session *sess, + struct ksmbd_tree_connect *tree_conn); +--- a/fs/ksmbd/misc.c ++++ b/fs/ksmbd/misc.c +@@ -7,6 +7,7 @@ + #include + #include + #include ++#include + + #include "misc.h" + #include "smb_common.h" +@@ -226,26 +227,53 @@ void ksmbd_conv_path_to_windows(char *pa + strreplace(path, '/', '\\'); + } + ++static char *casefold_sharename(struct unicode_map *um, const char *name) ++{ ++ char *cf_name; ++ int cf_len; ++ ++ cf_name = kzalloc(KSMBD_REQ_MAX_SHARE_NAME, GFP_KERNEL); ++ if (!cf_name) ++ return ERR_PTR(-ENOMEM); ++ ++ if (IS_ENABLED(CONFIG_UNICODE) && um) { ++ const struct qstr q_name = {.name = name, .len = strlen(name)}; ++ ++ cf_len = utf8_casefold(um, &q_name, cf_name, ++ KSMBD_REQ_MAX_SHARE_NAME); ++ if (cf_len < 0) ++ goto out_ascii; ++ ++ return cf_name; ++ } ++ ++out_ascii: ++ cf_len = strscpy(cf_name, name, KSMBD_REQ_MAX_SHARE_NAME); ++ if (cf_len < 0) { ++ kfree(cf_name); ++ return ERR_PTR(-E2BIG); ++ } ++ ++ for (; *cf_name; ++cf_name) ++ *cf_name = isascii(*cf_name) ? tolower(*cf_name) : *cf_name; ++ return cf_name - cf_len; ++} ++ + /** + * ksmbd_extract_sharename() - get share name from tree connect request + * @treename: buffer containing tree name and share name + * + * Return: share name on success, otherwise error + */ +-char *ksmbd_extract_sharename(char *treename) ++char *ksmbd_extract_sharename(struct unicode_map *um, const char *treename) + { +- char *name = treename; +- char *dst; +- char *pos = strrchr(name, '\\'); ++ const char *name = treename, *pos = strrchr(name, '\\'); + + if (pos) + name = (pos + 1); + + /* caller has to free the memory */ +- dst = kstrdup(name, GFP_KERNEL); +- if (!dst) +- return ERR_PTR(-ENOMEM); +- return dst; ++ return casefold_sharename(um, name); + } + + /** +--- a/fs/ksmbd/misc.h ++++ b/fs/ksmbd/misc.h +@@ -20,7 +20,7 @@ int get_nlink(struct kstat *st); + void ksmbd_conv_path_to_unix(char *path); + void ksmbd_strip_last_slash(char *path); + void ksmbd_conv_path_to_windows(char *path); +-char *ksmbd_extract_sharename(char *treename); ++char *ksmbd_extract_sharename(struct unicode_map *um, const char *treename); + char *convert_to_unix_name(struct ksmbd_share_config *share, const char *name); + + #define KSMBD_DIR_INFO_ALIGNMENT 8 +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -1924,7 +1924,7 @@ int smb2_tree_connect(struct ksmbd_work + goto out_err1; + } + +- name = ksmbd_extract_sharename(treename); ++ name = ksmbd_extract_sharename(conn->um, treename); + if (IS_ERR(name)) { + status.ret = KSMBD_TREE_CONN_STATUS_ERROR; + goto out_err1; +--- a/fs/ksmbd/unicode.h ++++ b/fs/ksmbd/unicode.h +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + + #define UNIUPR_NOLOWER /* Example to not expand lower case tables */ + +@@ -69,7 +70,7 @@ char *smb_strndup_from_utf16(const char + const struct nls_table *codepage); + int smbConvertToUTF16(__le16 *target, const char *source, int srclen, + const struct nls_table *cp, int mapchars); +-char *ksmbd_extract_sharename(char *treename); ++char *ksmbd_extract_sharename(struct unicode_map *um, const char *treename); + #endif + + /* diff --git a/queue-5.15/ksmbd-change-leasekey-data-type-to-u8-array.patch b/queue-5.15/ksmbd-change-leasekey-data-type-to-u8-array.patch new file mode 100644 index 00000000000..207ed3c366a --- /dev/null +++ b/queue-5.15/ksmbd-change-leasekey-data-type-to-u8-array.patch @@ -0,0 +1,125 @@ +From linkinjeon@gmail.com Mon Dec 18 16:35:41 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:32:27 +0900 +Subject: ksmbd: change LeaseKey data type to u8 array +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-8-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit 2734b692f7b8167b93498dcd698067623d4267ca ] + +cifs define LeaseKey as u8 array in structure. To move lease structure +to smbfs_common, ksmbd change LeaseKey data type to u8 array. + +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/oplock.c | 24 +++++++++--------------- + fs/ksmbd/oplock.h | 2 -- + fs/ksmbd/smb2pdu.h | 11 +++++------ + 3 files changed, 14 insertions(+), 23 deletions(-) + +--- a/fs/ksmbd/oplock.c ++++ b/fs/ksmbd/oplock.c +@@ -1336,19 +1336,16 @@ __u8 smb2_map_lease_to_oplock(__le32 lea + */ + void create_lease_buf(u8 *rbuf, struct lease *lease) + { +- char *LeaseKey = (char *)&lease->lease_key; +- + if (lease->version == 2) { + struct create_lease_v2 *buf = (struct create_lease_v2 *)rbuf; +- char *ParentLeaseKey = (char *)&lease->parent_lease_key; + + memset(buf, 0, sizeof(struct create_lease_v2)); +- buf->lcontext.LeaseKeyLow = *((__le64 *)LeaseKey); +- buf->lcontext.LeaseKeyHigh = *((__le64 *)(LeaseKey + 8)); ++ memcpy(buf->lcontext.LeaseKey, lease->lease_key, ++ SMB2_LEASE_KEY_SIZE); + buf->lcontext.LeaseFlags = lease->flags; + buf->lcontext.LeaseState = lease->state; +- buf->lcontext.ParentLeaseKeyLow = *((__le64 *)ParentLeaseKey); +- buf->lcontext.ParentLeaseKeyHigh = *((__le64 *)(ParentLeaseKey + 8)); ++ memcpy(buf->lcontext.ParentLeaseKey, lease->parent_lease_key, ++ SMB2_LEASE_KEY_SIZE); + buf->ccontext.DataOffset = cpu_to_le16(offsetof + (struct create_lease_v2, lcontext)); + buf->ccontext.DataLength = cpu_to_le32(sizeof(struct lease_context_v2)); +@@ -1363,8 +1360,7 @@ void create_lease_buf(u8 *rbuf, struct l + struct create_lease *buf = (struct create_lease *)rbuf; + + memset(buf, 0, sizeof(struct create_lease)); +- buf->lcontext.LeaseKeyLow = *((__le64 *)LeaseKey); +- buf->lcontext.LeaseKeyHigh = *((__le64 *)(LeaseKey + 8)); ++ memcpy(buf->lcontext.LeaseKey, lease->lease_key, SMB2_LEASE_KEY_SIZE); + buf->lcontext.LeaseFlags = lease->flags; + buf->lcontext.LeaseState = lease->state; + buf->ccontext.DataOffset = cpu_to_le16(offsetof +@@ -1417,19 +1413,17 @@ struct lease_ctx_info *parse_lease_state + if (sizeof(struct lease_context_v2) == le32_to_cpu(cc->DataLength)) { + struct create_lease_v2 *lc = (struct create_lease_v2 *)cc; + +- *((__le64 *)lreq->lease_key) = lc->lcontext.LeaseKeyLow; +- *((__le64 *)(lreq->lease_key + 8)) = lc->lcontext.LeaseKeyHigh; ++ memcpy(lreq->lease_key, lc->lcontext.LeaseKey, SMB2_LEASE_KEY_SIZE); + lreq->req_state = lc->lcontext.LeaseState; + lreq->flags = lc->lcontext.LeaseFlags; + lreq->duration = lc->lcontext.LeaseDuration; +- *((__le64 *)lreq->parent_lease_key) = lc->lcontext.ParentLeaseKeyLow; +- *((__le64 *)(lreq->parent_lease_key + 8)) = lc->lcontext.ParentLeaseKeyHigh; ++ memcpy(lreq->parent_lease_key, lc->lcontext.ParentLeaseKey, ++ SMB2_LEASE_KEY_SIZE); + lreq->version = 2; + } else { + struct create_lease *lc = (struct create_lease *)cc; + +- *((__le64 *)lreq->lease_key) = lc->lcontext.LeaseKeyLow; +- *((__le64 *)(lreq->lease_key + 8)) = lc->lcontext.LeaseKeyHigh; ++ memcpy(lreq->lease_key, lc->lcontext.LeaseKey, SMB2_LEASE_KEY_SIZE); + lreq->req_state = lc->lcontext.LeaseState; + lreq->flags = lc->lcontext.LeaseFlags; + lreq->duration = lc->lcontext.LeaseDuration; +--- a/fs/ksmbd/oplock.h ++++ b/fs/ksmbd/oplock.h +@@ -28,8 +28,6 @@ + #define OPLOCK_WRITE_TO_NONE 0x04 + #define OPLOCK_READ_TO_NONE 0x08 + +-#define SMB2_LEASE_KEY_SIZE 16 +- + struct lease_ctx_info { + __u8 lease_key[SMB2_LEASE_KEY_SIZE]; + __le32 req_state; +--- a/fs/ksmbd/smb2pdu.h ++++ b/fs/ksmbd/smb2pdu.h +@@ -734,22 +734,21 @@ struct create_posix_rsp { + + #define SMB2_LEASE_FLAG_BREAK_IN_PROGRESS_LE cpu_to_le32(0x02) + ++#define SMB2_LEASE_KEY_SIZE 16 ++ + struct lease_context { +- __le64 LeaseKeyLow; +- __le64 LeaseKeyHigh; ++ __u8 LeaseKey[SMB2_LEASE_KEY_SIZE]; + __le32 LeaseState; + __le32 LeaseFlags; + __le64 LeaseDuration; + } __packed; + + struct lease_context_v2 { +- __le64 LeaseKeyLow; +- __le64 LeaseKeyHigh; ++ __u8 LeaseKey[SMB2_LEASE_KEY_SIZE]; + __le32 LeaseState; + __le32 LeaseFlags; + __le64 LeaseDuration; +- __le64 ParentLeaseKeyLow; +- __le64 ParentLeaseKeyHigh; ++ __u8 ParentLeaseKey[SMB2_LEASE_KEY_SIZE]; + __le16 Epoch; + __le16 Reserved; + } __packed; diff --git a/queue-5.15/ksmbd-change-security-id-to-the-one-samba-used-for-posix-extension.patch b/queue-5.15/ksmbd-change-security-id-to-the-one-samba-used-for-posix-extension.patch new file mode 100644 index 00000000000..0ea9b4e6323 --- /dev/null +++ b/queue-5.15/ksmbd-change-security-id-to-the-one-samba-used-for-posix-extension.patch @@ -0,0 +1,104 @@ +From linkinjeon@gmail.com Mon Dec 18 16:38:16 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:33:13 +0900 +Subject: ksmbd: change security id to the one samba used for posix extension +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-54-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit 5609bdd9ffdccd83f9003511b1801584b703baa5 ] + +Samba set SIDOWNER and SIDUNIX_GROUP in create posix context and +set SIDUNIX_USER/GROUP in other sids for posix extension. +This patch change security id to the one samba used. + +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/oplock.c | 17 ++++++++++++++--- + fs/ksmbd/smb2pdu.c | 9 +++++++-- + fs/ksmbd/smb2pdu.h | 6 ++++-- + 3 files changed, 25 insertions(+), 7 deletions(-) + +--- a/fs/ksmbd/oplock.c ++++ b/fs/ksmbd/oplock.c +@@ -1615,7 +1615,11 @@ void create_posix_rsp_buf(char *cc, stru + memset(buf, 0, sizeof(struct create_posix_rsp)); + buf->ccontext.DataOffset = cpu_to_le16(offsetof + (struct create_posix_rsp, nlink)); +- buf->ccontext.DataLength = cpu_to_le32(52); ++ /* ++ * DataLength = nlink(4) + reparse_tag(4) + mode(4) + ++ * domain sid(28) + unix group sid(16). ++ */ ++ buf->ccontext.DataLength = cpu_to_le32(56); + buf->ccontext.NameOffset = cpu_to_le16(offsetof + (struct create_posix_rsp, Name)); + buf->ccontext.NameLength = cpu_to_le16(POSIX_CTXT_DATA_LEN); +@@ -1640,12 +1644,19 @@ void create_posix_rsp_buf(char *cc, stru + buf->nlink = cpu_to_le32(inode->i_nlink); + buf->reparse_tag = cpu_to_le32(fp->volatile_id); + buf->mode = cpu_to_le32(inode->i_mode); ++ /* ++ * SidBuffer(44) contain two sids(Domain sid(28), UNIX group sid(16)). ++ * Domain sid(28) = revision(1) + num_subauth(1) + authority(6) + ++ * sub_auth(4 * 4(num_subauth)) + RID(4). ++ * UNIX group id(16) = revision(1) + num_subauth(1) + authority(6) + ++ * sub_auth(4 * 1(num_subauth)) + RID(4). ++ */ + id_to_sid(from_kuid_munged(&init_user_ns, + i_uid_into_mnt(user_ns, inode)), +- SIDNFS_USER, (struct smb_sid *)&buf->SidBuffer[0]); ++ SIDOWNER, (struct smb_sid *)&buf->SidBuffer[0]); + id_to_sid(from_kgid_munged(&init_user_ns, + i_gid_into_mnt(user_ns, inode)), +- SIDNFS_GROUP, (struct smb_sid *)&buf->SidBuffer[20]); ++ SIDUNIX_GROUP, (struct smb_sid *)&buf->SidBuffer[28]); + } + + /* +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -3619,10 +3619,15 @@ static int smb2_populate_readdir_entry(s + S_ISDIR(ksmbd_kstat->kstat->mode) ? ATTR_DIRECTORY_LE : ATTR_ARCHIVE_LE; + if (d_info->hide_dot_file && d_info->name[0] == '.') + posix_info->DosAttributes |= ATTR_HIDDEN_LE; ++ /* ++ * SidBuffer(32) contain two sids(Domain sid(16), UNIX group sid(16)). ++ * UNIX sid(16) = revision(1) + num_subauth(1) + authority(6) + ++ * sub_auth(4 * 1(num_subauth)) + RID(4). ++ */ + id_to_sid(from_kuid_munged(&init_user_ns, ksmbd_kstat->kstat->uid), +- SIDNFS_USER, (struct smb_sid *)&posix_info->SidBuffer[0]); ++ SIDUNIX_USER, (struct smb_sid *)&posix_info->SidBuffer[0]); + id_to_sid(from_kgid_munged(&init_user_ns, ksmbd_kstat->kstat->gid), +- SIDNFS_GROUP, (struct smb_sid *)&posix_info->SidBuffer[20]); ++ SIDUNIX_GROUP, (struct smb_sid *)&posix_info->SidBuffer[16]); + memcpy(posix_info->name, conv_name, conv_len); + posix_info->name_len = cpu_to_le32(conv_len); + posix_info->NextEntryOffset = cpu_to_le32(next_entry_offset); +--- a/fs/ksmbd/smb2pdu.h ++++ b/fs/ksmbd/smb2pdu.h +@@ -724,7 +724,8 @@ struct create_posix_rsp { + __le32 nlink; + __le32 reparse_tag; + __le32 mode; +- u8 SidBuffer[40]; ++ /* SidBuffer contain two sids(Domain sid(28), UNIX group sid(16)) */ ++ u8 SidBuffer[44]; + } __packed; + + #define SMB2_LEASE_NONE_LE cpu_to_le32(0x00) +@@ -1617,7 +1618,8 @@ struct smb2_posix_info { + __le32 HardLinks; + __le32 ReparseTag; + __le32 Mode; +- u8 SidBuffer[40]; ++ /* SidBuffer contain two sids (UNIX user sid(16), UNIX group sid(16)) */ ++ u8 SidBuffer[32]; + __le32 name_len; + u8 name[1]; + /* diff --git a/queue-5.15/ksmbd-change-the-return-value-of-ksmbd_vfs_query_maximal_access-to-void.patch b/queue-5.15/ksmbd-change-the-return-value-of-ksmbd_vfs_query_maximal_access-to-void.patch new file mode 100644 index 00000000000..4cf57279746 --- /dev/null +++ b/queue-5.15/ksmbd-change-the-return-value-of-ksmbd_vfs_query_maximal_access-to-void.patch @@ -0,0 +1,75 @@ +From linkinjeon@gmail.com Mon Dec 18 16:41:05 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:34:07 +0900 +Subject: ksmbd: Change the return value of ksmbd_vfs_query_maximal_access to void +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Lu Hongfei , Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-108-linkinjeon@kernel.org> + +From: Lu Hongfei + +[ Upstream commit ccb5889af97c03c67a83fcd649602034578c0d61 ] + +The return value of ksmbd_vfs_query_maximal_access is meaningless, +it is better to modify it to void. + +Signed-off-by: Lu Hongfei +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/smb2pdu.c | 4 +--- + fs/ksmbd/vfs.c | 6 +----- + fs/ksmbd/vfs.h | 2 +- + 3 files changed, 3 insertions(+), 9 deletions(-) + +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -2877,11 +2877,9 @@ int smb2_open(struct ksmbd_work *work) + if (!file_present) { + daccess = cpu_to_le32(GENERIC_ALL_FLAGS); + } else { +- rc = ksmbd_vfs_query_maximal_access(user_ns, ++ ksmbd_vfs_query_maximal_access(user_ns, + path.dentry, + &daccess); +- if (rc) +- goto err_out; + already_permitted = true; + } + maximal_access = daccess; +--- a/fs/ksmbd/vfs.c ++++ b/fs/ksmbd/vfs.c +@@ -121,11 +121,9 @@ err_out: + return -ENOENT; + } + +-int ksmbd_vfs_query_maximal_access(struct user_namespace *user_ns, ++void ksmbd_vfs_query_maximal_access(struct user_namespace *user_ns, + struct dentry *dentry, __le32 *daccess) + { +- int ret = 0; +- + *daccess = cpu_to_le32(FILE_READ_ATTRIBUTES | READ_CONTROL); + + if (!inode_permission(user_ns, d_inode(dentry), MAY_OPEN | MAY_WRITE)) +@@ -142,8 +140,6 @@ int ksmbd_vfs_query_maximal_access(struc + + if (!inode_permission(user_ns, d_inode(dentry->d_parent), MAY_EXEC | MAY_WRITE)) + *daccess |= FILE_DELETE_LE; +- +- return ret; + } + + /** +--- a/fs/ksmbd/vfs.h ++++ b/fs/ksmbd/vfs.h +@@ -111,7 +111,7 @@ struct ksmbd_kstat { + }; + + int ksmbd_vfs_lock_parent(struct dentry *parent, struct dentry *child); +-int ksmbd_vfs_query_maximal_access(struct user_namespace *user_ns, ++void ksmbd_vfs_query_maximal_access(struct user_namespace *user_ns, + struct dentry *dentry, __le32 *daccess); + int ksmbd_vfs_create(struct ksmbd_work *work, const char *name, umode_t mode); + int ksmbd_vfs_mkdir(struct ksmbd_work *work, const char *name, umode_t mode); diff --git a/queue-5.15/ksmbd-check-if-a-mount-point-is-crossed-during-path-lookup.patch b/queue-5.15/ksmbd-check-if-a-mount-point-is-crossed-during-path-lookup.patch new file mode 100644 index 00000000000..6d352aac446 --- /dev/null +++ b/queue-5.15/ksmbd-check-if-a-mount-point-is-crossed-during-path-lookup.patch @@ -0,0 +1,295 @@ +From linkinjeon@gmail.com Mon Dec 18 16:41:33 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:34:15 +0900 +Subject: ksmbd: check if a mount point is crossed during path lookup +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-116-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit 2b57a4322b1b14348940744fdc02f9a86cbbdbeb ] + +Since commit 74d7970febf7 ("ksmbd: fix racy issue from using ->d_parent and +->d_name"), ksmbd can not lookup cross mount points. If last component is +a cross mount point during path lookup, check if it is crossed to follow it +down. And allow path lookup to cross a mount point when a crossmnt +parameter is set to 'yes' in smb.conf. + +Cc: stable@vger.kernel.org +Fixes: 74d7970febf7 ("ksmbd: fix racy issue from using ->d_parent and ->d_name") +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/ksmbd_netlink.h | 3 +- + fs/ksmbd/smb2pdu.c | 27 ++++++++++++--------- + fs/ksmbd/vfs.c | 58 ++++++++++++++++++++++++++--------------------- + fs/ksmbd/vfs.h | 4 +-- + 4 files changed, 53 insertions(+), 39 deletions(-) + +--- a/fs/ksmbd/ksmbd_netlink.h ++++ b/fs/ksmbd/ksmbd_netlink.h +@@ -352,7 +352,8 @@ enum KSMBD_TREE_CONN_STATUS { + #define KSMBD_SHARE_FLAG_STREAMS BIT(11) + #define KSMBD_SHARE_FLAG_FOLLOW_SYMLINKS BIT(12) + #define KSMBD_SHARE_FLAG_ACL_XATTR BIT(13) +-#define KSMBD_SHARE_FLAG_UPDATE BIT(14) ++#define KSMBD_SHARE_FLAG_UPDATE BIT(14) ++#define KSMBD_SHARE_FLAG_CROSSMNT BIT(15) + + /* + * Tree connect request flags. +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -2475,8 +2475,9 @@ static void smb2_update_xattrs(struct ks + } + } + +-static int smb2_creat(struct ksmbd_work *work, struct path *path, char *name, +- int open_flags, umode_t posix_mode, bool is_dir) ++static int smb2_creat(struct ksmbd_work *work, struct path *parent_path, ++ struct path *path, char *name, int open_flags, ++ umode_t posix_mode, bool is_dir) + { + struct ksmbd_tree_connect *tcon = work->tcon; + struct ksmbd_share_config *share = tcon->share_conf; +@@ -2503,7 +2504,7 @@ static int smb2_creat(struct ksmbd_work + return rc; + } + +- rc = ksmbd_vfs_kern_path_locked(work, name, 0, path, 0); ++ rc = ksmbd_vfs_kern_path_locked(work, name, 0, parent_path, path, 0); + if (rc) { + pr_err("cannot get linux path (%s), err = %d\n", + name, rc); +@@ -2570,7 +2571,7 @@ int smb2_open(struct ksmbd_work *work) + struct ksmbd_tree_connect *tcon = work->tcon; + struct smb2_create_req *req; + struct smb2_create_rsp *rsp; +- struct path path; ++ struct path path, parent_path; + struct ksmbd_share_config *share = tcon->share_conf; + struct ksmbd_file *fp = NULL; + struct file *filp = NULL; +@@ -2791,7 +2792,8 @@ int smb2_open(struct ksmbd_work *work) + goto err_out1; + } + +- rc = ksmbd_vfs_kern_path_locked(work, name, LOOKUP_NO_SYMLINKS, &path, 1); ++ rc = ksmbd_vfs_kern_path_locked(work, name, LOOKUP_NO_SYMLINKS, ++ &parent_path, &path, 1); + if (!rc) { + file_present = true; + +@@ -2911,7 +2913,8 @@ int smb2_open(struct ksmbd_work *work) + + /*create file if not present */ + if (!file_present) { +- rc = smb2_creat(work, &path, name, open_flags, posix_mode, ++ rc = smb2_creat(work, &parent_path, &path, name, open_flags, ++ posix_mode, + req->CreateOptions & FILE_DIRECTORY_FILE_LE); + if (rc) { + if (rc == -ENOENT) { +@@ -3326,8 +3329,9 @@ int smb2_open(struct ksmbd_work *work) + + err_out: + if (file_present || created) { +- inode_unlock(d_inode(path.dentry->d_parent)); +- dput(path.dentry); ++ inode_unlock(d_inode(parent_path.dentry)); ++ path_put(&path); ++ path_put(&parent_path); + } + ksmbd_revert_fsids(work); + err_out1: +@@ -5553,7 +5557,7 @@ static int smb2_create_link(struct ksmbd + struct nls_table *local_nls) + { + char *link_name = NULL, *target_name = NULL, *pathname = NULL; +- struct path path; ++ struct path path, parent_path; + bool file_present = false; + int rc; + +@@ -5583,7 +5587,7 @@ static int smb2_create_link(struct ksmbd + + ksmbd_debug(SMB, "target name is %s\n", target_name); + rc = ksmbd_vfs_kern_path_locked(work, link_name, LOOKUP_NO_SYMLINKS, +- &path, 0); ++ &parent_path, &path, 0); + if (rc) { + if (rc != -ENOENT) + goto out; +@@ -5613,8 +5617,9 @@ static int smb2_create_link(struct ksmbd + rc = -EINVAL; + out: + if (file_present) { +- inode_unlock(d_inode(path.dentry->d_parent)); ++ inode_unlock(d_inode(parent_path.dentry)); + path_put(&path); ++ path_put(&parent_path); + } + if (!IS_ERR(link_name)) + kfree(link_name); +--- a/fs/ksmbd/vfs.c ++++ b/fs/ksmbd/vfs.c +@@ -63,13 +63,13 @@ int ksmbd_vfs_lock_parent(struct dentry + + static int ksmbd_vfs_path_lookup_locked(struct ksmbd_share_config *share_conf, + char *pathname, unsigned int flags, ++ struct path *parent_path, + struct path *path) + { + struct qstr last; + struct filename *filename; + struct path *root_share_path = &share_conf->vfs_path; + int err, type; +- struct path parent_path; + struct dentry *d; + + if (pathname[0] == '\0') { +@@ -84,7 +84,7 @@ static int ksmbd_vfs_path_lookup_locked( + return PTR_ERR(filename); + + err = vfs_path_parent_lookup(filename, flags, +- &parent_path, &last, &type, ++ parent_path, &last, &type, + root_share_path); + if (err) { + putname(filename); +@@ -92,13 +92,13 @@ static int ksmbd_vfs_path_lookup_locked( + } + + if (unlikely(type != LAST_NORM)) { +- path_put(&parent_path); ++ path_put(parent_path); + putname(filename); + return -ENOENT; + } + +- inode_lock_nested(parent_path.dentry->d_inode, I_MUTEX_PARENT); +- d = lookup_one_qstr_excl(&last, parent_path.dentry, 0); ++ inode_lock_nested(parent_path->dentry->d_inode, I_MUTEX_PARENT); ++ d = lookup_one_qstr_excl(&last, parent_path->dentry, 0); + if (IS_ERR(d)) + goto err_out; + +@@ -108,15 +108,22 @@ static int ksmbd_vfs_path_lookup_locked( + } + + path->dentry = d; +- path->mnt = share_conf->vfs_path.mnt; +- path_put(&parent_path); +- putname(filename); ++ path->mnt = mntget(parent_path->mnt); ++ ++ if (test_share_config_flag(share_conf, KSMBD_SHARE_FLAG_CROSSMNT)) { ++ err = follow_down(path); ++ if (err < 0) { ++ path_put(path); ++ goto err_out; ++ } ++ } + ++ putname(filename); + return 0; + + err_out: +- inode_unlock(parent_path.dentry->d_inode); +- path_put(&parent_path); ++ inode_unlock(d_inode(parent_path->dentry)); ++ path_put(parent_path); + putname(filename); + return -ENOENT; + } +@@ -1197,14 +1204,14 @@ static int ksmbd_vfs_lookup_in_dir(const + * Return: 0 on success, otherwise error + */ + int ksmbd_vfs_kern_path_locked(struct ksmbd_work *work, char *name, +- unsigned int flags, struct path *path, +- bool caseless) ++ unsigned int flags, struct path *parent_path, ++ struct path *path, bool caseless) + { + struct ksmbd_share_config *share_conf = work->tcon->share_conf; + int err; +- struct path parent_path; + +- err = ksmbd_vfs_path_lookup_locked(share_conf, name, flags, path); ++ err = ksmbd_vfs_path_lookup_locked(share_conf, name, flags, parent_path, ++ path); + if (!err) + return 0; + +@@ -1219,10 +1226,10 @@ int ksmbd_vfs_kern_path_locked(struct ks + path_len = strlen(filepath); + remain_len = path_len; + +- parent_path = share_conf->vfs_path; +- path_get(&parent_path); ++ *parent_path = share_conf->vfs_path; ++ path_get(parent_path); + +- while (d_can_lookup(parent_path.dentry)) { ++ while (d_can_lookup(parent_path->dentry)) { + char *filename = filepath + path_len - remain_len; + char *next = strchrnul(filename, '/'); + size_t filename_len = next - filename; +@@ -1231,7 +1238,7 @@ int ksmbd_vfs_kern_path_locked(struct ks + if (filename_len == 0) + break; + +- err = ksmbd_vfs_lookup_in_dir(&parent_path, filename, ++ err = ksmbd_vfs_lookup_in_dir(parent_path, filename, + filename_len, + work->conn->um); + if (err) +@@ -1248,8 +1255,8 @@ int ksmbd_vfs_kern_path_locked(struct ks + goto out2; + else if (is_last) + goto out1; +- path_put(&parent_path); +- parent_path = *path; ++ path_put(parent_path); ++ *parent_path = *path; + + next[0] = '/'; + remain_len -= filename_len + 1; +@@ -1257,16 +1264,17 @@ int ksmbd_vfs_kern_path_locked(struct ks + + err = -EINVAL; + out2: +- path_put(&parent_path); ++ path_put(parent_path); + out1: + kfree(filepath); + } + + if (!err) { +- err = ksmbd_vfs_lock_parent(parent_path.dentry, path->dentry); +- if (err) +- dput(path->dentry); +- path_put(&parent_path); ++ err = ksmbd_vfs_lock_parent(parent_path->dentry, path->dentry); ++ if (err) { ++ path_put(path); ++ path_put(parent_path); ++ } + } + return err; + } +--- a/fs/ksmbd/vfs.h ++++ b/fs/ksmbd/vfs.h +@@ -154,8 +154,8 @@ int ksmbd_vfs_xattr_stream_name(char *st + int ksmbd_vfs_remove_xattr(struct user_namespace *user_ns, + const struct path *path, char *attr_name); + int ksmbd_vfs_kern_path_locked(struct ksmbd_work *work, char *name, +- unsigned int flags, struct path *path, +- bool caseless); ++ unsigned int flags, struct path *parent_path, ++ struct path *path, bool caseless); + struct dentry *ksmbd_vfs_kern_path_create(struct ksmbd_work *work, + const char *name, + unsigned int flags, diff --git a/queue-5.15/ksmbd-check-iov-vector-index-in-ksmbd_conn_write.patch b/queue-5.15/ksmbd-check-iov-vector-index-in-ksmbd_conn_write.patch new file mode 100644 index 00000000000..026ca9011c0 --- /dev/null +++ b/queue-5.15/ksmbd-check-iov-vector-index-in-ksmbd_conn_write.patch @@ -0,0 +1,36 @@ +From linkinjeon@gmail.com Mon Dec 18 16:42:20 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:34:30 +0900 +Subject: ksmbd: check iov vector index in ksmbd_conn_write() +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-131-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit 73f949ea87c7d697210653501ca21efe57295327 ] + +If ->iov_idx is zero, This means that the iov vector for the response +was not added during the request process. In other words, it means that +there is a problem in generating a response, So this patch return as +an error to avoid NULL pointer dereferencing problem. + +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/connection.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/fs/ksmbd/connection.c ++++ b/fs/ksmbd/connection.c +@@ -197,6 +197,9 @@ int ksmbd_conn_write(struct ksmbd_work * + if (work->send_no_response) + return 0; + ++ if (!work->iov_idx) ++ return -EINVAL; ++ + ksmbd_conn_lock(conn); + sent = conn->transport->ops->writev(conn->transport, work->iov, + work->iov_cnt, diff --git a/queue-5.15/ksmbd-check-the-validation-of-pdu_size-in-ksmbd_conn_handler_loop.patch b/queue-5.15/ksmbd-check-the-validation-of-pdu_size-in-ksmbd_conn_handler_loop.patch new file mode 100644 index 00000000000..5809857b192 --- /dev/null +++ b/queue-5.15/ksmbd-check-the-validation-of-pdu_size-in-ksmbd_conn_handler_loop.patch @@ -0,0 +1,76 @@ +From stable+bounces-7729-greg=kroah.com@vger.kernel.org Mon Dec 18 16:45:21 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:34:01 +0900 +Subject: ksmbd: check the validation of pdu_size in ksmbd_conn_handler_loop +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , Chih-Yen Chang , Steve French +Message-ID: <20231218153454.8090-102-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit 368ba06881c395f1c9a7ba22203cf8d78b4addc0 ] + +The length field of netbios header must be greater than the SMB header +sizes(smb1 or smb2 header), otherwise the packet is an invalid SMB packet. + +If `pdu_size` is 0, ksmbd allocates a 4 bytes chunk to `conn->request_buf`. +In the function `get_smb2_cmd_val` ksmbd will read cmd from +`rcv_hdr->Command`, which is `conn->request_buf + 12`, causing the KASAN +detector to print the following error message: + +[ 7.205018] BUG: KASAN: slab-out-of-bounds in get_smb2_cmd_val+0x45/0x60 +[ 7.205423] Read of size 2 at addr ffff8880062d8b50 by task ksmbd:42632/248 +... +[ 7.207125] +[ 7.209191] get_smb2_cmd_val+0x45/0x60 +[ 7.209426] ksmbd_conn_enqueue_request+0x3a/0x100 +[ 7.209712] ksmbd_server_process_request+0x72/0x160 +[ 7.210295] ksmbd_conn_handler_loop+0x30c/0x550 +[ 7.212280] kthread+0x160/0x190 +[ 7.212762] ret_from_fork+0x1f/0x30 +[ 7.212981] + +Cc: stable@vger.kernel.org +Reported-by: Chih-Yen Chang +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/connection.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +--- a/fs/ksmbd/connection.c ++++ b/fs/ksmbd/connection.c +@@ -294,6 +294,9 @@ bool ksmbd_conn_alive(struct ksmbd_conn + return true; + } + ++#define SMB1_MIN_SUPPORTED_HEADER_SIZE (sizeof(struct smb_hdr)) ++#define SMB2_MIN_SUPPORTED_HEADER_SIZE (sizeof(struct smb2_hdr) + 4) ++ + /** + * ksmbd_conn_handler_loop() - session thread to listen on new smb requests + * @p: connection instance +@@ -350,6 +353,9 @@ int ksmbd_conn_handler_loop(void *p) + if (pdu_size > MAX_STREAM_PROT_LEN) + break; + ++ if (pdu_size < SMB1_MIN_SUPPORTED_HEADER_SIZE) ++ break; ++ + /* 4 for rfc1002 length field */ + /* 1 for implied bcc[0] */ + size = pdu_size + 4 + 1; +@@ -377,6 +383,12 @@ int ksmbd_conn_handler_loop(void *p) + continue; + } + ++ if (((struct smb2_hdr *)smb2_get_msg(conn->request_buf))->ProtocolId == ++ SMB2_PROTO_NUMBER) { ++ if (pdu_size < SMB2_MIN_SUPPORTED_HEADER_SIZE) ++ break; ++ } ++ + if (!default_conn_ops.process_fn) { + pr_err("No connection request callback\n"); + break; diff --git a/queue-5.15/ksmbd-constify-struct-path.patch b/queue-5.15/ksmbd-constify-struct-path.patch new file mode 100644 index 00000000000..05e9585e85d --- /dev/null +++ b/queue-5.15/ksmbd-constify-struct-path.patch @@ -0,0 +1,212 @@ +From linkinjeon@gmail.com Mon Dec 18 16:38:07 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:33:10 +0900 +Subject: ksmbd: constify struct path +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Al Viro , Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-51-linkinjeon@kernel.org> + +From: Al Viro + +[ Upstream commit c22180a5e2a9e1426fab01d9e54011ec531b1b52 ] + +... in particular, there should never be a non-const pointers to +any file->f_path. + +Acked-by: Namjae Jeon +Signed-off-by: Al Viro +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/misc.c | 2 +- + fs/ksmbd/misc.h | 2 +- + fs/ksmbd/smb2pdu.c | 18 +++++++++--------- + fs/ksmbd/smbacl.c | 6 +++--- + fs/ksmbd/smbacl.h | 6 +++--- + fs/ksmbd/vfs.c | 4 ++-- + fs/ksmbd/vfs.h | 2 +- + 7 files changed, 20 insertions(+), 20 deletions(-) + +--- a/fs/ksmbd/misc.c ++++ b/fs/ksmbd/misc.c +@@ -159,7 +159,7 @@ out: + */ + + char *convert_to_nt_pathname(struct ksmbd_share_config *share, +- struct path *path) ++ const struct path *path) + { + char *pathname, *ab_pathname, *nt_pathname; + int share_path_len = share->path_sz; +--- a/fs/ksmbd/misc.h ++++ b/fs/ksmbd/misc.h +@@ -15,7 +15,7 @@ int match_pattern(const char *str, size_ + int ksmbd_validate_filename(char *filename); + int parse_stream_name(char *filename, char **stream_name, int *s_type); + char *convert_to_nt_pathname(struct ksmbd_share_config *share, +- struct path *path); ++ const struct path *path); + int get_nlink(struct kstat *st); + void ksmbd_conv_path_to_unix(char *path); + void ksmbd_strip_last_slash(char *path); +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -2226,7 +2226,7 @@ out: + * Return: 0 on success, otherwise error + */ + static int smb2_set_ea(struct smb2_ea_info *eabuf, unsigned int buf_len, +- struct path *path) ++ const struct path *path) + { + struct user_namespace *user_ns = mnt_user_ns(path->mnt); + char *attr_name = NULL, *value; +@@ -2320,7 +2320,7 @@ next: + return rc; + } + +-static noinline int smb2_set_stream_name_xattr(struct path *path, ++static noinline int smb2_set_stream_name_xattr(const struct path *path, + struct ksmbd_file *fp, + char *stream_name, int s_type) + { +@@ -2359,7 +2359,7 @@ static noinline int smb2_set_stream_name + return 0; + } + +-static int smb2_remove_smb_xattrs(struct path *path) ++static int smb2_remove_smb_xattrs(const struct path *path) + { + struct user_namespace *user_ns = mnt_user_ns(path->mnt); + char *name, *xattr_list = NULL; +@@ -2393,7 +2393,7 @@ out: + return err; + } + +-static int smb2_create_truncate(struct path *path) ++static int smb2_create_truncate(const struct path *path) + { + int rc = vfs_truncate(path, 0); + +@@ -2412,7 +2412,7 @@ static int smb2_create_truncate(struct p + return rc; + } + +-static void smb2_new_xattrs(struct ksmbd_tree_connect *tcon, struct path *path, ++static void smb2_new_xattrs(struct ksmbd_tree_connect *tcon, const struct path *path, + struct ksmbd_file *fp) + { + struct xattr_dos_attrib da = {0}; +@@ -2435,7 +2435,7 @@ static void smb2_new_xattrs(struct ksmbd + } + + static void smb2_update_xattrs(struct ksmbd_tree_connect *tcon, +- struct path *path, struct ksmbd_file *fp) ++ const struct path *path, struct ksmbd_file *fp) + { + struct xattr_dos_attrib da; + int rc; +@@ -2495,7 +2495,7 @@ static int smb2_creat(struct ksmbd_work + + static int smb2_create_sd_buffer(struct ksmbd_work *work, + struct smb2_create_req *req, +- struct path *path) ++ const struct path *path) + { + struct create_context *context; + struct create_sd_buf_req *sd_buf; +@@ -4201,7 +4201,7 @@ static int smb2_get_ea(struct ksmbd_work + int rc, name_len, value_len, xattr_list_len, idx; + ssize_t buf_free_len, alignment_bytes, next_offset, rsp_data_cnt = 0; + struct smb2_ea_info_req *ea_req = NULL; +- struct path *path; ++ const struct path *path; + struct user_namespace *user_ns = file_mnt_user_ns(fp->filp); + + if (!(fp->daccess & FILE_READ_EA_LE)) { +@@ -4523,7 +4523,7 @@ static void get_file_stream_info(struct + struct smb2_file_stream_info *file_info; + char *stream_name, *xattr_list = NULL, *stream_buf; + struct kstat stat; +- struct path *path = &fp->filp->f_path; ++ const struct path *path = &fp->filp->f_path; + ssize_t xattr_list_len; + int nbytes = 0, streamlen, stream_name_len, next, idx = 0; + int buf_free_len; +--- a/fs/ksmbd/smbacl.c ++++ b/fs/ksmbd/smbacl.c +@@ -991,7 +991,7 @@ static void smb_set_ace(struct smb_ace * + } + + int smb_inherit_dacl(struct ksmbd_conn *conn, +- struct path *path, ++ const struct path *path, + unsigned int uid, unsigned int gid) + { + const struct smb_sid *psid, *creator = NULL; +@@ -1208,7 +1208,7 @@ bool smb_inherit_flags(int flags, bool i + return false; + } + +-int smb_check_perm_dacl(struct ksmbd_conn *conn, struct path *path, ++int smb_check_perm_dacl(struct ksmbd_conn *conn, const struct path *path, + __le32 *pdaccess, int uid) + { + struct user_namespace *user_ns = mnt_user_ns(path->mnt); +@@ -1375,7 +1375,7 @@ err_out: + } + + int set_info_sec(struct ksmbd_conn *conn, struct ksmbd_tree_connect *tcon, +- struct path *path, struct smb_ntsd *pntsd, int ntsd_len, ++ const struct path *path, struct smb_ntsd *pntsd, int ntsd_len, + bool type_check) + { + int rc; +--- a/fs/ksmbd/smbacl.h ++++ b/fs/ksmbd/smbacl.h +@@ -201,12 +201,12 @@ void posix_state_to_acl(struct posix_acl + struct posix_acl_entry *pace); + int compare_sids(const struct smb_sid *ctsid, const struct smb_sid *cwsid); + bool smb_inherit_flags(int flags, bool is_dir); +-int smb_inherit_dacl(struct ksmbd_conn *conn, struct path *path, ++int smb_inherit_dacl(struct ksmbd_conn *conn, const struct path *path, + unsigned int uid, unsigned int gid); +-int smb_check_perm_dacl(struct ksmbd_conn *conn, struct path *path, ++int smb_check_perm_dacl(struct ksmbd_conn *conn, const struct path *path, + __le32 *pdaccess, int uid); + int set_info_sec(struct ksmbd_conn *conn, struct ksmbd_tree_connect *tcon, +- struct path *path, struct smb_ntsd *pntsd, int ntsd_len, ++ const struct path *path, struct smb_ntsd *pntsd, int ntsd_len, + bool type_check); + void id_to_sid(unsigned int cid, uint sidtype, struct smb_sid *ssid); + void ksmbd_init_domain(u32 *sub_auth); +--- a/fs/ksmbd/vfs.c ++++ b/fs/ksmbd/vfs.c +@@ -540,7 +540,7 @@ out: + * + * Return: 0 on success, otherwise error + */ +-int ksmbd_vfs_getattr(struct path *path, struct kstat *stat) ++int ksmbd_vfs_getattr(const struct path *path, struct kstat *stat) + { + int err; + +@@ -1165,7 +1165,7 @@ static int __caseless_lookup(struct dir_ + * + * Return: 0 on success, otherwise error + */ +-static int ksmbd_vfs_lookup_in_dir(struct path *dir, char *name, size_t namelen) ++static int ksmbd_vfs_lookup_in_dir(const struct path *dir, char *name, size_t namelen) + { + int ret; + struct file *dfilp; +--- a/fs/ksmbd/vfs.h ++++ b/fs/ksmbd/vfs.h +@@ -124,7 +124,7 @@ int ksmbd_vfs_fsync(struct ksmbd_work *w + int ksmbd_vfs_remove_file(struct ksmbd_work *work, char *name); + int ksmbd_vfs_link(struct ksmbd_work *work, + const char *oldname, const char *newname); +-int ksmbd_vfs_getattr(struct path *path, struct kstat *stat); ++int ksmbd_vfs_getattr(const struct path *path, struct kstat *stat); + int ksmbd_vfs_fp_rename(struct ksmbd_work *work, struct ksmbd_file *fp, + char *newname); + int ksmbd_vfs_truncate(struct ksmbd_work *work, diff --git a/queue-5.15/ksmbd-convert-to-use-sysfs_emit-sysfs_emit_at-apis.patch b/queue-5.15/ksmbd-convert-to-use-sysfs_emit-sysfs_emit_at-apis.patch new file mode 100644 index 00000000000..aaf0e46c895 --- /dev/null +++ b/queue-5.15/ksmbd-convert-to-use-sysfs_emit-sysfs_emit_at-apis.patch @@ -0,0 +1,65 @@ +From linkinjeon@gmail.com Mon Dec 18 16:39:02 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:33:28 +0900 +Subject: ksmbd: Convert to use sysfs_emit()/sysfs_emit_at() APIs +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, ye xingchen , Sergey Senozhatsky , Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-69-linkinjeon@kernel.org> + +From: ye xingchen + +[ Upstream commit 72ee45fd46d0d3578c4e6046f66fae3218543ce3 ] + +Follow the advice of the Documentation/filesystems/sysfs.rst and show() +should only use sysfs_emit() or sysfs_emit_at() when formatting the +value to be returned to user space. + +Signed-off-by: ye xingchen +Reviewed-by: Sergey Senozhatsky +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/server.c | 20 ++++++-------------- + 1 file changed, 6 insertions(+), 14 deletions(-) + +--- a/fs/ksmbd/server.c ++++ b/fs/ksmbd/server.c +@@ -439,11 +439,9 @@ static ssize_t stats_show(struct class * + "reset", + "shutdown" + }; +- +- ssize_t sz = scnprintf(buf, PAGE_SIZE, "%d %s %d %lu\n", stats_version, +- state[server_conf.state], server_conf.tcp_port, +- server_conf.ipc_last_active / HZ); +- return sz; ++ return sysfs_emit(buf, "%d %s %d %lu\n", stats_version, ++ state[server_conf.state], server_conf.tcp_port, ++ server_conf.ipc_last_active / HZ); + } + + static ssize_t kill_server_store(struct class *class, +@@ -475,19 +473,13 @@ static ssize_t debug_show(struct class * + + for (i = 0; i < ARRAY_SIZE(debug_type_strings); i++) { + if ((ksmbd_debug_types >> i) & 1) { +- pos = scnprintf(buf + sz, +- PAGE_SIZE - sz, +- "[%s] ", +- debug_type_strings[i]); ++ pos = sysfs_emit_at(buf, sz, "[%s] ", debug_type_strings[i]); + } else { +- pos = scnprintf(buf + sz, +- PAGE_SIZE - sz, +- "%s ", +- debug_type_strings[i]); ++ pos = sysfs_emit_at(buf, sz, "%s ", debug_type_strings[i]); + } + sz += pos; + } +- sz += scnprintf(buf + sz, PAGE_SIZE - sz, "\n"); ++ sz += sysfs_emit_at(buf, sz, "\n"); + return sz; + } + diff --git a/queue-5.15/ksmbd-decrease-the-number-of-smb3-smbdirect-server-sges.patch b/queue-5.15/ksmbd-decrease-the-number-of-smb3-smbdirect-server-sges.patch new file mode 100644 index 00000000000..763ab70079c --- /dev/null +++ b/queue-5.15/ksmbd-decrease-the-number-of-smb3-smbdirect-server-sges.patch @@ -0,0 +1,36 @@ +From linkinjeon@gmail.com Mon Dec 18 16:38:31 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:33:18 +0900 +Subject: ksmbd: decrease the number of SMB3 smbdirect server SGEs +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Tom Talpey , Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-59-linkinjeon@kernel.org> + +From: Tom Talpey + +[ Upstream commit 2b4eeeaa90617c5e37da7c804c422b4e833b87b2 ] + +The server-side SMBDirect layer requires no more than 6 send SGEs +The previous default of 8 causes ksmbd to fail on the SoftiWARP +(siw) provider, and possibly others. Additionally, large numbers +of SGEs reduces performance significantly on adapter implementations. + +Signed-off-by: Tom Talpey +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/transport_rdma.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/fs/ksmbd/transport_rdma.c ++++ b/fs/ksmbd/transport_rdma.c +@@ -32,7 +32,7 @@ + /* SMB_DIRECT negotiation timeout in seconds */ + #define SMB_DIRECT_NEGOTIATE_TIMEOUT 120 + +-#define SMB_DIRECT_MAX_SEND_SGES 8 ++#define SMB_DIRECT_MAX_SEND_SGES 6 + #define SMB_DIRECT_MAX_RECV_SGES 1 + + /* diff --git a/queue-5.15/ksmbd-delete-an-invalid-argument-description-in-smb2_populate_readdir_entry.patch b/queue-5.15/ksmbd-delete-an-invalid-argument-description-in-smb2_populate_readdir_entry.patch new file mode 100644 index 00000000000..48b54f7eae5 --- /dev/null +++ b/queue-5.15/ksmbd-delete-an-invalid-argument-description-in-smb2_populate_readdir_entry.patch @@ -0,0 +1,37 @@ +From stable+bounces-7643-greg=kroah.com@vger.kernel.org Mon Dec 18 16:36:55 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:32:34 +0900 +Subject: ksmbd: Delete an invalid argument description in smb2_populate_readdir_entry() +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Yang Li , Abaci Robot , Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-15-linkinjeon@kernel.org> + +From: Yang Li + +[ Upstream commit f5c381392948dcae19f854b9586b806654f08a11 ] + +A warning is reported because an invalid argument description, it is found +by running scripts/kernel-doc, which is caused by using 'make W=1'. +fs/ksmbd/smb2pdu.c:3406: warning: Excess function parameter 'user_ns' +description in 'smb2_populate_readdir_entry' + +Reported-by: Abaci Robot +Fixes: 475d6f98804c ("ksmbd: fix translation in smb2_populate_readdir_entry()") +Acked-by: Namjae Jeon +Signed-off-by: Yang Li +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/smb2pdu.c | 1 - + 1 file changed, 1 deletion(-) + +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -3466,7 +3466,6 @@ static int dentry_name(struct ksmbd_dir_ + * @conn: connection instance + * @info_level: smb information level + * @d_info: structure included variables for query dir +- * @user_ns: user namespace + * @ksmbd_kstat: ksmbd wrapper of dirent stat information + * + * if directory has many entries, find first can't read it fully. diff --git a/queue-5.15/ksmbd-delete-asynchronous-work-from-list.patch b/queue-5.15/ksmbd-delete-asynchronous-work-from-list.patch new file mode 100644 index 00000000000..28c168e894a --- /dev/null +++ b/queue-5.15/ksmbd-delete-asynchronous-work-from-list.patch @@ -0,0 +1,164 @@ +From linkinjeon@gmail.com Mon Dec 18 16:39:39 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:33:40 +0900 +Subject: ksmbd: delete asynchronous work from list +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-81-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit 3a9b557f44ea8f216aab515a7db20e23f0eb51b9 ] + +When smb2_lock request is canceled by smb2_cancel or smb2_close(), +ksmbd is missing deleting async_request_entry async_requests list. +Because calling init_smb2_rsp_hdr() in smb2_lock() mark ->synchronous +as true and then it will not be deleted in +ksmbd_conn_try_dequeue_request(). This patch add release_async_work() to +release the ones allocated for async work. + +Cc: stable@vger.kernel.org +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/connection.c | 12 +++++------- + fs/ksmbd/ksmbd_work.h | 2 +- + fs/ksmbd/smb2pdu.c | 33 +++++++++++++++++++++------------ + fs/ksmbd/smb2pdu.h | 1 + + 4 files changed, 28 insertions(+), 20 deletions(-) + +--- a/fs/ksmbd/connection.c ++++ b/fs/ksmbd/connection.c +@@ -112,10 +112,8 @@ void ksmbd_conn_enqueue_request(struct k + struct ksmbd_conn *conn = work->conn; + struct list_head *requests_queue = NULL; + +- if (conn->ops->get_cmd_val(work) != SMB2_CANCEL_HE) { ++ if (conn->ops->get_cmd_val(work) != SMB2_CANCEL_HE) + requests_queue = &conn->requests; +- work->synchronous = true; +- } + + if (requests_queue) { + atomic_inc(&conn->req_running); +@@ -136,14 +134,14 @@ int ksmbd_conn_try_dequeue_request(struc + + if (!work->multiRsp) + atomic_dec(&conn->req_running); +- spin_lock(&conn->request_lock); + if (!work->multiRsp) { ++ spin_lock(&conn->request_lock); + list_del_init(&work->request_entry); +- if (!work->synchronous) +- list_del_init(&work->async_request_entry); ++ spin_unlock(&conn->request_lock); ++ if (work->asynchronous) ++ release_async_work(work); + ret = 0; + } +- spin_unlock(&conn->request_lock); + + wake_up_all(&conn->req_running_q); + return ret; +--- 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 synchronous:1; ++ bool asynchronous:1; + bool need_invalidate_rkey:1; + + unsigned int remote_key; +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -512,12 +512,6 @@ int init_smb2_rsp_hdr(struct ksmbd_work + rsp_hdr->SessionId = rcv_hdr->SessionId; + memcpy(rsp_hdr->Signature, rcv_hdr->Signature, 16); + +- work->synchronous = true; +- if (work->async_id) { +- ksmbd_release_id(&conn->async_ida, work->async_id); +- work->async_id = 0; +- } +- + return 0; + } + +@@ -675,7 +669,7 @@ int setup_async_work(struct ksmbd_work * + pr_err("Failed to alloc async message id\n"); + return id; + } +- work->synchronous = false; ++ work->asynchronous = true; + work->async_id = id; + rsp_hdr->Id.AsyncId = cpu_to_le64(id); + +@@ -695,6 +689,24 @@ int setup_async_work(struct ksmbd_work * + return 0; + } + ++void release_async_work(struct ksmbd_work *work) ++{ ++ struct ksmbd_conn *conn = work->conn; ++ ++ spin_lock(&conn->request_lock); ++ list_del_init(&work->async_request_entry); ++ spin_unlock(&conn->request_lock); ++ ++ work->asynchronous = 0; ++ work->cancel_fn = NULL; ++ kfree(work->cancel_argv); ++ work->cancel_argv = NULL; ++ if (work->async_id) { ++ ksmbd_release_id(&conn->async_ida, work->async_id); ++ work->async_id = 0; ++ } ++} ++ + void smb2_send_interim_resp(struct ksmbd_work *work, __le32 status) + { + struct smb2_hdr *rsp_hdr; +@@ -7090,13 +7102,9 @@ 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); +@@ -7114,6 +7122,7 @@ skip: + work->send_no_response = 1; + goto out; + } ++ + init_smb2_rsp_hdr(work); + smb2_set_err_rsp(work); + rsp->hdr.Status = +@@ -7126,7 +7135,7 @@ skip: + spin_lock(&work->conn->llist_lock); + list_del(&smb_lock->clist); + spin_unlock(&work->conn->llist_lock); +- ++ release_async_work(work); + goto retry; + } else if (!rc) { + spin_lock(&work->conn->llist_lock); +--- a/fs/ksmbd/smb2pdu.h ++++ b/fs/ksmbd/smb2pdu.h +@@ -1663,6 +1663,7 @@ int find_matching_smb2_dialect(int start + struct file_lock *smb_flock_init(struct file *f); + int setup_async_work(struct ksmbd_work *work, void (*fn)(void **), + void **arg); ++void release_async_work(struct ksmbd_work *work); + void smb2_send_interim_resp(struct ksmbd_work *work, __le32 status); + struct channel *lookup_chann_list(struct ksmbd_session *sess, + struct ksmbd_conn *conn); diff --git a/queue-5.15/ksmbd-destroy-expired-sessions.patch b/queue-5.15/ksmbd-destroy-expired-sessions.patch new file mode 100644 index 00000000000..0e86580b160 --- /dev/null +++ b/queue-5.15/ksmbd-destroy-expired-sessions.patch @@ -0,0 +1,184 @@ +From linkinjeon@gmail.com Mon Dec 18 16:40:08 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:33:49 +0900 +Subject: ksmbd: destroy expired sessions +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , zdi-disclosures@trendmicro.com, Steve French +Message-ID: <20231218153454.8090-90-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit ea174a91893956450510945a0c5d1a10b5323656 ] + +client can indefinitely send smb2 session setup requests with +the SessionId set to 0, thus indefinitely spawning new sessions, +and causing indefinite memory usage. This patch limit to the number +of sessions using expired timeout and session state. + +Cc: stable@vger.kernel.org +Reported-by: zdi-disclosures@trendmicro.com # ZDI-CAN-20478 +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/mgmt/user_session.c | 68 +++++++++++++++++++++++-------------------- + fs/ksmbd/mgmt/user_session.h | 1 + fs/ksmbd/smb2pdu.c | 1 + fs/ksmbd/smb2pdu.h | 2 + + 4 files changed, 41 insertions(+), 31 deletions(-) + +--- a/fs/ksmbd/mgmt/user_session.c ++++ b/fs/ksmbd/mgmt/user_session.c +@@ -165,70 +165,73 @@ static struct ksmbd_session *__session_l + struct ksmbd_session *sess; + + hash_for_each_possible(sessions_table, sess, hlist, id) { +- if (id == sess->id) ++ if (id == sess->id) { ++ sess->last_active = jiffies; + return sess; ++ } + } + return NULL; + } + ++static void ksmbd_expire_session(struct ksmbd_conn *conn) ++{ ++ unsigned long id; ++ struct ksmbd_session *sess; ++ ++ xa_for_each(&conn->sessions, id, sess) { ++ if (sess->state != SMB2_SESSION_VALID || ++ time_after(jiffies, ++ sess->last_active + SMB2_SESSION_TIMEOUT)) { ++ xa_erase(&conn->sessions, sess->id); ++ ksmbd_session_destroy(sess); ++ continue; ++ } ++ } ++} ++ + int ksmbd_session_register(struct ksmbd_conn *conn, + struct ksmbd_session *sess) + { + sess->dialect = conn->dialect; + memcpy(sess->ClientGUID, conn->ClientGUID, SMB2_CLIENT_GUID_SIZE); ++ ksmbd_expire_session(conn); + return xa_err(xa_store(&conn->sessions, sess->id, sess, GFP_KERNEL)); + } + +-static int ksmbd_chann_del(struct ksmbd_conn *conn, struct ksmbd_session *sess) ++static void ksmbd_chann_del(struct ksmbd_conn *conn, struct ksmbd_session *sess) + { + struct channel *chann; + + chann = xa_erase(&sess->ksmbd_chann_list, (long)conn); + if (!chann) +- return -ENOENT; ++ return; + + kfree(chann); +- +- return 0; + } + + void ksmbd_sessions_deregister(struct ksmbd_conn *conn) + { + struct ksmbd_session *sess; ++ unsigned long id; + +- if (conn->binding) { +- int bkt; +- +- down_write(&sessions_table_lock); +- hash_for_each(sessions_table, bkt, sess, hlist) { +- if (!ksmbd_chann_del(conn, sess)) { +- up_write(&sessions_table_lock); +- goto sess_destroy; +- } +- } +- up_write(&sessions_table_lock); +- } else { +- unsigned long id; +- +- xa_for_each(&conn->sessions, id, sess) { +- if (!ksmbd_chann_del(conn, sess)) +- goto sess_destroy; ++ xa_for_each(&conn->sessions, id, sess) { ++ ksmbd_chann_del(conn, sess); ++ if (xa_empty(&sess->ksmbd_chann_list)) { ++ xa_erase(&conn->sessions, sess->id); ++ ksmbd_session_destroy(sess); + } + } +- +- return; +- +-sess_destroy: +- if (xa_empty(&sess->ksmbd_chann_list)) { +- xa_erase(&conn->sessions, sess->id); +- ksmbd_session_destroy(sess); +- } + } + + struct ksmbd_session *ksmbd_session_lookup(struct ksmbd_conn *conn, + unsigned long long id) + { +- return xa_load(&conn->sessions, id); ++ struct ksmbd_session *sess; ++ ++ sess = xa_load(&conn->sessions, id); ++ if (sess) ++ sess->last_active = jiffies; ++ return sess; + } + + struct ksmbd_session *ksmbd_session_lookup_slowpath(unsigned long long id) +@@ -237,6 +240,8 @@ struct ksmbd_session *ksmbd_session_look + + down_read(&sessions_table_lock); + sess = __session_lookup(id); ++ if (sess) ++ sess->last_active = jiffies; + up_read(&sessions_table_lock); + + return sess; +@@ -315,6 +320,7 @@ static struct ksmbd_session *__session_c + if (ksmbd_init_file_table(&sess->file_table)) + goto error; + ++ sess->last_active = jiffies; + sess->state = SMB2_SESSION_IN_PROGRESS; + set_session_flag(sess, protocol); + xa_init(&sess->tree_conns); +--- a/fs/ksmbd/mgmt/user_session.h ++++ b/fs/ksmbd/mgmt/user_session.h +@@ -59,6 +59,7 @@ struct ksmbd_session { + __u8 smb3signingkey[SMB3_SIGN_KEY_SIZE]; + + struct ksmbd_file_table file_table; ++ unsigned long last_active; + }; + + static inline int test_session_flag(struct ksmbd_session *sess, int bit) +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -1875,6 +1875,7 @@ out_err: + if (sess->user && sess->user->flags & KSMBD_USER_FLAG_DELAY_SESSION) + try_delay = true; + ++ sess->last_active = jiffies; + sess->state = SMB2_SESSION_EXPIRED; + if (try_delay) + ssleep(5); +--- a/fs/ksmbd/smb2pdu.h ++++ b/fs/ksmbd/smb2pdu.h +@@ -619,6 +619,8 @@ struct create_context { + __u8 Buffer[0]; + } __packed; + ++#define SMB2_SESSION_TIMEOUT (10 * HZ) ++ + struct create_durable_req_v2 { + struct create_context ccontext; + __u8 Name[8]; diff --git a/queue-5.15/ksmbd-don-t-open-code-file_path.patch b/queue-5.15/ksmbd-don-t-open-code-file_path.patch new file mode 100644 index 00000000000..a58d7b9eb1c --- /dev/null +++ b/queue-5.15/ksmbd-don-t-open-code-file_path.patch @@ -0,0 +1,40 @@ +From linkinjeon@gmail.com Mon Dec 18 16:38:00 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:33:08 +0900 +Subject: ksmbd: don't open-code file_path() +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Al Viro , Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-49-linkinjeon@kernel.org> + +From: Al Viro + +[ Upstream commit 2f5930c1d7936b74eb820c5b157011994c707a74 ] + +Acked-by: Namjae Jeon +Signed-off-by: Al Viro +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/smb2pdu.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -5449,7 +5449,7 @@ static int smb2_rename(struct ksmbd_work + if (!pathname) + return -ENOMEM; + +- abs_oldname = d_path(&fp->filp->f_path, pathname, PATH_MAX); ++ abs_oldname = file_path(fp->filp, pathname, PATH_MAX); + if (IS_ERR(abs_oldname)) { + rc = -EINVAL; + goto out; +@@ -5584,7 +5584,7 @@ static int smb2_create_link(struct ksmbd + } + + ksmbd_debug(SMB, "link name is %s\n", link_name); +- target_name = d_path(&filp->f_path, pathname, PATH_MAX); ++ target_name = file_path(filp, pathname, PATH_MAX); + if (IS_ERR(target_name)) { + rc = -EINVAL; + goto out; diff --git a/queue-5.15/ksmbd-don-t-open-code-pd.patch b/queue-5.15/ksmbd-don-t-open-code-pd.patch new file mode 100644 index 00000000000..2457548e71e --- /dev/null +++ b/queue-5.15/ksmbd-don-t-open-code-pd.patch @@ -0,0 +1,105 @@ +From linkinjeon@gmail.com Mon Dec 18 16:38:03 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:33:09 +0900 +Subject: ksmbd: don't open-code %pD +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Al Viro , Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-50-linkinjeon@kernel.org> + +From: Al Viro + +[ Upstream commit 369c1634cc7ae8645a5cba4c7eb874755c2a6a07 ] + +a bunch of places used %pd with file->f_path.dentry; shorter (and saner) +way to spell that is %pD with file... + +Acked-by: Namjae Jeon +Signed-off-by: Al Viro +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/smb2pdu.c | 11 +++++------ + fs/ksmbd/vfs.c | 14 ++++++-------- + 2 files changed, 11 insertions(+), 14 deletions(-) + +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -3939,8 +3939,7 @@ int smb2_query_dir(struct ksmbd_work *wo + inode_permission(file_mnt_user_ns(dir_fp->filp), + file_inode(dir_fp->filp), + MAY_READ | MAY_EXEC)) { +- pr_err("no right to enumerate directory (%pd)\n", +- dir_fp->filp->f_path.dentry); ++ pr_err("no right to enumerate directory (%pD)\n", dir_fp->filp); + rc = -EACCES; + goto err_out2; + } +@@ -6309,8 +6308,8 @@ int smb2_read(struct ksmbd_work *work) + goto out; + } + +- ksmbd_debug(SMB, "filename %pd, offset %lld, len %zu\n", +- fp->filp->f_path.dentry, offset, length); ++ ksmbd_debug(SMB, "filename %pD, offset %lld, len %zu\n", ++ fp->filp, offset, length); + + work->aux_payload_buf = kvmalloc(length, GFP_KERNEL | __GFP_ZERO); + if (!work->aux_payload_buf) { +@@ -6574,8 +6573,8 @@ int smb2_write(struct ksmbd_work *work) + data_buf = (char *)(((char *)&req->hdr.ProtocolId) + + le16_to_cpu(req->DataOffset)); + +- ksmbd_debug(SMB, "filename %pd, offset %lld, len %zu\n", +- fp->filp->f_path.dentry, offset, length); ++ ksmbd_debug(SMB, "filename %pD, offset %lld, len %zu\n", ++ fp->filp, offset, length); + err = ksmbd_vfs_write(work, fp, data_buf, length, &offset, + writethrough, &nbytes); + if (err < 0) +--- a/fs/ksmbd/vfs.c ++++ b/fs/ksmbd/vfs.c +@@ -376,8 +376,7 @@ int ksmbd_vfs_read(struct ksmbd_work *wo + + if (work->conn->connection_type) { + if (!(fp->daccess & (FILE_READ_DATA_LE | FILE_EXECUTE_LE))) { +- pr_err("no right to read(%pd)\n", +- fp->filp->f_path.dentry); ++ pr_err("no right to read(%pD)\n", fp->filp); + return -EACCES; + } + } +@@ -486,8 +485,7 @@ int ksmbd_vfs_write(struct ksmbd_work *w + + if (work->conn->connection_type) { + if (!(fp->daccess & FILE_WRITE_DATA_LE)) { +- pr_err("no right to write(%pd)\n", +- fp->filp->f_path.dentry); ++ pr_err("no right to write(%pD)\n", fp->filp); + err = -EACCES; + goto out; + } +@@ -526,8 +524,8 @@ int ksmbd_vfs_write(struct ksmbd_work *w + if (sync) { + err = vfs_fsync_range(filp, offset, offset + *written, 0); + if (err < 0) +- pr_err("fsync failed for filename = %pd, err = %d\n", +- fp->filp->f_path.dentry, err); ++ pr_err("fsync failed for filename = %pD, err = %d\n", ++ fp->filp, err); + } + + out: +@@ -1742,11 +1740,11 @@ int ksmbd_vfs_copy_file_ranges(struct ks + *total_size_written = 0; + + if (!(src_fp->daccess & (FILE_READ_DATA_LE | FILE_EXECUTE_LE))) { +- pr_err("no right to read(%pd)\n", src_fp->filp->f_path.dentry); ++ pr_err("no right to read(%pD)\n", src_fp->filp); + return -EACCES; + } + if (!(dst_fp->daccess & (FILE_WRITE_DATA_LE | FILE_APPEND_DATA_LE))) { +- pr_err("no right to write(%pd)\n", dst_fp->filp->f_path.dentry); ++ pr_err("no right to write(%pD)\n", dst_fp->filp); + return -EACCES; + } + diff --git a/queue-5.15/ksmbd-don-t-update-op_state-as-oplock_state_none-on-error.patch b/queue-5.15/ksmbd-don-t-update-op_state-as-oplock_state_none-on-error.patch new file mode 100644 index 00000000000..f4064c9bd85 --- /dev/null +++ b/queue-5.15/ksmbd-don-t-update-op_state-as-oplock_state_none-on-error.patch @@ -0,0 +1,33 @@ +From linkinjeon@gmail.com Mon Dec 18 16:43:41 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:34:54 +0900 +Subject: ksmbd: don't update ->op_state as OPLOCK_STATE_NONE on error +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-155-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit cd80ce7e68f1624ac29cd0a6b057789d1236641e ] + +ksmbd set ->op_state as OPLOCK_STATE_NONE on lease break ack error. +op_state of lease should not be updated because client can send lease +break ack again. This patch fix smb2.lease.breaking2 test failure. + +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/smb2pdu.c | 1 - + 1 file changed, 1 deletion(-) + +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -8237,7 +8237,6 @@ static void smb21_lease_break_ack(struct + return; + + err_out: +- opinfo->op_state = OPLOCK_STATE_NONE; + wake_up_interruptible_all(&opinfo->oplock_q); + atomic_dec(&opinfo->breaking_cnt); + wake_up_interruptible_all(&opinfo->oplock_brk); diff --git a/queue-5.15/ksmbd-fill-sids-in-smb_find_file_posix_info-response.patch b/queue-5.15/ksmbd-fill-sids-in-smb_find_file_posix_info-response.patch new file mode 100644 index 00000000000..d952b1430ae --- /dev/null +++ b/queue-5.15/ksmbd-fill-sids-in-smb_find_file_posix_info-response.patch @@ -0,0 +1,73 @@ +From linkinjeon@gmail.com Mon Dec 18 16:38:22 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:33:15 +0900 +Subject: ksmbd: fill sids in SMB_FIND_FILE_POSIX_INFO response +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-56-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit d5919f2a1459083bd0aaede7fc44e945290e44df ] + +This patch fill missing sids in SMB_FIND_FILE_POSIX_INFO response. + +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/smb2pdu.c | 28 ++++++++++++++++++++++------ + 1 file changed, 22 insertions(+), 6 deletions(-) + +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -4754,7 +4754,9 @@ static int find_file_posix_info(struct s + { + struct smb311_posix_qinfo *file_info; + struct inode *inode = file_inode(fp->filp); ++ struct user_namespace *user_ns = file_mnt_user_ns(fp->filp); + u64 time; ++ int out_buf_len = sizeof(struct smb311_posix_qinfo) + 32; + + file_info = (struct smb311_posix_qinfo *)rsp->Buffer; + file_info->CreationTime = cpu_to_le64(fp->create_time); +@@ -4771,10 +4773,24 @@ static int find_file_posix_info(struct s + file_info->HardLinks = cpu_to_le32(inode->i_nlink); + file_info->Mode = cpu_to_le32(inode->i_mode & 0777); + file_info->DeviceId = cpu_to_le32(inode->i_rdev); +- rsp->OutputBufferLength = +- cpu_to_le32(sizeof(struct smb311_posix_qinfo)); +- inc_rfc1001_len(rsp_org, sizeof(struct smb311_posix_qinfo)); +- return 0; ++ ++ /* ++ * Sids(32) contain two sids(Domain sid(16), UNIX group sid(16)). ++ * UNIX sid(16) = revision(1) + num_subauth(1) + authority(6) + ++ * sub_auth(4 * 1(num_subauth)) + RID(4). ++ */ ++ id_to_sid(from_kuid_munged(&init_user_ns, ++ i_uid_into_mnt(user_ns, inode)), ++ SIDUNIX_USER, ++ (struct smb_sid *)&file_info->Sids[0]); ++ id_to_sid(from_kgid_munged(&init_user_ns, ++ i_gid_into_mnt(user_ns, inode)), ++ SIDUNIX_GROUP, ++ (struct smb_sid *)&file_info->Sids[16]); ++ ++ rsp->OutputBufferLength = cpu_to_le32(out_buf_len); ++ inc_rfc1001_len(rsp_org, out_buf_len); ++ return out_buf_len; + } + + static int smb2_get_info_file(struct ksmbd_work *work, +@@ -4894,8 +4910,8 @@ static int smb2_get_info_file(struct ksm + pr_err("client doesn't negotiate with SMB3.1.1 POSIX Extensions\n"); + rc = -EOPNOTSUPP; + } else { +- rc = find_file_posix_info(rsp, fp, work->response_buf); +- file_infoclass_size = sizeof(struct smb311_posix_qinfo); ++ file_infoclass_size = find_file_posix_info(rsp, fp, ++ work->response_buf); + } + break; + default: diff --git a/queue-5.15/ksmbd-fix-buffer_check_err-kernel-doc-comment.patch b/queue-5.15/ksmbd-fix-buffer_check_err-kernel-doc-comment.patch new file mode 100644 index 00000000000..492037331d7 --- /dev/null +++ b/queue-5.15/ksmbd-fix-buffer_check_err-kernel-doc-comment.patch @@ -0,0 +1,38 @@ +From stable+bounces-7641-greg=kroah.com@vger.kernel.org Mon Dec 18 16:36:28 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:32:32 +0900 +Subject: ksmbd: Fix buffer_check_err() kernel-doc comment +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Yang Li , Abaci Robot , Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-13-linkinjeon@kernel.org> + +From: Yang Li + +[ Upstream commit e230d013378489bcd4b5589ca1d2a5b91ff8d098 ] + +Add the description of @rsp_org in buffer_check_err() kernel-doc comment +to remove a warning found by running scripts/kernel-doc, which is caused +by using 'make W=1'. +fs/ksmbd/smb2pdu.c:4028: warning: Function parameter or member 'rsp_org' +not described in 'buffer_check_err' + +Reported-by: Abaci Robot +Fixes: cb4517201b8a ("ksmbd: remove smb2_buf_length in smb2_hdr") +Acked-by: Namjae Jeon +Signed-off-by: Yang Li +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/smb2pdu.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -4101,6 +4101,7 @@ err_out2: + * buffer_check_err() - helper function to check buffer errors + * @reqOutputBufferLength: max buffer length expected in command response + * @rsp: query info response buffer contains output buffer length ++ * @rsp_org: base response buffer pointer in case of chained response + * @infoclass_size: query info class response buffer size + * + * Return: 0 on success, otherwise error diff --git a/queue-5.15/ksmbd-fix-encryption-failure-issue-for-session-logoff-response.patch b/queue-5.15/ksmbd-fix-encryption-failure-issue-for-session-logoff-response.patch new file mode 100644 index 00000000000..3ea3000e085 --- /dev/null +++ b/queue-5.15/ksmbd-fix-encryption-failure-issue-for-session-logoff-response.patch @@ -0,0 +1,125 @@ +From linkinjeon@gmail.com Mon Dec 18 16:38:25 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:33:16 +0900 +Subject: ksmbd: fix encryption failure issue for session logoff response +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-57-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit af705ef2b0ded0d8f54c238fdf3c17a1d47ad924 ] + +If client send encrypted session logoff request on seal mount, +Encryption for that response fails. + +ksmbd: Could not get encryption key +CIFS: VFS: cifs_put_smb_ses: Session Logoff failure rc=-512 + +Session lookup fails in ksmbd_get_encryption_key() because sess->state is +set to SMB2_SESSION_EXPIRED in session logoff. There is no need to do +session lookup again to encrypt the response. This patch change to use +ksmbd_session in ksmbd_work. + +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/auth.c | 12 ++++++++---- + fs/ksmbd/auth.h | 3 ++- + fs/ksmbd/smb2pdu.c | 7 +++---- + 3 files changed, 13 insertions(+), 9 deletions(-) + +--- a/fs/ksmbd/auth.c ++++ b/fs/ksmbd/auth.c +@@ -988,13 +988,16 @@ out: + return rc; + } + +-static int ksmbd_get_encryption_key(struct ksmbd_conn *conn, __u64 ses_id, ++static int ksmbd_get_encryption_key(struct ksmbd_work *work, __u64 ses_id, + int enc, u8 *key) + { + struct ksmbd_session *sess; + u8 *ses_enc_key; + +- sess = ksmbd_session_lookup_all(conn, ses_id); ++ if (enc) ++ sess = work->sess; ++ else ++ sess = ksmbd_session_lookup_all(work->conn, ses_id); + if (!sess) + return -EINVAL; + +@@ -1082,9 +1085,10 @@ static struct scatterlist *ksmbd_init_sg + return sg; + } + +-int ksmbd_crypt_message(struct ksmbd_conn *conn, struct kvec *iov, ++int ksmbd_crypt_message(struct ksmbd_work *work, struct kvec *iov, + unsigned int nvec, int enc) + { ++ struct ksmbd_conn *conn = work->conn; + struct smb2_transform_hdr *tr_hdr = smb2_get_msg(iov[0].iov_base); + unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 20; + int rc; +@@ -1098,7 +1102,7 @@ int ksmbd_crypt_message(struct ksmbd_con + unsigned int crypt_len = le32_to_cpu(tr_hdr->OriginalMessageSize); + struct ksmbd_crypto_ctx *ctx; + +- rc = ksmbd_get_encryption_key(conn, ++ rc = ksmbd_get_encryption_key(work, + le64_to_cpu(tr_hdr->SessionId), + enc, + key); +--- a/fs/ksmbd/auth.h ++++ b/fs/ksmbd/auth.h +@@ -33,9 +33,10 @@ + + struct ksmbd_session; + struct ksmbd_conn; ++struct ksmbd_work; + struct kvec; + +-int ksmbd_crypt_message(struct ksmbd_conn *conn, struct kvec *iov, ++int ksmbd_crypt_message(struct ksmbd_work *work, struct kvec *iov, + unsigned int nvec, int enc); + void ksmbd_copy_gss_neg_header(void *buf); + int ksmbd_auth_ntlmv2(struct ksmbd_conn *conn, struct ksmbd_session *sess, +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -8646,7 +8646,7 @@ int smb3_encrypt_resp(struct ksmbd_work + buf_size += iov[1].iov_len; + work->resp_hdr_sz = iov[1].iov_len; + +- rc = ksmbd_crypt_message(work->conn, iov, rq_nvec, 1); ++ rc = ksmbd_crypt_message(work, iov, rq_nvec, 1); + if (rc) + return rc; + +@@ -8665,7 +8665,6 @@ bool smb3_is_transform_hdr(void *buf) + + int smb3_decrypt_req(struct ksmbd_work *work) + { +- struct ksmbd_conn *conn = work->conn; + struct ksmbd_session *sess; + char *buf = work->request_buf; + unsigned int pdu_length = get_rfc1002_len(buf); +@@ -8686,7 +8685,7 @@ int smb3_decrypt_req(struct ksmbd_work * + return -ECONNABORTED; + } + +- sess = ksmbd_session_lookup_all(conn, le64_to_cpu(tr_hdr->SessionId)); ++ sess = ksmbd_session_lookup_all(work->conn, le64_to_cpu(tr_hdr->SessionId)); + if (!sess) { + pr_err("invalid session id(%llx) in transform header\n", + le64_to_cpu(tr_hdr->SessionId)); +@@ -8697,7 +8696,7 @@ int smb3_decrypt_req(struct ksmbd_work * + iov[0].iov_len = sizeof(struct smb2_transform_hdr) + 4; + iov[1].iov_base = buf + sizeof(struct smb2_transform_hdr) + 4; + iov[1].iov_len = buf_data_size; +- rc = ksmbd_crypt_message(conn, iov, 2, 0); ++ rc = ksmbd_crypt_message(work, iov, 2, 0); + if (rc) + return rc; + diff --git a/queue-5.15/ksmbd-fix-force-create-mode-and-force-directory-mode.patch b/queue-5.15/ksmbd-fix-force-create-mode-and-force-directory-mode.patch new file mode 100644 index 00000000000..98b57b57f25 --- /dev/null +++ b/queue-5.15/ksmbd-fix-force-create-mode-and-force-directory-mode.patch @@ -0,0 +1,67 @@ +From linkinjeon@gmail.com Mon Dec 18 16:41:51 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:34:21 +0900 +Subject: ksmbd: fix `force create mode' and `force directory mode' +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, "Atte Heikkilä" , "Namjae Jeon" , "Steve French" +Message-ID: <20231218153454.8090-122-linkinjeon@kernel.org> + +From: Atte Heikkilä + +[ Upstream commit 65656f5242e500dcfeffa6a0a1519eae14724f86 ] + +`force create mode' and `force directory mode' should be bitwise ORed +with the perms after `create mask' and `directory mask' have been +applied, respectively. + +Signed-off-by: Atte Heikkilä +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/mgmt/share_config.h | 29 +++++++++++------------------ + 1 file changed, 11 insertions(+), 18 deletions(-) + +--- a/fs/ksmbd/mgmt/share_config.h ++++ b/fs/ksmbd/mgmt/share_config.h +@@ -34,29 +34,22 @@ struct ksmbd_share_config { + #define KSMBD_SHARE_INVALID_UID ((__u16)-1) + #define KSMBD_SHARE_INVALID_GID ((__u16)-1) + +-static inline int share_config_create_mode(struct ksmbd_share_config *share, +- umode_t posix_mode) ++static inline umode_t ++share_config_create_mode(struct ksmbd_share_config *share, ++ umode_t posix_mode) + { +- if (!share->force_create_mode) { +- if (!posix_mode) +- return share->create_mask; +- else +- return posix_mode & share->create_mask; +- } +- return share->force_create_mode & share->create_mask; ++ umode_t mode = (posix_mode ?: (umode_t)-1) & share->create_mask; ++ ++ return mode | share->force_create_mode; + } + +-static inline int share_config_directory_mode(struct ksmbd_share_config *share, +- umode_t posix_mode) ++static inline umode_t ++share_config_directory_mode(struct ksmbd_share_config *share, ++ umode_t posix_mode) + { +- if (!share->force_directory_mode) { +- if (!posix_mode) +- return share->directory_mask; +- else +- return posix_mode & share->directory_mask; +- } ++ umode_t mode = (posix_mode ?: (umode_t)-1) & share->directory_mask; + +- return share->force_directory_mode & share->directory_mask; ++ return mode | share->force_directory_mode; + } + + static inline int test_share_config_flag(struct ksmbd_share_config *share, diff --git a/queue-5.15/ksmbd-fix-kernel-doc-comment-of-ksmbd_vfs_kern_path_locked.patch b/queue-5.15/ksmbd-fix-kernel-doc-comment-of-ksmbd_vfs_kern_path_locked.patch new file mode 100644 index 00000000000..7df71fcf484 --- /dev/null +++ b/queue-5.15/ksmbd-fix-kernel-doc-comment-of-ksmbd_vfs_kern_path_locked.patch @@ -0,0 +1,42 @@ +From linkinjeon@gmail.com Mon Dec 18 16:43:13 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:34:46 +0900 +Subject: ksmbd: fix kernel-doc comment of ksmbd_vfs_kern_path_locked() +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , kernel test robot , Steve French +Message-ID: <20231218153454.8090-147-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit f6049712e520287ad695e9d4f1572ab76807fa0c ] + +Fix argument list that the kdoc format and script verified in +ksmbd_vfs_kern_path_locked(). + +fs/smb/server/vfs.c:1207: warning: Function parameter or member 'parent_path' +not described in 'ksmbd_vfs_kern_path_locked' + +Reported-by: kernel test robot +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/vfs.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +--- a/fs/ksmbd/vfs.c ++++ b/fs/ksmbd/vfs.c +@@ -1179,9 +1179,10 @@ static int ksmbd_vfs_lookup_in_dir(const + + /** + * ksmbd_vfs_kern_path_locked() - lookup a file and get path info +- * @name: file path that is relative to share +- * @flags: lookup flags +- * @path: if lookup succeed, return path info ++ * @name: file path that is relative to share ++ * @flags: lookup flags ++ * @parent_path: if lookup succeed, return parent_path info ++ * @path: if lookup succeed, return path info + * @caseless: caseless filename lookup + * + * Return: 0 on success, otherwise error diff --git a/queue-5.15/ksmbd-fix-kernel-doc-comment-of-ksmbd_vfs_setxattr.patch b/queue-5.15/ksmbd-fix-kernel-doc-comment-of-ksmbd_vfs_setxattr.patch new file mode 100644 index 00000000000..2fbe145a8ed --- /dev/null +++ b/queue-5.15/ksmbd-fix-kernel-doc-comment-of-ksmbd_vfs_setxattr.patch @@ -0,0 +1,37 @@ +From linkinjeon@gmail.com Mon Dec 18 16:42:57 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:34:41 +0900 +Subject: ksmbd: fix kernel-doc comment of ksmbd_vfs_setxattr() +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , kernel test robot , Steve French +Message-ID: <20231218153454.8090-142-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit 3354db668808d5b6d7c5e0cb19ff4c9da4bb5e58 ] + +Fix argument list that the kdoc format and script verified in +ksmbd_vfs_setxattr(). + +fs/smb/server/vfs.c:929: warning: Function parameter or member 'path' +not described in 'ksmbd_vfs_setxattr' + +Reported-by: kernel test robot +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/vfs.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/fs/ksmbd/vfs.c ++++ b/fs/ksmbd/vfs.c +@@ -919,7 +919,7 @@ ssize_t ksmbd_vfs_getxattr(struct user_n + /** + * ksmbd_vfs_setxattr() - vfs helper for smb set extended attributes value + * @user_ns: user namespace +- * @dentry: dentry to set XATTR at ++ * @path: path of dentry to set XATTR at + * @attr_name: xattr name for setxattr + * @attr_value: xattr value to set + * @attr_size: size of xattr value diff --git a/queue-5.15/ksmbd-fix-missing-rdma-capable-flag-for-ipoib-device-in-ksmbd_rdma_capable_netdev.patch b/queue-5.15/ksmbd-fix-missing-rdma-capable-flag-for-ipoib-device-in-ksmbd_rdma_capable_netdev.patch new file mode 100644 index 00000000000..3dedf8188ee --- /dev/null +++ b/queue-5.15/ksmbd-fix-missing-rdma-capable-flag-for-ipoib-device-in-ksmbd_rdma_capable_netdev.patch @@ -0,0 +1,87 @@ +From linkinjeon@gmail.com Mon Dec 18 16:43:05 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:34:43 +0900 +Subject: ksmbd: fix missing RDMA-capable flag for IPoIB device in ksmbd_rdma_capable_netdev() +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Kangjing Huang , Namjae Jeon , Tom Talpey , Steve French +Message-ID: <20231218153454.8090-144-linkinjeon@kernel.org> + +From: Kangjing Huang + +[ Upstream commit ecce70cf17d91c3dd87a0c4ea00b2d1387729701 ] + +Physical ib_device does not have an underlying net_device, thus its +association with IPoIB net_device cannot be retrieved via +ops.get_netdev() or ib_device_get_by_netdev(). ksmbd reads physical +ib_device port GUID from the lower 16 bytes of the hardware addresses on +IPoIB net_device and match its underlying ib_device using ib_find_gid() + +Signed-off-by: Kangjing Huang +Acked-by: Namjae Jeon +Reviewed-by: Tom Talpey +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/transport_rdma.c | 42 +++++++++++++++++++++++++++++++----------- + 1 file changed, 31 insertions(+), 11 deletions(-) + +--- a/fs/ksmbd/transport_rdma.c ++++ b/fs/ksmbd/transport_rdma.c +@@ -2140,8 +2140,7 @@ static int smb_direct_ib_client_add(stru + if (ib_dev->node_type != RDMA_NODE_IB_CA) + smb_direct_port = SMB_DIRECT_PORT_IWARP; + +- if (!ib_dev->ops.get_netdev || +- !rdma_frwr_is_supported(&ib_dev->attrs)) ++ if (!rdma_frwr_is_supported(&ib_dev->attrs)) + return 0; + + smb_dev = kzalloc(sizeof(*smb_dev), GFP_KERNEL); +@@ -2241,17 +2240,38 @@ bool ksmbd_rdma_capable_netdev(struct ne + for (i = 0; i < smb_dev->ib_dev->phys_port_cnt; i++) { + struct net_device *ndev; + +- ndev = smb_dev->ib_dev->ops.get_netdev(smb_dev->ib_dev, +- i + 1); +- if (!ndev) +- continue; +- +- if (ndev == netdev) { ++ if (smb_dev->ib_dev->ops.get_netdev) { ++ ndev = smb_dev->ib_dev->ops.get_netdev( ++ smb_dev->ib_dev, i + 1); ++ if (!ndev) ++ continue; ++ ++ if (ndev == netdev) { ++ dev_put(ndev); ++ rdma_capable = true; ++ goto out; ++ } + dev_put(ndev); +- rdma_capable = true; +- goto out; ++ /* if ib_dev does not implement ops.get_netdev ++ * check for matching infiniband GUID in hw_addr ++ */ ++ } else if (netdev->type == ARPHRD_INFINIBAND) { ++ struct netdev_hw_addr *ha; ++ union ib_gid gid; ++ u32 port_num; ++ int ret; ++ ++ netdev_hw_addr_list_for_each( ++ ha, &netdev->dev_addrs) { ++ memcpy(&gid, ha->addr + 4, sizeof(gid)); ++ ret = ib_find_gid(smb_dev->ib_dev, &gid, ++ &port_num, NULL); ++ if (!ret) { ++ rdma_capable = true; ++ goto out; ++ } ++ } + } +- dev_put(ndev); + } + } + out: diff --git a/queue-5.15/ksmbd-fix-multiple-out-of-bounds-read-during-context-decoding.patch b/queue-5.15/ksmbd-fix-multiple-out-of-bounds-read-during-context-decoding.patch new file mode 100644 index 00000000000..94aad5ebb7b --- /dev/null +++ b/queue-5.15/ksmbd-fix-multiple-out-of-bounds-read-during-context-decoding.patch @@ -0,0 +1,154 @@ +From linkinjeon@gmail.com Mon Dec 18 16:40:27 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:33:55 +0900 +Subject: ksmbd: fix multiple out-of-bounds read during context decoding +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Kuan-Ting Chen , Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-96-linkinjeon@kernel.org> + +From: Kuan-Ting Chen + +[ Upstream commit 0512a5f89e1fae74251fde6893ff634f1c96c6fb ] + +Check the remaining data length before accessing the context structure +to ensure that the entire structure is contained within the packet. +Additionally, since the context data length `ctxt_len` has already been +checked against the total packet length `len_of_ctxts`, update the +comparison to use `ctxt_len`. + +Cc: stable@vger.kernel.org +Signed-off-by: Kuan-Ting Chen +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/smb2pdu.c | 53 ++++++++++++++++++++++++++++++++++------------------- + 1 file changed, 34 insertions(+), 19 deletions(-) + +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -879,13 +879,14 @@ static void assemble_neg_contexts(struct + + static __le32 decode_preauth_ctxt(struct ksmbd_conn *conn, + struct smb2_preauth_neg_context *pneg_ctxt, +- int len_of_ctxts) ++ int ctxt_len) + { + /* + * sizeof(smb2_preauth_neg_context) assumes SMB311_SALT_SIZE Salt, + * which may not be present. Only check for used HashAlgorithms[1]. + */ +- if (len_of_ctxts < 6) ++ if (ctxt_len < ++ sizeof(struct smb2_neg_context) + 6) + return STATUS_INVALID_PARAMETER; + + if (pneg_ctxt->HashAlgorithms != SMB2_PREAUTH_INTEGRITY_SHA512) +@@ -897,15 +898,23 @@ static __le32 decode_preauth_ctxt(struct + + static void decode_encrypt_ctxt(struct ksmbd_conn *conn, + struct smb2_encryption_neg_context *pneg_ctxt, +- int len_of_ctxts) ++ int ctxt_len) + { +- int cph_cnt = le16_to_cpu(pneg_ctxt->CipherCount); +- int i, cphs_size = cph_cnt * sizeof(__le16); ++ int cph_cnt; ++ int i, cphs_size; ++ ++ if (sizeof(struct smb2_encryption_neg_context) > ctxt_len) { ++ pr_err("Invalid SMB2_ENCRYPTION_CAPABILITIES context size\n"); ++ return; ++ } + + conn->cipher_type = 0; + ++ cph_cnt = le16_to_cpu(pneg_ctxt->CipherCount); ++ cphs_size = cph_cnt * sizeof(__le16); ++ + if (sizeof(struct smb2_encryption_neg_context) + cphs_size > +- len_of_ctxts) { ++ ctxt_len) { + pr_err("Invalid cipher count(%d)\n", cph_cnt); + return; + } +@@ -953,15 +962,22 @@ static void decode_compress_ctxt(struct + + static void decode_sign_cap_ctxt(struct ksmbd_conn *conn, + struct smb2_signing_capabilities *pneg_ctxt, +- int len_of_ctxts) ++ int ctxt_len) + { +- int sign_algo_cnt = le16_to_cpu(pneg_ctxt->SigningAlgorithmCount); +- int i, sign_alos_size = sign_algo_cnt * sizeof(__le16); ++ int sign_algo_cnt; ++ int i, sign_alos_size; ++ ++ if (sizeof(struct smb2_signing_capabilities) > ctxt_len) { ++ pr_err("Invalid SMB2_SIGNING_CAPABILITIES context length\n"); ++ return; ++ } + + conn->signing_negotiated = false; ++ sign_algo_cnt = le16_to_cpu(pneg_ctxt->SigningAlgorithmCount); ++ sign_alos_size = sign_algo_cnt * sizeof(__le16); + + if (sizeof(struct smb2_signing_capabilities) + sign_alos_size > +- len_of_ctxts) { ++ ctxt_len) { + pr_err("Invalid signing algorithm count(%d)\n", sign_algo_cnt); + return; + } +@@ -999,18 +1015,16 @@ static __le32 deassemble_neg_contexts(st + len_of_ctxts = len_of_smb - offset; + + while (i++ < neg_ctxt_cnt) { +- int clen; +- +- /* check that offset is not beyond end of SMB */ +- if (len_of_ctxts == 0) +- break; ++ int clen, ctxt_len; + + if (len_of_ctxts < sizeof(struct smb2_neg_context)) + break; + + pctx = (struct smb2_neg_context *)((char *)pctx + offset); + clen = le16_to_cpu(pctx->DataLength); +- if (clen + sizeof(struct smb2_neg_context) > len_of_ctxts) ++ ctxt_len = clen + sizeof(struct smb2_neg_context); ++ ++ if (ctxt_len > len_of_ctxts) + break; + + if (pctx->ContextType == SMB2_PREAUTH_INTEGRITY_CAPABILITIES) { +@@ -1021,7 +1035,7 @@ static __le32 deassemble_neg_contexts(st + + status = decode_preauth_ctxt(conn, + (struct smb2_preauth_neg_context *)pctx, +- len_of_ctxts); ++ ctxt_len); + if (status != STATUS_SUCCESS) + break; + } else if (pctx->ContextType == SMB2_ENCRYPTION_CAPABILITIES) { +@@ -1032,7 +1046,7 @@ static __le32 deassemble_neg_contexts(st + + decode_encrypt_ctxt(conn, + (struct smb2_encryption_neg_context *)pctx, +- len_of_ctxts); ++ ctxt_len); + } else if (pctx->ContextType == SMB2_COMPRESSION_CAPABILITIES) { + ksmbd_debug(SMB, + "deassemble SMB2_COMPRESSION_CAPABILITIES context\n"); +@@ -1051,9 +1065,10 @@ static __le32 deassemble_neg_contexts(st + } else if (pctx->ContextType == SMB2_SIGNING_CAPABILITIES) { + ksmbd_debug(SMB, + "deassemble SMB2_SIGNING_CAPABILITIES context\n"); ++ + decode_sign_cap_ctxt(conn, + (struct smb2_signing_capabilities *)pctx, +- len_of_ctxts); ++ ctxt_len); + } + + /* offsets must be 8 byte aligned */ diff --git a/queue-5.15/ksmbd-fix-null-pointer-dereferences-in-ksmbd_update_fstate.patch b/queue-5.15/ksmbd-fix-null-pointer-dereferences-in-ksmbd_update_fstate.patch new file mode 100644 index 00000000000..8eeac1e8e70 --- /dev/null +++ b/queue-5.15/ksmbd-fix-null-pointer-dereferences-in-ksmbd_update_fstate.patch @@ -0,0 +1,54 @@ +From linkinjeon@gmail.com Mon Dec 18 16:42:43 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:34:37 +0900 +Subject: ksmbd: fix Null pointer dereferences in ksmbd_update_fstate() +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , Coverity Scan , Steve French +Message-ID: <20231218153454.8090-138-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit 414849040fcf11d45025b8ae26c9fd91da1465da ] + +Coverity Scan report the following one. This report is a false alarm. +Because fp is never NULL when rc is zero. This patch add null check for fp +in ksmbd_update_fstate to make alarm silence. + +*** CID 1568583: Null pointer dereferences (FORWARD_NULL) +/fs/smb/server/smb2pdu.c: 3408 in smb2_open() +3402 path_put(&path); +3403 path_put(&parent_path); +3404 } +3405 ksmbd_revert_fsids(work); +3406 err_out1: +3407 if (!rc) { +>>> CID 1568583: Null pointer dereferences (FORWARD_NULL) +>>> Passing null pointer "fp" to "ksmbd_update_fstate", which dereferences it. +3408 ksmbd_update_fstate(&work->sess->file_table, fp, FP_INITED); +3409 rc = ksmbd_iov_pin_rsp(work, (void *)rsp, iov_len); +3410 } +3411 if (rc) { +3412 if (rc == -EINVAL) +3413 rsp->hdr.Status = STATUS_INVALID_PARAMETER; + +Fixes: e2b76ab8b5c9 ("ksmbd: add support for read compound") +Reported-by: Coverity Scan +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/vfs_cache.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/fs/ksmbd/vfs_cache.c ++++ b/fs/ksmbd/vfs_cache.c +@@ -602,6 +602,9 @@ err_out: + void ksmbd_update_fstate(struct ksmbd_file_table *ft, struct ksmbd_file *fp, + unsigned int state) + { ++ if (!fp) ++ return; ++ + write_lock(&ft->lock); + fp->f_state = state; + write_unlock(&ft->lock); diff --git a/queue-5.15/ksmbd-fix-one-kernel-doc-comment.patch b/queue-5.15/ksmbd-fix-one-kernel-doc-comment.patch new file mode 100644 index 00000000000..ad6739ad9b5 --- /dev/null +++ b/queue-5.15/ksmbd-fix-one-kernel-doc-comment.patch @@ -0,0 +1,33 @@ +From linkinjeon@gmail.com Mon Dec 18 16:41:58 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:34:23 +0900 +Subject: ksmbd: Fix one kernel-doc comment +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Yang Li , Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-124-linkinjeon@kernel.org> + +From: Yang Li + +[ Upstream commit bf26f1b4e0918f017775edfeacf6d867204b680b ] + +Fix one kernel-doc comment to silence the warning: +fs/smb/server/smb2pdu.c:4160: warning: Excess function parameter 'infoclass_size' description in 'buffer_check_err' + +Signed-off-by: Yang Li +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/smb2pdu.c | 1 - + 1 file changed, 1 deletion(-) + +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -4154,7 +4154,6 @@ err_out2: + * @reqOutputBufferLength: max buffer length expected in command response + * @rsp: query info response buffer contains output buffer length + * @rsp_org: base response buffer pointer in case of chained response +- * @infoclass_size: query info class response buffer size + * + * Return: 0 on success, otherwise error + */ diff --git a/queue-5.15/ksmbd-fix-out-of-bound-read-in-deassemble_neg_contexts.patch b/queue-5.15/ksmbd-fix-out-of-bound-read-in-deassemble_neg_contexts.patch new file mode 100644 index 00000000000..2ff676fc5c8 --- /dev/null +++ b/queue-5.15/ksmbd-fix-out-of-bound-read-in-deassemble_neg_contexts.patch @@ -0,0 +1,86 @@ +From linkinjeon@gmail.com Mon Dec 18 16:40:36 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:33:58 +0900 +Subject: ksmbd: fix out-of-bound read in deassemble_neg_contexts() +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , Chih-Yen Chang , Steve French +Message-ID: <20231218153454.8090-99-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit f1a411873c85b642f13b01f21b534c2bab81fc1b ] + +The check in the beginning is +`clen + sizeof(struct smb2_neg_context) <= len_of_ctxts`, +but in the end of loop, `len_of_ctxts` will subtract +`((clen + 7) & ~0x7) + sizeof(struct smb2_neg_context)`, which causes +integer underflow when clen does the 8 alignment. We should use +`(clen + 7) & ~0x7` in the check to avoid underflow from happening. + +Then there are some variables that need to be declared unsigned +instead of signed. + +[ 11.671070] BUG: KASAN: slab-out-of-bounds in smb2_handle_negotiate+0x799/0x1610 +[ 11.671533] Read of size 2 at addr ffff888005e86cf2 by task kworker/0:0/7 +... +[ 11.673383] Call Trace: +[ 11.673541] +[ 11.673679] dump_stack_lvl+0x33/0x50 +[ 11.673913] print_report+0xcc/0x620 +[ 11.674671] kasan_report+0xae/0xe0 +[ 11.675171] kasan_check_range+0x35/0x1b0 +[ 11.675412] smb2_handle_negotiate+0x799/0x1610 +[ 11.676217] ksmbd_smb_negotiate_common+0x526/0x770 +[ 11.676795] handle_ksmbd_work+0x274/0x810 +... + +Cc: stable@vger.kernel.org +Signed-off-by: Chih-Yen Chang +Tested-by: Chih-Yen Chang +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/smb2pdu.c | 13 ++++++------- + 1 file changed, 6 insertions(+), 7 deletions(-) + +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -997,13 +997,13 @@ static void decode_sign_cap_ctxt(struct + + static __le32 deassemble_neg_contexts(struct ksmbd_conn *conn, + struct smb2_negotiate_req *req, +- int len_of_smb) ++ unsigned int len_of_smb) + { + /* +4 is to account for the RFC1001 len field */ + struct smb2_neg_context *pctx = (struct smb2_neg_context *)req; + int i = 0, len_of_ctxts; +- int offset = le32_to_cpu(req->NegotiateContextOffset); +- int neg_ctxt_cnt = le16_to_cpu(req->NegotiateContextCount); ++ unsigned int offset = le32_to_cpu(req->NegotiateContextOffset); ++ unsigned int neg_ctxt_cnt = le16_to_cpu(req->NegotiateContextCount); + __le32 status = STATUS_INVALID_PARAMETER; + + ksmbd_debug(SMB, "decoding %d negotiate contexts\n", neg_ctxt_cnt); +@@ -1017,7 +1017,7 @@ static __le32 deassemble_neg_contexts(st + while (i++ < neg_ctxt_cnt) { + int clen, ctxt_len; + +- if (len_of_ctxts < sizeof(struct smb2_neg_context)) ++ if (len_of_ctxts < (int)sizeof(struct smb2_neg_context)) + break; + + pctx = (struct smb2_neg_context *)((char *)pctx + offset); +@@ -1072,9 +1072,8 @@ static __le32 deassemble_neg_contexts(st + } + + /* offsets must be 8 byte aligned */ +- clen = (clen + 7) & ~0x7; +- offset = clen + sizeof(struct smb2_neg_context); +- len_of_ctxts -= clen + sizeof(struct smb2_neg_context); ++ offset = (ctxt_len + 7) & ~0x7; ++ len_of_ctxts -= offset; + } + return status; + } diff --git a/queue-5.15/ksmbd-fix-out-of-bound-read-in-parse_lease_state.patch b/queue-5.15/ksmbd-fix-out-of-bound-read-in-parse_lease_state.patch new file mode 100644 index 00000000000..d04e9f84780 --- /dev/null +++ b/queue-5.15/ksmbd-fix-out-of-bound-read-in-parse_lease_state.patch @@ -0,0 +1,128 @@ +From linkinjeon@gmail.com Mon Dec 18 16:40:39 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:33:59 +0900 +Subject: ksmbd: fix out-of-bound read in parse_lease_state() +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , Chih-Yen Chang , Steve French +Message-ID: <20231218153454.8090-100-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit fc6c6a3c324c1b3e93a03d0cfa3749c781f23de0 ] + +This bug is in parse_lease_state, and it is caused by the missing check +of `struct create_context`. When the ksmbd traverses the create_contexts, +it doesn't check if the field of `NameOffset` and `Next` is valid, +The KASAN message is following: + +[ 6.664323] BUG: KASAN: slab-out-of-bounds in parse_lease_state+0x7d/0x280 +[ 6.664738] Read of size 2 at addr ffff888005c08988 by task kworker/0:3/103 +... +[ 6.666644] Call Trace: +[ 6.666796] +[ 6.666933] dump_stack_lvl+0x33/0x50 +[ 6.667167] print_report+0xcc/0x620 +[ 6.667903] kasan_report+0xae/0xe0 +[ 6.668374] kasan_check_range+0x35/0x1b0 +[ 6.668621] parse_lease_state+0x7d/0x280 +[ 6.668868] smb2_open+0xbe8/0x4420 +[ 6.675137] handle_ksmbd_work+0x282/0x820 + +Use smb2_find_context_vals() to find smb2 create request lease context. +smb2_find_context_vals validate create context fields. + +Cc: stable@vger.kernel.org +Reported-by: Chih-Yen Chang +Tested-by: Chih-Yen Chang +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/oplock.c | 70 ++++++++++++++++++++---------------------------------- + 1 file changed, 26 insertions(+), 44 deletions(-) + +--- a/fs/ksmbd/oplock.c ++++ b/fs/ksmbd/oplock.c +@@ -1415,56 +1415,38 @@ void create_lease_buf(u8 *rbuf, struct l + */ + struct lease_ctx_info *parse_lease_state(void *open_req) + { +- char *data_offset; + struct create_context *cc; +- unsigned int next = 0; +- char *name; +- bool found = false; + struct smb2_create_req *req = (struct smb2_create_req *)open_req; +- struct lease_ctx_info *lreq = kzalloc(sizeof(struct lease_ctx_info), +- GFP_KERNEL); ++ struct lease_ctx_info *lreq; ++ ++ cc = smb2_find_context_vals(req, SMB2_CREATE_REQUEST_LEASE, 4); ++ if (IS_ERR_OR_NULL(cc)) ++ return NULL; ++ ++ lreq = kzalloc(sizeof(struct lease_ctx_info), GFP_KERNEL); + if (!lreq) + return NULL; + +- data_offset = (char *)req + le32_to_cpu(req->CreateContextsOffset); +- cc = (struct create_context *)data_offset; +- do { +- cc = (struct create_context *)((char *)cc + next); +- name = le16_to_cpu(cc->NameOffset) + (char *)cc; +- if (le16_to_cpu(cc->NameLength) != 4 || +- strncmp(name, SMB2_CREATE_REQUEST_LEASE, 4)) { +- next = le32_to_cpu(cc->Next); +- continue; +- } +- found = true; +- break; +- } while (next != 0); +- +- if (found) { +- if (sizeof(struct lease_context_v2) == le32_to_cpu(cc->DataLength)) { +- struct create_lease_v2 *lc = (struct create_lease_v2 *)cc; +- +- memcpy(lreq->lease_key, lc->lcontext.LeaseKey, SMB2_LEASE_KEY_SIZE); +- lreq->req_state = lc->lcontext.LeaseState; +- lreq->flags = lc->lcontext.LeaseFlags; +- lreq->duration = lc->lcontext.LeaseDuration; +- memcpy(lreq->parent_lease_key, lc->lcontext.ParentLeaseKey, +- SMB2_LEASE_KEY_SIZE); +- lreq->version = 2; +- } else { +- struct create_lease *lc = (struct create_lease *)cc; +- +- memcpy(lreq->lease_key, lc->lcontext.LeaseKey, SMB2_LEASE_KEY_SIZE); +- lreq->req_state = lc->lcontext.LeaseState; +- lreq->flags = lc->lcontext.LeaseFlags; +- lreq->duration = lc->lcontext.LeaseDuration; +- lreq->version = 1; +- } +- return lreq; +- } ++ if (sizeof(struct lease_context_v2) == le32_to_cpu(cc->DataLength)) { ++ struct create_lease_v2 *lc = (struct create_lease_v2 *)cc; + +- kfree(lreq); +- return NULL; ++ memcpy(lreq->lease_key, lc->lcontext.LeaseKey, SMB2_LEASE_KEY_SIZE); ++ lreq->req_state = lc->lcontext.LeaseState; ++ lreq->flags = lc->lcontext.LeaseFlags; ++ lreq->duration = lc->lcontext.LeaseDuration; ++ memcpy(lreq->parent_lease_key, lc->lcontext.ParentLeaseKey, ++ SMB2_LEASE_KEY_SIZE); ++ lreq->version = 2; ++ } else { ++ struct create_lease *lc = (struct create_lease *)cc; ++ ++ memcpy(lreq->lease_key, lc->lcontext.LeaseKey, SMB2_LEASE_KEY_SIZE); ++ lreq->req_state = lc->lcontext.LeaseState; ++ lreq->flags = lc->lcontext.LeaseFlags; ++ lreq->duration = lc->lcontext.LeaseDuration; ++ lreq->version = 1; ++ } ++ return lreq; + } + + /** diff --git a/queue-5.15/ksmbd-fix-out-of-bounds-in-init_smb2_rsp_hdr.patch b/queue-5.15/ksmbd-fix-out-of-bounds-in-init_smb2_rsp_hdr.patch new file mode 100644 index 00000000000..cc69f47c4d4 --- /dev/null +++ b/queue-5.15/ksmbd-fix-out-of-bounds-in-init_smb2_rsp_hdr.patch @@ -0,0 +1,101 @@ +From linkinjeon@gmail.com Mon Dec 18 16:41:39 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:34:17 +0900 +Subject: ksmbd: fix out of bounds in init_smb2_rsp_hdr() +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , zdi-disclosures@trendmicro.com, Steve French +Message-ID: <20231218153454.8090-118-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit 536bb492d39bb6c080c92f31e8a55fe9934f452b ] + +If client send smb2 negotiate request and then send smb1 negotiate +request, init_smb2_rsp_hdr is called for smb1 negotiate request since +need_neg is set to false. This patch ignore smb1 packets after ->need_neg +is set to false. + +Reported-by: zdi-disclosures@trendmicro.com # ZDI-CAN-21541 +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/server.c | 7 ++++++- + fs/ksmbd/smb_common.c | 19 +++++++++++-------- + fs/ksmbd/smb_common.h | 2 +- + 3 files changed, 18 insertions(+), 10 deletions(-) + +--- a/fs/ksmbd/server.c ++++ b/fs/ksmbd/server.c +@@ -286,6 +286,7 @@ static void handle_ksmbd_work(struct wor + static int queue_ksmbd_work(struct ksmbd_conn *conn) + { + struct ksmbd_work *work; ++ int err; + + work = ksmbd_alloc_work_struct(); + if (!work) { +@@ -297,7 +298,11 @@ static int queue_ksmbd_work(struct ksmbd + work->request_buf = conn->request_buf; + conn->request_buf = NULL; + +- ksmbd_init_smb_server(work); ++ err = ksmbd_init_smb_server(work); ++ if (err) { ++ ksmbd_free_work_struct(work); ++ return 0; ++ } + + ksmbd_conn_enqueue_request(work); + atomic_inc(&conn->r_count); +--- a/fs/ksmbd/smb_common.c ++++ b/fs/ksmbd/smb_common.c +@@ -388,26 +388,29 @@ static struct smb_version_cmds smb1_serv + [SMB_COM_NEGOTIATE_EX] = { .proc = smb1_negotiate, }, + }; + +-static void init_smb1_server(struct ksmbd_conn *conn) ++static int init_smb1_server(struct ksmbd_conn *conn) + { + conn->ops = &smb1_server_ops; + conn->cmds = smb1_server_cmds; + conn->max_cmds = ARRAY_SIZE(smb1_server_cmds); ++ return 0; + } + +-void ksmbd_init_smb_server(struct ksmbd_work *work) ++int ksmbd_init_smb_server(struct ksmbd_work *work) + { + struct ksmbd_conn *conn = work->conn; + __le32 proto; + +- if (conn->need_neg == false) +- return; +- + proto = *(__le32 *)((struct smb_hdr *)work->request_buf)->Protocol; ++ if (conn->need_neg == false) { ++ if (proto == SMB1_PROTO_NUMBER) ++ return -EINVAL; ++ return 0; ++ } ++ + if (proto == SMB1_PROTO_NUMBER) +- init_smb1_server(conn); +- else +- init_smb3_11_server(conn); ++ return init_smb1_server(conn); ++ return init_smb3_11_server(conn); + } + + int ksmbd_populate_dot_dotdot_entries(struct ksmbd_work *work, int info_level, +--- a/fs/ksmbd/smb_common.h ++++ b/fs/ksmbd/smb_common.h +@@ -474,7 +474,7 @@ bool ksmbd_smb_request(struct ksmbd_conn + + int ksmbd_lookup_dialect_by_id(__le16 *cli_dialects, __le16 dialects_count); + +-void ksmbd_init_smb_server(struct ksmbd_work *work); ++int ksmbd_init_smb_server(struct ksmbd_work *work); + + struct ksmbd_kstat; + int ksmbd_populate_dot_dotdot_entries(struct ksmbd_work *work, diff --git a/queue-5.15/ksmbd-fix-out-of-bounds-read-in-smb2_sess_setup.patch b/queue-5.15/ksmbd-fix-out-of-bounds-read-in-smb2_sess_setup.patch new file mode 100644 index 00000000000..ecef0e9118c --- /dev/null +++ b/queue-5.15/ksmbd-fix-out-of-bounds-read-in-smb2_sess_setup.patch @@ -0,0 +1,125 @@ +From linkinjeon@gmail.com Mon Dec 18 16:41:15 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:34:10 +0900 +Subject: ksmbd: fix out of bounds read in smb2_sess_setup +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , zdi-disclosures@trendmicro.com, Steve French +Message-ID: <20231218153454.8090-111-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit 98422bdd4cb3ca4d08844046f6507d7ec2c2b8d8 ] + +ksmbd does not consider the case of that smb2 session setup is +in compound request. If this is the second payload of the compound, +OOB read issue occurs while processing the first payload in +the smb2_sess_setup(). + +Cc: stable@vger.kernel.org +Reported-by: zdi-disclosures@trendmicro.com # ZDI-CAN-21355 +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/smb2pdu.c | 31 +++++++++++++++++-------------- + 1 file changed, 17 insertions(+), 14 deletions(-) + +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -1323,9 +1323,8 @@ static int decode_negotiation_token(stru + + static int ntlm_negotiate(struct ksmbd_work *work, + struct negotiate_message *negblob, +- size_t negblob_len) ++ size_t negblob_len, struct smb2_sess_setup_rsp *rsp) + { +- struct smb2_sess_setup_rsp *rsp = smb2_get_msg(work->response_buf); + struct challenge_message *chgblob; + unsigned char *spnego_blob = NULL; + u16 spnego_blob_len; +@@ -1430,10 +1429,10 @@ static struct ksmbd_user *session_user(s + return user; + } + +-static int ntlm_authenticate(struct ksmbd_work *work) ++static int ntlm_authenticate(struct ksmbd_work *work, ++ struct smb2_sess_setup_req *req, ++ struct smb2_sess_setup_rsp *rsp) + { +- struct smb2_sess_setup_req *req = smb2_get_msg(work->request_buf); +- struct smb2_sess_setup_rsp *rsp = smb2_get_msg(work->response_buf); + struct ksmbd_conn *conn = work->conn; + struct ksmbd_session *sess = work->sess; + struct channel *chann = NULL; +@@ -1567,10 +1566,10 @@ binding_session: + } + + #ifdef CONFIG_SMB_SERVER_KERBEROS5 +-static int krb5_authenticate(struct ksmbd_work *work) ++static int krb5_authenticate(struct ksmbd_work *work, ++ struct smb2_sess_setup_req *req, ++ struct smb2_sess_setup_rsp *rsp) + { +- struct smb2_sess_setup_req *req = smb2_get_msg(work->request_buf); +- struct smb2_sess_setup_rsp *rsp = smb2_get_msg(work->response_buf); + struct ksmbd_conn *conn = work->conn; + struct ksmbd_session *sess = work->sess; + char *in_blob, *out_blob; +@@ -1648,7 +1647,9 @@ static int krb5_authenticate(struct ksmb + return 0; + } + #else +-static int krb5_authenticate(struct ksmbd_work *work) ++static int krb5_authenticate(struct ksmbd_work *work, ++ struct smb2_sess_setup_req *req, ++ struct smb2_sess_setup_rsp *rsp) + { + return -EOPNOTSUPP; + } +@@ -1657,8 +1658,8 @@ static int krb5_authenticate(struct ksmb + int smb2_sess_setup(struct ksmbd_work *work) + { + struct ksmbd_conn *conn = work->conn; +- struct smb2_sess_setup_req *req = smb2_get_msg(work->request_buf); +- struct smb2_sess_setup_rsp *rsp = smb2_get_msg(work->response_buf); ++ struct smb2_sess_setup_req *req; ++ struct smb2_sess_setup_rsp *rsp; + struct ksmbd_session *sess; + struct negotiate_message *negblob; + unsigned int negblob_len, negblob_off; +@@ -1666,6 +1667,8 @@ int smb2_sess_setup(struct ksmbd_work *w + + ksmbd_debug(SMB, "Received request for session setup\n"); + ++ WORK_BUFFERS(work, req, rsp); ++ + rsp->StructureSize = cpu_to_le16(9); + rsp->SessionFlags = 0; + rsp->SecurityBufferOffset = cpu_to_le16(72); +@@ -1787,7 +1790,7 @@ int smb2_sess_setup(struct ksmbd_work *w + + if (conn->preferred_auth_mech & + (KSMBD_AUTH_KRB5 | KSMBD_AUTH_MSKRB5)) { +- rc = krb5_authenticate(work); ++ rc = krb5_authenticate(work, req, rsp); + if (rc) { + rc = -EINVAL; + goto out_err; +@@ -1801,7 +1804,7 @@ int smb2_sess_setup(struct ksmbd_work *w + sess->Preauth_HashValue = NULL; + } else if (conn->preferred_auth_mech == KSMBD_AUTH_NTLMSSP) { + if (negblob->MessageType == NtLmNegotiate) { +- rc = ntlm_negotiate(work, negblob, negblob_len); ++ rc = ntlm_negotiate(work, negblob, negblob_len, rsp); + if (rc) + goto out_err; + rsp->hdr.Status = +@@ -1814,7 +1817,7 @@ int smb2_sess_setup(struct ksmbd_work *w + le16_to_cpu(rsp->SecurityBufferLength) - 1); + + } else if (negblob->MessageType == NtLmAuthenticate) { +- rc = ntlm_authenticate(work); ++ rc = ntlm_authenticate(work, req, rsp); + if (rc) + goto out_err; + diff --git a/queue-5.15/ksmbd-fix-parameter-name-and-comment-mismatch.patch b/queue-5.15/ksmbd-fix-parameter-name-and-comment-mismatch.patch new file mode 100644 index 00000000000..9e7517badf3 --- /dev/null +++ b/queue-5.15/ksmbd-fix-parameter-name-and-comment-mismatch.patch @@ -0,0 +1,40 @@ +From stable+bounces-7705-greg=kroah.com@vger.kernel.org Mon Dec 18 16:44:36 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:33:36 +0900 +Subject: ksmbd: Fix parameter name and comment mismatch +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Jiapeng Chong , Abaci Robot , Namjae Jeon , Sergey Senozhatsky , Steve French +Message-ID: <20231218153454.8090-77-linkinjeon@kernel.org> + +From: Jiapeng Chong + +[ Upstream commit 63f09a9986eb58578ed6ad0e27a6e2c54e49f797 ] + +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 +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/vfs.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/fs/ksmbd/vfs.c ++++ b/fs/ksmbd/vfs.c +@@ -950,9 +950,9 @@ ssize_t ksmbd_vfs_getxattr(struct user_n + * 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 diff --git a/queue-5.15/ksmbd-fix-passing-freed-memory-aux_payload_buf.patch b/queue-5.15/ksmbd-fix-passing-freed-memory-aux_payload_buf.patch new file mode 100644 index 00000000000..1f5c9a1137e --- /dev/null +++ b/queue-5.15/ksmbd-fix-passing-freed-memory-aux_payload_buf.patch @@ -0,0 +1,41 @@ +From linkinjeon@gmail.com Mon Dec 18 16:42:13 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:34:28 +0900 +Subject: ksmbd: fix passing freed memory 'aux_payload_buf' +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , Dan Carpenter , Steve French +Message-ID: <20231218153454.8090-129-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit 59d8d24f4610333560cf2e8fe3f44cafe30322eb ] + +The patch e2b76ab8b5c9: "ksmbd: add support for read compound" leads +to the following Smatch static checker warning: + + fs/smb/server/smb2pdu.c:6329 smb2_read() + warn: passing freed memory 'aux_payload_buf' + +It doesn't matter that we're passing a freed variable because nbytes is +zero. This patch set "aux_payload_buf = NULL" to make smatch silence. + +Fixes: e2b76ab8b5c9 ("ksmbd: add support for read compound") +Reported-by: Dan Carpenter +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/smb2pdu.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -6314,7 +6314,7 @@ int smb2_read(struct ksmbd_work *work) + aux_payload_buf, + nbytes); + kvfree(aux_payload_buf); +- ++ aux_payload_buf = NULL; + nbytes = 0; + if (remain_bytes < 0) { + err = (int)remain_bytes; diff --git a/queue-5.15/ksmbd-fix-posix_acls-and-acls-dereferencing-possible-err_ptr.patch b/queue-5.15/ksmbd-fix-posix_acls-and-acls-dereferencing-possible-err_ptr.patch new file mode 100644 index 00000000000..02eadea463c --- /dev/null +++ b/queue-5.15/ksmbd-fix-posix_acls-and-acls-dereferencing-possible-err_ptr.patch @@ -0,0 +1,75 @@ +From linkinjeon@gmail.com Mon Dec 18 16:40:42 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:34:00 +0900 +Subject: ksmbd: fix posix_acls and acls dereferencing possible ERR_PTR() +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , Dan Carpenter , Steve French +Message-ID: <20231218153454.8090-101-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit 25933573ef48f3586f559c2cac6c436c62dcf63f ] + +Dan reported the following error message: + +fs/smb/server/smbacl.c:1296 smb_check_perm_dacl() + error: 'posix_acls' dereferencing possible ERR_PTR() +fs/smb/server/vfs.c:1323 ksmbd_vfs_make_xattr_posix_acl() + error: 'posix_acls' dereferencing possible ERR_PTR() +fs/smb/server/vfs.c:1830 ksmbd_vfs_inherit_posix_acl() + error: 'acls' dereferencing possible ERR_PTR() + +__get_acl() returns a mix of error pointers and NULL. This change it +with IS_ERR_OR_NULL(). + +Fixes: e2f34481b24d ("cifsd: add server-side procedures for SMB3") +Cc: stable@vger.kernel.org +Reported-by: Dan Carpenter +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/smbacl.c | 4 ++-- + fs/ksmbd/vfs.c | 4 ++-- + 2 files changed, 4 insertions(+), 4 deletions(-) + +--- a/fs/ksmbd/smbacl.c ++++ b/fs/ksmbd/smbacl.c +@@ -1311,7 +1311,7 @@ int smb_check_perm_dacl(struct ksmbd_con + + if (IS_ENABLED(CONFIG_FS_POSIX_ACL)) { + posix_acls = get_acl(d_inode(path->dentry), ACL_TYPE_ACCESS); +- if (posix_acls && !found) { ++ if (!IS_ERR_OR_NULL(posix_acls) && !found) { + unsigned int id = -1; + + pa_entry = posix_acls->a_entries; +@@ -1335,7 +1335,7 @@ int smb_check_perm_dacl(struct ksmbd_con + } + } + } +- if (posix_acls) ++ if (!IS_ERR_OR_NULL(posix_acls)) + posix_acl_release(posix_acls); + } + +--- a/fs/ksmbd/vfs.c ++++ b/fs/ksmbd/vfs.c +@@ -1323,7 +1323,7 @@ static struct xattr_smb_acl *ksmbd_vfs_m + return NULL; + + posix_acls = get_acl(inode, acl_type); +- if (!posix_acls) ++ if (IS_ERR_OR_NULL(posix_acls)) + return NULL; + + smb_acl = kzalloc(sizeof(struct xattr_smb_acl) + +@@ -1831,7 +1831,7 @@ int ksmbd_vfs_inherit_posix_acl(struct u + return -EOPNOTSUPP; + + acls = get_acl(parent_inode, ACL_TYPE_DEFAULT); +- if (!acls) ++ if (IS_ERR_OR_NULL(acls)) + return -ENOENT; + pace = acls->a_entries; + diff --git a/queue-5.15/ksmbd-fix-possible-deadlock-in-smb2_open.patch b/queue-5.15/ksmbd-fix-possible-deadlock-in-smb2_open.patch new file mode 100644 index 00000000000..4ed6a2e7066 --- /dev/null +++ b/queue-5.15/ksmbd-fix-possible-deadlock-in-smb2_open.patch @@ -0,0 +1,478 @@ +From linkinjeon@gmail.com Mon Dec 18 16:43:25 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:34:49 +0900 +Subject: ksmbd: fix possible deadlock in smb2_open +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , Marios Makassikis , Steve French +Message-ID: <20231218153454.8090-150-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit 864fb5d3716303a045c3ffb397f651bfd37bfb36 ] + +[ 8743.393379] ====================================================== +[ 8743.393385] WARNING: possible circular locking dependency detected +[ 8743.393391] 6.4.0-rc1+ #11 Tainted: G OE +[ 8743.393397] ------------------------------------------------------ +[ 8743.393402] kworker/0:2/12921 is trying to acquire lock: +[ 8743.393408] ffff888127a14460 (sb_writers#8){.+.+}-{0:0}, at: ksmbd_vfs_setxattr+0x3d/0xd0 [ksmbd] +[ 8743.393510] + but task is already holding lock: +[ 8743.393515] ffff8880360d97f0 (&type->i_mutex_dir_key#6/1){+.+.}-{3:3}, at: ksmbd_vfs_kern_path_locked+0x181/0x670 [ksmbd] +[ 8743.393618] + which lock already depends on the new lock. + +[ 8743.393623] + the existing dependency chain (in reverse order) is: +[ 8743.393628] + -> #1 (&type->i_mutex_dir_key#6/1){+.+.}-{3:3}: +[ 8743.393648] down_write_nested+0x9a/0x1b0 +[ 8743.393660] filename_create+0x128/0x270 +[ 8743.393670] do_mkdirat+0xab/0x1f0 +[ 8743.393680] __x64_sys_mkdir+0x47/0x60 +[ 8743.393690] do_syscall_64+0x5d/0x90 +[ 8743.393701] entry_SYSCALL_64_after_hwframe+0x72/0xdc +[ 8743.393711] + -> #0 (sb_writers#8){.+.+}-{0:0}: +[ 8743.393728] __lock_acquire+0x2201/0x3b80 +[ 8743.393737] lock_acquire+0x18f/0x440 +[ 8743.393746] mnt_want_write+0x5f/0x240 +[ 8743.393755] ksmbd_vfs_setxattr+0x3d/0xd0 [ksmbd] +[ 8743.393839] ksmbd_vfs_set_dos_attrib_xattr+0xcc/0x110 [ksmbd] +[ 8743.393924] compat_ksmbd_vfs_set_dos_attrib_xattr+0x39/0x50 [ksmbd] +[ 8743.394010] smb2_open+0x3432/0x3cc0 [ksmbd] +[ 8743.394099] handle_ksmbd_work+0x2c9/0x7b0 [ksmbd] +[ 8743.394187] process_one_work+0x65a/0xb30 +[ 8743.394198] worker_thread+0x2cf/0x700 +[ 8743.394209] kthread+0x1ad/0x1f0 +[ 8743.394218] ret_from_fork+0x29/0x50 + +This patch add mnt_want_write() above parent inode lock and remove +nested mnt_want_write calls in smb2_open(). + +Fixes: 40b268d384a2 ("ksmbd: add mnt_want_write to ksmbd vfs functions") +Cc: stable@vger.kernel.org +Reported-by: Marios Makassikis +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/smb2pdu.c | 47 +++++++++++++++++------------------- + fs/ksmbd/smbacl.c | 7 +++-- + fs/ksmbd/smbacl.h | 2 - + fs/ksmbd/vfs.c | 68 +++++++++++++++++++++++++++++++---------------------- + fs/ksmbd/vfs.h | 10 +++++-- + 5 files changed, 75 insertions(+), 59 deletions(-) + +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -2380,7 +2380,8 @@ static int smb2_set_ea(struct smb2_ea_in + rc = 0; + } else { + rc = ksmbd_vfs_setxattr(user_ns, path, attr_name, value, +- le16_to_cpu(eabuf->EaValueLength), 0); ++ le16_to_cpu(eabuf->EaValueLength), ++ 0, true); + if (rc < 0) { + ksmbd_debug(SMB, + "ksmbd_vfs_setxattr is failed(%d)\n", +@@ -2443,7 +2444,7 @@ static noinline int smb2_set_stream_name + return -EBADF; + } + +- rc = ksmbd_vfs_setxattr(user_ns, path, xattr_stream_name, NULL, 0, 0); ++ rc = ksmbd_vfs_setxattr(user_ns, path, xattr_stream_name, NULL, 0, 0, false); + if (rc < 0) + pr_err("Failed to store XATTR stream name :%d\n", rc); + return 0; +@@ -2518,7 +2519,7 @@ static void smb2_new_xattrs(struct ksmbd + da.flags = XATTR_DOSINFO_ATTRIB | XATTR_DOSINFO_CREATE_TIME | + XATTR_DOSINFO_ITIME; + +- rc = ksmbd_vfs_set_dos_attrib_xattr(mnt_user_ns(path->mnt), path, &da); ++ rc = ksmbd_vfs_set_dos_attrib_xattr(mnt_user_ns(path->mnt), path, &da, false); + if (rc) + ksmbd_debug(SMB, "failed to store file attribute into xattr\n"); + } +@@ -2608,7 +2609,7 @@ static int smb2_create_sd_buffer(struct + sizeof(struct create_sd_buf_req)) + return -EINVAL; + return set_info_sec(work->conn, work->tcon, path, &sd_buf->ntsd, +- le32_to_cpu(sd_buf->ccontext.DataLength), true); ++ le32_to_cpu(sd_buf->ccontext.DataLength), true, false); + } + + static void ksmbd_acls_fattr(struct smb_fattr *fattr, +@@ -3149,7 +3150,8 @@ int smb2_open(struct ksmbd_work *work) + user_ns, + &path, + pntsd, +- pntsd_size); ++ pntsd_size, ++ false); + kfree(pntsd); + if (rc) + pr_err("failed to store ntacl in xattr : %d\n", +@@ -3225,12 +3227,6 @@ int smb2_open(struct ksmbd_work *work) + if (req->CreateOptions & FILE_DELETE_ON_CLOSE_LE) + ksmbd_fd_set_delete_on_close(fp, file_info); + +- if (need_truncate) { +- rc = smb2_create_truncate(&path); +- if (rc) +- goto err_out; +- } +- + if (req->CreateContextsOffset) { + struct create_alloc_size_req *az_req; + +@@ -3395,11 +3391,12 @@ int smb2_open(struct ksmbd_work *work) + } + + err_out: +- if (file_present || created) { +- inode_unlock(d_inode(parent_path.dentry)); +- path_put(&path); +- path_put(&parent_path); +- } ++ if (file_present || created) ++ ksmbd_vfs_kern_path_unlock(&parent_path, &path); ++ ++ if (fp && need_truncate) ++ rc = smb2_create_truncate(&fp->filp->f_path); ++ + ksmbd_revert_fsids(work); + err_out1: + if (!rc) { +@@ -5537,7 +5534,7 @@ static int smb2_rename(struct ksmbd_work + rc = ksmbd_vfs_setxattr(file_mnt_user_ns(fp->filp), + &fp->filp->f_path, + xattr_stream_name, +- NULL, 0, 0); ++ NULL, 0, 0, true); + if (rc < 0) { + pr_err("failed to store stream name in xattr: %d\n", + rc); +@@ -5630,11 +5627,9 @@ static int smb2_create_link(struct ksmbd + if (rc) + rc = -EINVAL; + out: +- if (file_present) { +- inode_unlock(d_inode(parent_path.dentry)); +- path_put(&path); +- path_put(&parent_path); +- } ++ if (file_present) ++ ksmbd_vfs_kern_path_unlock(&parent_path, &path); ++ + if (!IS_ERR(link_name)) + kfree(link_name); + kfree(pathname); +@@ -5701,7 +5696,8 @@ static int set_file_basic_info(struct ks + da.flags = XATTR_DOSINFO_ATTRIB | XATTR_DOSINFO_CREATE_TIME | + XATTR_DOSINFO_ITIME; + +- rc = ksmbd_vfs_set_dos_attrib_xattr(user_ns, &filp->f_path, &da); ++ rc = ksmbd_vfs_set_dos_attrib_xattr(user_ns, &filp->f_path, &da, ++ true); + if (rc) + ksmbd_debug(SMB, + "failed to restore file attribute in EA\n"); +@@ -6015,7 +6011,7 @@ static int smb2_set_info_sec(struct ksmb + fp->saccess |= FILE_SHARE_DELETE_LE; + + return set_info_sec(fp->conn, fp->tcon, &fp->filp->f_path, pntsd, +- buf_len, false); ++ buf_len, false, true); + } + + /** +@@ -7585,7 +7581,8 @@ static inline int fsctl_set_sparse(struc + + da.attr = le32_to_cpu(fp->f_ci->m_fattr); + ret = ksmbd_vfs_set_dos_attrib_xattr(user_ns, +- &fp->filp->f_path, &da); ++ &fp->filp->f_path, ++ &da, true); + if (ret) + fp->f_ci->m_fattr = old_fattr; + } +--- a/fs/ksmbd/smbacl.c ++++ b/fs/ksmbd/smbacl.c +@@ -1183,7 +1183,7 @@ pass: + pntsd_size += sizeof(struct smb_acl) + nt_size; + } + +- ksmbd_vfs_set_sd_xattr(conn, user_ns, path, pntsd, pntsd_size); ++ ksmbd_vfs_set_sd_xattr(conn, user_ns, path, pntsd, pntsd_size, false); + kfree(pntsd); + } + +@@ -1375,7 +1375,7 @@ err_out: + + int set_info_sec(struct ksmbd_conn *conn, struct ksmbd_tree_connect *tcon, + const struct path *path, struct smb_ntsd *pntsd, int ntsd_len, +- bool type_check) ++ bool type_check, bool get_write) + { + int rc; + struct smb_fattr fattr = {{0}}; +@@ -1435,7 +1435,8 @@ int set_info_sec(struct ksmbd_conn *conn + if (test_share_config_flag(tcon->share_conf, KSMBD_SHARE_FLAG_ACL_XATTR)) { + /* Update WinACL in xattr */ + ksmbd_vfs_remove_sd_xattrs(user_ns, path); +- ksmbd_vfs_set_sd_xattr(conn, user_ns, path, pntsd, ntsd_len); ++ ksmbd_vfs_set_sd_xattr(conn, user_ns, path, pntsd, ntsd_len, ++ get_write); + } + + out: +--- a/fs/ksmbd/smbacl.h ++++ b/fs/ksmbd/smbacl.h +@@ -207,7 +207,7 @@ int smb_check_perm_dacl(struct ksmbd_con + __le32 *pdaccess, int uid); + int set_info_sec(struct ksmbd_conn *conn, struct ksmbd_tree_connect *tcon, + const struct path *path, struct smb_ntsd *pntsd, int ntsd_len, +- bool type_check); ++ bool type_check, bool get_write); + void id_to_sid(unsigned int cid, uint sidtype, struct smb_sid *ssid); + void ksmbd_init_domain(u32 *sub_auth); + +--- a/fs/ksmbd/vfs.c ++++ b/fs/ksmbd/vfs.c +@@ -97,6 +97,13 @@ static int ksmbd_vfs_path_lookup_locked( + return -ENOENT; + } + ++ err = mnt_want_write(parent_path->mnt); ++ if (err) { ++ path_put(parent_path); ++ putname(filename); ++ return -ENOENT; ++ } ++ + inode_lock_nested(parent_path->dentry->d_inode, I_MUTEX_PARENT); + d = lookup_one_qstr_excl(&last, parent_path->dentry, 0); + if (IS_ERR(d)) +@@ -123,6 +130,7 @@ static int ksmbd_vfs_path_lookup_locked( + + err_out: + inode_unlock(d_inode(parent_path->dentry)); ++ mnt_drop_write(parent_path->mnt); + path_put(parent_path); + putname(filename); + return -ENOENT; +@@ -451,7 +459,8 @@ static int ksmbd_vfs_stream_write(struct + fp->stream.name, + (void *)stream_buf, + size, +- 0); ++ 0, ++ true); + if (err < 0) + goto out; + +@@ -593,10 +602,6 @@ int ksmbd_vfs_remove_file(struct ksmbd_w + goto out_err; + } + +- err = mnt_want_write(path->mnt); +- if (err) +- goto out_err; +- + user_ns = mnt_user_ns(path->mnt); + if (S_ISDIR(d_inode(path->dentry)->i_mode)) { + err = vfs_rmdir(user_ns, d_inode(parent), path->dentry); +@@ -607,7 +612,6 @@ int ksmbd_vfs_remove_file(struct ksmbd_w + if (err) + ksmbd_debug(VFS, "unlink failed, err %d\n", err); + } +- mnt_drop_write(path->mnt); + + out_err: + ksmbd_revert_fsids(work); +@@ -907,18 +911,22 @@ ssize_t ksmbd_vfs_getxattr(struct user_n + * @attr_value: xattr value to set + * @attr_size: size of xattr value + * @flags: destination buffer length ++ * @get_write: get write access to a mount + * + * Return: 0 on success, otherwise error + */ + int ksmbd_vfs_setxattr(struct user_namespace *user_ns, + const struct path *path, const char *attr_name, +- const void *attr_value, size_t attr_size, int flags) ++ const void *attr_value, size_t attr_size, int flags, ++ bool get_write) + { + int err; + +- err = mnt_want_write(path->mnt); +- if (err) +- return err; ++ if (get_write == true) { ++ err = mnt_want_write(path->mnt); ++ if (err) ++ return err; ++ } + + err = vfs_setxattr(user_ns, + path->dentry, +@@ -928,7 +936,8 @@ int ksmbd_vfs_setxattr(struct user_names + flags); + if (err) + ksmbd_debug(VFS, "setxattr failed, err %d\n", err); +- mnt_drop_write(path->mnt); ++ if (get_write == true) ++ mnt_drop_write(path->mnt); + return err; + } + +@@ -1254,6 +1263,13 @@ out1: + } + + if (!err) { ++ err = mnt_want_write(parent_path->mnt); ++ if (err) { ++ path_put(path); ++ path_put(parent_path); ++ return err; ++ } ++ + err = ksmbd_vfs_lock_parent(parent_path->dentry, path->dentry); + if (err) { + path_put(path); +@@ -1263,6 +1279,14 @@ out1: + return err; + } + ++void ksmbd_vfs_kern_path_unlock(struct path *parent_path, struct path *path) ++{ ++ inode_unlock(d_inode(parent_path->dentry)); ++ mnt_drop_write(parent_path->mnt); ++ path_put(path); ++ path_put(parent_path); ++} ++ + struct dentry *ksmbd_vfs_kern_path_create(struct ksmbd_work *work, + const char *name, + unsigned int flags, +@@ -1412,7 +1436,8 @@ out: + int ksmbd_vfs_set_sd_xattr(struct ksmbd_conn *conn, + struct user_namespace *user_ns, + const struct path *path, +- struct smb_ntsd *pntsd, int len) ++ struct smb_ntsd *pntsd, int len, ++ bool get_write) + { + int rc; + struct ndr sd_ndr = {0}, acl_ndr = {0}; +@@ -1472,7 +1497,7 @@ int ksmbd_vfs_set_sd_xattr(struct ksmbd_ + + rc = ksmbd_vfs_setxattr(user_ns, path, + XATTR_NAME_SD, sd_ndr.data, +- sd_ndr.offset, 0); ++ sd_ndr.offset, 0, get_write); + if (rc < 0) + pr_err("Failed to store XATTR ntacl :%d\n", rc); + +@@ -1561,7 +1586,8 @@ free_n_data: + + int ksmbd_vfs_set_dos_attrib_xattr(struct user_namespace *user_ns, + const struct path *path, +- struct xattr_dos_attrib *da) ++ struct xattr_dos_attrib *da, ++ bool get_write) + { + struct ndr n; + int err; +@@ -1571,7 +1597,7 @@ int ksmbd_vfs_set_dos_attrib_xattr(struc + return err; + + err = ksmbd_vfs_setxattr(user_ns, path, XATTR_NAME_DOS_ATTRIBUTE, +- (void *)n.data, n.offset, 0); ++ (void *)n.data, n.offset, 0, get_write); + if (err) + ksmbd_debug(SMB, "failed to store dos attribute in xattr\n"); + kfree(n.data); +@@ -1841,10 +1867,6 @@ int ksmbd_vfs_set_init_posix_acl(struct + } + posix_state_to_acl(&acl_state, acls->a_entries); + +- rc = mnt_want_write(path->mnt); +- if (rc) +- goto out_err; +- + rc = set_posix_acl(user_ns, inode, ACL_TYPE_ACCESS, acls); + if (rc < 0) + ksmbd_debug(SMB, "Set posix acl(ACL_TYPE_ACCESS) failed, rc : %d\n", +@@ -1857,9 +1879,7 @@ int ksmbd_vfs_set_init_posix_acl(struct + ksmbd_debug(SMB, "Set posix acl(ACL_TYPE_DEFAULT) failed, rc : %d\n", + rc); + } +- mnt_drop_write(path->mnt); + +-out_err: + free_acl_state(&acl_state); + posix_acl_release(acls); + return rc; +@@ -1888,10 +1908,6 @@ int ksmbd_vfs_inherit_posix_acl(struct u + } + } + +- rc = mnt_want_write(path->mnt); +- if (rc) +- goto out_err; +- + rc = set_posix_acl(user_ns, inode, ACL_TYPE_ACCESS, acls); + if (rc < 0) + ksmbd_debug(SMB, "Set posix acl(ACL_TYPE_ACCESS) failed, rc : %d\n", +@@ -1903,9 +1919,7 @@ int ksmbd_vfs_inherit_posix_acl(struct u + ksmbd_debug(SMB, "Set posix acl(ACL_TYPE_DEFAULT) failed, rc : %d\n", + rc); + } +- mnt_drop_write(path->mnt); + +-out_err: + posix_acl_release(acls); + return rc; + } +--- a/fs/ksmbd/vfs.h ++++ b/fs/ksmbd/vfs.h +@@ -148,7 +148,8 @@ ssize_t ksmbd_vfs_casexattr_len(struct u + int attr_name_len); + int ksmbd_vfs_setxattr(struct user_namespace *user_ns, + const struct path *path, const char *attr_name, +- const void *attr_value, size_t attr_size, int flags); ++ const void *attr_value, size_t attr_size, int flags, ++ bool get_write); + int ksmbd_vfs_xattr_stream_name(char *stream_name, char **xattr_stream_name, + size_t *xattr_stream_name_size, int s_type); + int ksmbd_vfs_remove_xattr(struct user_namespace *user_ns, +@@ -156,6 +157,7 @@ int ksmbd_vfs_remove_xattr(struct user_n + int ksmbd_vfs_kern_path_locked(struct ksmbd_work *work, char *name, + unsigned int flags, struct path *parent_path, + struct path *path, bool caseless); ++void ksmbd_vfs_kern_path_unlock(struct path *parent_path, struct path *path); + struct dentry *ksmbd_vfs_kern_path_create(struct ksmbd_work *work, + const char *name, + unsigned int flags, +@@ -183,14 +185,16 @@ int ksmbd_vfs_remove_sd_xattrs(struct us + int ksmbd_vfs_set_sd_xattr(struct ksmbd_conn *conn, + struct user_namespace *user_ns, + const struct path *path, +- struct smb_ntsd *pntsd, int len); ++ struct smb_ntsd *pntsd, int len, ++ bool get_write); + int ksmbd_vfs_get_sd_xattr(struct ksmbd_conn *conn, + struct user_namespace *user_ns, + struct dentry *dentry, + struct smb_ntsd **pntsd); + int ksmbd_vfs_set_dos_attrib_xattr(struct user_namespace *user_ns, + const struct path *path, +- struct xattr_dos_attrib *da); ++ struct xattr_dos_attrib *da, ++ bool get_write); + int ksmbd_vfs_get_dos_attrib_xattr(struct user_namespace *user_ns, + struct dentry *dentry, + struct xattr_dos_attrib *da); diff --git a/queue-5.15/ksmbd-fix-possible-memory-leak-in-smb2_lock.patch b/queue-5.15/ksmbd-fix-possible-memory-leak-in-smb2_lock.patch new file mode 100644 index 00000000000..4304ec5d12e --- /dev/null +++ b/queue-5.15/ksmbd-fix-possible-memory-leak-in-smb2_lock.patch @@ -0,0 +1,120 @@ +From linkinjeon@gmail.com Mon Dec 18 16:39:30 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:33:37 +0900 +Subject: ksmbd: fix possible memory leak in smb2_lock() +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Hangyu Hua , Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-78-linkinjeon@kernel.org> + +From: Hangyu Hua + +[ Upstream commit d3ca9f7aeba793d74361d88a8800b2f205c9236b ] + +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 +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/smb2pdu.c | 28 +++++++++++++--------------- + fs/ksmbd/vfs_cache.c | 5 ++--- + 2 files changed, 15 insertions(+), 18 deletions(-) + +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -6676,7 +6676,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", +@@ -6698,7 +6698,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); +@@ -6717,18 +6719,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; +@@ -7094,6 +7090,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); +@@ -7102,9 +7106,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); +@@ -7126,9 +7127,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); +--- a/fs/ksmbd/vfs_cache.c ++++ b/fs/ksmbd/vfs_cache.c +@@ -364,12 +364,11 @@ static void __put_fd_final(struct ksmbd_ + + 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); + } diff --git a/queue-5.15/ksmbd-fix-potential-double-free-on-smb2_read_pipe-error-path.patch b/queue-5.15/ksmbd-fix-potential-double-free-on-smb2_read_pipe-error-path.patch new file mode 100644 index 00000000000..eebc8f142fb --- /dev/null +++ b/queue-5.15/ksmbd-fix-potential-double-free-on-smb2_read_pipe-error-path.patch @@ -0,0 +1,41 @@ +From linkinjeon@gmail.com Mon Dec 18 16:42:46 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:34:38 +0900 +Subject: ksmbd: fix potential double free on smb2_read_pipe() error path +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , kernel test robot , Dan Carpenter , Steve French +Message-ID: <20231218153454.8090-139-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit 1903e6d0578118e9aab1ee23f4a9de55737d1d05 ] + +Fix new smatch warnings: +fs/smb/server/smb2pdu.c:6131 smb2_read_pipe() error: double free of 'rpc_resp' + +Fixes: e2b76ab8b5c9 ("ksmbd: add support for read compound") +Reported-by: kernel test robot +Reported-by: Dan Carpenter +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/smb2pdu.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -6154,12 +6154,12 @@ static noinline int smb2_read_pipe(struc + memcpy(aux_payload_buf, rpc_resp->payload, rpc_resp->payload_sz); + + nbytes = rpc_resp->payload_sz; +- kvfree(rpc_resp); + err = ksmbd_iov_pin_rsp_read(work, (void *)rsp, + offsetof(struct smb2_read_rsp, Buffer), + aux_payload_buf, nbytes); + if (err) + goto out; ++ kvfree(rpc_resp); + } else { + err = ksmbd_iov_pin_rsp(work, (void *)rsp, + offsetof(struct smb2_read_rsp, Buffer)); diff --git a/queue-5.15/ksmbd-fix-race-condition-between-session-lookup-and-expire.patch b/queue-5.15/ksmbd-fix-race-condition-between-session-lookup-and-expire.patch new file mode 100644 index 00000000000..3894170081d --- /dev/null +++ b/queue-5.15/ksmbd-fix-race-condition-between-session-lookup-and-expire.patch @@ -0,0 +1,109 @@ +From linkinjeon@gmail.com Mon Dec 18 16:42:24 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:34:31 +0900 +Subject: ksmbd: fix race condition between session lookup and expire +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , luosili , Steve French +Message-ID: <20231218153454.8090-132-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit 53ff5cf89142b978b1a5ca8dc4d4425e6a09745f ] + + Thread A + Thread B + ksmbd_session_lookup | smb2_sess_setup + sess = xa_load | + | + | xa_erase(&conn->sessions, sess->id); + | + | ksmbd_session_destroy(sess) --> kfree(sess) + | + // UAF! | + sess->last_active = jiffies | + + + +This patch add rwsem to fix race condition between ksmbd_session_lookup +and ksmbd_expire_session. + +Reported-by: luosili +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/connection.c | 2 ++ + fs/ksmbd/connection.h | 1 + + fs/ksmbd/mgmt/user_session.c | 10 +++++++--- + 3 files changed, 10 insertions(+), 3 deletions(-) + +--- a/fs/ksmbd/connection.c ++++ b/fs/ksmbd/connection.c +@@ -84,6 +84,8 @@ struct ksmbd_conn *ksmbd_conn_alloc(void + spin_lock_init(&conn->llist_lock); + INIT_LIST_HEAD(&conn->lock_list); + ++ init_rwsem(&conn->session_lock); ++ + down_write(&conn_list_lock); + list_add(&conn->conns_list, &conn_list); + up_write(&conn_list_lock); +--- a/fs/ksmbd/connection.h ++++ b/fs/ksmbd/connection.h +@@ -50,6 +50,7 @@ struct ksmbd_conn { + struct nls_table *local_nls; + struct unicode_map *um; + struct list_head conns_list; ++ struct rw_semaphore session_lock; + /* smb session 1 per user */ + struct xarray sessions; + unsigned long last_active; +--- a/fs/ksmbd/mgmt/user_session.c ++++ b/fs/ksmbd/mgmt/user_session.c +@@ -174,7 +174,7 @@ static void ksmbd_expire_session(struct + unsigned long id; + struct ksmbd_session *sess; + +- down_write(&sessions_table_lock); ++ down_write(&conn->session_lock); + xa_for_each(&conn->sessions, id, sess) { + if (sess->state != SMB2_SESSION_VALID || + time_after(jiffies, +@@ -185,7 +185,7 @@ static void ksmbd_expire_session(struct + continue; + } + } +- up_write(&sessions_table_lock); ++ up_write(&conn->session_lock); + } + + int ksmbd_session_register(struct ksmbd_conn *conn, +@@ -227,7 +227,9 @@ void ksmbd_sessions_deregister(struct ks + } + } + } ++ up_write(&sessions_table_lock); + ++ down_write(&conn->session_lock); + xa_for_each(&conn->sessions, id, sess) { + unsigned long chann_id; + struct channel *chann; +@@ -244,7 +246,7 @@ void ksmbd_sessions_deregister(struct ks + ksmbd_session_destroy(sess); + } + } +- up_write(&sessions_table_lock); ++ up_write(&conn->session_lock); + } + + struct ksmbd_session *ksmbd_session_lookup(struct ksmbd_conn *conn, +@@ -252,9 +254,11 @@ struct ksmbd_session *ksmbd_session_look + { + struct ksmbd_session *sess; + ++ down_read(&conn->session_lock); + sess = xa_load(&conn->sessions, id); + if (sess) + sess->last_active = jiffies; ++ up_read(&conn->session_lock); + return sess; + } + diff --git a/queue-5.15/ksmbd-fix-race-condition-between-tree-conn-lookup-and-disconnect.patch b/queue-5.15/ksmbd-fix-race-condition-between-tree-conn-lookup-and-disconnect.patch new file mode 100644 index 00000000000..2f7f6fc126b --- /dev/null +++ b/queue-5.15/ksmbd-fix-race-condition-between-tree-conn-lookup-and-disconnect.patch @@ -0,0 +1,268 @@ +From linkinjeon@gmail.com Mon Dec 18 16:42:36 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:34:35 +0900 +Subject: ksmbd: fix race condition between tree conn lookup and disconnect +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , luosili , Steve French +Message-ID: <20231218153454.8090-136-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit 33b235a6e6ebe0f05f3586a71e8d281d00f71e2e ] + +if thread A in smb2_write is using work-tcon, other thread B use +smb2_tree_disconnect free the tcon, then thread A will use free'd tcon. + + Time + + + Thread A | Thread A + smb2_write | smb2_tree_disconnect + | + | + | kfree(tree_conn) + | + // UAF! | + work->tcon->share_conf | + + + +This patch add state, reference count and lock for tree conn to fix race +condition issue. + +Reported-by: luosili +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/mgmt/tree_connect.c | 42 +++++++++++++++++++++++++++++++++--- + fs/ksmbd/mgmt/tree_connect.h | 11 +++++++-- + fs/ksmbd/mgmt/user_session.c | 1 + fs/ksmbd/mgmt/user_session.h | 1 + fs/ksmbd/server.c | 2 + + fs/ksmbd/smb2pdu.c | 50 ++++++++++++++++++++++++++++++++----------- + 6 files changed, 90 insertions(+), 17 deletions(-) + +--- a/fs/ksmbd/mgmt/tree_connect.c ++++ b/fs/ksmbd/mgmt/tree_connect.c +@@ -73,7 +73,10 @@ ksmbd_tree_conn_connect(struct ksmbd_con + + tree_conn->user = sess->user; + tree_conn->share_conf = sc; ++ tree_conn->t_state = TREE_NEW; + status.tree_conn = tree_conn; ++ atomic_set(&tree_conn->refcount, 1); ++ init_waitqueue_head(&tree_conn->refcount_q); + + ret = xa_err(xa_store(&sess->tree_conns, tree_conn->id, tree_conn, + GFP_KERNEL)); +@@ -93,14 +96,33 @@ out_error: + return status; + } + ++void ksmbd_tree_connect_put(struct ksmbd_tree_connect *tcon) ++{ ++ /* ++ * Checking waitqueue to releasing tree connect on ++ * tree disconnect. waitqueue_active is safe because it ++ * uses atomic operation for condition. ++ */ ++ if (!atomic_dec_return(&tcon->refcount) && ++ waitqueue_active(&tcon->refcount_q)) ++ wake_up(&tcon->refcount_q); ++} ++ + int ksmbd_tree_conn_disconnect(struct ksmbd_session *sess, + struct ksmbd_tree_connect *tree_conn) + { + int ret; + ++ write_lock(&sess->tree_conns_lock); ++ xa_erase(&sess->tree_conns, tree_conn->id); ++ write_unlock(&sess->tree_conns_lock); ++ ++ if (!atomic_dec_and_test(&tree_conn->refcount)) ++ wait_event(tree_conn->refcount_q, ++ atomic_read(&tree_conn->refcount) == 0); ++ + ret = ksmbd_ipc_tree_disconnect_request(sess->id, tree_conn->id); + ksmbd_release_tree_conn_id(sess, tree_conn->id); +- xa_erase(&sess->tree_conns, tree_conn->id); + ksmbd_share_config_put(tree_conn->share_conf); + kfree(tree_conn); + return ret; +@@ -111,11 +133,15 @@ struct ksmbd_tree_connect *ksmbd_tree_co + { + struct ksmbd_tree_connect *tcon; + ++ read_lock(&sess->tree_conns_lock); + tcon = xa_load(&sess->tree_conns, id); + if (tcon) { +- if (test_bit(TREE_CONN_EXPIRE, &tcon->status)) ++ if (tcon->t_state != TREE_CONNECTED) ++ tcon = NULL; ++ else if (!atomic_inc_not_zero(&tcon->refcount)) + tcon = NULL; + } ++ read_unlock(&sess->tree_conns_lock); + + return tcon; + } +@@ -129,8 +155,18 @@ int ksmbd_tree_conn_session_logoff(struc + if (!sess) + return -EINVAL; + +- xa_for_each(&sess->tree_conns, id, tc) ++ xa_for_each(&sess->tree_conns, id, tc) { ++ write_lock(&sess->tree_conns_lock); ++ if (tc->t_state == TREE_DISCONNECTED) { ++ write_unlock(&sess->tree_conns_lock); ++ ret = -ENOENT; ++ continue; ++ } ++ tc->t_state = TREE_DISCONNECTED; ++ write_unlock(&sess->tree_conns_lock); ++ + ret |= ksmbd_tree_conn_disconnect(sess, tc); ++ } + xa_destroy(&sess->tree_conns); + return ret; + } +--- a/fs/ksmbd/mgmt/tree_connect.h ++++ b/fs/ksmbd/mgmt/tree_connect.h +@@ -14,7 +14,11 @@ struct ksmbd_share_config; + struct ksmbd_user; + struct ksmbd_conn; + +-#define TREE_CONN_EXPIRE 1 ++enum { ++ TREE_NEW = 0, ++ TREE_CONNECTED, ++ TREE_DISCONNECTED ++}; + + struct ksmbd_tree_connect { + int id; +@@ -27,7 +31,9 @@ struct ksmbd_tree_connect { + + int maximal_access; + bool posix_extensions; +- unsigned long status; ++ atomic_t refcount; ++ wait_queue_head_t refcount_q; ++ unsigned int t_state; + }; + + struct ksmbd_tree_conn_status { +@@ -46,6 +52,7 @@ struct ksmbd_session; + struct ksmbd_tree_conn_status + ksmbd_tree_conn_connect(struct ksmbd_conn *conn, struct ksmbd_session *sess, + const char *share_name); ++void ksmbd_tree_connect_put(struct ksmbd_tree_connect *tcon); + + int ksmbd_tree_conn_disconnect(struct ksmbd_session *sess, + struct ksmbd_tree_connect *tree_conn); +--- a/fs/ksmbd/mgmt/user_session.c ++++ b/fs/ksmbd/mgmt/user_session.c +@@ -355,6 +355,7 @@ static struct ksmbd_session *__session_c + xa_init(&sess->ksmbd_chann_list); + xa_init(&sess->rpc_handle_list); + sess->sequence_number = 1; ++ rwlock_init(&sess->tree_conns_lock); + + ret = __init_smb2_session(sess); + if (ret) +--- a/fs/ksmbd/mgmt/user_session.h ++++ b/fs/ksmbd/mgmt/user_session.h +@@ -60,6 +60,7 @@ struct ksmbd_session { + + struct ksmbd_file_table file_table; + unsigned long last_active; ++ rwlock_t tree_conns_lock; + }; + + static inline int test_session_flag(struct ksmbd_session *sess, int bit) +--- a/fs/ksmbd/server.c ++++ b/fs/ksmbd/server.c +@@ -241,6 +241,8 @@ static void __handle_ksmbd_work(struct k + } while (is_chained == true); + + send: ++ if (work->tcon) ++ ksmbd_tree_connect_put(work->tcon); + smb3_preauth_hash_rsp(work); + if (work->sess && work->sess->enc && work->encrypted && + conn->ops->encrypt_resp) { +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -1993,6 +1993,9 @@ int smb2_tree_connect(struct ksmbd_work + if (conn->posix_ext_supported) + status.tree_conn->posix_extensions = true; + ++ write_lock(&sess->tree_conns_lock); ++ status.tree_conn->t_state = TREE_CONNECTED; ++ write_unlock(&sess->tree_conns_lock); + rsp->StructureSize = cpu_to_le16(16); + out_err1: + rsp->Capabilities = 0; +@@ -2122,27 +2125,50 @@ int smb2_tree_disconnect(struct ksmbd_wo + + ksmbd_debug(SMB, "request\n"); + ++ if (!tcon) { ++ ksmbd_debug(SMB, "Invalid tid %d\n", req->hdr.Id.SyncId.TreeId); ++ ++ rsp->hdr.Status = STATUS_NETWORK_NAME_DELETED; ++ err = -ENOENT; ++ goto err_out; ++ } ++ ++ ksmbd_close_tree_conn_fds(work); ++ ++ write_lock(&sess->tree_conns_lock); ++ if (tcon->t_state == TREE_DISCONNECTED) { ++ write_unlock(&sess->tree_conns_lock); ++ rsp->hdr.Status = STATUS_NETWORK_NAME_DELETED; ++ err = -ENOENT; ++ goto err_out; ++ } ++ ++ WARN_ON_ONCE(atomic_dec_and_test(&tcon->refcount)); ++ tcon->t_state = TREE_DISCONNECTED; ++ write_unlock(&sess->tree_conns_lock); ++ ++ err = ksmbd_tree_conn_disconnect(sess, tcon); ++ if (err) { ++ rsp->hdr.Status = STATUS_NETWORK_NAME_DELETED; ++ goto err_out; ++ } ++ ++ work->tcon = NULL; ++ + rsp->StructureSize = cpu_to_le16(4); + err = ksmbd_iov_pin_rsp(work, rsp, + sizeof(struct smb2_tree_disconnect_rsp)); + if (err) { + rsp->hdr.Status = STATUS_INSUFFICIENT_RESOURCES; +- smb2_set_err_rsp(work); +- return err; ++ goto err_out; + } + +- if (!tcon || test_and_set_bit(TREE_CONN_EXPIRE, &tcon->status)) { +- ksmbd_debug(SMB, "Invalid tid %d\n", req->hdr.Id.SyncId.TreeId); ++ return 0; + +- rsp->hdr.Status = STATUS_NETWORK_NAME_DELETED; +- smb2_set_err_rsp(work); +- return -ENOENT; +- } ++err_out: ++ smb2_set_err_rsp(work); ++ return err; + +- ksmbd_close_tree_conn_fds(work); +- ksmbd_tree_conn_disconnect(sess, tcon); +- work->tcon = NULL; +- return 0; + } + + /** diff --git a/queue-5.15/ksmbd-fix-race-condition-from-parallel-smb2-lock-requests.patch b/queue-5.15/ksmbd-fix-race-condition-from-parallel-smb2-lock-requests.patch new file mode 100644 index 00000000000..b2092f265e9 --- /dev/null +++ b/queue-5.15/ksmbd-fix-race-condition-from-parallel-smb2-lock-requests.patch @@ -0,0 +1,83 @@ +From linkinjeon@gmail.com Mon Dec 18 16:42:33 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:34:34 +0900 +Subject: ksmbd: fix race condition from parallel smb2 lock requests +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , luosili , Steve French +Message-ID: <20231218153454.8090-135-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit 75ac9a3dd65f7eab4d12b0a0f744234b5300a491 ] + +There is a race condition issue between parallel smb2 lock request. + + Time + + +Thread A | Thread A +smb2_lock | smb2_lock + | + insert smb_lock to lock_list | + spin_unlock(&work->conn->llist_lock) | + | + | spin_lock(&conn->llist_lock); + | kfree(cmp_lock); + | + // UAF! | + list_add(&smb_lock->llist, &rollback_list) + + +This patch swaps the line for adding the smb lock to the rollback list and +adding the lock list of connection to fix the race issue. + +Reported-by: luosili +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/smb2pdu.c | 12 +----------- + 1 file changed, 1 insertion(+), 11 deletions(-) + +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -7040,10 +7040,6 @@ skip: + + ksmbd_debug(SMB, + "would have to wait for getting lock\n"); +- spin_lock(&work->conn->llist_lock); +- list_add_tail(&smb_lock->clist, +- &work->conn->lock_list); +- spin_unlock(&work->conn->llist_lock); + list_add(&smb_lock->llist, &rollback_list); + + argv = kmalloc(sizeof(void *), GFP_KERNEL); +@@ -7075,9 +7071,6 @@ skip: + + if (work->state != KSMBD_WORK_ACTIVE) { + list_del(&smb_lock->llist); +- spin_lock(&work->conn->llist_lock); +- list_del(&smb_lock->clist); +- spin_unlock(&work->conn->llist_lock); + locks_free_lock(flock); + + if (work->state == KSMBD_WORK_CANCELLED) { +@@ -7097,19 +7090,16 @@ skip: + } + + list_del(&smb_lock->llist); +- spin_lock(&work->conn->llist_lock); +- list_del(&smb_lock->clist); +- spin_unlock(&work->conn->llist_lock); + release_async_work(work); + goto retry; + } else if (!rc) { ++ list_add(&smb_lock->llist, &rollback_list); + spin_lock(&work->conn->llist_lock); + list_add_tail(&smb_lock->clist, + &work->conn->lock_list); + list_add_tail(&smb_lock->flist, + &fp->lock_list); + spin_unlock(&work->conn->llist_lock); +- list_add(&smb_lock->llist, &rollback_list); + ksmbd_debug(SMB, "successful in taking lock\n"); + } else { + goto out; diff --git a/queue-5.15/ksmbd-fix-race-condition-from-parallel-smb2-logoff-requests.patch b/queue-5.15/ksmbd-fix-race-condition-from-parallel-smb2-logoff-requests.patch new file mode 100644 index 00000000000..8355168fc8c --- /dev/null +++ b/queue-5.15/ksmbd-fix-race-condition-from-parallel-smb2-logoff-requests.patch @@ -0,0 +1,69 @@ +From linkinjeon@gmail.com Mon Dec 18 16:42:30 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:34:33 +0900 +Subject: ksmbd: fix race condition from parallel smb2 logoff requests +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , luosili , Steve French +Message-ID: <20231218153454.8090-134-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit 7ca9da7d873ee8024e9548d3366101c2b6843eab ] + +If parallel smb2 logoff requests come in before closing door, running +request count becomes more than 1 even though connection status is set to +KSMBD_SESS_NEED_RECONNECT. It can't get condition true, and sleep forever. +This patch fix race condition problem by returning error if connection +status was already set to KSMBD_SESS_NEED_RECONNECT. + +Reported-by: luosili +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/smb2pdu.c | 24 ++++++++++++++++-------- + 1 file changed, 16 insertions(+), 8 deletions(-) + +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -2164,17 +2164,17 @@ int smb2_session_logoff(struct ksmbd_wor + + ksmbd_debug(SMB, "request\n"); + +- sess_id = le64_to_cpu(req->hdr.SessionId); +- +- rsp->StructureSize = cpu_to_le16(4); +- err = ksmbd_iov_pin_rsp(work, rsp, sizeof(struct smb2_logoff_rsp)); +- if (err) { +- rsp->hdr.Status = STATUS_INSUFFICIENT_RESOURCES; ++ ksmbd_conn_lock(conn); ++ if (!ksmbd_conn_good(conn)) { ++ ksmbd_conn_unlock(conn); ++ rsp->hdr.Status = STATUS_NETWORK_NAME_DELETED; + smb2_set_err_rsp(work); +- return err; ++ return -ENOENT; + } +- ++ sess_id = le64_to_cpu(req->hdr.SessionId); + ksmbd_all_conn_set_status(sess_id, KSMBD_SESS_NEED_RECONNECT); ++ ksmbd_conn_unlock(conn); ++ + ksmbd_close_session_fds(work); + ksmbd_conn_wait_idle(conn, sess_id); + +@@ -2196,6 +2196,14 @@ int smb2_session_logoff(struct ksmbd_wor + ksmbd_free_user(sess->user); + sess->user = NULL; + ksmbd_all_conn_set_status(sess_id, KSMBD_SESS_NEED_NEGOTIATE); ++ ++ rsp->StructureSize = cpu_to_le16(4); ++ err = ksmbd_iov_pin_rsp(work, rsp, sizeof(struct smb2_logoff_rsp)); ++ if (err) { ++ rsp->hdr.Status = STATUS_INSUFFICIENT_RESOURCES; ++ smb2_set_err_rsp(work); ++ return err; ++ } + return 0; + } + diff --git a/queue-5.15/ksmbd-fix-race-condition-with-fp.patch b/queue-5.15/ksmbd-fix-race-condition-with-fp.patch new file mode 100644 index 00000000000..7974919aa9b --- /dev/null +++ b/queue-5.15/ksmbd-fix-race-condition-with-fp.patch @@ -0,0 +1,146 @@ +From linkinjeon@gmail.com Mon Dec 18 16:42:27 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:34:32 +0900 +Subject: ksmbd: fix race condition with fp +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , luosili , Steve French +Message-ID: <20231218153454.8090-133-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit 5a7ee91d1154f35418367a6eaae74046fd06ed89 ] + +fp can used in each command. If smb2_close command is coming at the +same time, UAF issue can happen by race condition. + + Time + + +Thread A | Thread B1 B2 .... B5 +smb2_open | smb2_close + | + __open_id | + insert fp to file_table | + | + | atomic_dec_and_test(&fp->refcount) + | if fp->refcount == 0, free fp by kfree. + // UAF! | + use fp | + + +This patch add f_state not to use freed fp is used and not to free fp in +use. + +Reported-by: luosili +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/smb2pdu.c | 4 +++- + fs/ksmbd/vfs_cache.c | 23 ++++++++++++++++++++--- + fs/ksmbd/vfs_cache.h | 9 +++++++++ + 3 files changed, 32 insertions(+), 4 deletions(-) + +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -3367,8 +3367,10 @@ err_out: + } + ksmbd_revert_fsids(work); + err_out1: +- if (!rc) ++ if (!rc) { ++ ksmbd_update_fstate(&work->sess->file_table, fp, FP_INITED); + rc = ksmbd_iov_pin_rsp(work, (void *)rsp, iov_len); ++ } + if (rc) { + if (rc == -EINVAL) + rsp->hdr.Status = STATUS_INVALID_PARAMETER; +--- a/fs/ksmbd/vfs_cache.c ++++ b/fs/ksmbd/vfs_cache.c +@@ -332,6 +332,9 @@ static void __ksmbd_close_fd(struct ksmb + + static struct ksmbd_file *ksmbd_fp_get(struct ksmbd_file *fp) + { ++ if (fp->f_state != FP_INITED) ++ return NULL; ++ + if (!atomic_inc_not_zero(&fp->refcount)) + return NULL; + return fp; +@@ -381,15 +384,20 @@ int ksmbd_close_fd(struct ksmbd_work *wo + return 0; + + ft = &work->sess->file_table; +- read_lock(&ft->lock); ++ write_lock(&ft->lock); + fp = idr_find(ft->idr, id); + if (fp) { + set_close_state_blocked_works(fp); + +- if (!atomic_dec_and_test(&fp->refcount)) ++ if (fp->f_state != FP_INITED) + fp = NULL; ++ else { ++ fp->f_state = FP_CLOSED; ++ if (!atomic_dec_and_test(&fp->refcount)) ++ fp = NULL; ++ } + } +- read_unlock(&ft->lock); ++ write_unlock(&ft->lock); + + if (!fp) + return -EINVAL; +@@ -569,6 +577,7 @@ struct ksmbd_file *ksmbd_open_fd(struct + fp->tcon = work->tcon; + fp->volatile_id = KSMBD_NO_FID; + fp->persistent_id = KSMBD_NO_FID; ++ fp->f_state = FP_NEW; + fp->f_ci = ksmbd_inode_get(fp); + + if (!fp->f_ci) { +@@ -590,6 +599,14 @@ err_out: + return ERR_PTR(ret); + } + ++void ksmbd_update_fstate(struct ksmbd_file_table *ft, struct ksmbd_file *fp, ++ unsigned int state) ++{ ++ write_lock(&ft->lock); ++ fp->f_state = state; ++ write_unlock(&ft->lock); ++} ++ + static int + __close_file_table_ids(struct ksmbd_file_table *ft, + struct ksmbd_tree_connect *tcon, +--- a/fs/ksmbd/vfs_cache.h ++++ b/fs/ksmbd/vfs_cache.h +@@ -60,6 +60,12 @@ struct ksmbd_inode { + __le32 m_fattr; + }; + ++enum { ++ FP_NEW = 0, ++ FP_INITED, ++ FP_CLOSED ++}; ++ + struct ksmbd_file { + struct file *filp; + u64 persistent_id; +@@ -98,6 +104,7 @@ struct ksmbd_file { + /* if ls is happening on directory, below is valid*/ + struct ksmbd_readdir_data readdir_data; + int dot_dotdot[2]; ++ unsigned int f_state; + }; + + static inline void set_ctx_actor(struct dir_context *ctx, +@@ -142,6 +149,8 @@ int ksmbd_close_inode_fds(struct ksmbd_w + int ksmbd_init_global_file_table(void); + void ksmbd_free_global_file_table(void); + void ksmbd_set_fd_limit(unsigned long limit); ++void ksmbd_update_fstate(struct ksmbd_file_table *ft, struct ksmbd_file *fp, ++ unsigned int state); + + /* + * INODE hash diff --git a/queue-5.15/ksmbd-fix-racy-issue-from-session-setup-and-logoff.patch b/queue-5.15/ksmbd-fix-racy-issue-from-session-setup-and-logoff.patch new file mode 100644 index 00000000000..e88e69e5047 --- /dev/null +++ b/queue-5.15/ksmbd-fix-racy-issue-from-session-setup-and-logoff.patch @@ -0,0 +1,387 @@ +From linkinjeon@gmail.com Mon Dec 18 16:40:04 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:33:48 +0900 +Subject: ksmbd: fix racy issue from session setup and logoff +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , zdi-disclosures@trendmicro.com, Steve French +Message-ID: <20231218153454.8090-89-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit f5c779b7ddbda30866cf2a27c63e34158f858c73 ] + +This racy issue is triggered by sending concurrent session setup and +logoff requests. This patch does not set connection status as +KSMBD_SESS_GOOD if state is KSMBD_SESS_NEED_RECONNECT in session setup. +And relookup session to validate if session is deleted in logoff. + +Cc: stable@vger.kernel.org +Reported-by: zdi-disclosures@trendmicro.com # ZDI-CAN-20481, ZDI-CAN-20590, ZDI-CAN-20596 +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/connection.c | 14 ++++---- + fs/ksmbd/connection.h | 39 ++++++++++++++----------- + fs/ksmbd/mgmt/user_session.c | 1 + fs/ksmbd/server.c | 3 + + fs/ksmbd/smb2pdu.c | 67 +++++++++++++++++++++++++++---------------- + fs/ksmbd/transport_tcp.c | 2 - + 6 files changed, 77 insertions(+), 49 deletions(-) + +--- a/fs/ksmbd/connection.c ++++ b/fs/ksmbd/connection.c +@@ -56,7 +56,7 @@ struct ksmbd_conn *ksmbd_conn_alloc(void + return NULL; + + conn->need_neg = true; +- conn->status = KSMBD_SESS_NEW; ++ ksmbd_conn_set_new(conn); + conn->local_nls = load_nls("utf8"); + if (!conn->local_nls) + conn->local_nls = load_nls_default(); +@@ -147,12 +147,12 @@ int ksmbd_conn_try_dequeue_request(struc + return ret; + } + +-static void ksmbd_conn_lock(struct ksmbd_conn *conn) ++void ksmbd_conn_lock(struct ksmbd_conn *conn) + { + 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); + } +@@ -243,7 +243,7 @@ bool ksmbd_conn_alive(struct ksmbd_conn + if (!ksmbd_server_running()) + return false; + +- if (conn->status == KSMBD_SESS_EXITING) ++ if (ksmbd_conn_exiting(conn)) + return false; + + if (kthread_should_stop()) +@@ -303,7 +303,7 @@ int ksmbd_conn_handler_loop(void *p) + pdu_size = get_rfc1002_len(hdr_buf); + ksmbd_debug(CONN, "RFC1002 header %u bytes\n", pdu_size); + +- if (conn->status == KSMBD_SESS_GOOD) ++ if (ksmbd_conn_good(conn)) + max_allowed_pdu_size = + SMB3_MAX_MSGSIZE + conn->vals->max_write_size; + else +@@ -312,7 +312,7 @@ int ksmbd_conn_handler_loop(void *p) + 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, +- conn->status); ++ READ_ONCE(conn->status)); + break; + } + +@@ -417,7 +417,7 @@ again: + if (task) + ksmbd_debug(CONN, "Stop session handler %s/%d\n", + task->comm, task_pid_nr(task)); +- conn->status = KSMBD_SESS_EXITING; ++ ksmbd_conn_set_exiting(conn); + if (t->ops->shutdown) { + read_unlock(&conn_list_lock); + t->ops->shutdown(t); +--- a/fs/ksmbd/connection.h ++++ b/fs/ksmbd/connection.h +@@ -162,6 +162,8 @@ void ksmbd_conn_init_server_callbacks(st + int ksmbd_conn_handler_loop(void *p); + int ksmbd_conn_transport_init(void); + void ksmbd_conn_transport_destroy(void); ++void ksmbd_conn_lock(struct ksmbd_conn *conn); ++void ksmbd_conn_unlock(struct ksmbd_conn *conn); + + /* + * WARNING +@@ -169,43 +171,48 @@ void ksmbd_conn_transport_destroy(void); + * This is a hack. We will move status to a proper place once we land + * 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__ */ +--- a/fs/ksmbd/mgmt/user_session.c ++++ b/fs/ksmbd/mgmt/user_session.c +@@ -315,6 +315,7 @@ static struct ksmbd_session *__session_c + if (ksmbd_init_file_table(&sess->file_table)) + goto error; + ++ sess->state = SMB2_SESSION_IN_PROGRESS; + set_session_flag(sess, protocol); + xa_init(&sess->tree_conns); + xa_init(&sess->ksmbd_chann_list); +--- a/fs/ksmbd/server.c ++++ b/fs/ksmbd/server.c +@@ -93,7 +93,8 @@ static inline int check_conn_state(struc + { + 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->Status.CifsError = STATUS_CONNECTION_DISCONNECTED; + return 1; +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -265,7 +265,7 @@ int init_smb2_neg_rsp(struct ksmbd_work + + 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); + ksmbd_debug(SMB, "conn->dialect 0x%x\n", conn->dialect); +@@ -295,7 +295,7 @@ int init_smb2_neg_rsp(struct ksmbd_work + rsp->SecurityMode |= SMB2_NEGOTIATE_SIGNING_REQUIRED_LE; + conn->use_spnego = true; + +- ksmbd_conn_set_need_negotiate(work); ++ ksmbd_conn_set_need_negotiate(conn); + return 0; + } + +@@ -574,7 +574,7 @@ int smb2_check_user_session(struct ksmbd + cmd == SMB2_SESSION_SETUP_HE) + return 0; + +- if (!ksmbd_conn_good(work)) ++ if (!ksmbd_conn_good(conn)) + return -EIO; + + sess_id = le64_to_cpu(req_hdr->SessionId); +@@ -625,7 +625,7 @@ static void destroy_previous_session(str + + prev_sess->state = SMB2_SESSION_EXPIRED; + xa_for_each(&prev_sess->ksmbd_chann_list, index, chann) +- chann->conn->status = KSMBD_SESS_EXITING; ++ ksmbd_conn_set_exiting(chann->conn); + } + + /** +@@ -1081,7 +1081,7 @@ int smb2_handle_negotiate(struct ksmbd_w + + ksmbd_debug(SMB, "Received negotiate request\n"); + 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"); + work->send_no_response = 1; + return rc; +@@ -1236,7 +1236,7 @@ int smb2_handle_negotiate(struct ksmbd_w + } + + conn->srv_sec_mode = le16_to_cpu(rsp->SecurityMode); +- ksmbd_conn_set_need_negotiate(work); ++ ksmbd_conn_set_need_negotiate(conn); + + err_out: + if (rc < 0) +@@ -1658,6 +1658,7 @@ int smb2_sess_setup(struct ksmbd_work *w + rsp->SecurityBufferLength = 0; + inc_rfc1001_len(work->response_buf, 9); + ++ ksmbd_conn_lock(conn); + if (!req->hdr.SessionId) { + sess = ksmbd_smb2_session_create(); + if (!sess) { +@@ -1705,6 +1706,12 @@ int smb2_sess_setup(struct ksmbd_work *w + goto out_err; + } + ++ if (ksmbd_conn_need_reconnect(conn)) { ++ rc = -EFAULT; ++ sess = NULL; ++ goto out_err; ++ } ++ + if (ksmbd_session_lookup(conn, sess_id)) { + rc = -EACCES; + goto out_err; +@@ -1729,12 +1736,20 @@ int smb2_sess_setup(struct ksmbd_work *w + rc = -ENOENT; + 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; + +- if (sess->state == SMB2_SESSION_EXPIRED) +- sess->state = SMB2_SESSION_IN_PROGRESS; +- + negblob_off = le16_to_cpu(req->SecurityBufferOffset); + negblob_len = le16_to_cpu(req->SecurityBufferLength); + if (negblob_off < offsetof(struct smb2_sess_setup_req, Buffer) || +@@ -1764,8 +1779,10 @@ int smb2_sess_setup(struct ksmbd_work *w + goto out_err; + } + +- ksmbd_conn_set_good(work); +- sess->state = SMB2_SESSION_VALID; ++ if (!ksmbd_conn_need_reconnect(conn)) { ++ ksmbd_conn_set_good(conn); ++ sess->state = SMB2_SESSION_VALID; ++ } + kfree(sess->Preauth_HashValue); + sess->Preauth_HashValue = NULL; + } else if (conn->preferred_auth_mech == KSMBD_AUTH_NTLMSSP) { +@@ -1787,8 +1804,10 @@ int smb2_sess_setup(struct ksmbd_work *w + if (rc) + goto out_err; + +- ksmbd_conn_set_good(work); +- sess->state = SMB2_SESSION_VALID; ++ if (!ksmbd_conn_need_reconnect(conn)) { ++ ksmbd_conn_set_good(conn); ++ sess->state = SMB2_SESSION_VALID; ++ } + if (conn->binding) { + struct preauth_session *preauth_sess; + +@@ -1856,14 +1875,13 @@ out_err: + if (sess->user && sess->user->flags & KSMBD_USER_FLAG_DELAY_SESSION) + try_delay = true; + +- xa_erase(&conn->sessions, sess->id); +- ksmbd_session_destroy(sess); +- work->sess = NULL; ++ sess->state = SMB2_SESSION_EXPIRED; + if (try_delay) + ssleep(5); + } + } + ++ ksmbd_conn_unlock(conn); + return rc; + } + +@@ -2087,21 +2105,24 @@ int smb2_session_logoff(struct ksmbd_wor + { + struct ksmbd_conn *conn = work->conn; + 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); + inc_rfc1001_len(work->response_buf, 4); + + ksmbd_debug(SMB, "request\n"); + +- /* setting CifsExiting here may race with start_tcp_sess */ +- ksmbd_conn_set_need_reconnect(work); ++ ksmbd_conn_set_need_reconnect(conn); + ksmbd_close_session_fds(work); + 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)) { +- struct smb2_logoff_req *req = smb2_get_msg(work->request_buf); +- + ksmbd_debug(SMB, "Invalid tid %d\n", req->hdr.Id.SyncId.TreeId); + rsp->hdr.Status = STATUS_NETWORK_NAME_DELETED; + smb2_set_err_rsp(work); +@@ -2113,9 +2134,7 @@ int smb2_session_logoff(struct ksmbd_wor + + ksmbd_free_user(sess->user); + sess->user = NULL; +- +- /* let start_tcp_sess free connection info now */ +- ksmbd_conn_set_need_negotiate(work); ++ ksmbd_conn_set_need_negotiate(conn); + return 0; + } + +--- a/fs/ksmbd/transport_tcp.c ++++ b/fs/ksmbd/transport_tcp.c +@@ -333,7 +333,7 @@ static int ksmbd_tcp_readv(struct tcp_tr + if (length == -EINTR) { + total_read = -ESHUTDOWN; + break; +- } else if (conn->status == KSMBD_SESS_NEED_RECONNECT) { ++ } else if (ksmbd_conn_need_reconnect(conn)) { + total_read = -EAGAIN; + break; + } else if (length == -ERESTARTSYS || length == -EAGAIN) { diff --git a/queue-5.15/ksmbd-fix-racy-issue-from-smb2-close-and-logoff-with-multichannel.patch b/queue-5.15/ksmbd-fix-racy-issue-from-smb2-close-and-logoff-with-multichannel.patch new file mode 100644 index 00000000000..6342d1a7cf2 --- /dev/null +++ b/queue-5.15/ksmbd-fix-racy-issue-from-smb2-close-and-logoff-with-multichannel.patch @@ -0,0 +1,401 @@ +From linkinjeon@gmail.com Mon Dec 18 16:40:14 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:33:51 +0900 +Subject: ksmbd: fix racy issue from smb2 close and logoff with multichannel +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , zdi-disclosures@trendmicro.com, Steve French +Message-ID: <20231218153454.8090-92-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit abcc506a9a71976a8b4c9bf3ee6efd13229c1e19 ] + +When smb client send concurrent smb2 close and logoff request +with multichannel connection, It can cause racy issue. logoff request +free tcon and can cause UAF issues in smb2 close. When receiving logoff +request with multichannel, ksmbd should wait until all remaning requests +complete as well as ones in the current connection, and then make +session expired. + +Cc: stable@vger.kernel.org +Reported-by: zdi-disclosures@trendmicro.com # ZDI-CAN-20796 ZDI-CAN-20595 +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/connection.c | 54 ++++++++++++++++++++++++++++++++----------- + fs/ksmbd/connection.h | 19 ++++++++++++--- + fs/ksmbd/mgmt/tree_connect.c | 3 ++ + fs/ksmbd/mgmt/user_session.c | 36 +++++++++++++++++++++++----- + fs/ksmbd/smb2pdu.c | 21 ++++++++-------- + 5 files changed, 101 insertions(+), 32 deletions(-) + +--- a/fs/ksmbd/connection.c ++++ b/fs/ksmbd/connection.c +@@ -20,7 +20,7 @@ static DEFINE_MUTEX(init_lock); + static struct ksmbd_conn_ops default_conn_ops; + + LIST_HEAD(conn_list); +-DEFINE_RWLOCK(conn_list_lock); ++DECLARE_RWSEM(conn_list_lock); + + /** + * ksmbd_conn_free() - free resources of the connection instance +@@ -32,9 +32,9 @@ DEFINE_RWLOCK(conn_list_lock); + */ + void ksmbd_conn_free(struct ksmbd_conn *conn) + { +- write_lock(&conn_list_lock); ++ down_write(&conn_list_lock); + list_del(&conn->conns_list); +- write_unlock(&conn_list_lock); ++ up_write(&conn_list_lock); + + xa_destroy(&conn->sessions); + kvfree(conn->request_buf); +@@ -84,9 +84,9 @@ struct ksmbd_conn *ksmbd_conn_alloc(void + spin_lock_init(&conn->llist_lock); + INIT_LIST_HEAD(&conn->lock_list); + +- write_lock(&conn_list_lock); ++ down_write(&conn_list_lock); + list_add(&conn->conns_list, &conn_list); +- write_unlock(&conn_list_lock); ++ up_write(&conn_list_lock); + return conn; + } + +@@ -95,7 +95,7 @@ bool ksmbd_conn_lookup_dialect(struct ks + struct ksmbd_conn *t; + bool ret = false; + +- read_lock(&conn_list_lock); ++ down_read(&conn_list_lock); + list_for_each_entry(t, &conn_list, conns_list) { + if (memcmp(t->ClientGUID, c->ClientGUID, SMB2_CLIENT_GUID_SIZE)) + continue; +@@ -103,7 +103,7 @@ bool ksmbd_conn_lookup_dialect(struct ks + ret = true; + break; + } +- read_unlock(&conn_list_lock); ++ up_read(&conn_list_lock); + return ret; + } + +@@ -157,9 +157,37 @@ void ksmbd_conn_unlock(struct ksmbd_conn + mutex_unlock(&conn->srv_mutex); + } + +-void ksmbd_conn_wait_idle(struct ksmbd_conn *conn) ++void ksmbd_all_conn_set_status(u64 sess_id, u32 status) + { ++ struct ksmbd_conn *conn; ++ ++ down_read(&conn_list_lock); ++ list_for_each_entry(conn, &conn_list, conns_list) { ++ if (conn->binding || xa_load(&conn->sessions, sess_id)) ++ WRITE_ONCE(conn->status, status); ++ } ++ up_read(&conn_list_lock); ++} ++ ++void ksmbd_conn_wait_idle(struct ksmbd_conn *conn, u64 sess_id) ++{ ++ struct ksmbd_conn *bind_conn; ++ + wait_event(conn->req_running_q, atomic_read(&conn->req_running) < 2); ++ ++ down_read(&conn_list_lock); ++ list_for_each_entry(bind_conn, &conn_list, conns_list) { ++ if (bind_conn == conn) ++ continue; ++ ++ if ((bind_conn->binding || xa_load(&bind_conn->sessions, sess_id)) && ++ !ksmbd_conn_releasing(bind_conn) && ++ atomic_read(&bind_conn->req_running)) { ++ wait_event(bind_conn->req_running_q, ++ atomic_read(&bind_conn->req_running) == 0); ++ } ++ } ++ up_read(&conn_list_lock); + } + + int ksmbd_conn_write(struct ksmbd_work *work) +@@ -361,10 +389,10 @@ int ksmbd_conn_handler_loop(void *p) + } + + out: ++ ksmbd_conn_set_releasing(conn); + /* Wait till all reference dropped to the Server object*/ + wait_event(conn->r_count_q, atomic_read(&conn->r_count) == 0); + +- + if (IS_ENABLED(CONFIG_UNICODE)) + utf8_unload(conn->um); + unload_nls(conn->local_nls); +@@ -408,7 +436,7 @@ static void stop_sessions(void) + struct ksmbd_transport *t; + + again: +- read_lock(&conn_list_lock); ++ down_read(&conn_list_lock); + list_for_each_entry(conn, &conn_list, conns_list) { + struct task_struct *task; + +@@ -419,12 +447,12 @@ again: + task->comm, task_pid_nr(task)); + ksmbd_conn_set_exiting(conn); + if (t->ops->shutdown) { +- read_unlock(&conn_list_lock); ++ up_read(&conn_list_lock); + t->ops->shutdown(t); +- read_lock(&conn_list_lock); ++ down_read(&conn_list_lock); + } + } +- read_unlock(&conn_list_lock); ++ up_read(&conn_list_lock); + + if (!list_empty(&conn_list)) { + schedule_timeout_interruptible(HZ / 10); /* 100ms */ +--- a/fs/ksmbd/connection.h ++++ b/fs/ksmbd/connection.h +@@ -26,7 +26,8 @@ enum { + KSMBD_SESS_GOOD, + KSMBD_SESS_EXITING, + KSMBD_SESS_NEED_RECONNECT, +- KSMBD_SESS_NEED_NEGOTIATE ++ KSMBD_SESS_NEED_NEGOTIATE, ++ KSMBD_SESS_RELEASING + }; + + struct ksmbd_stats { +@@ -140,10 +141,10 @@ struct ksmbd_transport { + #define KSMBD_TCP_PEER_SOCKADDR(c) ((struct sockaddr *)&((c)->peer_addr)) + + extern struct list_head conn_list; +-extern rwlock_t conn_list_lock; ++extern struct rw_semaphore conn_list_lock; + + bool ksmbd_conn_alive(struct ksmbd_conn *conn); +-void ksmbd_conn_wait_idle(struct ksmbd_conn *conn); ++void ksmbd_conn_wait_idle(struct ksmbd_conn *conn, u64 sess_id); + struct ksmbd_conn *ksmbd_conn_alloc(void); + void ksmbd_conn_free(struct ksmbd_conn *conn); + bool ksmbd_conn_lookup_dialect(struct ksmbd_conn *c); +@@ -191,6 +192,11 @@ static inline bool ksmbd_conn_exiting(st + return READ_ONCE(conn->status) == KSMBD_SESS_EXITING; + } + ++static inline bool ksmbd_conn_releasing(struct ksmbd_conn *conn) ++{ ++ return READ_ONCE(conn->status) == KSMBD_SESS_RELEASING; ++} ++ + static inline void ksmbd_conn_set_new(struct ksmbd_conn *conn) + { + WRITE_ONCE(conn->status, KSMBD_SESS_NEW); +@@ -215,4 +221,11 @@ static inline void ksmbd_conn_set_exitin + { + WRITE_ONCE(conn->status, KSMBD_SESS_EXITING); + } ++ ++static inline void ksmbd_conn_set_releasing(struct ksmbd_conn *conn) ++{ ++ WRITE_ONCE(conn->status, KSMBD_SESS_RELEASING); ++} ++ ++void ksmbd_all_conn_set_status(u64 sess_id, u32 status); + #endif /* __CONNECTION_H__ */ +--- a/fs/ksmbd/mgmt/tree_connect.c ++++ b/fs/ksmbd/mgmt/tree_connect.c +@@ -129,6 +129,9 @@ int ksmbd_tree_conn_session_logoff(struc + struct ksmbd_tree_connect *tc; + unsigned long id; + ++ if (!sess) ++ return -EINVAL; ++ + xa_for_each(&sess->tree_conns, id, tc) + ret |= ksmbd_tree_conn_disconnect(sess, tc); + xa_destroy(&sess->tree_conns); +--- a/fs/ksmbd/mgmt/user_session.c ++++ b/fs/ksmbd/mgmt/user_session.c +@@ -144,10 +144,6 @@ void ksmbd_session_destroy(struct ksmbd_ + if (!sess) + return; + +- down_write(&sessions_table_lock); +- hash_del(&sess->hlist); +- up_write(&sessions_table_lock); +- + if (sess->user) + ksmbd_free_user(sess->user); + +@@ -178,15 +174,18 @@ static void ksmbd_expire_session(struct + unsigned long id; + struct ksmbd_session *sess; + ++ down_write(&sessions_table_lock); + xa_for_each(&conn->sessions, id, sess) { + if (sess->state != SMB2_SESSION_VALID || + time_after(jiffies, + sess->last_active + SMB2_SESSION_TIMEOUT)) { + xa_erase(&conn->sessions, sess->id); ++ hash_del(&sess->hlist); + ksmbd_session_destroy(sess); + continue; + } + } ++ up_write(&sessions_table_lock); + } + + int ksmbd_session_register(struct ksmbd_conn *conn, +@@ -198,15 +197,16 @@ int ksmbd_session_register(struct ksmbd_ + return xa_err(xa_store(&conn->sessions, sess->id, sess, GFP_KERNEL)); + } + +-static void 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; + + chann = xa_erase(&sess->ksmbd_chann_list, (long)conn); + if (!chann) +- return; ++ return -ENOENT; + + kfree(chann); ++ return 0; + } + + void ksmbd_sessions_deregister(struct ksmbd_conn *conn) +@@ -214,13 +214,37 @@ void ksmbd_sessions_deregister(struct ks + struct ksmbd_session *sess; + unsigned long id; + ++ down_write(&sessions_table_lock); ++ if (conn->binding) { ++ int bkt; ++ struct hlist_node *tmp; ++ ++ hash_for_each_safe(sessions_table, bkt, tmp, sess, hlist) { ++ if (!ksmbd_chann_del(conn, sess) && ++ xa_empty(&sess->ksmbd_chann_list)) { ++ hash_del(&sess->hlist); ++ ksmbd_session_destroy(sess); ++ } ++ } ++ } ++ + xa_for_each(&conn->sessions, id, sess) { ++ unsigned long chann_id; ++ struct channel *chann; ++ ++ xa_for_each(&sess->ksmbd_chann_list, chann_id, chann) { ++ if (chann->conn != conn) ++ ksmbd_conn_set_exiting(chann->conn); ++ } ++ + ksmbd_chann_del(conn, sess); + if (xa_empty(&sess->ksmbd_chann_list)) { + xa_erase(&conn->sessions, sess->id); ++ hash_del(&sess->hlist); + ksmbd_session_destroy(sess); + } + } ++ up_write(&sessions_table_lock); + } + + struct ksmbd_session *ksmbd_session_lookup(struct ksmbd_conn *conn, +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -2111,21 +2111,22 @@ int smb2_session_logoff(struct ksmbd_wor + struct smb2_logoff_rsp *rsp = smb2_get_msg(work->response_buf); + struct ksmbd_session *sess; + struct smb2_logoff_req *req = smb2_get_msg(work->request_buf); ++ u64 sess_id = le64_to_cpu(req->hdr.SessionId); + + rsp->StructureSize = cpu_to_le16(4); + inc_rfc1001_len(work->response_buf, 4); + + ksmbd_debug(SMB, "request\n"); + +- ksmbd_conn_set_need_reconnect(conn); ++ ksmbd_all_conn_set_status(sess_id, KSMBD_SESS_NEED_RECONNECT); + ksmbd_close_session_fds(work); +- ksmbd_conn_wait_idle(conn); ++ ksmbd_conn_wait_idle(conn, sess_id); + + /* + * Re-lookup session to validate if session is deleted + * while waiting request complete + */ +- sess = ksmbd_session_lookup(conn, le64_to_cpu(req->hdr.SessionId)); ++ sess = ksmbd_session_lookup_all(conn, sess_id); + if (ksmbd_tree_conn_session_logoff(sess)) { + ksmbd_debug(SMB, "Invalid tid %d\n", req->hdr.Id.SyncId.TreeId); + rsp->hdr.Status = STATUS_NETWORK_NAME_DELETED; +@@ -2138,7 +2139,7 @@ int smb2_session_logoff(struct ksmbd_wor + + ksmbd_free_user(sess->user); + sess->user = NULL; +- ksmbd_conn_set_need_negotiate(conn); ++ ksmbd_all_conn_set_status(sess_id, KSMBD_SESS_NEED_NEGOTIATE); + return 0; + } + +@@ -6892,7 +6893,7 @@ int smb2_lock(struct ksmbd_work *work) + + nolock = 1; + /* check locks in connection list */ +- read_lock(&conn_list_lock); ++ down_read(&conn_list_lock); + list_for_each_entry(conn, &conn_list, conns_list) { + spin_lock(&conn->llist_lock); + list_for_each_entry_safe(cmp_lock, tmp2, &conn->lock_list, clist) { +@@ -6909,7 +6910,7 @@ int smb2_lock(struct ksmbd_work *work) + list_del(&cmp_lock->flist); + list_del(&cmp_lock->clist); + spin_unlock(&conn->llist_lock); +- read_unlock(&conn_list_lock); ++ up_read(&conn_list_lock); + + locks_free_lock(cmp_lock->fl); + kfree(cmp_lock); +@@ -6931,7 +6932,7 @@ int smb2_lock(struct ksmbd_work *work) + cmp_lock->start > smb_lock->start && + cmp_lock->start < smb_lock->end) { + spin_unlock(&conn->llist_lock); +- read_unlock(&conn_list_lock); ++ up_read(&conn_list_lock); + pr_err("previous lock conflict with zero byte lock range\n"); + goto out; + } +@@ -6940,7 +6941,7 @@ int smb2_lock(struct ksmbd_work *work) + smb_lock->start > cmp_lock->start && + smb_lock->start < cmp_lock->end) { + spin_unlock(&conn->llist_lock); +- read_unlock(&conn_list_lock); ++ up_read(&conn_list_lock); + pr_err("current lock conflict with zero byte lock range\n"); + goto out; + } +@@ -6951,14 +6952,14 @@ int smb2_lock(struct ksmbd_work *work) + cmp_lock->end >= smb_lock->end)) && + !cmp_lock->zero_len && !smb_lock->zero_len) { + spin_unlock(&conn->llist_lock); +- read_unlock(&conn_list_lock); ++ up_read(&conn_list_lock); + pr_err("Not allow lock operation on exclusive lock range\n"); + goto out; + } + } + spin_unlock(&conn->llist_lock); + } +- read_unlock(&conn_list_lock); ++ up_read(&conn_list_lock); + out_check_cl: + if (smb_lock->fl->fl_type == F_UNLCK && nolock) { + pr_err("Try to unlock nolocked range\n"); diff --git a/queue-5.15/ksmbd-fix-racy-issue-from-using-d_parent-and-d_name.patch b/queue-5.15/ksmbd-fix-racy-issue-from-using-d_parent-and-d_name.patch new file mode 100644 index 00000000000..a9e095f1770 --- /dev/null +++ b/queue-5.15/ksmbd-fix-racy-issue-from-using-d_parent-and-d_name.patch @@ -0,0 +1,1183 @@ +From linkinjeon@gmail.com Mon Dec 18 16:40:02 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:33:47 +0900 +Subject: ksmbd: fix racy issue from using ->d_parent and ->d_name +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-88-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit 74d7970febf7e9005375aeda0df821d2edffc9f7 ] + +Al pointed out that ksmbd has racy issue from using ->d_parent and ->d_name +in ksmbd_vfs_unlink and smb2_vfs_rename(). and use new lock_rename_child() +to lock stable parent while underlying rename racy. +Introduce vfs_path_parent_lookup helper to avoid out of share access and +export vfs functions like the following ones to use +vfs_path_parent_lookup(). + - rename __lookup_hash() to lookup_one_qstr_excl(). + - export lookup_one_qstr_excl(). + - export getname_kernel() and putname(). + +vfs_path_parent_lookup() is used for parent lookup of destination file +using absolute pathname given from FILE_RENAME_INFORMATION request. + +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/smb2pdu.c | 147 +++------------- + fs/ksmbd/vfs.c | 439 +++++++++++++++++++++----------------------------- + fs/ksmbd/vfs.h | 19 -- + fs/ksmbd/vfs_cache.c | 5 + fs/namei.c | 57 +++++- + include/linux/namei.h | 6 + 6 files changed, 285 insertions(+), 388 deletions(-) + +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -2456,7 +2456,7 @@ static int smb2_creat(struct ksmbd_work + return rc; + } + +- rc = ksmbd_vfs_kern_path(work, name, 0, path, 0); ++ rc = ksmbd_vfs_kern_path_locked(work, name, 0, path, 0); + if (rc) { + pr_err("cannot get linux path (%s), err = %d\n", + name, rc); +@@ -2744,8 +2744,10 @@ int smb2_open(struct ksmbd_work *work) + goto err_out1; + } + +- rc = ksmbd_vfs_kern_path(work, name, LOOKUP_NO_SYMLINKS, &path, 1); ++ rc = ksmbd_vfs_kern_path_locked(work, name, LOOKUP_NO_SYMLINKS, &path, 1); + if (!rc) { ++ file_present = true; ++ + if (req->CreateOptions & FILE_DELETE_ON_CLOSE_LE) { + /* + * If file exists with under flags, return access +@@ -2754,7 +2756,6 @@ int smb2_open(struct ksmbd_work *work) + if (req->CreateDisposition == FILE_OVERWRITE_IF_LE || + req->CreateDisposition == FILE_OPEN_IF_LE) { + rc = -EACCES; +- path_put(&path); + goto err_out; + } + +@@ -2762,26 +2763,23 @@ int smb2_open(struct ksmbd_work *work) + ksmbd_debug(SMB, + "User does not have write permission\n"); + rc = -EACCES; +- path_put(&path); + goto err_out; + } + } else if (d_is_symlink(path.dentry)) { + rc = -EACCES; +- path_put(&path); + goto err_out; + } +- } + +- if (rc) { ++ file_present = true; ++ user_ns = mnt_user_ns(path.mnt); ++ } else { + if (rc != -ENOENT) + goto err_out; + ksmbd_debug(SMB, "can not get linux path for %s, rc = %d\n", + name, rc); + rc = 0; +- } else { +- file_present = true; +- user_ns = mnt_user_ns(path.mnt); + } ++ + if (stream_name) { + if (req->CreateOptions & FILE_DIRECTORY_FILE_LE) { + if (s_type == DATA_STREAM) { +@@ -2909,8 +2907,9 @@ int smb2_open(struct ksmbd_work *work) + + if ((daccess & FILE_DELETE_LE) || + (req->CreateOptions & FILE_DELETE_ON_CLOSE_LE)) { +- rc = ksmbd_vfs_may_delete(user_ns, +- path.dentry); ++ rc = inode_permission(user_ns, ++ d_inode(path.dentry->d_parent), ++ MAY_EXEC | MAY_WRITE); + if (rc) + goto err_out; + } +@@ -3281,10 +3280,13 @@ int smb2_open(struct ksmbd_work *work) + } + + err_out: +- if (file_present || created) +- path_put(&path); ++ if (file_present || created) { ++ inode_unlock(d_inode(path.dentry->d_parent)); ++ dput(path.dentry); ++ } + ksmbd_revert_fsids(work); + err_out1: ++ + if (rc) { + if (rc == -EINVAL) + rsp->hdr.Status = STATUS_INVALID_PARAMETER; +@@ -5426,44 +5428,19 @@ int smb2_echo(struct ksmbd_work *work) + + static int smb2_rename(struct ksmbd_work *work, + struct ksmbd_file *fp, +- struct user_namespace *user_ns, + struct smb2_file_rename_info *file_info, + struct nls_table *local_nls) + { + struct ksmbd_share_config *share = fp->tcon->share_conf; +- char *new_name = NULL, *abs_oldname = NULL, *old_name = NULL; +- char *pathname = NULL; +- struct path path; +- bool file_present = true; +- int rc; ++ char *new_name = NULL; ++ int rc, flags = 0; + + ksmbd_debug(SMB, "setting FILE_RENAME_INFO\n"); +- pathname = kmalloc(PATH_MAX, GFP_KERNEL); +- if (!pathname) +- return -ENOMEM; +- +- abs_oldname = file_path(fp->filp, pathname, PATH_MAX); +- if (IS_ERR(abs_oldname)) { +- rc = -EINVAL; +- goto out; +- } +- old_name = strrchr(abs_oldname, '/'); +- if (old_name && old_name[1] != '\0') { +- old_name++; +- } else { +- ksmbd_debug(SMB, "can't get last component in path %s\n", +- abs_oldname); +- rc = -ENOENT; +- goto out; +- } +- + new_name = smb2_get_name(file_info->FileName, + le32_to_cpu(file_info->FileNameLength), + local_nls); +- if (IS_ERR(new_name)) { +- rc = PTR_ERR(new_name); +- goto out; +- } ++ if (IS_ERR(new_name)) ++ return PTR_ERR(new_name); + + if (strchr(new_name, ':')) { + int s_type; +@@ -5489,7 +5466,7 @@ static int smb2_rename(struct ksmbd_work + if (rc) + goto out; + +- rc = ksmbd_vfs_setxattr(user_ns, ++ rc = ksmbd_vfs_setxattr(file_mnt_user_ns(fp->filp), + fp->filp->f_path.dentry, + xattr_stream_name, + NULL, 0, 0); +@@ -5504,47 +5481,18 @@ static int smb2_rename(struct ksmbd_work + } + + ksmbd_debug(SMB, "new name %s\n", new_name); +- rc = ksmbd_vfs_kern_path(work, new_name, LOOKUP_NO_SYMLINKS, &path, 1); +- if (rc) { +- if (rc != -ENOENT) +- goto out; +- file_present = false; +- } else { +- path_put(&path); +- } +- + if (ksmbd_share_veto_filename(share, new_name)) { + rc = -ENOENT; + ksmbd_debug(SMB, "Can't rename vetoed file: %s\n", new_name); + goto out; + } + +- if (file_info->ReplaceIfExists) { +- if (file_present) { +- rc = ksmbd_vfs_remove_file(work, new_name); +- if (rc) { +- if (rc != -ENOTEMPTY) +- rc = -EINVAL; +- ksmbd_debug(SMB, "cannot delete %s, rc %d\n", +- new_name, rc); +- goto out; +- } +- } +- } else { +- if (file_present && +- strncmp(old_name, path.dentry->d_name.name, strlen(old_name))) { +- rc = -EEXIST; +- ksmbd_debug(SMB, +- "cannot rename already existing file\n"); +- goto out; +- } +- } ++ if (!file_info->ReplaceIfExists) ++ flags = RENAME_NOREPLACE; + +- rc = ksmbd_vfs_fp_rename(work, fp, new_name); ++ rc = ksmbd_vfs_rename(work, &fp->filp->f_path, new_name, flags); + out: +- kfree(pathname); +- if (!IS_ERR(new_name)) +- kfree(new_name); ++ kfree(new_name); + return rc; + } + +@@ -5584,18 +5532,17 @@ static int smb2_create_link(struct ksmbd + } + + ksmbd_debug(SMB, "target name is %s\n", target_name); +- rc = ksmbd_vfs_kern_path(work, link_name, LOOKUP_NO_SYMLINKS, &path, 0); ++ rc = ksmbd_vfs_kern_path_locked(work, link_name, LOOKUP_NO_SYMLINKS, ++ &path, 0); + if (rc) { + if (rc != -ENOENT) + goto out; + file_present = false; +- } else { +- path_put(&path); + } + + if (file_info->ReplaceIfExists) { + if (file_present) { +- rc = ksmbd_vfs_remove_file(work, link_name); ++ rc = ksmbd_vfs_remove_file(work, &path); + if (rc) { + rc = -EINVAL; + ksmbd_debug(SMB, "cannot delete %s\n", +@@ -5615,6 +5562,10 @@ static int smb2_create_link(struct ksmbd + if (rc) + rc = -EINVAL; + out: ++ if (file_present) { ++ inode_unlock(d_inode(path.dentry->d_parent)); ++ path_put(&path); ++ } + if (!IS_ERR(link_name)) + kfree(link_name); + kfree(pathname); +@@ -5792,12 +5743,6 @@ static int set_rename_info(struct ksmbd_ + struct smb2_file_rename_info *rename_info, + unsigned int buf_len) + { +- struct user_namespace *user_ns; +- struct ksmbd_file *parent_fp; +- struct dentry *parent; +- struct dentry *dentry = fp->filp->f_path.dentry; +- int ret; +- + if (!(fp->daccess & FILE_DELETE_LE)) { + pr_err("no right to delete : 0x%x\n", fp->daccess); + return -EACCES; +@@ -5807,32 +5752,10 @@ static int set_rename_info(struct ksmbd_ + le32_to_cpu(rename_info->FileNameLength)) + return -EINVAL; + +- user_ns = file_mnt_user_ns(fp->filp); +- if (ksmbd_stream_fd(fp)) +- goto next; ++ if (!le32_to_cpu(rename_info->FileNameLength)) ++ return -EINVAL; + +- parent = dget_parent(dentry); +- ret = ksmbd_vfs_lock_parent(user_ns, parent, dentry); +- if (ret) { +- dput(parent); +- return ret; +- } +- +- parent_fp = ksmbd_lookup_fd_inode(d_inode(parent)); +- inode_unlock(d_inode(parent)); +- dput(parent); +- +- if (parent_fp) { +- if (parent_fp->daccess & FILE_DELETE_LE) { +- pr_err("parent dir is opened with delete access\n"); +- ksmbd_fd_put(work, parent_fp); +- return -ESHARE; +- } +- ksmbd_fd_put(work, parent_fp); +- } +-next: +- return smb2_rename(work, fp, user_ns, rename_info, +- work->conn->local_nls); ++ return smb2_rename(work, fp, rename_info, work->conn->local_nls); + } + + static int set_file_disposition_info(struct ksmbd_file *fp, +--- a/fs/ksmbd/vfs.c ++++ b/fs/ksmbd/vfs.c +@@ -18,6 +18,7 @@ + #include + #include + #include ++#include + + #include "glob.h" + #include "oplock.h" +@@ -35,19 +36,6 @@ + #include "mgmt/user_session.h" + #include "mgmt/user_config.h" + +-static char *extract_last_component(char *path) +-{ +- char *p = strrchr(path, '/'); +- +- if (p && p[1] != '\0') { +- *p = '\0'; +- p++; +- } else { +- p = NULL; +- } +- return p; +-} +- + static void ksmbd_vfs_inherit_owner(struct ksmbd_work *work, + struct inode *parent_inode, + struct inode *inode) +@@ -61,65 +49,77 @@ static void ksmbd_vfs_inherit_owner(stru + + /** + * ksmbd_vfs_lock_parent() - lock parent dentry if it is stable +- * +- * the parent dentry got by dget_parent or @parent could be +- * unstable, we try to lock a parent inode and lookup the +- * child dentry again. +- * +- * the reference count of @parent isn't incremented. + */ +-int ksmbd_vfs_lock_parent(struct user_namespace *user_ns, struct dentry *parent, +- struct dentry *child) ++int ksmbd_vfs_lock_parent(struct dentry *parent, struct dentry *child) + { +- struct dentry *dentry; +- int ret = 0; +- + inode_lock_nested(d_inode(parent), I_MUTEX_PARENT); +- dentry = lookup_one(user_ns, child->d_name.name, parent, +- child->d_name.len); +- if (IS_ERR(dentry)) { +- ret = PTR_ERR(dentry); +- goto out_err; +- } +- +- if (dentry != child) { +- ret = -ESTALE; +- dput(dentry); +- goto out_err; ++ if (child->d_parent != parent) { ++ inode_unlock(d_inode(parent)); ++ return -ENOENT; + } + +- dput(dentry); + return 0; +-out_err: +- inode_unlock(d_inode(parent)); +- return ret; + } + +-int ksmbd_vfs_may_delete(struct user_namespace *user_ns, +- struct dentry *dentry) +-{ +- struct dentry *parent; +- int ret; ++static int ksmbd_vfs_path_lookup_locked(struct ksmbd_share_config *share_conf, ++ char *pathname, unsigned int flags, ++ struct path *path) ++{ ++ struct qstr last; ++ struct filename *filename; ++ struct path *root_share_path = &share_conf->vfs_path; ++ int err, type; ++ struct path parent_path; ++ struct dentry *d; ++ ++ if (pathname[0] == '\0') { ++ pathname = share_conf->path; ++ root_share_path = NULL; ++ } else { ++ flags |= LOOKUP_BENEATH; ++ } + +- parent = dget_parent(dentry); +- ret = ksmbd_vfs_lock_parent(user_ns, parent, dentry); +- if (ret) { +- dput(parent); +- return ret; ++ filename = getname_kernel(pathname); ++ if (IS_ERR(filename)) ++ return PTR_ERR(filename); ++ ++ err = vfs_path_parent_lookup(filename, flags, ++ &parent_path, &last, &type, ++ root_share_path); ++ putname(filename); ++ if (err) ++ return err; ++ ++ if (unlikely(type != LAST_NORM)) { ++ path_put(&parent_path); ++ return -ENOENT; + } + +- ret = inode_permission(user_ns, d_inode(parent), +- MAY_EXEC | MAY_WRITE); ++ inode_lock_nested(parent_path.dentry->d_inode, I_MUTEX_PARENT); ++ d = lookup_one_qstr_excl(&last, parent_path.dentry, 0); ++ if (IS_ERR(d)) ++ goto err_out; + +- inode_unlock(d_inode(parent)); +- dput(parent); +- return ret; ++ if (d_is_negative(d)) { ++ dput(d); ++ goto err_out; ++ } ++ ++ path->dentry = d; ++ path->mnt = share_conf->vfs_path.mnt; ++ path_put(&parent_path); ++ ++ return 0; ++ ++err_out: ++ inode_unlock(parent_path.dentry->d_inode); ++ path_put(&parent_path); ++ return -ENOENT; + } + + int ksmbd_vfs_query_maximal_access(struct user_namespace *user_ns, + struct dentry *dentry, __le32 *daccess) + { +- struct dentry *parent; + int ret = 0; + + *daccess = cpu_to_le32(FILE_READ_ATTRIBUTES | READ_CONTROL); +@@ -136,18 +136,9 @@ int ksmbd_vfs_query_maximal_access(struc + if (!inode_permission(user_ns, d_inode(dentry), MAY_OPEN | MAY_EXEC)) + *daccess |= FILE_EXECUTE_LE; + +- parent = dget_parent(dentry); +- ret = ksmbd_vfs_lock_parent(user_ns, parent, dentry); +- if (ret) { +- dput(parent); +- return ret; +- } +- +- if (!inode_permission(user_ns, d_inode(parent), MAY_EXEC | MAY_WRITE)) ++ if (!inode_permission(user_ns, d_inode(dentry->d_parent), MAY_EXEC | MAY_WRITE)) + *daccess |= FILE_DELETE_LE; + +- inode_unlock(d_inode(parent)); +- dput(parent); + return ret; + } + +@@ -580,54 +571,32 @@ int ksmbd_vfs_fsync(struct ksmbd_work *w + * + * Return: 0 on success, otherwise error + */ +-int ksmbd_vfs_remove_file(struct ksmbd_work *work, char *name) ++int ksmbd_vfs_remove_file(struct ksmbd_work *work, const struct path *path) + { + struct user_namespace *user_ns; +- struct path path; +- struct dentry *parent; ++ struct dentry *parent = path->dentry->d_parent; + int err; + + if (ksmbd_override_fsids(work)) + return -ENOMEM; + +- err = ksmbd_vfs_kern_path(work, name, LOOKUP_NO_SYMLINKS, &path, false); +- if (err) { +- ksmbd_debug(VFS, "can't get %s, err %d\n", name, err); +- ksmbd_revert_fsids(work); +- return err; +- } +- +- user_ns = mnt_user_ns(path.mnt); +- parent = dget_parent(path.dentry); +- err = ksmbd_vfs_lock_parent(user_ns, parent, path.dentry); +- if (err) { +- dput(parent); +- path_put(&path); +- ksmbd_revert_fsids(work); +- return err; +- } +- +- if (!d_inode(path.dentry)->i_nlink) { ++ if (!d_inode(path->dentry)->i_nlink) { + err = -ENOENT; + goto out_err; + } + +- if (S_ISDIR(d_inode(path.dentry)->i_mode)) { +- err = vfs_rmdir(user_ns, d_inode(parent), path.dentry); ++ user_ns = mnt_user_ns(path->mnt); ++ if (S_ISDIR(d_inode(path->dentry)->i_mode)) { ++ err = vfs_rmdir(user_ns, d_inode(parent), path->dentry); + if (err && err != -ENOTEMPTY) +- ksmbd_debug(VFS, "%s: rmdir failed, err %d\n", name, +- err); ++ ksmbd_debug(VFS, "rmdir failed, err %d\n", err); + } else { +- err = vfs_unlink(user_ns, d_inode(parent), path.dentry, NULL); ++ err = vfs_unlink(user_ns, d_inode(parent), path->dentry, NULL); + if (err) +- ksmbd_debug(VFS, "%s: unlink failed, err %d\n", name, +- err); ++ ksmbd_debug(VFS, "unlink failed, err %d\n", err); + } + + out_err: +- inode_unlock(d_inode(parent)); +- dput(parent); +- path_put(&path); + ksmbd_revert_fsids(work); + return err; + } +@@ -686,149 +655,114 @@ out1: + return err; + } + +-static int ksmbd_validate_entry_in_use(struct dentry *src_dent) ++int ksmbd_vfs_rename(struct ksmbd_work *work, const struct path *old_path, ++ char *newname, int flags) + { +- struct dentry *dst_dent; +- +- spin_lock(&src_dent->d_lock); +- list_for_each_entry(dst_dent, &src_dent->d_subdirs, d_child) { +- struct ksmbd_file *child_fp; ++ struct dentry *old_parent, *new_dentry, *trap; ++ struct dentry *old_child = old_path->dentry; ++ struct path new_path; ++ struct qstr new_last; ++ struct renamedata rd; ++ struct filename *to; ++ struct ksmbd_share_config *share_conf = work->tcon->share_conf; ++ struct ksmbd_file *parent_fp; ++ int new_type; ++ int err, lookup_flags = LOOKUP_NO_SYMLINKS; + +- if (d_really_is_negative(dst_dent)) +- continue; ++ if (ksmbd_override_fsids(work)) ++ return -ENOMEM; + +- child_fp = ksmbd_lookup_fd_inode(d_inode(dst_dent)); +- if (child_fp) { +- spin_unlock(&src_dent->d_lock); +- ksmbd_debug(VFS, "Forbid rename, sub file/dir is in use\n"); +- return -EACCES; +- } ++ to = getname_kernel(newname); ++ if (IS_ERR(to)) { ++ err = PTR_ERR(to); ++ goto revert_fsids; + } +- spin_unlock(&src_dent->d_lock); + +- return 0; +-} +- +-static int __ksmbd_vfs_rename(struct ksmbd_work *work, +- struct user_namespace *src_user_ns, +- struct dentry *src_dent_parent, +- struct dentry *src_dent, +- struct user_namespace *dst_user_ns, +- struct dentry *dst_dent_parent, +- struct dentry *trap_dent, +- char *dst_name) +-{ +- struct dentry *dst_dent; +- int err; ++retry: ++ err = vfs_path_parent_lookup(to, lookup_flags | LOOKUP_BENEATH, ++ &new_path, &new_last, &new_type, ++ &share_conf->vfs_path); ++ if (err) ++ goto out1; + +- if (!work->tcon->posix_extensions) { +- err = ksmbd_validate_entry_in_use(src_dent); +- if (err) +- return err; ++ if (old_path->mnt != new_path.mnt) { ++ err = -EXDEV; ++ goto out2; + } + +- if (d_really_is_negative(src_dent_parent)) +- return -ENOENT; +- if (d_really_is_negative(dst_dent_parent)) +- return -ENOENT; +- if (d_really_is_negative(src_dent)) +- return -ENOENT; +- if (src_dent == trap_dent) +- return -EINVAL; ++ trap = lock_rename_child(old_child, new_path.dentry); + +- if (ksmbd_override_fsids(work)) +- return -ENOMEM; ++ old_parent = dget(old_child->d_parent); ++ if (d_unhashed(old_child)) { ++ err = -EINVAL; ++ goto out3; ++ } + +- dst_dent = lookup_one(dst_user_ns, dst_name, dst_dent_parent, +- strlen(dst_name)); +- err = PTR_ERR(dst_dent); +- if (IS_ERR(dst_dent)) { +- pr_err("lookup failed %s [%d]\n", dst_name, err); +- goto out; ++ parent_fp = ksmbd_lookup_fd_inode(d_inode(old_child->d_parent)); ++ if (parent_fp) { ++ if (parent_fp->daccess & FILE_DELETE_LE) { ++ pr_err("parent dir is opened with delete access\n"); ++ err = -ESHARE; ++ ksmbd_fd_put(work, parent_fp); ++ goto out3; ++ } ++ ksmbd_fd_put(work, parent_fp); + } + +- err = -ENOTEMPTY; +- if (dst_dent != trap_dent && !d_really_is_positive(dst_dent)) { +- struct renamedata rd = { +- .old_mnt_userns = src_user_ns, +- .old_dir = d_inode(src_dent_parent), +- .old_dentry = src_dent, +- .new_mnt_userns = dst_user_ns, +- .new_dir = d_inode(dst_dent_parent), +- .new_dentry = dst_dent, +- }; +- err = vfs_rename(&rd); ++ new_dentry = lookup_one_qstr_excl(&new_last, new_path.dentry, ++ lookup_flags | LOOKUP_RENAME_TARGET); ++ if (IS_ERR(new_dentry)) { ++ err = PTR_ERR(new_dentry); ++ goto out3; + } +- if (err) +- pr_err("vfs_rename failed err %d\n", err); +- if (dst_dent) +- dput(dst_dent); +-out: +- ksmbd_revert_fsids(work); +- return err; +-} + +-int ksmbd_vfs_fp_rename(struct ksmbd_work *work, struct ksmbd_file *fp, +- char *newname) +-{ +- struct user_namespace *user_ns; +- struct path dst_path; +- struct dentry *src_dent_parent, *dst_dent_parent; +- struct dentry *src_dent, *trap_dent, *src_child; +- char *dst_name; +- int err; ++ if (d_is_symlink(new_dentry)) { ++ err = -EACCES; ++ goto out4; ++ } + +- dst_name = extract_last_component(newname); +- if (!dst_name) { +- dst_name = newname; +- newname = ""; ++ if ((flags & RENAME_NOREPLACE) && d_is_positive(new_dentry)) { ++ err = -EEXIST; ++ goto out4; + } + +- src_dent_parent = dget_parent(fp->filp->f_path.dentry); +- src_dent = fp->filp->f_path.dentry; +- +- err = ksmbd_vfs_kern_path(work, newname, +- LOOKUP_NO_SYMLINKS | LOOKUP_DIRECTORY, +- &dst_path, false); +- if (err) { +- ksmbd_debug(VFS, "Cannot get path for %s [%d]\n", newname, err); +- goto out; ++ if (old_child == trap) { ++ err = -EINVAL; ++ goto out4; + } +- dst_dent_parent = dst_path.dentry; + +- trap_dent = lock_rename(src_dent_parent, dst_dent_parent); +- dget(src_dent); +- dget(dst_dent_parent); +- user_ns = file_mnt_user_ns(fp->filp); +- src_child = lookup_one(user_ns, src_dent->d_name.name, src_dent_parent, +- src_dent->d_name.len); +- if (IS_ERR(src_child)) { +- err = PTR_ERR(src_child); +- goto out_lock; +- } +- +- if (src_child != src_dent) { +- err = -ESTALE; +- dput(src_child); +- goto out_lock; +- } +- dput(src_child); +- +- err = __ksmbd_vfs_rename(work, +- user_ns, +- src_dent_parent, +- src_dent, +- mnt_user_ns(dst_path.mnt), +- dst_dent_parent, +- trap_dent, +- dst_name); +-out_lock: +- dput(src_dent); +- dput(dst_dent_parent); +- unlock_rename(src_dent_parent, dst_dent_parent); +- path_put(&dst_path); +-out: +- dput(src_dent_parent); ++ if (new_dentry == trap) { ++ err = -ENOTEMPTY; ++ goto out4; ++ } ++ ++ rd.old_mnt_userns = mnt_user_ns(old_path->mnt), ++ rd.old_dir = d_inode(old_parent), ++ rd.old_dentry = old_child, ++ rd.new_mnt_userns = mnt_user_ns(new_path.mnt), ++ rd.new_dir = new_path.dentry->d_inode, ++ rd.new_dentry = new_dentry, ++ rd.flags = flags, ++ err = vfs_rename(&rd); ++ if (err) ++ ksmbd_debug(VFS, "vfs_rename failed err %d\n", err); ++ ++out4: ++ dput(new_dentry); ++out3: ++ dput(old_parent); ++ unlock_rename(old_parent, new_path.dentry); ++out2: ++ path_put(&new_path); ++ ++ if (retry_estale(err, lookup_flags)) { ++ lookup_flags |= LOOKUP_REVAL; ++ goto retry; ++ } ++out1: ++ putname(to); ++revert_fsids: ++ ksmbd_revert_fsids(work); + return err; + } + +@@ -1079,14 +1013,16 @@ int ksmbd_vfs_remove_xattr(struct user_n + return vfs_removexattr(user_ns, dentry, attr_name); + } + +-int ksmbd_vfs_unlink(struct user_namespace *user_ns, +- struct dentry *dir, struct dentry *dentry) ++int ksmbd_vfs_unlink(struct file *filp) + { + int err = 0; ++ struct dentry *dir, *dentry = filp->f_path.dentry; ++ struct user_namespace *user_ns = file_mnt_user_ns(filp); + +- err = ksmbd_vfs_lock_parent(user_ns, dir, dentry); ++ dir = dget_parent(dentry); ++ err = ksmbd_vfs_lock_parent(dir, dentry); + if (err) +- return err; ++ goto out; + dget(dentry); + + if (S_ISDIR(d_inode(dentry)->i_mode)) +@@ -1098,6 +1034,8 @@ int ksmbd_vfs_unlink(struct user_namespa + inode_unlock(d_inode(dir)); + if (err) + ksmbd_debug(VFS, "failed to delete, err %d\n", err); ++out: ++ dput(dir); + + return err; + } +@@ -1202,7 +1140,7 @@ static int ksmbd_vfs_lookup_in_dir(const + } + + /** +- * ksmbd_vfs_kern_path() - lookup a file and get path info ++ * ksmbd_vfs_kern_path_locked() - lookup a file and get path info + * @name: file path that is relative to share + * @flags: lookup flags + * @path: if lookup succeed, return path info +@@ -1210,24 +1148,20 @@ static int ksmbd_vfs_lookup_in_dir(const + * + * Return: 0 on success, otherwise error + */ +-int ksmbd_vfs_kern_path(struct ksmbd_work *work, char *name, +- unsigned int flags, struct path *path, bool caseless) ++int ksmbd_vfs_kern_path_locked(struct ksmbd_work *work, char *name, ++ unsigned int flags, struct path *path, ++ bool caseless) + { + struct ksmbd_share_config *share_conf = work->tcon->share_conf; + int err; ++ struct path parent_path; + +- flags |= LOOKUP_BENEATH; +- err = vfs_path_lookup(share_conf->vfs_path.dentry, +- share_conf->vfs_path.mnt, +- name, +- flags, +- path); ++ err = ksmbd_vfs_path_lookup_locked(share_conf, name, flags, path); + if (!err) +- return 0; ++ return err; + + if (caseless) { + char *filepath; +- struct path parent; + size_t path_len, remain_len; + + filepath = kstrdup(name, GFP_KERNEL); +@@ -1237,10 +1171,10 @@ int ksmbd_vfs_kern_path(struct ksmbd_wor + path_len = strlen(filepath); + remain_len = path_len; + +- parent = share_conf->vfs_path; +- path_get(&parent); ++ parent_path = share_conf->vfs_path; ++ path_get(&parent_path); + +- while (d_can_lookup(parent.dentry)) { ++ while (d_can_lookup(parent_path.dentry)) { + char *filename = filepath + path_len - remain_len; + char *next = strchrnul(filename, '/'); + size_t filename_len = next - filename; +@@ -1249,12 +1183,11 @@ int ksmbd_vfs_kern_path(struct ksmbd_wor + if (filename_len == 0) + break; + +- err = ksmbd_vfs_lookup_in_dir(&parent, filename, ++ err = ksmbd_vfs_lookup_in_dir(&parent_path, filename, + filename_len, + work->conn->um); +- path_put(&parent); + if (err) +- goto out; ++ goto out2; + + next[0] = '\0'; + +@@ -1262,23 +1195,31 @@ int ksmbd_vfs_kern_path(struct ksmbd_wor + share_conf->vfs_path.mnt, + filepath, + flags, +- &parent); ++ path); + if (err) +- goto out; +- else if (is_last) { +- *path = parent; +- goto out; +- } ++ goto out2; ++ else if (is_last) ++ goto out1; ++ path_put(&parent_path); ++ parent_path = *path; + + next[0] = '/'; + remain_len -= filename_len + 1; + } + +- path_put(&parent); + err = -EINVAL; +-out: ++out2: ++ path_put(&parent_path); ++out1: + kfree(filepath); + } ++ ++ if (!err) { ++ err = ksmbd_vfs_lock_parent(parent_path.dentry, path->dentry); ++ if (err) ++ dput(path->dentry); ++ path_put(&parent_path); ++ } + return err; + } + +--- a/fs/ksmbd/vfs.h ++++ b/fs/ksmbd/vfs.h +@@ -110,9 +110,7 @@ struct ksmbd_kstat { + __le32 file_attributes; + }; + +-int ksmbd_vfs_lock_parent(struct user_namespace *user_ns, struct dentry *parent, +- struct dentry *child); +-int ksmbd_vfs_may_delete(struct user_namespace *user_ns, struct dentry *dentry); ++int ksmbd_vfs_lock_parent(struct dentry *parent, struct dentry *child); + int ksmbd_vfs_query_maximal_access(struct user_namespace *user_ns, + struct dentry *dentry, __le32 *daccess); + int ksmbd_vfs_create(struct ksmbd_work *work, const char *name, umode_t mode); +@@ -123,12 +121,12 @@ int ksmbd_vfs_write(struct ksmbd_work *w + char *buf, size_t count, loff_t *pos, bool sync, + ssize_t *written); + int ksmbd_vfs_fsync(struct ksmbd_work *work, u64 fid, u64 p_id); +-int ksmbd_vfs_remove_file(struct ksmbd_work *work, char *name); ++int ksmbd_vfs_remove_file(struct ksmbd_work *work, const struct path *path); + int ksmbd_vfs_link(struct ksmbd_work *work, + const char *oldname, const char *newname); + int ksmbd_vfs_getattr(const struct path *path, struct kstat *stat); +-int ksmbd_vfs_fp_rename(struct ksmbd_work *work, struct ksmbd_file *fp, +- char *newname); ++int ksmbd_vfs_rename(struct ksmbd_work *work, const struct path *old_path, ++ char *newname, int flags); + int ksmbd_vfs_truncate(struct ksmbd_work *work, + struct ksmbd_file *fp, loff_t size); + struct srv_copychunk; +@@ -155,9 +153,9 @@ int ksmbd_vfs_xattr_stream_name(char *st + size_t *xattr_stream_name_size, int s_type); + int ksmbd_vfs_remove_xattr(struct user_namespace *user_ns, + struct dentry *dentry, char *attr_name); +-int ksmbd_vfs_kern_path(struct ksmbd_work *work, +- char *name, unsigned int flags, struct path *path, +- bool caseless); ++int ksmbd_vfs_kern_path_locked(struct ksmbd_work *work, char *name, ++ unsigned int flags, struct path *path, ++ bool caseless); + struct dentry *ksmbd_vfs_kern_path_create(struct ksmbd_work *work, + const char *name, + unsigned int flags, +@@ -170,8 +168,7 @@ struct file_allocated_range_buffer; + int ksmbd_vfs_fqar_lseek(struct ksmbd_file *fp, loff_t start, loff_t length, + struct file_allocated_range_buffer *ranges, + unsigned int in_count, unsigned int *out_count); +-int ksmbd_vfs_unlink(struct user_namespace *user_ns, +- struct dentry *dir, struct dentry *dentry); ++int ksmbd_vfs_unlink(struct file *filp); + void *ksmbd_vfs_init_kstat(char **p, struct ksmbd_kstat *ksmbd_kstat); + int ksmbd_vfs_fill_dentry_attrs(struct ksmbd_work *work, + struct user_namespace *user_ns, +--- a/fs/ksmbd/vfs_cache.c ++++ b/fs/ksmbd/vfs_cache.c +@@ -243,7 +243,6 @@ void ksmbd_release_inode_hash(void) + + static void __ksmbd_inode_close(struct ksmbd_file *fp) + { +- struct dentry *dir, *dentry; + struct ksmbd_inode *ci = fp->f_ci; + int err; + struct file *filp; +@@ -262,11 +261,9 @@ static void __ksmbd_inode_close(struct k + if (atomic_dec_and_test(&ci->m_count)) { + write_lock(&ci->m_lock); + if (ci->m_flags & (S_DEL_ON_CLS | S_DEL_PENDING)) { +- dentry = filp->f_path.dentry; +- dir = dentry->d_parent; + ci->m_flags &= ~(S_DEL_ON_CLS | S_DEL_PENDING); + write_unlock(&ci->m_lock); +- ksmbd_vfs_unlink(file_mnt_user_ns(filp), dir, dentry); ++ ksmbd_vfs_unlink(filp); + write_lock(&ci->m_lock); + } + write_unlock(&ci->m_lock); +--- a/fs/namei.c ++++ b/fs/namei.c +@@ -252,6 +252,7 @@ getname_kernel(const char * filename) + + return result; + } ++EXPORT_SYMBOL(getname_kernel); + + void putname(struct filename *name) + { +@@ -269,6 +270,7 @@ void putname(struct filename *name) + } else + __putname(name); + } ++EXPORT_SYMBOL(putname); + + /** + * check_acl - perform ACL permission checking +@@ -1539,8 +1541,9 @@ static struct dentry *lookup_dcache(cons + * when directory is guaranteed to have no in-lookup children + * at all. + */ +-static struct dentry *__lookup_hash(const struct qstr *name, +- struct dentry *base, unsigned int flags) ++struct dentry *lookup_one_qstr_excl(const struct qstr *name, ++ struct dentry *base, ++ unsigned int flags) + { + struct dentry *dentry = lookup_dcache(name, base, flags); + struct dentry *old; +@@ -1564,6 +1567,7 @@ static struct dentry *__lookup_hash(cons + } + return dentry; + } ++EXPORT_SYMBOL(lookup_one_qstr_excl); + + static struct dentry *lookup_fast(struct nameidata *nd, + struct inode **inode, +@@ -2508,16 +2512,17 @@ static int path_parentat(struct nameidat + } + + /* Note: this does not consume "name" */ +-static int filename_parentat(int dfd, struct filename *name, +- unsigned int flags, struct path *parent, +- struct qstr *last, int *type) ++static int __filename_parentat(int dfd, struct filename *name, ++ unsigned int flags, struct path *parent, ++ struct qstr *last, int *type, ++ const struct path *root) + { + int retval; + struct nameidata nd; + + if (IS_ERR(name)) + return PTR_ERR(name); +- set_nameidata(&nd, dfd, name, NULL); ++ set_nameidata(&nd, dfd, name, root); + retval = path_parentat(&nd, flags | LOOKUP_RCU, parent); + if (unlikely(retval == -ECHILD)) + retval = path_parentat(&nd, flags, parent); +@@ -2532,6 +2537,13 @@ static int filename_parentat(int dfd, st + return retval; + } + ++static int filename_parentat(int dfd, struct filename *name, ++ unsigned int flags, struct path *parent, ++ struct qstr *last, int *type) ++{ ++ return __filename_parentat(dfd, name, flags, parent, last, type, NULL); ++} ++ + /* does lookup, returns the object with parent locked */ + static struct dentry *__kern_path_locked(struct filename *name, struct path *path) + { +@@ -2547,7 +2559,7 @@ static struct dentry *__kern_path_locked + return ERR_PTR(-EINVAL); + } + inode_lock_nested(path->dentry->d_inode, I_MUTEX_PARENT); +- d = __lookup_hash(&last, path->dentry, 0); ++ d = lookup_one_qstr_excl(&last, path->dentry, 0); + if (IS_ERR(d)) { + inode_unlock(path->dentry->d_inode); + path_put(path); +@@ -2576,6 +2588,24 @@ int kern_path(const char *name, unsigned + EXPORT_SYMBOL(kern_path); + + /** ++ * vfs_path_parent_lookup - lookup a parent path relative to a dentry-vfsmount pair ++ * @filename: filename structure ++ * @flags: lookup flags ++ * @parent: pointer to struct path to fill ++ * @last: last component ++ * @type: type of the last component ++ * @root: pointer to struct path of the base directory ++ */ ++int vfs_path_parent_lookup(struct filename *filename, unsigned int flags, ++ struct path *parent, struct qstr *last, int *type, ++ const struct path *root) ++{ ++ return __filename_parentat(AT_FDCWD, filename, flags, parent, last, ++ type, root); ++} ++EXPORT_SYMBOL(vfs_path_parent_lookup); ++ ++/** + * vfs_path_lookup - lookup a file path relative to a dentry-vfsmount pair + * @dentry: pointer to dentry of the base directory + * @mnt: pointer to vfs mount of the base directory +@@ -3809,7 +3839,8 @@ static struct dentry *filename_create(in + if (last.name[last.len] && !want_dir) + create_flags = 0; + inode_lock_nested(path->dentry->d_inode, I_MUTEX_PARENT); +- dentry = __lookup_hash(&last, path->dentry, reval_flag | create_flags); ++ dentry = lookup_one_qstr_excl(&last, path->dentry, ++ reval_flag | create_flags); + if (IS_ERR(dentry)) + goto unlock; + +@@ -4170,7 +4201,7 @@ retry: + goto exit2; + + inode_lock_nested(path.dentry->d_inode, I_MUTEX_PARENT); +- dentry = __lookup_hash(&last, path.dentry, lookup_flags); ++ dentry = lookup_one_qstr_excl(&last, path.dentry, lookup_flags); + error = PTR_ERR(dentry); + if (IS_ERR(dentry)) + goto exit3; +@@ -4304,7 +4335,7 @@ retry: + goto exit2; + retry_deleg: + inode_lock_nested(path.dentry->d_inode, I_MUTEX_PARENT); +- dentry = __lookup_hash(&last, path.dentry, lookup_flags); ++ dentry = lookup_one_qstr_excl(&last, path.dentry, lookup_flags); + error = PTR_ERR(dentry); + if (!IS_ERR(dentry)) { + struct user_namespace *mnt_userns; +@@ -4878,7 +4909,8 @@ retry: + retry_deleg: + trap = lock_rename(new_path.dentry, old_path.dentry); + +- old_dentry = __lookup_hash(&old_last, old_path.dentry, lookup_flags); ++ old_dentry = lookup_one_qstr_excl(&old_last, old_path.dentry, ++ lookup_flags); + error = PTR_ERR(old_dentry); + if (IS_ERR(old_dentry)) + goto exit3; +@@ -4886,7 +4918,8 @@ retry_deleg: + error = -ENOENT; + if (d_is_negative(old_dentry)) + goto exit4; +- new_dentry = __lookup_hash(&new_last, new_path.dentry, lookup_flags | target_flags); ++ new_dentry = lookup_one_qstr_excl(&new_last, new_path.dentry, ++ lookup_flags | target_flags); + error = PTR_ERR(new_dentry); + if (IS_ERR(new_dentry)) + goto exit4; +--- a/include/linux/namei.h ++++ b/include/linux/namei.h +@@ -57,12 +57,18 @@ static inline int user_path_at(int dfd, + return user_path_at_empty(dfd, name, flags, path, NULL); + } + ++struct dentry *lookup_one_qstr_excl(const struct qstr *name, ++ struct dentry *base, ++ unsigned int flags); + extern int kern_path(const char *, unsigned, struct path *); + + extern struct dentry *kern_path_create(int, const char *, struct path *, unsigned int); + extern struct dentry *user_path_create(int, const char __user *, struct path *, unsigned int); + extern void done_path_create(struct path *, struct dentry *); + extern struct dentry *kern_path_locked(const char *, struct path *); ++int vfs_path_parent_lookup(struct filename *filename, unsigned int flags, ++ struct path *parent, struct qstr *last, int *type, ++ const struct path *root); + int vfs_path_lookup(struct dentry *, struct vfsmount *, const char *, + unsigned int, struct path *); + diff --git a/queue-5.15/ksmbd-fix-racy-issue-under-cocurrent-smb2-tree-disconnect.patch b/queue-5.15/ksmbd-fix-racy-issue-under-cocurrent-smb2-tree-disconnect.patch new file mode 100644 index 00000000000..de90540c9d4 --- /dev/null +++ b/queue-5.15/ksmbd-fix-racy-issue-under-cocurrent-smb2-tree-disconnect.patch @@ -0,0 +1,81 @@ +From linkinjeon@gmail.com Mon Dec 18 16:40:17 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:33:52 +0900 +Subject: ksmbd: fix racy issue under cocurrent smb2 tree disconnect +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , zdi-disclosures@trendmicro.com, Steve French +Message-ID: <20231218153454.8090-93-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit 30210947a343b6b3ca13adc9bfc88e1543e16dd5 ] + +There is UAF issue under cocurrent smb2 tree disconnect. +This patch introduce TREE_CONN_EXPIRE flags for tcon to avoid cocurrent +access. + +Cc: stable@vger.kernel.org +Reported-by: zdi-disclosures@trendmicro.com # ZDI-CAN-20592 +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/mgmt/tree_connect.c | 10 +++++++++- + fs/ksmbd/mgmt/tree_connect.h | 3 +++ + fs/ksmbd/smb2pdu.c | 3 ++- + 3 files changed, 14 insertions(+), 2 deletions(-) + +--- a/fs/ksmbd/mgmt/tree_connect.c ++++ b/fs/ksmbd/mgmt/tree_connect.c +@@ -109,7 +109,15 @@ int ksmbd_tree_conn_disconnect(struct ks + struct ksmbd_tree_connect *ksmbd_tree_conn_lookup(struct ksmbd_session *sess, + unsigned int id) + { +- return xa_load(&sess->tree_conns, id); ++ struct ksmbd_tree_connect *tcon; ++ ++ tcon = xa_load(&sess->tree_conns, id); ++ if (tcon) { ++ if (test_bit(TREE_CONN_EXPIRE, &tcon->status)) ++ tcon = NULL; ++ } ++ ++ return tcon; + } + + struct ksmbd_share_config *ksmbd_tree_conn_share(struct ksmbd_session *sess, +--- a/fs/ksmbd/mgmt/tree_connect.h ++++ b/fs/ksmbd/mgmt/tree_connect.h +@@ -14,6 +14,8 @@ struct ksmbd_share_config; + struct ksmbd_user; + struct ksmbd_conn; + ++#define TREE_CONN_EXPIRE 1 ++ + struct ksmbd_tree_connect { + int id; + +@@ -25,6 +27,7 @@ struct ksmbd_tree_connect { + + int maximal_access; + bool posix_extensions; ++ unsigned long status; + }; + + struct ksmbd_tree_conn_status { +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -2083,11 +2083,12 @@ int smb2_tree_disconnect(struct ksmbd_wo + + ksmbd_debug(SMB, "request\n"); + +- if (!tcon) { ++ if (!tcon || test_and_set_bit(TREE_CONN_EXPIRE, &tcon->status)) { + struct smb2_tree_disconnect_req *req = + smb2_get_msg(work->request_buf); + + ksmbd_debug(SMB, "Invalid tid %d\n", req->hdr.Id.SyncId.TreeId); ++ + rsp->hdr.Status = STATUS_NETWORK_NAME_DELETED; + smb2_set_err_rsp(work); + return 0; diff --git a/queue-5.15/ksmbd-fix-recursive-locking-in-vfs-helpers.patch b/queue-5.15/ksmbd-fix-recursive-locking-in-vfs-helpers.patch new file mode 100644 index 00000000000..f1d2cc62af1 --- /dev/null +++ b/queue-5.15/ksmbd-fix-recursive-locking-in-vfs-helpers.patch @@ -0,0 +1,143 @@ +From linkinjeon@gmail.com Mon Dec 18 16:43:00 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:34:42 +0900 +Subject: ksmbd: fix recursive locking in vfs helpers +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Marios Makassikis , Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-143-linkinjeon@kernel.org> + +From: Marios Makassikis + +[ Upstream commit 807252f028c59b9a3bac4d62ad84761548c10f11 ] + +Running smb2.rename test from Samba smbtorture suite against a kernel built +with lockdep triggers a "possible recursive locking detected" warning. + +This is because mnt_want_write() is called twice with no mnt_drop_write() +in between: + -> ksmbd_vfs_mkdir() + -> ksmbd_vfs_kern_path_create() + -> kern_path_create() + -> filename_create() + -> mnt_want_write() + -> mnt_want_write() + +Fix this by removing the mnt_want_write/mnt_drop_write calls from vfs +helpers that call kern_path_create(). + +Full lockdep trace below: + +============================================ +WARNING: possible recursive locking detected +6.6.0-rc5 #775 Not tainted +-------------------------------------------- +kworker/1:1/32 is trying to acquire lock: +ffff888005ac83f8 (sb_writers#5){.+.+}-{0:0}, at: ksmbd_vfs_mkdir+0xe1/0x410 + +but task is already holding lock: +ffff888005ac83f8 (sb_writers#5){.+.+}-{0:0}, at: filename_create+0xb6/0x260 + +other info that might help us debug this: + Possible unsafe locking scenario: + + CPU0 + ---- + lock(sb_writers#5); + lock(sb_writers#5); + + *** DEADLOCK *** + + May be due to missing lock nesting notation + +4 locks held by kworker/1:1/32: + #0: ffff8880064e4138 ((wq_completion)ksmbd-io){+.+.}-{0:0}, at: process_one_work+0x40e/0x980 + #1: ffff888005b0fdd0 ((work_completion)(&work->work)){+.+.}-{0:0}, at: process_one_work+0x40e/0x980 + #2: ffff888005ac83f8 (sb_writers#5){.+.+}-{0:0}, at: filename_create+0xb6/0x260 + #3: ffff8880057ce760 (&type->i_mutex_dir_key#3/1){+.+.}-{3:3}, at: filename_create+0x123/0x260 + +Cc: stable@vger.kernel.org +Fixes: 40b268d384a2 ("ksmbd: add mnt_want_write to ksmbd vfs functions") +Signed-off-by: Marios Makassikis +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/vfs.c | 23 +++-------------------- + 1 file changed, 3 insertions(+), 20 deletions(-) + +--- a/fs/ksmbd/vfs.c ++++ b/fs/ksmbd/vfs.c +@@ -173,10 +173,6 @@ int ksmbd_vfs_create(struct ksmbd_work * + return err; + } + +- err = mnt_want_write(path.mnt); +- if (err) +- goto out_err; +- + mode |= S_IFREG; + err = vfs_create(mnt_user_ns(path.mnt), d_inode(path.dentry), + dentry, mode, true); +@@ -186,9 +182,7 @@ int ksmbd_vfs_create(struct ksmbd_work * + } else { + pr_err("File(%s): creation failed (err:%d)\n", name, err); + } +- mnt_drop_write(path.mnt); + +-out_err: + done_path_create(&path, dentry); + return err; + } +@@ -219,10 +213,6 @@ int ksmbd_vfs_mkdir(struct ksmbd_work *w + return err; + } + +- err = mnt_want_write(path.mnt); +- if (err) +- goto out_err2; +- + user_ns = mnt_user_ns(path.mnt); + mode |= S_IFDIR; + err = vfs_mkdir(user_ns, d_inode(path.dentry), dentry, mode); +@@ -233,21 +223,19 @@ int ksmbd_vfs_mkdir(struct ksmbd_work *w + dentry->d_name.len); + if (IS_ERR(d)) { + err = PTR_ERR(d); +- goto out_err1; ++ goto out_err; + } + if (unlikely(d_is_negative(d))) { + dput(d); + err = -ENOENT; +- goto out_err1; ++ goto out_err; + } + + ksmbd_vfs_inherit_owner(work, d_inode(path.dentry), d_inode(d)); + dput(d); + } + +-out_err1: +- mnt_drop_write(path.mnt); +-out_err2: ++out_err: + done_path_create(&path, dentry); + if (err) + pr_err("mkdir(%s): creation failed (err:%d)\n", name, err); +@@ -665,16 +653,11 @@ int ksmbd_vfs_link(struct ksmbd_work *wo + goto out3; + } + +- err = mnt_want_write(newpath.mnt); +- if (err) +- goto out3; +- + err = vfs_link(oldpath.dentry, mnt_user_ns(newpath.mnt), + d_inode(newpath.dentry), + dentry, NULL); + if (err) + ksmbd_debug(VFS, "vfs_link failed err %d\n", err); +- mnt_drop_write(newpath.mnt); + + out3: + done_path_create(&newpath, dentry); diff --git a/queue-5.15/ksmbd-fix-resource-leak-in-smb2_lock.patch b/queue-5.15/ksmbd-fix-resource-leak-in-smb2_lock.patch new file mode 100644 index 00000000000..df09ba61215 --- /dev/null +++ b/queue-5.15/ksmbd-fix-resource-leak-in-smb2_lock.patch @@ -0,0 +1,57 @@ +From linkinjeon@gmail.com Mon Dec 18 16:38:59 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:33:27 +0900 +Subject: ksmbd: Fix resource leak in smb2_lock() +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Marios Makassikis , Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-68-linkinjeon@kernel.org> + +From: Marios Makassikis + +[ Upstream commit 01f6c61bae3d658058ee6322af77acea26a5ee3a ] + +"flock" is leaked if an error happens before smb2_lock_init(), as the +lock is not added to the lock_list to be cleaned up. + +Signed-off-by: Marios Makassikis +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/smb2pdu.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -6907,6 +6907,7 @@ int smb2_lock(struct ksmbd_work *work) + if (lock_start > U64_MAX - lock_length) { + pr_err("Invalid lock range requested\n"); + rsp->hdr.Status = STATUS_INVALID_LOCK_RANGE; ++ locks_free_lock(flock); + goto out; + } + +@@ -6926,6 +6927,7 @@ int smb2_lock(struct ksmbd_work *work) + "the end offset(%llx) is smaller than the start offset(%llx)\n", + flock->fl_end, flock->fl_start); + rsp->hdr.Status = STATUS_INVALID_LOCK_RANGE; ++ locks_free_lock(flock); + goto out; + } + +@@ -6937,6 +6939,7 @@ int smb2_lock(struct ksmbd_work *work) + flock->fl_type != F_UNLCK) { + pr_err("conflict two locks in one request\n"); + err = -EINVAL; ++ locks_free_lock(flock); + goto out; + } + } +@@ -6945,6 +6948,7 @@ int smb2_lock(struct ksmbd_work *work) + smb_lock = smb2_lock_init(flock, cmd, flags, &lock_list); + if (!smb_lock) { + err = -EINVAL; ++ locks_free_lock(flock); + goto out; + } + } diff --git a/queue-5.15/ksmbd-fix-slab-out-of-bounds-in-init_smb2_rsp_hdr.patch b/queue-5.15/ksmbd-fix-slab-out-of-bounds-in-init_smb2_rsp_hdr.patch new file mode 100644 index 00000000000..3742a13d5b7 --- /dev/null +++ b/queue-5.15/ksmbd-fix-slab-out-of-bounds-in-init_smb2_rsp_hdr.patch @@ -0,0 +1,282 @@ +From linkinjeon@gmail.com Mon Dec 18 16:39:42 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:33:41 +0900 +Subject: ksmbd: fix slab-out-of-bounds in init_smb2_rsp_hdr +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-82-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit dc8289f912387c3bcfbc5d2db29c8947fa207c11 ] + +When smb1 mount fails, KASAN detect slab-out-of-bounds in +init_smb2_rsp_hdr like the following one. +For smb1 negotiate(56bytes) , init_smb2_rsp_hdr() for smb2 is called. +The issue occurs while handling smb1 negotiate as smb2 server operations. +Add smb server operations for smb1 (get_cmd_val, init_rsp_hdr, +allocate_rsp_buf, check_user_session) to handle smb1 negotiate so that +smb2 server operation does not handle it. + +[ 411.400423] CIFS: VFS: Use of the less secure dialect vers=1.0 is +not recommended unless required for access to very old servers +[ 411.400452] CIFS: Attempting to mount \\192.168.45.139\homes +[ 411.479312] ksmbd: init_smb2_rsp_hdr : 492 +[ 411.479323] ================================================================== +[ 411.479327] BUG: KASAN: slab-out-of-bounds in +init_smb2_rsp_hdr+0x1e2/0x1f4 [ksmbd] +[ 411.479369] Read of size 16 at addr ffff888488ed0734 by task kworker/14:1/199 + +[ 411.479379] CPU: 14 PID: 199 Comm: kworker/14:1 Tainted: G + OE 6.1.21 #3 +[ 411.479386] Hardware name: ASUSTeK COMPUTER INC. Z10PA-D8 +Series/Z10PA-D8 Series, BIOS 3801 08/23/2019 +[ 411.479390] Workqueue: ksmbd-io handle_ksmbd_work [ksmbd] +[ 411.479425] Call Trace: +[ 411.479428] +[ 411.479432] dump_stack_lvl+0x49/0x63 +[ 411.479444] print_report+0x171/0x4a8 +[ 411.479452] ? kasan_complete_mode_report_info+0x3c/0x200 +[ 411.479463] ? init_smb2_rsp_hdr+0x1e2/0x1f4 [ksmbd] +[ 411.479497] kasan_report+0xb4/0x130 +[ 411.479503] ? init_smb2_rsp_hdr+0x1e2/0x1f4 [ksmbd] +[ 411.479537] kasan_check_range+0x149/0x1e0 +[ 411.479543] memcpy+0x24/0x70 +[ 411.479550] init_smb2_rsp_hdr+0x1e2/0x1f4 [ksmbd] +[ 411.479585] handle_ksmbd_work+0x109/0x760 [ksmbd] +[ 411.479616] ? _raw_spin_unlock_irqrestore+0x50/0x50 +[ 411.479624] ? smb3_encrypt_resp+0x340/0x340 [ksmbd] +[ 411.479656] process_one_work+0x49c/0x790 +[ 411.479667] worker_thread+0x2b1/0x6e0 +[ 411.479674] ? process_one_work+0x790/0x790 +[ 411.479680] kthread+0x177/0x1b0 +[ 411.479686] ? kthread_complete_and_exit+0x30/0x30 +[ 411.479692] ret_from_fork+0x22/0x30 +[ 411.479702] + +Fixes: 39b291b86b59 ("ksmbd: return unsupported error on smb1 mount") +Cc: stable@vger.kernel.org +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/server.c | 5 - + fs/ksmbd/smb2pdu.c | 3 - + fs/ksmbd/smb_common.c | 138 +++++++++++++++++++++++++++++++++++++++----------- + fs/ksmbd/smb_common.h | 2 + 4 files changed, 111 insertions(+), 37 deletions(-) + +--- a/fs/ksmbd/server.c ++++ b/fs/ksmbd/server.c +@@ -296,10 +296,7 @@ static int queue_ksmbd_work(struct ksmbd + work->request_buf = conn->request_buf; + conn->request_buf = NULL; + +- if (ksmbd_init_smb_server(work)) { +- ksmbd_free_work_struct(work); +- return -EINVAL; +- } ++ ksmbd_init_smb_server(work); + + ksmbd_conn_enqueue_request(work); + atomic_inc(&conn->r_count); +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -246,9 +246,6 @@ int init_smb2_neg_rsp(struct ksmbd_work + struct smb2_negotiate_rsp *rsp; + struct ksmbd_conn *conn = work->conn; + +- if (conn->need_neg == false) +- return -EINVAL; +- + *(__be32 *)work->response_buf = + cpu_to_be32(conn->vals->header_size); + +--- a/fs/ksmbd/smb_common.c ++++ b/fs/ksmbd/smb_common.c +@@ -283,20 +283,121 @@ err_out: + return BAD_PROT_ID; + } + +-int ksmbd_init_smb_server(struct ksmbd_work *work) ++#define SMB_COM_NEGOTIATE_EX 0x0 ++ ++/** ++ * get_smb1_cmd_val() - get smb command value from smb header ++ * @work: smb work containing smb header ++ * ++ * Return: smb command value ++ */ ++static u16 get_smb1_cmd_val(struct ksmbd_work *work) + { +- struct ksmbd_conn *conn = work->conn; ++ return SMB_COM_NEGOTIATE_EX; ++} + +- if (conn->need_neg == false) ++/** ++ * init_smb1_rsp_hdr() - initialize smb negotiate response header ++ * @work: smb work containing smb request ++ * ++ * Return: 0 on success, otherwise -EINVAL ++ */ ++static int init_smb1_rsp_hdr(struct ksmbd_work *work) ++{ ++ struct smb_hdr *rsp_hdr = (struct smb_hdr *)work->response_buf; ++ struct smb_hdr *rcv_hdr = (struct smb_hdr *)work->request_buf; ++ ++ /* ++ * Remove 4 byte direct TCP header. ++ */ ++ *(__be32 *)work->response_buf = ++ cpu_to_be32(sizeof(struct smb_hdr) - 4); ++ ++ rsp_hdr->Command = SMB_COM_NEGOTIATE; ++ *(__le32 *)rsp_hdr->Protocol = SMB1_PROTO_NUMBER; ++ rsp_hdr->Flags = SMBFLG_RESPONSE; ++ rsp_hdr->Flags2 = SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS | ++ SMBFLG2_EXT_SEC | SMBFLG2_IS_LONG_NAME; ++ rsp_hdr->Pid = rcv_hdr->Pid; ++ rsp_hdr->Mid = rcv_hdr->Mid; ++ return 0; ++} ++ ++/** ++ * smb1_check_user_session() - check for valid session for a user ++ * @work: smb work containing smb request buffer ++ * ++ * Return: 0 on success, otherwise error ++ */ ++static int smb1_check_user_session(struct ksmbd_work *work) ++{ ++ unsigned int cmd = work->conn->ops->get_cmd_val(work); ++ ++ if (cmd == SMB_COM_NEGOTIATE_EX) + return 0; + +- init_smb3_11_server(conn); ++ return -EINVAL; ++} ++ ++/** ++ * smb1_allocate_rsp_buf() - allocate response buffer for a command ++ * @work: smb work containing smb request ++ * ++ * Return: 0 on success, otherwise -ENOMEM ++ */ ++static int smb1_allocate_rsp_buf(struct ksmbd_work *work) ++{ ++ work->response_buf = kmalloc(MAX_CIFS_SMALL_BUFFER_SIZE, ++ GFP_KERNEL | __GFP_ZERO); ++ work->response_sz = MAX_CIFS_SMALL_BUFFER_SIZE; ++ ++ if (!work->response_buf) { ++ pr_err("Failed to allocate %u bytes buffer\n", ++ MAX_CIFS_SMALL_BUFFER_SIZE); ++ return -ENOMEM; ++ } + +- if (conn->ops->get_cmd_val(work) != SMB_COM_NEGOTIATE) +- conn->need_neg = false; + return 0; + } + ++static struct smb_version_ops smb1_server_ops = { ++ .get_cmd_val = get_smb1_cmd_val, ++ .init_rsp_hdr = init_smb1_rsp_hdr, ++ .allocate_rsp_buf = smb1_allocate_rsp_buf, ++ .check_user_session = smb1_check_user_session, ++}; ++ ++static int smb1_negotiate(struct ksmbd_work *work) ++{ ++ return ksmbd_smb_negotiate_common(work, SMB_COM_NEGOTIATE); ++} ++ ++static struct smb_version_cmds smb1_server_cmds[1] = { ++ [SMB_COM_NEGOTIATE_EX] = { .proc = smb1_negotiate, }, ++}; ++ ++static void init_smb1_server(struct ksmbd_conn *conn) ++{ ++ conn->ops = &smb1_server_ops; ++ conn->cmds = smb1_server_cmds; ++ conn->max_cmds = ARRAY_SIZE(smb1_server_cmds); ++} ++ ++void ksmbd_init_smb_server(struct ksmbd_work *work) ++{ ++ struct ksmbd_conn *conn = work->conn; ++ __le32 proto; ++ ++ if (conn->need_neg == false) ++ return; ++ ++ proto = *(__le32 *)((struct smb_hdr *)work->request_buf)->Protocol; ++ if (proto == SMB1_PROTO_NUMBER) ++ init_smb1_server(conn); ++ else ++ init_smb3_11_server(conn); ++} ++ + int ksmbd_populate_dot_dotdot_entries(struct ksmbd_work *work, int info_level, + struct ksmbd_file *dir, + struct ksmbd_dir_info *d_info, +@@ -444,20 +545,10 @@ static int smb_handle_negotiate(struct k + + ksmbd_debug(SMB, "Unsupported SMB1 protocol\n"); + +- /* +- * Remove 4 byte direct TCP header, add 2 byte bcc and +- * 2 byte DialectIndex. +- */ +- *(__be32 *)work->response_buf = +- cpu_to_be32(sizeof(struct smb_hdr) - 4 + 2 + 2); ++ /* Add 2 byte bcc and 2 byte DialectIndex. */ ++ inc_rfc1001_len(work->response_buf, 4); + neg_rsp->hdr.Status.CifsError = STATUS_SUCCESS; + +- neg_rsp->hdr.Command = SMB_COM_NEGOTIATE; +- *(__le32 *)neg_rsp->hdr.Protocol = SMB1_PROTO_NUMBER; +- neg_rsp->hdr.Flags = SMBFLG_RESPONSE; +- neg_rsp->hdr.Flags2 = SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS | +- SMBFLG2_EXT_SEC | SMBFLG2_IS_LONG_NAME; +- + neg_rsp->hdr.WordCount = 1; + neg_rsp->DialectIndex = cpu_to_le16(work->conn->dialect); + neg_rsp->ByteCount = 0; +@@ -474,23 +565,12 @@ int ksmbd_smb_negotiate_common(struct ks + ksmbd_debug(SMB, "conn->dialect 0x%x\n", conn->dialect); + + if (command == SMB2_NEGOTIATE_HE) { +- struct smb2_hdr *smb2_hdr = smb2_get_msg(work->request_buf); +- +- if (smb2_hdr->ProtocolId != SMB2_PROTO_NUMBER) { +- ksmbd_debug(SMB, "Downgrade to SMB1 negotiation\n"); +- command = SMB_COM_NEGOTIATE; +- } +- } +- +- if (command == SMB2_NEGOTIATE_HE) { + ret = smb2_handle_negotiate(work); +- init_smb2_neg_rsp(work); + return ret; + } + + if (command == SMB_COM_NEGOTIATE) { + if (__smb2_negotiate(conn)) { +- conn->need_neg = true; + init_smb3_11_server(conn); + init_smb2_neg_rsp(work); + ksmbd_debug(SMB, "Upgrade to SMB2 negotiation\n"); +--- a/fs/ksmbd/smb_common.h ++++ b/fs/ksmbd/smb_common.h +@@ -474,7 +474,7 @@ bool ksmbd_smb_request(struct ksmbd_conn + + int ksmbd_lookup_dialect_by_id(__le16 *cli_dialects, __le16 dialects_count); + +-int ksmbd_init_smb_server(struct ksmbd_work *work); ++void ksmbd_init_smb_server(struct ksmbd_work *work); + + struct ksmbd_kstat; + int ksmbd_populate_dot_dotdot_entries(struct ksmbd_work *work, diff --git a/queue-5.15/ksmbd-fix-slub-overflow-in-ksmbd_decode_ntlmssp_auth_blob.patch b/queue-5.15/ksmbd-fix-slub-overflow-in-ksmbd_decode_ntlmssp_auth_blob.patch new file mode 100644 index 00000000000..db115dfac56 --- /dev/null +++ b/queue-5.15/ksmbd-fix-slub-overflow-in-ksmbd_decode_ntlmssp_auth_blob.patch @@ -0,0 +1,37 @@ +From linkinjeon@gmail.com Mon Dec 18 16:42:01 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:34:24 +0900 +Subject: ksmbd: fix slub overflow in ksmbd_decode_ntlmssp_auth_blob() +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , zdi-disclosures@trendmicro.com, Steve French +Message-ID: <20231218153454.8090-125-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit 4b081ce0d830b684fdf967abc3696d1261387254 ] + +If authblob->SessionKey.Length is bigger than session key +size(CIFS_KEY_SIZE), slub overflow can happen in key exchange codes. +cifs_arc4_crypt copy to session key array from SessionKey from client. + +Cc: stable@vger.kernel.org +Reported-by: zdi-disclosures@trendmicro.com # ZDI-CAN-21940 +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/auth.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/fs/ksmbd/auth.c ++++ b/fs/ksmbd/auth.c +@@ -355,6 +355,9 @@ int ksmbd_decode_ntlmssp_auth_blob(struc + if (blob_len < (u64)sess_key_off + sess_key_len) + return -EINVAL; + ++ if (sess_key_len > CIFS_KEY_SIZE) ++ return -EINVAL; ++ + ctx_arc4 = kmalloc(sizeof(*ctx_arc4), GFP_KERNEL); + if (!ctx_arc4) + return -ENOMEM; diff --git a/queue-5.15/ksmbd-fix-smb2_get_name-kernel-doc-comment.patch b/queue-5.15/ksmbd-fix-smb2_get_name-kernel-doc-comment.patch new file mode 100644 index 00000000000..787e107bc2c --- /dev/null +++ b/queue-5.15/ksmbd-fix-smb2_get_name-kernel-doc-comment.patch @@ -0,0 +1,39 @@ +From stable+bounces-7644-greg=kroah.com@vger.kernel.org Mon Dec 18 16:37:20 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:32:35 +0900 +Subject: ksmbd: Fix smb2_get_name() kernel-doc comment +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Yang Li , Abaci Robot , Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-16-linkinjeon@kernel.org> + +From: Yang Li + +[ Upstream commit d4eeb82674acadf789277b577986e8e7d3faf695 ] + +Remove some warnings found by running scripts/kernel-doc, +which is caused by using 'make W=1'. +fs/ksmbd/smb2pdu.c:623: warning: Function parameter or member +'local_nls' not described in 'smb2_get_name' +fs/ksmbd/smb2pdu.c:623: warning: Excess function parameter 'nls_table' +description in 'smb2_get_name' + +Reported-by: Abaci Robot +Acked-by: Namjae Jeon +Signed-off-by: Yang Li +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/smb2pdu.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -653,7 +653,7 @@ static void destroy_previous_session(str + * smb2_get_name() - get filename string from on the wire smb format + * @src: source buffer + * @maxlen: maxlen of source string +- * @nls_table: nls_table pointer ++ * @local_nls: nls_table pointer + * + * Return: matching converted filename on success, otherwise error ptr + */ diff --git a/queue-5.15/ksmbd-fix-smb2_set_info_file-kernel-doc-comment.patch b/queue-5.15/ksmbd-fix-smb2_set_info_file-kernel-doc-comment.patch new file mode 100644 index 00000000000..9177e0c9671 --- /dev/null +++ b/queue-5.15/ksmbd-fix-smb2_set_info_file-kernel-doc-comment.patch @@ -0,0 +1,43 @@ +From stable+bounces-7642-greg=kroah.com@vger.kernel.org Mon Dec 18 16:36:29 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:32:33 +0900 +Subject: ksmbd: Fix smb2_set_info_file() kernel-doc comment +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Yang Li , Abaci Robot , Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-14-linkinjeon@kernel.org> + +From: Yang Li + +[ Upstream commit 4bfd9eed15e163969156e976c62db5ef423e5b0f ] + +Fix argument list that the kdoc format and script verified in +smb2_set_info_file(). + +The warnings were found by running scripts/kernel-doc, which is +caused by using 'make W=1'. +fs/ksmbd/smb2pdu.c:5862: warning: Function parameter or member 'req' not +described in 'smb2_set_info_file' +fs/ksmbd/smb2pdu.c:5862: warning: Excess function parameter 'info_class' +description in 'smb2_set_info_file' + +Reported-by: Abaci Robot +Fixes: 9496e268e3af ("ksmbd: add request buffer validation in smb2_set_info") +Acked-by: Namjae Jeon +Signed-off-by: Yang Li +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/smb2pdu.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -5932,7 +5932,7 @@ static int set_file_mode_info(struct ksm + * smb2_set_info_file() - handler for smb2 set info command + * @work: smb work containing set info command buffer + * @fp: ksmbd_file pointer +- * @info_class: smb2 set info class ++ * @req: request buffer pointer + * @share: ksmbd_share_config pointer + * + * Return: 0 on success, otherwise error diff --git a/queue-5.15/ksmbd-fix-some-kernel-doc-comments.patch b/queue-5.15/ksmbd-fix-some-kernel-doc-comments.patch new file mode 100644 index 00000000000..640937a061a --- /dev/null +++ b/queue-5.15/ksmbd-fix-some-kernel-doc-comments.patch @@ -0,0 +1,78 @@ +From linkinjeon@gmail.com Mon Dec 18 16:37:27 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:32:59 +0900 +Subject: ksmbd: Fix some kernel-doc comments +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Yang Li , Abaci Robot , Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-40-linkinjeon@kernel.org> + +From: Yang Li + +[ Upstream commit 7820c6ee029548290b318e522eb2578516d05393 ] + +Remove some warnings found by running scripts/kernel-doc, +which is caused by using 'make W=1'. + +fs/ksmbd/misc.c:30: warning: Function parameter or member 'str' not +described in 'match_pattern' +fs/ksmbd/misc.c:30: warning: Excess function parameter 'string' +description in 'match_pattern' +fs/ksmbd/misc.c:163: warning: Function parameter or member 'share' not +described in 'convert_to_nt_pathname' +fs/ksmbd/misc.c:163: warning: Function parameter or member 'path' not +described in 'convert_to_nt_pathname' +fs/ksmbd/misc.c:163: warning: Excess function parameter 'filename' +description in 'convert_to_nt_pathname' +fs/ksmbd/misc.c:163: warning: Excess function parameter 'sharepath' +description in 'convert_to_nt_pathname' +fs/ksmbd/misc.c:259: warning: Function parameter or member 'share' not +described in 'convert_to_unix_name' +fs/ksmbd/misc.c:259: warning: Function parameter or member 'name' not +described in 'convert_to_unix_name' +fs/ksmbd/misc.c:259: warning: Excess function parameter 'path' +description in 'convert_to_unix_name' +fs/ksmbd/misc.c:259: warning: Excess function parameter 'tid' +description in 'convert_to_unix_name' + +Reported-by: Abaci Robot +Signed-off-by: Yang Li +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/misc.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +--- a/fs/ksmbd/misc.c ++++ b/fs/ksmbd/misc.c +@@ -20,7 +20,7 @@ + * wildcard '*' and '?' + * TODO : implement consideration about DOS_DOT, DOS_QM and DOS_STAR + * +- * @string: string to compare with a pattern ++ * @str: string to compare with a pattern + * @len: string length + * @pattern: pattern string which might include wildcard '*' and '?' + * +@@ -152,8 +152,8 @@ out: + /** + * convert_to_nt_pathname() - extract and return windows path string + * whose share directory prefix was removed from file path +- * @filename : unix filename +- * @sharepath: share path string ++ * @share: ksmbd_share_config pointer ++ * @path: path to report + * + * Return : windows path string or error + */ +@@ -250,8 +250,8 @@ char *ksmbd_extract_sharename(char *tree + + /** + * convert_to_unix_name() - convert windows name to unix format +- * @path: name to be converted +- * @tid: tree id of mathing share ++ * @share: ksmbd_share_config pointer ++ * @name: file name that is relative to share + * + * Return: converted name on success, otherwise NULL + */ diff --git a/queue-5.15/ksmbd-fix-spelling-mistake-excceed-exceeded.patch b/queue-5.15/ksmbd-fix-spelling-mistake-excceed-exceeded.patch new file mode 100644 index 00000000000..e09e32dd250 --- /dev/null +++ b/queue-5.15/ksmbd-fix-spelling-mistake-excceed-exceeded.patch @@ -0,0 +1,33 @@ +From linkinjeon@gmail.com Mon Dec 18 16:39:25 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:33:35 +0900 +Subject: ksmbd: Fix spelling mistake "excceed" -> "exceeded" +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Colin Ian King , Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-76-linkinjeon@kernel.org> + +From: Colin Ian King + +[ Upstream commit 7a17c61ee3b2683c40090179c273f4701fca9677 ] + +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 +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/connection.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- 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; diff --git a/queue-5.15/ksmbd-fix-typo-syncronous-synchronous.patch b/queue-5.15/ksmbd-fix-typo-syncronous-synchronous.patch new file mode 100644 index 00000000000..f32197f5dc8 --- /dev/null +++ b/queue-5.15/ksmbd-fix-typo-syncronous-synchronous.patch @@ -0,0 +1,76 @@ +From linkinjeon@gmail.com Mon Dec 18 16:39:14 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:33:32 +0900 +Subject: ksmbd: fix typo, syncronous->synchronous +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Dawei Li , Namjae Jeon , Sergey Senozhatsky , Steve French +Message-ID: <20231218153454.8090-73-linkinjeon@kernel.org> + +From: Dawei Li + +[ Upstream commit f8d6e7442aa716a233c7eba99dec628f8885e00b ] + +syncronous->synchronous + +Signed-off-by: Dawei Li +Acked-by: Namjae Jeon +Reviewed-by: Sergey Senozhatsky +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/connection.c | 4 ++-- + fs/ksmbd/ksmbd_work.h | 2 +- + fs/ksmbd/smb2pdu.c | 4 ++-- + 3 files changed, 5 insertions(+), 5 deletions(-) + +--- a/fs/ksmbd/connection.c ++++ b/fs/ksmbd/connection.c +@@ -114,7 +114,7 @@ void ksmbd_conn_enqueue_request(struct k + + 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(struc + 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; + } +--- 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; +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -512,7 +512,7 @@ int init_smb2_rsp_hdr(struct ksmbd_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; +@@ -675,7 +675,7 @@ int setup_async_work(struct ksmbd_work * + 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); + diff --git a/queue-5.15/ksmbd-fix-uaf-issue-from-opinfo-conn.patch b/queue-5.15/ksmbd-fix-uaf-issue-from-opinfo-conn.patch new file mode 100644 index 00000000000..f84e5bbf7dc --- /dev/null +++ b/queue-5.15/ksmbd-fix-uaf-issue-from-opinfo-conn.patch @@ -0,0 +1,196 @@ +From linkinjeon@gmail.com Mon Dec 18 16:40:30 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:33:56 +0900 +Subject: ksmbd: fix UAF issue from opinfo->conn +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , Per Forlin , Steve French +Message-ID: <20231218153454.8090-97-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit 36322523dddb11107e9f7f528675a0dec2536103 ] + +If opinfo->conn is another connection and while ksmbd send oplock break +request to cient on current connection, The connection for opinfo->conn +can be disconnect and conn could be freed. When sending oplock break +request, this ksmbd_conn can be used and cause user-after-free issue. +When getting opinfo from the list, ksmbd check connection is being +released. If it is not released, Increase ->r_count to wait that connection +is freed. + +Cc: stable@vger.kernel.org +Reported-by: Per Forlin +Tested-by: Per Forlin +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/oplock.c | 72 +++++++++++++++++++++++++++++++++++------------------- + 1 file changed, 47 insertions(+), 25 deletions(-) + +--- a/fs/ksmbd/oplock.c ++++ b/fs/ksmbd/oplock.c +@@ -157,13 +157,42 @@ static struct oplock_info *opinfo_get_li + rcu_read_lock(); + opinfo = list_first_or_null_rcu(&ci->m_op_list, struct oplock_info, + op_entry); +- if (opinfo && !atomic_inc_not_zero(&opinfo->refcount)) +- opinfo = NULL; ++ if (opinfo) { ++ if (!atomic_inc_not_zero(&opinfo->refcount)) ++ opinfo = NULL; ++ else { ++ atomic_inc(&opinfo->conn->r_count); ++ if (ksmbd_conn_releasing(opinfo->conn)) { ++ atomic_dec(&opinfo->conn->r_count); ++ atomic_dec(&opinfo->refcount); ++ opinfo = NULL; ++ } ++ } ++ } ++ + rcu_read_unlock(); + + return opinfo; + } + ++static void opinfo_conn_put(struct oplock_info *opinfo) ++{ ++ struct ksmbd_conn *conn; ++ ++ if (!opinfo) ++ return; ++ ++ conn = opinfo->conn; ++ /* ++ * Checking waitqueue to dropping pending requests on ++ * disconnection. waitqueue_active is safe because it ++ * uses atomic operation for condition. ++ */ ++ if (!atomic_dec_return(&conn->r_count) && waitqueue_active(&conn->r_count_q)) ++ wake_up(&conn->r_count_q); ++ opinfo_put(opinfo); ++} ++ + void opinfo_put(struct oplock_info *opinfo) + { + if (!atomic_dec_and_test(&opinfo->refcount)) +@@ -666,13 +695,6 @@ static void __smb2_oplock_break_noti(str + + out: + ksmbd_free_work_struct(work); +- /* +- * Checking waitqueue to dropping pending requests on +- * disconnection. waitqueue_active is safe because it +- * uses atomic operation for condition. +- */ +- if (!atomic_dec_return(&conn->r_count) && waitqueue_active(&conn->r_count_q)) +- wake_up(&conn->r_count_q); + } + + /** +@@ -706,7 +728,6 @@ static int smb2_oplock_break_noti(struct + work->conn = conn; + work->sess = opinfo->sess; + +- atomic_inc(&conn->r_count); + if (opinfo->op_state == OPLOCK_ACK_WAIT) { + INIT_WORK(&work->work, __smb2_oplock_break_noti); + ksmbd_queue_work(work); +@@ -776,13 +797,6 @@ static void __smb2_lease_break_noti(stru + + out: + ksmbd_free_work_struct(work); +- /* +- * Checking waitqueue to dropping pending requests on +- * disconnection. waitqueue_active is safe because it +- * uses atomic operation for condition. +- */ +- if (!atomic_dec_return(&conn->r_count) && waitqueue_active(&conn->r_count_q)) +- wake_up(&conn->r_count_q); + } + + /** +@@ -822,7 +836,6 @@ static int smb2_lease_break_noti(struct + work->conn = conn; + work->sess = opinfo->sess; + +- atomic_inc(&conn->r_count); + if (opinfo->op_state == OPLOCK_ACK_WAIT) { + list_for_each_safe(tmp, t, &opinfo->interim_list) { + struct ksmbd_work *in_work; +@@ -1144,8 +1157,10 @@ int smb_grant_oplock(struct ksmbd_work * + } + prev_opinfo = opinfo_get_list(ci); + if (!prev_opinfo || +- (prev_opinfo->level == SMB2_OPLOCK_LEVEL_NONE && lctx)) ++ (prev_opinfo->level == SMB2_OPLOCK_LEVEL_NONE && lctx)) { ++ opinfo_conn_put(prev_opinfo); + goto set_lev; ++ } + prev_op_has_lease = prev_opinfo->is_lease; + if (prev_op_has_lease) + prev_op_state = prev_opinfo->o_lease->state; +@@ -1153,19 +1168,19 @@ int smb_grant_oplock(struct ksmbd_work * + if (share_ret < 0 && + prev_opinfo->level == SMB2_OPLOCK_LEVEL_EXCLUSIVE) { + err = share_ret; +- opinfo_put(prev_opinfo); ++ opinfo_conn_put(prev_opinfo); + goto err_out; + } + + if (prev_opinfo->level != SMB2_OPLOCK_LEVEL_BATCH && + prev_opinfo->level != SMB2_OPLOCK_LEVEL_EXCLUSIVE) { +- opinfo_put(prev_opinfo); ++ opinfo_conn_put(prev_opinfo); + goto op_break_not_needed; + } + + list_add(&work->interim_entry, &prev_opinfo->interim_list); + err = oplock_break(prev_opinfo, SMB2_OPLOCK_LEVEL_II); +- opinfo_put(prev_opinfo); ++ opinfo_conn_put(prev_opinfo); + if (err == -ENOENT) + goto set_lev; + /* Check all oplock was freed by close */ +@@ -1228,14 +1243,14 @@ static void smb_break_all_write_oplock(s + return; + if (brk_opinfo->level != SMB2_OPLOCK_LEVEL_BATCH && + brk_opinfo->level != SMB2_OPLOCK_LEVEL_EXCLUSIVE) { +- opinfo_put(brk_opinfo); ++ opinfo_conn_put(brk_opinfo); + return; + } + + brk_opinfo->open_trunc = is_trunc; + list_add(&work->interim_entry, &brk_opinfo->interim_list); + oplock_break(brk_opinfo, SMB2_OPLOCK_LEVEL_II); +- opinfo_put(brk_opinfo); ++ opinfo_conn_put(brk_opinfo); + } + + /** +@@ -1263,6 +1278,13 @@ void smb_break_all_levII_oplock(struct k + list_for_each_entry_rcu(brk_op, &ci->m_op_list, op_entry) { + if (!atomic_inc_not_zero(&brk_op->refcount)) + continue; ++ ++ atomic_inc(&brk_op->conn->r_count); ++ if (ksmbd_conn_releasing(brk_op->conn)) { ++ atomic_dec(&brk_op->conn->r_count); ++ continue; ++ } ++ + rcu_read_unlock(); + if (brk_op->is_lease && (brk_op->o_lease->state & + (~(SMB2_LEASE_READ_CACHING_LE | +@@ -1292,7 +1314,7 @@ void smb_break_all_levII_oplock(struct k + brk_op->open_trunc = is_trunc; + oplock_break(brk_op, SMB2_OPLOCK_LEVEL_NONE); + next: +- opinfo_put(brk_op); ++ opinfo_conn_put(brk_op); + rcu_read_lock(); + } + rcu_read_unlock(); diff --git a/queue-5.15/ksmbd-fix-uninitialized-pointer-read-in-ksmbd_vfs_rename.patch b/queue-5.15/ksmbd-fix-uninitialized-pointer-read-in-ksmbd_vfs_rename.patch new file mode 100644 index 00000000000..ab8a7b5758e --- /dev/null +++ b/queue-5.15/ksmbd-fix-uninitialized-pointer-read-in-ksmbd_vfs_rename.patch @@ -0,0 +1,35 @@ +From linkinjeon@gmail.com Mon Dec 18 16:40:20 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:33:53 +0900 +Subject: ksmbd: fix uninitialized pointer read in ksmbd_vfs_rename() +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , Coverity Scan , Steve French +Message-ID: <20231218153454.8090-94-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit 48b47f0caaa8a9f05ed803cb4f335fa3a7bfc622 ] + +Uninitialized rd.delegated_inode can be used in vfs_rename(). +Fix this by setting rd.delegated_inode to NULL to avoid the uninitialized +read. + +Fixes: 74d7970febf7 ("ksmbd: fix racy issue from using ->d_parent and ->d_name") +Reported-by: Coverity Scan +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/vfs.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/fs/ksmbd/vfs.c ++++ b/fs/ksmbd/vfs.c +@@ -743,6 +743,7 @@ retry: + rd.new_dir = new_path.dentry->d_inode, + rd.new_dentry = new_dentry, + rd.flags = flags, ++ rd.delegated_inode = NULL, + err = vfs_rename(&rd); + if (err) + ksmbd_debug(VFS, "vfs_rename failed err %d\n", err); diff --git a/queue-5.15/ksmbd-fix-uninitialized-pointer-read-in-smb2_create_link.patch b/queue-5.15/ksmbd-fix-uninitialized-pointer-read-in-smb2_create_link.patch new file mode 100644 index 00000000000..b2c4246e69b --- /dev/null +++ b/queue-5.15/ksmbd-fix-uninitialized-pointer-read-in-smb2_create_link.patch @@ -0,0 +1,47 @@ +From linkinjeon@gmail.com Mon Dec 18 16:40:24 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:33:54 +0900 +Subject: ksmbd: fix uninitialized pointer read in smb2_create_link() +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , Coverity Scan , Steve French +Message-ID: <20231218153454.8090-95-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit df14afeed2e6c1bbadef7d2f9c46887bbd6d8d94 ] + +There is a case that file_present is true and path is uninitialized. +This patch change file_present is set to false by default and set to +true when patch is initialized. + +Fixes: 74d7970febf7 ("ksmbd: fix racy issue from using ->d_parent and ->d_name") +Reported-by: Coverity Scan +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/smb2pdu.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -5529,7 +5529,7 @@ static int smb2_create_link(struct ksmbd + { + char *link_name = NULL, *target_name = NULL, *pathname = NULL; + struct path path; +- bool file_present = true; ++ bool file_present = false; + int rc; + + if (buf_len < (u64)sizeof(struct smb2_file_link_info) + +@@ -5562,8 +5562,8 @@ static int smb2_create_link(struct ksmbd + if (rc) { + if (rc != -ENOENT) + goto out; +- file_present = false; +- } ++ } else ++ file_present = true; + + if (file_info->ReplaceIfExists) { + if (file_present) { diff --git a/queue-5.15/ksmbd-fix-unsigned-expression-compared-with-zero.patch b/queue-5.15/ksmbd-fix-unsigned-expression-compared-with-zero.patch new file mode 100644 index 00000000000..cbddab9a4fe --- /dev/null +++ b/queue-5.15/ksmbd-fix-unsigned-expression-compared-with-zero.patch @@ -0,0 +1,50 @@ +From linkinjeon@gmail.com Mon Dec 18 16:41:29 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:34:14 +0900 +Subject: ksmbd: Fix unsigned expression compared with zero +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Wang Ming , Tom Talpey , Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-115-linkinjeon@kernel.org> + +From: Wang Ming + +[ Upstream commit 0266a2f791294e0b4ba36f4a1d89b8615ea3cac0 ] + +The return value of the ksmbd_vfs_getcasexattr() is signed. +However, the return value is being assigned to an unsigned +variable and subsequently recasted, causing warnings. Use +a signed type. + +Signed-off-by: Wang Ming +Acked-by: Tom Talpey +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/vfs.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +--- a/fs/ksmbd/vfs.c ++++ b/fs/ksmbd/vfs.c +@@ -412,7 +412,8 @@ static int ksmbd_vfs_stream_write(struct + { + char *stream_buf = NULL, *wbuf; + struct user_namespace *user_ns = file_mnt_user_ns(fp->filp); +- size_t size, v_len; ++ size_t size; ++ ssize_t v_len; + int err = 0; + + ksmbd_debug(VFS, "write stream data pos : %llu, count : %zd\n", +@@ -429,9 +430,9 @@ static int ksmbd_vfs_stream_write(struct + fp->stream.name, + fp->stream.size, + &stream_buf); +- if ((int)v_len < 0) { ++ if (v_len < 0) { + pr_err("not found stream in xattr : %zd\n", v_len); +- err = (int)v_len; ++ err = v_len; + goto out; + } + diff --git a/queue-5.15/ksmbd-fix-wrong-error-response-status-by-using-set_smb2_rsp_status.patch b/queue-5.15/ksmbd-fix-wrong-error-response-status-by-using-set_smb2_rsp_status.patch new file mode 100644 index 00000000000..5b55e918e21 --- /dev/null +++ b/queue-5.15/ksmbd-fix-wrong-error-response-status-by-using-set_smb2_rsp_status.patch @@ -0,0 +1,43 @@ +From linkinjeon@gmail.com Mon Dec 18 16:42:40 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:34:36 +0900 +Subject: ksmbd: fix wrong error response status by using set_smb2_rsp_status() +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-137-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit be0f89d4419dc5413a1cf06db3671c9949be0d52 ] + +set_smb2_rsp_status() after __process_request() sets the wrong error +status. This patch resets all iov vectors and sets the error status +on clean one. + +Fixes: e2b76ab8b5c9 ("ksmbd: add support for read compound") +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/smb2pdu.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -231,11 +231,12 @@ void set_smb2_rsp_status(struct ksmbd_wo + { + struct smb2_hdr *rsp_hdr; + +- if (work->next_smb2_rcv_hdr_off) +- rsp_hdr = ksmbd_resp_buf_next(work); +- else +- rsp_hdr = smb2_get_msg(work->response_buf); ++ rsp_hdr = smb2_get_msg(work->response_buf); + rsp_hdr->Status = err; ++ ++ work->iov_idx = 0; ++ work->iov_cnt = 0; ++ work->next_smb2_rcv_hdr_off = 0; + smb2_set_err_rsp(work); + } + diff --git a/queue-5.15/ksmbd-fix-wrong-interim-response-on-compound.patch b/queue-5.15/ksmbd-fix-wrong-interim-response-on-compound.patch new file mode 100644 index 00000000000..fc8121d3274 --- /dev/null +++ b/queue-5.15/ksmbd-fix-wrong-interim-response-on-compound.patch @@ -0,0 +1,156 @@ +From linkinjeon@gmail.com Mon Dec 18 16:41:49 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:34:20 +0900 +Subject: ksmbd: fix wrong interim response on compound +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-121-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit 041bba4414cda37d00063952c9bff9c3d5812a19 ] + +If smb2_lock or smb2_open request is compound, ksmbd could send wrong +interim response to client. ksmbd allocate new interim buffer instead of +using resonse buffer to support compound request. + +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/ksmbd_work.c | 10 ++++++---- + fs/ksmbd/ksmbd_work.h | 2 +- + fs/ksmbd/oplock.c | 14 ++------------ + fs/ksmbd/smb2pdu.c | 26 +++++++++++++++++--------- + 4 files changed, 26 insertions(+), 26 deletions(-) + +--- a/fs/ksmbd/ksmbd_work.c ++++ b/fs/ksmbd/ksmbd_work.c +@@ -160,9 +160,11 @@ int ksmbd_iov_pin_rsp_read(struct ksmbd_ + return __ksmbd_iov_pin_rsp(work, ib, len, aux_buf, aux_size); + } + +-void ksmbd_iov_reset(struct ksmbd_work *work) ++int allocate_interim_rsp_buf(struct ksmbd_work *work) + { +- work->iov_idx = 0; +- work->iov_cnt = 0; +- *(__be32 *)work->iov[0].iov_base = 0; ++ work->response_buf = kzalloc(MAX_CIFS_SMALL_BUFFER_SIZE, GFP_KERNEL); ++ if (!work->response_buf) ++ return -ENOMEM; ++ work->response_sz = MAX_CIFS_SMALL_BUFFER_SIZE; ++ return 0; + } +--- a/fs/ksmbd/ksmbd_work.h ++++ b/fs/ksmbd/ksmbd_work.h +@@ -131,5 +131,5 @@ bool ksmbd_queue_work(struct ksmbd_work + int ksmbd_iov_pin_rsp_read(struct ksmbd_work *work, void *ib, int len, + void *aux_buf, unsigned int aux_size); + int ksmbd_iov_pin_rsp(struct ksmbd_work *work, void *ib, int len); +-void ksmbd_iov_reset(struct ksmbd_work *work); ++int allocate_interim_rsp_buf(struct ksmbd_work *work); + #endif /* __KSMBD_WORK_H__ */ +--- a/fs/ksmbd/oplock.c ++++ b/fs/ksmbd/oplock.c +@@ -616,15 +616,6 @@ static int oplock_break_pending(struct o + return 0; + } + +-static inline int allocate_oplock_break_buf(struct ksmbd_work *work) +-{ +- work->response_buf = kzalloc(MAX_CIFS_SMALL_BUFFER_SIZE, GFP_KERNEL); +- if (!work->response_buf) +- return -ENOMEM; +- work->response_sz = MAX_CIFS_SMALL_BUFFER_SIZE; +- return 0; +-} +- + /** + * __smb2_oplock_break_noti() - send smb2 oplock break cmd from conn + * to client +@@ -647,7 +638,7 @@ static void __smb2_oplock_break_noti(str + if (!fp) + goto out; + +- if (allocate_oplock_break_buf(work)) { ++ if (allocate_interim_rsp_buf(work)) { + pr_err("smb2_allocate_rsp_buf failed! "); + ksmbd_fd_put(work, fp); + goto out; +@@ -752,7 +743,7 @@ static void __smb2_lease_break_noti(stru + struct lease_break_info *br_info = work->request_buf; + struct smb2_hdr *rsp_hdr; + +- if (allocate_oplock_break_buf(work)) { ++ if (allocate_interim_rsp_buf(work)) { + ksmbd_debug(OPLOCK, "smb2_allocate_rsp_buf failed! "); + goto out; + } +@@ -843,7 +834,6 @@ static int smb2_lease_break_noti(struct + setup_async_work(in_work, NULL, NULL); + smb2_send_interim_resp(in_work, STATUS_PENDING); + list_del(&in_work->interim_entry); +- ksmbd_iov_reset(in_work); + } + INIT_WORK(&work->work, __smb2_lease_break_noti); + ksmbd_queue_work(work); +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -153,8 +153,8 @@ void smb2_set_err_rsp(struct ksmbd_work + err_rsp->ByteCount = 0; + err_rsp->ErrorData[0] = 0; + err = ksmbd_iov_pin_rsp(work, (void *)err_rsp, +- work->conn->vals->header_size + +- SMB2_ERROR_STRUCTURE_SIZE2); ++ __SMB2_HEADER_STRUCTURE_SIZE + ++ SMB2_ERROR_STRUCTURE_SIZE2); + if (err) + work->send_no_response = 1; + } +@@ -710,13 +710,24 @@ void release_async_work(struct ksmbd_wor + void smb2_send_interim_resp(struct ksmbd_work *work, __le32 status) + { + struct smb2_hdr *rsp_hdr; ++ struct ksmbd_work *in_work = ksmbd_alloc_work_struct(); + +- rsp_hdr = ksmbd_resp_buf_next(work); +- smb2_set_err_rsp(work); ++ if (allocate_interim_rsp_buf(in_work)) { ++ pr_err("smb_allocate_rsp_buf failed!\n"); ++ ksmbd_free_work_struct(in_work); ++ return; ++ } ++ ++ in_work->conn = work->conn; ++ memcpy(smb2_get_msg(in_work->response_buf), ksmbd_resp_buf_next(work), ++ __SMB2_HEADER_STRUCTURE_SIZE); ++ ++ rsp_hdr = smb2_get_msg(in_work->response_buf); ++ smb2_set_err_rsp(in_work); + rsp_hdr->Status = status; + +- ksmbd_conn_write(work); +- rsp_hdr->Status = 0; ++ ksmbd_conn_write(in_work); ++ ksmbd_free_work_struct(in_work); + } + + static __le32 smb2_get_reparse_tag_special_file(umode_t mode) +@@ -7052,8 +7063,6 @@ skip: + list_del(&work->fp_entry); + spin_unlock(&fp->f_lock); + +- ksmbd_iov_reset(work); +- + if (work->state != KSMBD_WORK_ACTIVE) { + list_del(&smb_lock->llist); + spin_lock(&work->conn->llist_lock); +@@ -7071,7 +7080,6 @@ skip: + goto out; + } + +- init_smb2_rsp_hdr(work); + rsp->hdr.Status = + STATUS_RANGE_NOT_LOCKED; + kfree(smb_lock); diff --git a/queue-5.15/ksmbd-fix-wrong-signingkey-creation-when-encryption-is-aes256.patch b/queue-5.15/ksmbd-fix-wrong-signingkey-creation-when-encryption-is-aes256.patch new file mode 100644 index 00000000000..2428128e4b0 --- /dev/null +++ b/queue-5.15/ksmbd-fix-wrong-signingkey-creation-when-encryption-is-aes256.patch @@ -0,0 +1,45 @@ +From linkinjeon@gmail.com Mon Dec 18 16:39:33 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:33:38 +0900 +Subject: ksmbd: fix wrong signingkey creation when encryption is AES256 +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , Miao Lihua <441884205@qq.com>, Steve French +Message-ID: <20231218153454.8090-79-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit 7a891d4b62d62566323676cb0e922ded4f37afe1 ] + +MacOS and Win11 support AES256 encrytion and it is included in the cipher +array of encryption context. Especially on macOS, The most preferred +cipher is AES256. Connecting to ksmbd fails on newer MacOS clients that +support AES256 encryption. MacOS send disconnect request after receiving +final session setup response from ksmbd. Because final session setup is +signed with signing key was generated incorrectly. +For signging key, 'L' value should be initialized to 128 if key size is +16bytes. + +Cc: stable@vger.kernel.org +Reported-by: Miao Lihua <441884205@qq.com> +Tested-by: Miao Lihua <441884205@qq.com> +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/auth.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +--- a/fs/ksmbd/auth.c ++++ b/fs/ksmbd/auth.c +@@ -730,8 +730,9 @@ static int generate_key(struct ksmbd_con + goto smb3signkey_ret; + } + +- if (conn->cipher_type == SMB2_ENCRYPTION_AES256_CCM || +- conn->cipher_type == SMB2_ENCRYPTION_AES256_GCM) ++ if (key_size == SMB3_ENC_DEC_KEY_SIZE && ++ (conn->cipher_type == SMB2_ENCRYPTION_AES256_CCM || ++ conn->cipher_type == SMB2_ENCRYPTION_AES256_GCM)) + rc = crypto_shash_update(CRYPTO_HMACSHA256(ctx), L256, 4); + else + rc = crypto_shash_update(CRYPTO_HMACSHA256(ctx), L128, 4); diff --git a/queue-5.15/ksmbd-fix-wrong-smbd-max-read-write-size-check.patch b/queue-5.15/ksmbd-fix-wrong-smbd-max-read-write-size-check.patch new file mode 100644 index 00000000000..43c7f330a39 --- /dev/null +++ b/queue-5.15/ksmbd-fix-wrong-smbd-max-read-write-size-check.patch @@ -0,0 +1,166 @@ +From linkinjeon@gmail.com Mon Dec 18 16:37:24 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:32:58 +0900 +Subject: ksmbd: fix wrong smbd max read/write size check +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , Hyunchul Lee , Steve French +Message-ID: <20231218153454.8090-39-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit 7a84399e1ce3f5f2fbec3e7dd93459ba25badc2f ] + +smb-direct max read/write size can be different with smb2 max read/write +size. So smb2_read() can return error by wrong max read/write size check. +This patch use smb_direct_max_read_write_size for this check in +smb-direct read/write(). + +Signed-off-by: Namjae Jeon +Reviewed-by: Hyunchul Lee +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/smb2pdu.c | 39 +++++++++++++++++++++++++-------------- + fs/ksmbd/transport_rdma.c | 5 +++++ + fs/ksmbd/transport_rdma.h | 2 ++ + 3 files changed, 32 insertions(+), 14 deletions(-) + +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -6252,6 +6252,8 @@ int smb2_read(struct ksmbd_work *work) + size_t length, mincount; + ssize_t nbytes = 0, remain_bytes = 0; + int err = 0; ++ bool is_rdma_channel = false; ++ unsigned int max_read_size = conn->vals->max_read_size; + + WORK_BUFFERS(work, req, rsp); + if (work->next_smb2_rcv_hdr_off) { +@@ -6268,6 +6270,11 @@ int smb2_read(struct ksmbd_work *work) + + if (req->Channel == SMB2_CHANNEL_RDMA_V1_INVALIDATE || + req->Channel == SMB2_CHANNEL_RDMA_V1) { ++ is_rdma_channel = true; ++ max_read_size = get_smbd_max_read_write_size(); ++ } ++ ++ if (is_rdma_channel == true) { + unsigned int ch_offset = le16_to_cpu(req->ReadChannelInfoOffset); + + if (ch_offset < offsetof(struct smb2_read_req, Buffer)) { +@@ -6299,9 +6306,9 @@ int smb2_read(struct ksmbd_work *work) + length = le32_to_cpu(req->Length); + mincount = le32_to_cpu(req->MinimumCount); + +- if (length > conn->vals->max_read_size) { ++ if (length > max_read_size) { + ksmbd_debug(SMB, "limiting read size to max size(%u)\n", +- conn->vals->max_read_size); ++ max_read_size); + err = -EINVAL; + goto out; + } +@@ -6333,8 +6340,7 @@ int smb2_read(struct ksmbd_work *work) + ksmbd_debug(SMB, "nbytes %zu, offset %lld mincount %zu\n", + nbytes, offset, mincount); + +- if (req->Channel == SMB2_CHANNEL_RDMA_V1_INVALIDATE || +- req->Channel == SMB2_CHANNEL_RDMA_V1) { ++ if (is_rdma_channel == true) { + /* write data to the client using rdma channel */ + remain_bytes = smb2_read_rdma_channel(work, req, + work->aux_payload_buf, +@@ -6495,8 +6501,9 @@ int smb2_write(struct ksmbd_work *work) + size_t length; + ssize_t nbytes; + char *data_buf; +- bool writethrough = false; ++ bool writethrough = false, is_rdma_channel = false; + int err = 0; ++ unsigned int max_write_size = work->conn->vals->max_write_size; + + WORK_BUFFERS(work, req, rsp); + +@@ -6505,8 +6512,17 @@ int smb2_write(struct ksmbd_work *work) + return smb2_write_pipe(work); + } + ++ offset = le64_to_cpu(req->Offset); ++ length = le32_to_cpu(req->Length); ++ + if (req->Channel == SMB2_CHANNEL_RDMA_V1 || + req->Channel == SMB2_CHANNEL_RDMA_V1_INVALIDATE) { ++ is_rdma_channel = true; ++ max_write_size = get_smbd_max_read_write_size(); ++ length = le32_to_cpu(req->RemainingBytes); ++ } ++ ++ if (is_rdma_channel == true) { + unsigned int ch_offset = le16_to_cpu(req->WriteChannelInfoOffset); + + if (req->Length != 0 || req->DataOffset != 0 || +@@ -6541,12 +6557,9 @@ int smb2_write(struct ksmbd_work *work) + goto out; + } + +- offset = le64_to_cpu(req->Offset); +- length = le32_to_cpu(req->Length); +- +- if (length > work->conn->vals->max_write_size) { ++ if (length > max_write_size) { + ksmbd_debug(SMB, "limiting write size to max size(%u)\n", +- work->conn->vals->max_write_size); ++ max_write_size); + err = -EINVAL; + goto out; + } +@@ -6554,8 +6567,7 @@ int smb2_write(struct ksmbd_work *work) + if (le32_to_cpu(req->Flags) & SMB2_WRITEFLAG_WRITE_THROUGH) + writethrough = true; + +- if (req->Channel != SMB2_CHANNEL_RDMA_V1 && +- req->Channel != SMB2_CHANNEL_RDMA_V1_INVALIDATE) { ++ if (is_rdma_channel == false) { + if (le16_to_cpu(req->DataOffset) < + offsetof(struct smb2_write_req, Buffer)) { + err = -EINVAL; +@@ -6579,8 +6591,7 @@ int smb2_write(struct ksmbd_work *work) + /* read data from the client using rdma channel, and + * write the data. + */ +- nbytes = smb2_write_rdma_channel(work, req, fp, offset, +- le32_to_cpu(req->RemainingBytes), ++ nbytes = smb2_write_rdma_channel(work, req, fp, offset, length, + writethrough); + if (nbytes < 0) { + err = (int)nbytes; +--- a/fs/ksmbd/transport_rdma.c ++++ b/fs/ksmbd/transport_rdma.c +@@ -220,6 +220,11 @@ void init_smbd_max_io_size(unsigned int + smb_direct_max_read_write_size = sz; + } + ++unsigned int get_smbd_max_read_write_size(void) ++{ ++ return smb_direct_max_read_write_size; ++} ++ + static inline int get_buf_page_count(void *buf, int size) + { + return DIV_ROUND_UP((uintptr_t)buf + size, PAGE_SIZE) - +--- a/fs/ksmbd/transport_rdma.h ++++ b/fs/ksmbd/transport_rdma.h +@@ -57,11 +57,13 @@ int ksmbd_rdma_init(void); + void ksmbd_rdma_destroy(void); + bool ksmbd_rdma_capable_netdev(struct net_device *netdev); + void init_smbd_max_io_size(unsigned int sz); ++unsigned int get_smbd_max_read_write_size(void); + #else + static inline int ksmbd_rdma_init(void) { return 0; } + static inline int ksmbd_rdma_destroy(void) { return 0; } + static inline bool ksmbd_rdma_capable_netdev(struct net_device *netdev) { return false; } + static inline void init_smbd_max_io_size(unsigned int sz) { } ++static inline unsigned int get_smbd_max_read_write_size(void) { return 0; } + #endif + + #endif /* __KSMBD_TRANSPORT_RDMA_H__ */ diff --git a/queue-5.15/ksmbd-handle-malformed-smb1-message.patch b/queue-5.15/ksmbd-handle-malformed-smb1-message.patch new file mode 100644 index 00000000000..87668533976 --- /dev/null +++ b/queue-5.15/ksmbd-handle-malformed-smb1-message.patch @@ -0,0 +1,50 @@ +From linkinjeon@gmail.com Mon Dec 18 16:43:17 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:34:47 +0900 +Subject: ksmbd: handle malformed smb1 message +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , Robert Morris , Steve French +Message-ID: <20231218153454.8090-148-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit 5a5409d90bd05f87fe5623a749ccfbf3f7c7d400 ] + +If set_smb1_rsp_status() is not implemented, It will cause NULL pointer +dereferece error when client send malformed smb1 message. +This patch add set_smb1_rsp_status() to ignore malformed smb1 message. + +Cc: stable@vger.kernel.org +Reported-by: Robert Morris +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/smb_common.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +--- a/fs/ksmbd/smb_common.c ++++ b/fs/ksmbd/smb_common.c +@@ -366,11 +366,22 @@ static int smb1_allocate_rsp_buf(struct + return 0; + } + ++/** ++ * set_smb1_rsp_status() - set error type in smb response header ++ * @work: smb work containing smb response header ++ * @err: error code to set in response ++ */ ++static void set_smb1_rsp_status(struct ksmbd_work *work, __le32 err) ++{ ++ work->send_no_response = 1; ++} ++ + static struct smb_version_ops smb1_server_ops = { + .get_cmd_val = get_smb1_cmd_val, + .init_rsp_hdr = init_smb1_rsp_hdr, + .allocate_rsp_buf = smb1_allocate_rsp_buf, + .check_user_session = smb1_check_user_session, ++ .set_rsp_status = set_smb1_rsp_status, + }; + + static int smb1_negotiate(struct ksmbd_work *work) diff --git a/queue-5.15/ksmbd-hide-socket-error-message-when-ipv6-config-is-disable.patch b/queue-5.15/ksmbd-hide-socket-error-message-when-ipv6-config-is-disable.patch new file mode 100644 index 00000000000..fd0370f9b15 --- /dev/null +++ b/queue-5.15/ksmbd-hide-socket-error-message-when-ipv6-config-is-disable.patch @@ -0,0 +1,37 @@ +From linkinjeon@gmail.com Mon Dec 18 16:38:37 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:33:20 +0900 +Subject: ksmbd: hide socket error message when ipv6 config is disable +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , Tom Talpey , Steve French +Message-ID: <20231218153454.8090-61-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit 5876e99611a91dfb2fb1f7af9d1ae5c017c8331c ] + +When ipv6 config is disable(CONFIG_IPV6 is not set), ksmbd fallback to +create ipv4 socket. User reported that this error message lead to +misunderstood some issue. Users have requested not to print this error +message that occurs even though there is no problem. + +Signed-off-by: Namjae Jeon +Acked-by: Tom Talpey +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/transport_tcp.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/fs/ksmbd/transport_tcp.c ++++ b/fs/ksmbd/transport_tcp.c +@@ -428,7 +428,8 @@ static int create_socket(struct interfac + + ret = sock_create(PF_INET6, SOCK_STREAM, IPPROTO_TCP, &ksmbd_socket); + if (ret) { +- pr_err("Can't create socket for ipv6, try ipv4: %d\n", ret); ++ if (ret != -EAFNOSUPPORT) ++ pr_err("Can't create socket for ipv6, fallback to ipv4: %d\n", ret); + ret = sock_create(PF_INET, SOCK_STREAM, IPPROTO_TCP, + &ksmbd_socket); + if (ret) { diff --git a/queue-5.15/ksmbd-implements-sess-ksmbd_chann_list-as-xarray.patch b/queue-5.15/ksmbd-implements-sess-ksmbd_chann_list-as-xarray.patch new file mode 100644 index 00000000000..9340214dcd3 --- /dev/null +++ b/queue-5.15/ksmbd-implements-sess-ksmbd_chann_list-as-xarray.patch @@ -0,0 +1,270 @@ +From linkinjeon@gmail.com Mon Dec 18 16:39:08 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:33:30 +0900 +Subject: ksmbd: Implements sess->ksmbd_chann_list as xarray +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Dawei Li , Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-71-linkinjeon@kernel.org> + +From: Dawei Li + +[ Upstream commit 1d9c4172110e645b383ff13eee759728d74f1a5d ] + +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 +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/mgmt/user_session.c | 59 ++++++++++++++++--------------------------- + fs/ksmbd/mgmt/user_session.h | 4 -- + fs/ksmbd/smb2pdu.c | 34 +++--------------------- + 3 files changed, 29 insertions(+), 68 deletions(-) + +--- 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_ + + 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); +- 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); ++ chann = xa_erase(&sess->ksmbd_chann_list, (long)conn); ++ if (!chann) ++ return -ENOENT; ++ ++ kfree(chann); + +- return -ENOENT; ++ return 0; + } + + void ksmbd_sessions_deregister(struct ksmbd_conn *conn) +@@ -234,7 +228,7 @@ void ksmbd_sessions_deregister(struct ks + 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_c + 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_c + + 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: +--- 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; +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -75,14 +75,7 @@ static inline bool check_session_id(stru + + 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); + } + + /** +@@ -626,6 +619,7 @@ static void destroy_previous_session(str + struct ksmbd_session *prev_sess = ksmbd_session_lookup_slowpath(id); + struct ksmbd_user *prev_user; + struct channel *chann; ++ long index; + + if (!prev_sess) + return; +@@ -639,10 +633,8 @@ static void destroy_previous_session(str + 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); + } + + /** +@@ -1549,19 +1541,14 @@ static int ntlm_authenticate(struct ksmb + + 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); + } + } + +@@ -1636,19 +1623,14 @@ static int krb5_authenticate(struct ksmb + } + + 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); + } + } + +@@ -8463,14 +8445,11 @@ int smb3_check_sign_req(struct ksmbd_wor + 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) { +@@ -8530,14 +8509,11 @@ void smb3_set_sign_rsp(struct ksmbd_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) diff --git a/queue-5.15/ksmbd-implements-sess-rpc_handle_list-as-xarray.patch b/queue-5.15/ksmbd-implements-sess-rpc_handle_list-as-xarray.patch new file mode 100644 index 00000000000..6b722ae2698 --- /dev/null +++ b/queue-5.15/ksmbd-implements-sess-rpc_handle_list-as-xarray.patch @@ -0,0 +1,138 @@ +From linkinjeon@gmail.com Mon Dec 18 16:39:11 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:33:31 +0900 +Subject: ksmbd: Implements sess->rpc_handle_list as xarray +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Dawei Li , Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-72-linkinjeon@kernel.org> + +From: Dawei Li + +[ Upstream commit b685757c7b08d5073046fb379be965fd6c06aafc ] + +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 +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/mgmt/user_session.c | 37 ++++++++++++++----------------------- + fs/ksmbd/mgmt/user_session.h | 2 +- + 2 files changed, 15 insertions(+), 24 deletions(-) + +--- 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 k + 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_ + + 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_ + 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 ksmb + { + 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_c + 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); +--- 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]; diff --git a/queue-5.15/ksmbd-make-utf-8-file-name-comparison-work-in-__caseless_lookup.patch b/queue-5.15/ksmbd-make-utf-8-file-name-comparison-work-in-__caseless_lookup.patch new file mode 100644 index 00000000000..b1f8edd7bdf --- /dev/null +++ b/queue-5.15/ksmbd-make-utf-8-file-name-comparison-work-in-__caseless_lookup.patch @@ -0,0 +1,115 @@ +From linkinjeon@gmail.com Mon Dec 18 16:38:40 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:33:21 +0900 +Subject: ksmbd: make utf-8 file name comparison work in __caseless_lookup() +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, "Atte Heikkilä" , "Namjae Jeon" , "Steve French" +Message-ID: <20231218153454.8090-62-linkinjeon@kernel.org> + +From: Atte Heikkilä + +[ Upstream commit dbab80e2071ad8c702e50dab43326608a127d27b ] + +Case-insensitive file name lookups with __caseless_lookup() use +strncasecmp() for file name comparison. strncasecmp() assumes an +ISO8859-1-compatible encoding, which is not the case here as UTF-8 +is always used. As such, use of strncasecmp() here produces correct +results only if both strings use characters in the ASCII range only. +Fix this by using utf8_strncasecmp() if CONFIG_UNICODE is set. On +failure or if CONFIG_UNICODE is not set, fallback to strncasecmp(). +Also, as we are adding an include for `linux/unicode.h', include it +in `fs/ksmbd/connection.h' as well since it should be explicit there. + +Signed-off-by: Atte Heikkilä +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/connection.h | 1 + + fs/ksmbd/vfs.c | 20 +++++++++++++++++--- + fs/ksmbd/vfs.h | 2 ++ + 3 files changed, 20 insertions(+), 3 deletions(-) + +--- a/fs/ksmbd/connection.h ++++ b/fs/ksmbd/connection.h +@@ -14,6 +14,7 @@ + #include + #include + #include ++#include + + #include "smb_common.h" + #include "ksmbd_work.h" +--- a/fs/ksmbd/vfs.c ++++ b/fs/ksmbd/vfs.c +@@ -1144,12 +1144,23 @@ static int __caseless_lookup(struct dir_ + unsigned int d_type) + { + struct ksmbd_readdir_data *buf; ++ int cmp = -EINVAL; + + buf = container_of(ctx, struct ksmbd_readdir_data, ctx); + + if (buf->used != namlen) + return 0; +- if (!strncasecmp((char *)buf->private, name, namlen)) { ++ if (IS_ENABLED(CONFIG_UNICODE) && buf->um) { ++ const struct qstr q_buf = {.name = buf->private, ++ .len = buf->used}; ++ const struct qstr q_name = {.name = name, ++ .len = namlen}; ++ ++ cmp = utf8_strncasecmp(buf->um, &q_buf, &q_name); ++ } ++ if (cmp < 0) ++ cmp = strncasecmp((char *)buf->private, name, namlen); ++ if (!cmp) { + memcpy((char *)buf->private, name, namlen); + buf->dirent_count = 1; + return -EEXIST; +@@ -1165,7 +1176,8 @@ static int __caseless_lookup(struct dir_ + * + * Return: 0 on success, otherwise error + */ +-static int ksmbd_vfs_lookup_in_dir(const struct path *dir, char *name, size_t namelen) ++static int ksmbd_vfs_lookup_in_dir(const struct path *dir, char *name, ++ size_t namelen, struct unicode_map *um) + { + int ret; + struct file *dfilp; +@@ -1175,6 +1187,7 @@ static int ksmbd_vfs_lookup_in_dir(const + .private = name, + .used = namelen, + .dirent_count = 0, ++ .um = um, + }; + + dfilp = dentry_open(dir, flags, current_cred()); +@@ -1237,7 +1250,8 @@ int ksmbd_vfs_kern_path(struct ksmbd_wor + break; + + err = ksmbd_vfs_lookup_in_dir(&parent, filename, +- filename_len); ++ filename_len, ++ work->conn->um); + path_put(&parent); + if (err) + goto out; +--- a/fs/ksmbd/vfs.h ++++ b/fs/ksmbd/vfs.h +@@ -12,6 +12,7 @@ + #include + #include + #include ++#include + + #include "smbacl.h" + #include "xattr.h" +@@ -99,6 +100,7 @@ struct ksmbd_readdir_data { + unsigned int used; + unsigned int dirent_count; + unsigned int file_attr; ++ struct unicode_map *um; + }; + + /* ksmbd kstat wrapper to get valid create time when reading dir entry */ diff --git a/queue-5.15/ksmbd-move-oplock-handling-after-unlock-parent-dir.patch b/queue-5.15/ksmbd-move-oplock-handling-after-unlock-parent-dir.patch new file mode 100644 index 00000000000..3a58822d939 --- /dev/null +++ b/queue-5.15/ksmbd-move-oplock-handling-after-unlock-parent-dir.patch @@ -0,0 +1,361 @@ +From linkinjeon@gmail.com Mon Dec 18 16:43:32 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:34:51 +0900 +Subject: ksmbd: move oplock handling after unlock parent dir +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-152-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit 2e450920d58b4991a436c8cecf3484bcacd8e535 ] + +ksmbd should process secound parallel smb2 create request during waiting +oplock break ack. parent lock range that is too large in smb2_open() causes +smb2_open() to be serialized. Move the oplock handling to the bottom of +smb2_open() and make it called after parent unlock. This fixes the failure +of smb2.lease.breaking1 testcase. + +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/smb2pdu.c | 121 ++++++++++++++++++++++++++++------------------------- + 1 file changed, 65 insertions(+), 56 deletions(-) + +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -2688,7 +2688,7 @@ int smb2_open(struct ksmbd_work *work) + *(char *)req->Buffer == '\\') { + pr_err("not allow directory name included leading slash\n"); + rc = -EINVAL; +- goto err_out1; ++ goto err_out2; + } + + name = smb2_get_name(req->Buffer, +@@ -2699,7 +2699,7 @@ int smb2_open(struct ksmbd_work *work) + if (rc != -ENOMEM) + rc = -ENOENT; + name = NULL; +- goto err_out1; ++ goto err_out2; + } + + ksmbd_debug(SMB, "converted name = %s\n", name); +@@ -2707,28 +2707,28 @@ int smb2_open(struct ksmbd_work *work) + if (!test_share_config_flag(work->tcon->share_conf, + KSMBD_SHARE_FLAG_STREAMS)) { + rc = -EBADF; +- goto err_out1; ++ goto err_out2; + } + rc = parse_stream_name(name, &stream_name, &s_type); + if (rc < 0) +- goto err_out1; ++ goto err_out2; + } + + rc = ksmbd_validate_filename(name); + if (rc < 0) +- goto err_out1; ++ goto err_out2; + + if (ksmbd_share_veto_filename(share, name)) { + rc = -ENOENT; + ksmbd_debug(SMB, "Reject open(), vetoed file: %s\n", + name); +- goto err_out1; ++ goto err_out2; + } + } else { + name = kstrdup("", GFP_KERNEL); + if (!name) { + rc = -ENOMEM; +- goto err_out1; ++ goto err_out2; + } + } + +@@ -2741,14 +2741,14 @@ int smb2_open(struct ksmbd_work *work) + le32_to_cpu(req->ImpersonationLevel)); + rc = -EIO; + rsp->hdr.Status = STATUS_BAD_IMPERSONATION_LEVEL; +- goto err_out1; ++ goto err_out2; + } + + if (req->CreateOptions && !(req->CreateOptions & CREATE_OPTIONS_MASK)) { + pr_err("Invalid create options : 0x%x\n", + le32_to_cpu(req->CreateOptions)); + rc = -EINVAL; +- goto err_out1; ++ goto err_out2; + } else { + if (req->CreateOptions & FILE_SEQUENTIAL_ONLY_LE && + req->CreateOptions & FILE_RANDOM_ACCESS_LE) +@@ -2758,13 +2758,13 @@ int smb2_open(struct ksmbd_work *work) + (FILE_OPEN_BY_FILE_ID_LE | CREATE_TREE_CONNECTION | + FILE_RESERVE_OPFILTER_LE)) { + rc = -EOPNOTSUPP; +- goto err_out1; ++ goto err_out2; + } + + if (req->CreateOptions & FILE_DIRECTORY_FILE_LE) { + if (req->CreateOptions & FILE_NON_DIRECTORY_FILE_LE) { + rc = -EINVAL; +- goto err_out1; ++ goto err_out2; + } else if (req->CreateOptions & FILE_NO_COMPRESSION_LE) { + req->CreateOptions = ~(FILE_NO_COMPRESSION_LE); + } +@@ -2776,21 +2776,21 @@ int smb2_open(struct ksmbd_work *work) + pr_err("Invalid create disposition : 0x%x\n", + le32_to_cpu(req->CreateDisposition)); + rc = -EINVAL; +- goto err_out1; ++ goto err_out2; + } + + if (!(req->DesiredAccess & DESIRED_ACCESS_MASK)) { + pr_err("Invalid desired access : 0x%x\n", + le32_to_cpu(req->DesiredAccess)); + rc = -EACCES; +- goto err_out1; ++ goto err_out2; + } + + if (req->FileAttributes && !(req->FileAttributes & ATTR_MASK_LE)) { + pr_err("Invalid file attribute : 0x%x\n", + le32_to_cpu(req->FileAttributes)); + rc = -EINVAL; +- goto err_out1; ++ goto err_out2; + } + + if (req->CreateContextsOffset) { +@@ -2798,19 +2798,19 @@ int smb2_open(struct ksmbd_work *work) + context = smb2_find_context_vals(req, SMB2_CREATE_EA_BUFFER, 4); + if (IS_ERR(context)) { + rc = PTR_ERR(context); +- goto err_out1; ++ goto err_out2; + } else if (context) { + ea_buf = (struct create_ea_buf_req *)context; + if (le16_to_cpu(context->DataOffset) + + le32_to_cpu(context->DataLength) < + sizeof(struct create_ea_buf_req)) { + rc = -EINVAL; +- goto err_out1; ++ goto err_out2; + } + if (req->CreateOptions & FILE_NO_EA_KNOWLEDGE_LE) { + rsp->hdr.Status = STATUS_ACCESS_DENIED; + rc = -EACCES; +- goto err_out1; ++ goto err_out2; + } + } + +@@ -2818,7 +2818,7 @@ int smb2_open(struct ksmbd_work *work) + SMB2_CREATE_QUERY_MAXIMAL_ACCESS_REQUEST, 4); + if (IS_ERR(context)) { + rc = PTR_ERR(context); +- goto err_out1; ++ goto err_out2; + } else if (context) { + ksmbd_debug(SMB, + "get query maximal access context\n"); +@@ -2829,11 +2829,11 @@ int smb2_open(struct ksmbd_work *work) + SMB2_CREATE_TIMEWARP_REQUEST, 4); + if (IS_ERR(context)) { + rc = PTR_ERR(context); +- goto err_out1; ++ goto err_out2; + } else if (context) { + ksmbd_debug(SMB, "get timewarp context\n"); + rc = -EBADF; +- goto err_out1; ++ goto err_out2; + } + + if (tcon->posix_extensions) { +@@ -2841,7 +2841,7 @@ int smb2_open(struct ksmbd_work *work) + SMB2_CREATE_TAG_POSIX, 16); + if (IS_ERR(context)) { + rc = PTR_ERR(context); +- goto err_out1; ++ goto err_out2; + } else if (context) { + struct create_posix *posix = + (struct create_posix *)context; +@@ -2849,7 +2849,7 @@ int smb2_open(struct ksmbd_work *work) + le32_to_cpu(context->DataLength) < + sizeof(struct create_posix) - 4) { + rc = -EINVAL; +- goto err_out1; ++ goto err_out2; + } + ksmbd_debug(SMB, "get posix context\n"); + +@@ -2861,7 +2861,7 @@ int smb2_open(struct ksmbd_work *work) + + if (ksmbd_override_fsids(work)) { + rc = -ENOMEM; +- goto err_out1; ++ goto err_out2; + } + + rc = ksmbd_vfs_kern_path_locked(work, name, LOOKUP_NO_SYMLINKS, +@@ -3174,11 +3174,6 @@ int smb2_open(struct ksmbd_work *work) + + fp->attrib_only = !(req->DesiredAccess & ~(FILE_READ_ATTRIBUTES_LE | + FILE_WRITE_ATTRIBUTES_LE | FILE_SYNCHRONIZE_LE)); +- if (!S_ISDIR(file_inode(filp)->i_mode) && open_flags & O_TRUNC && +- !fp->attrib_only && !stream_name) { +- smb_break_all_oplock(work, fp); +- need_truncate = 1; +- } + + /* fp should be searchable through ksmbd_inode.m_fp_list + * after daccess, saccess, attrib_only, and stream are +@@ -3194,13 +3189,39 @@ int smb2_open(struct ksmbd_work *work) + goto err_out; + } + ++ rc = ksmbd_vfs_getattr(&path, &stat); ++ if (rc) ++ goto err_out; ++ ++ if (stat.result_mask & STATX_BTIME) ++ fp->create_time = ksmbd_UnixTimeToNT(stat.btime); ++ else ++ fp->create_time = ksmbd_UnixTimeToNT(stat.ctime); ++ if (req->FileAttributes || fp->f_ci->m_fattr == 0) ++ fp->f_ci->m_fattr = ++ cpu_to_le32(smb2_get_dos_mode(&stat, le32_to_cpu(req->FileAttributes))); ++ ++ if (!created) ++ smb2_update_xattrs(tcon, &path, fp); ++ else ++ smb2_new_xattrs(tcon, &path, fp); ++ ++ if (file_present || created) ++ ksmbd_vfs_kern_path_unlock(&parent_path, &path); ++ ++ if (!S_ISDIR(file_inode(filp)->i_mode) && open_flags & O_TRUNC && ++ !fp->attrib_only && !stream_name) { ++ smb_break_all_oplock(work, fp); ++ need_truncate = 1; ++ } ++ + share_ret = ksmbd_smb_check_shared_mode(fp->filp, fp); + if (!test_share_config_flag(work->tcon->share_conf, KSMBD_SHARE_FLAG_OPLOCKS) || + (req_op_level == SMB2_OPLOCK_LEVEL_LEASE && + !(conn->vals->capabilities & SMB2_GLOBAL_CAP_LEASING))) { + if (share_ret < 0 && !S_ISDIR(file_inode(fp->filp)->i_mode)) { + rc = share_ret; +- goto err_out; ++ goto err_out1; + } + } else { + if (req_op_level == SMB2_OPLOCK_LEVEL_LEASE) { +@@ -3210,7 +3231,7 @@ int smb2_open(struct ksmbd_work *work) + name, req_op_level, lc->req_state); + rc = find_same_lease_key(sess, fp->f_ci, lc); + if (rc) +- goto err_out; ++ goto err_out1; + } else if (open_flags == O_RDONLY && + (req_op_level == SMB2_OPLOCK_LEVEL_BATCH || + req_op_level == SMB2_OPLOCK_LEVEL_EXCLUSIVE)) +@@ -3221,12 +3242,18 @@ int smb2_open(struct ksmbd_work *work) + le32_to_cpu(req->hdr.Id.SyncId.TreeId), + lc, share_ret); + if (rc < 0) +- goto err_out; ++ goto err_out1; + } + + if (req->CreateOptions & FILE_DELETE_ON_CLOSE_LE) + ksmbd_fd_set_delete_on_close(fp, file_info); + ++ if (need_truncate) { ++ rc = smb2_create_truncate(&fp->filp->f_path); ++ if (rc) ++ goto err_out1; ++ } ++ + if (req->CreateContextsOffset) { + struct create_alloc_size_req *az_req; + +@@ -3234,7 +3261,7 @@ int smb2_open(struct ksmbd_work *work) + SMB2_CREATE_ALLOCATION_SIZE, 4); + if (IS_ERR(az_req)) { + rc = PTR_ERR(az_req); +- goto err_out; ++ goto err_out1; + } else if (az_req) { + loff_t alloc_size; + int err; +@@ -3243,7 +3270,7 @@ int smb2_open(struct ksmbd_work *work) + le32_to_cpu(az_req->ccontext.DataLength) < + sizeof(struct create_alloc_size_req)) { + rc = -EINVAL; +- goto err_out; ++ goto err_out1; + } + alloc_size = le64_to_cpu(az_req->AllocationSize); + ksmbd_debug(SMB, +@@ -3261,30 +3288,13 @@ int smb2_open(struct ksmbd_work *work) + context = smb2_find_context_vals(req, SMB2_CREATE_QUERY_ON_DISK_ID, 4); + if (IS_ERR(context)) { + rc = PTR_ERR(context); +- goto err_out; ++ goto err_out1; + } else if (context) { + ksmbd_debug(SMB, "get query on disk id context\n"); + query_disk_id = 1; + } + } + +- rc = ksmbd_vfs_getattr(&path, &stat); +- if (rc) +- goto err_out; +- +- if (stat.result_mask & STATX_BTIME) +- fp->create_time = ksmbd_UnixTimeToNT(stat.btime); +- else +- fp->create_time = ksmbd_UnixTimeToNT(stat.ctime); +- if (req->FileAttributes || fp->f_ci->m_fattr == 0) +- fp->f_ci->m_fattr = +- cpu_to_le32(smb2_get_dos_mode(&stat, le32_to_cpu(req->FileAttributes))); +- +- if (!created) +- smb2_update_xattrs(tcon, &path, fp); +- else +- smb2_new_xattrs(tcon, &path, fp); +- + memcpy(fp->client_guid, conn->ClientGUID, SMB2_CLIENT_GUID_SIZE); + + rsp->StructureSize = cpu_to_le16(89); +@@ -3391,14 +3401,13 @@ int smb2_open(struct ksmbd_work *work) + } + + err_out: +- if (file_present || created) ++ if (rc && (file_present || created)) + ksmbd_vfs_kern_path_unlock(&parent_path, &path); + +- if (fp && need_truncate) +- rc = smb2_create_truncate(&fp->filp->f_path); +- +- ksmbd_revert_fsids(work); + err_out1: ++ ksmbd_revert_fsids(work); ++ ++err_out2: + if (!rc) { + ksmbd_update_fstate(&work->sess->file_table, fp, FP_INITED); + rc = ksmbd_iov_pin_rsp(work, (void *)rsp, iov_len); diff --git a/queue-5.15/ksmbd-move-setting-smb2_flags_async_command-and-asyncid.patch b/queue-5.15/ksmbd-move-setting-smb2_flags_async_command-and-asyncid.patch new file mode 100644 index 00000000000..f499b511648 --- /dev/null +++ b/queue-5.15/ksmbd-move-setting-smb2_flags_async_command-and-asyncid.patch @@ -0,0 +1,55 @@ +From linkinjeon@gmail.com Mon Dec 18 16:43:38 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:34:53 +0900 +Subject: ksmbd: move setting SMB2_FLAGS_ASYNC_COMMAND and AsyncId +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-154-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit 9ac45ac7cf65b0623ceeab9b28b307a08efa22dc ] + +Directly set SMB2_FLAGS_ASYNC_COMMAND flags and AsyncId in smb2 header of +interim response instead of current response header. + +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/smb2pdu.c | 7 ++----- + 1 file changed, 2 insertions(+), 5 deletions(-) + +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -658,13 +658,9 @@ smb2_get_name(const char *src, const int + + int setup_async_work(struct ksmbd_work *work, void (*fn)(void **), void **arg) + { +- struct smb2_hdr *rsp_hdr; + struct ksmbd_conn *conn = work->conn; + int id; + +- rsp_hdr = ksmbd_resp_buf_next(work); +- rsp_hdr->Flags |= SMB2_FLAGS_ASYNC_COMMAND; +- + id = ksmbd_acquire_async_msg_id(&conn->async_ida); + if (id < 0) { + pr_err("Failed to alloc async message id\n"); +@@ -672,7 +668,6 @@ int setup_async_work(struct ksmbd_work * + } + work->asynchronous = true; + work->async_id = id; +- rsp_hdr->Id.AsyncId = cpu_to_le64(id); + + ksmbd_debug(SMB, + "Send interim Response to inform async request id : %d\n", +@@ -724,6 +719,8 @@ void smb2_send_interim_resp(struct ksmbd + __SMB2_HEADER_STRUCTURE_SIZE); + + rsp_hdr = smb2_get_msg(in_work->response_buf); ++ rsp_hdr->Flags |= SMB2_FLAGS_ASYNC_COMMAND; ++ rsp_hdr->Id.AsyncId = cpu_to_le64(work->async_id); + smb2_set_err_rsp(in_work); + rsp_hdr->Status = status; + diff --git a/queue-5.15/ksmbd-no-need-to-wait-for-binded-connection-termination-at-logoff.patch b/queue-5.15/ksmbd-no-need-to-wait-for-binded-connection-termination-at-logoff.patch new file mode 100644 index 00000000000..a73177cb78d --- /dev/null +++ b/queue-5.15/ksmbd-no-need-to-wait-for-binded-connection-termination-at-logoff.patch @@ -0,0 +1,49 @@ +From linkinjeon@gmail.com Mon Dec 18 16:43:10 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:34:45 +0900 +Subject: ksmbd: no need to wait for binded connection termination at logoff +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-146-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit 67797da8a4b82446d42c52b6ee1419a3100d78ff ] + +The connection could be binded to the existing session for Multichannel. +session will be destroyed when binded connections are released. +So no need to wait for that's connection at logoff. + +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/connection.c | 16 ---------------- + 1 file changed, 16 deletions(-) + +--- a/fs/ksmbd/connection.c ++++ b/fs/ksmbd/connection.c +@@ -167,23 +167,7 @@ void ksmbd_all_conn_set_status(u64 sess_ + + void ksmbd_conn_wait_idle(struct ksmbd_conn *conn, u64 sess_id) + { +- struct ksmbd_conn *bind_conn; +- + wait_event(conn->req_running_q, atomic_read(&conn->req_running) < 2); +- +- down_read(&conn_list_lock); +- list_for_each_entry(bind_conn, &conn_list, conns_list) { +- if (bind_conn == conn) +- continue; +- +- if ((bind_conn->binding || xa_load(&bind_conn->sessions, sess_id)) && +- !ksmbd_conn_releasing(bind_conn) && +- atomic_read(&bind_conn->req_running)) { +- wait_event(bind_conn->req_running_q, +- atomic_read(&bind_conn->req_running) == 0); +- } +- } +- up_read(&conn_list_lock); + } + + int ksmbd_conn_write(struct ksmbd_work *work) diff --git a/queue-5.15/ksmbd-prevent-memory-leak-on-error-return.patch b/queue-5.15/ksmbd-prevent-memory-leak-on-error-return.patch new file mode 100644 index 00000000000..f715fcc52cd --- /dev/null +++ b/queue-5.15/ksmbd-prevent-memory-leak-on-error-return.patch @@ -0,0 +1,51 @@ +From linkinjeon@gmail.com Mon Dec 18 16:43:20 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:34:48 +0900 +Subject: ksmbd: prevent memory leak on error return +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Zongmin Zhou , kernel test robot , Dan Carpenter , Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-149-linkinjeon@kernel.org> + +From: Zongmin Zhou + +[ Upstream commit 90044481e7cca6cb3125b3906544954a25f1309f ] + +When allocated memory for 'new' failed,just return +will cause memory leak of 'ar'. + +Fixes: 1819a9042999 ("ksmbd: reorganize ksmbd_iov_pin_rsp()") +Reported-by: kernel test robot +Reported-by: Dan Carpenter +Closes: https://lore.kernel.org/r/202311031837.H3yo7JVl-lkp@intel.com/ +Signed-off-by: Zongmin Zhou +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/ksmbd_work.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +--- a/fs/ksmbd/ksmbd_work.c ++++ b/fs/ksmbd/ksmbd_work.c +@@ -106,7 +106,7 @@ static inline void __ksmbd_iov_pin(struc + static int __ksmbd_iov_pin_rsp(struct ksmbd_work *work, void *ib, int len, + void *aux_buf, unsigned int aux_size) + { +- struct aux_read *ar; ++ struct aux_read *ar = NULL; + int need_iov_cnt = 1; + + if (aux_size) { +@@ -123,8 +123,11 @@ static int __ksmbd_iov_pin_rsp(struct ks + new = krealloc(work->iov, + sizeof(struct kvec) * work->iov_alloc_cnt, + GFP_KERNEL | __GFP_ZERO); +- if (!new) ++ if (!new) { ++ kfree(ar); ++ work->iov_alloc_cnt -= 4; + return -ENOMEM; ++ } + work->iov = new; + } + diff --git a/queue-5.15/ksmbd-reduce-descriptor-size-if-remaining-bytes-is-less-than-request-size.patch b/queue-5.15/ksmbd-reduce-descriptor-size-if-remaining-bytes-is-less-than-request-size.patch new file mode 100644 index 00000000000..76f46afe5ec --- /dev/null +++ b/queue-5.15/ksmbd-reduce-descriptor-size-if-remaining-bytes-is-less-than-request-size.patch @@ -0,0 +1,107 @@ +From stable+bounces-7751-greg=kroah.com@vger.kernel.org Mon Dec 18 16:47:02 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:34:22 +0900 +Subject: ksmbd: reduce descriptor size if remaining bytes is less than request size +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-123-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit e628bf939aafb61fbc56e9bdac8795cea5127e25 ] + +Create 3 kinds of files to reproduce this problem. + +dd if=/dev/urandom of=127k.bin bs=1024 count=127 +dd if=/dev/urandom of=128k.bin bs=1024 count=128 +dd if=/dev/urandom of=129k.bin bs=1024 count=129 + +When copying files from ksmbd share to windows or cifs.ko, The following +error message happen from windows client. + +"The file '129k.bin' is too large for the destination filesystem." + +We can see the error logs from ksmbd debug prints + +[48394.611537] ksmbd: RDMA r/w request 0x0: token 0x669d, length 0x20000 +[48394.612054] ksmbd: smb_direct: RDMA write, len 0x20000, needed credits 0x1 +[48394.612572] ksmbd: filename 129k.bin, offset 131072, len 131072 +[48394.614189] ksmbd: nbytes 1024, offset 132096 mincount 0 +[48394.614585] ksmbd: Failed to process 8 [-22] + +And we can reproduce it with cifs.ko, +e.g. dd if=129k.bin of=/dev/null bs=128KB count=2 + +This problem is that ksmbd rdma return error if remaining bytes is less +than Length of Buffer Descriptor V1 Structure. + +smb_direct_rdma_xmit() +... + if (desc_buf_len == 0 || total_length > buf_len || + total_length > t->max_rdma_rw_size) + return -EINVAL; + +This patch reduce descriptor size with remaining bytes and remove the +check for total_length and buf_len. + +Cc: stable@vger.kernel.org +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/transport_rdma.c | 25 ++++++++++++++++++------- + 1 file changed, 18 insertions(+), 7 deletions(-) + +--- a/fs/ksmbd/transport_rdma.c ++++ b/fs/ksmbd/transport_rdma.c +@@ -1364,24 +1364,35 @@ static int smb_direct_rdma_xmit(struct s + LIST_HEAD(msg_list); + char *desc_buf; + int credits_needed; +- unsigned int desc_buf_len; +- size_t total_length = 0; ++ unsigned int desc_buf_len, desc_num = 0; + + if (t->status != SMB_DIRECT_CS_CONNECTED) + return -ENOTCONN; + ++ if (buf_len > t->max_rdma_rw_size) ++ return -EINVAL; ++ + /* calculate needed credits */ + credits_needed = 0; + desc_buf = buf; + for (i = 0; i < desc_len / sizeof(*desc); i++) { ++ if (!buf_len) ++ break; ++ + desc_buf_len = le32_to_cpu(desc[i].length); ++ if (!desc_buf_len) ++ return -EINVAL; ++ ++ if (desc_buf_len > buf_len) { ++ desc_buf_len = buf_len; ++ desc[i].length = cpu_to_le32(desc_buf_len); ++ buf_len = 0; ++ } + + credits_needed += calc_rw_credits(t, desc_buf, desc_buf_len); + desc_buf += desc_buf_len; +- total_length += desc_buf_len; +- if (desc_buf_len == 0 || total_length > buf_len || +- total_length > t->max_rdma_rw_size) +- return -EINVAL; ++ buf_len -= desc_buf_len; ++ desc_num++; + } + + ksmbd_debug(RDMA, "RDMA %s, len %#x, needed credits %#x\n", +@@ -1393,7 +1404,7 @@ static int smb_direct_rdma_xmit(struct s + + /* build rdma_rw_ctx for each descriptor */ + desc_buf = buf; +- for (i = 0; i < desc_len / sizeof(*desc); i++) { ++ for (i = 0; i < desc_num; i++) { + msg = kzalloc(offsetof(struct smb_direct_rdma_rw_msg, sg_list) + + sizeof(struct scatterlist) * SG_CHUNK_SIZE, GFP_KERNEL); + if (!msg) { diff --git a/queue-5.15/ksmbd-reduce-server-smbdirect-max-send-receive-segment-sizes.patch b/queue-5.15/ksmbd-reduce-server-smbdirect-max-send-receive-segment-sizes.patch new file mode 100644 index 00000000000..fc741a441be --- /dev/null +++ b/queue-5.15/ksmbd-reduce-server-smbdirect-max-send-receive-segment-sizes.patch @@ -0,0 +1,42 @@ +From linkinjeon@gmail.com Mon Dec 18 16:38:34 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:33:19 +0900 +Subject: ksmbd: reduce server smbdirect max send/receive segment sizes +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Tom Talpey , Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-60-linkinjeon@kernel.org> + +From: Tom Talpey + +[ Upstream commit 78af146e109bef5b3c411964141c6f8adbccd3b0 ] + +Reduce ksmbd smbdirect max segment send and receive size to 1364 +to match protocol norms. Larger buffers are unnecessary and add +significant memory overhead. + +Signed-off-by: Tom Talpey +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/transport_rdma.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/fs/ksmbd/transport_rdma.c ++++ b/fs/ksmbd/transport_rdma.c +@@ -62,13 +62,13 @@ static int smb_direct_receive_credit_max + static int smb_direct_send_credit_target = 255; + + /* The maximum single message size can be sent to remote peer */ +-static int smb_direct_max_send_size = 8192; ++static int smb_direct_max_send_size = 1364; + + /* The maximum fragmented upper-layer payload receive size supported */ + static int smb_direct_max_fragmented_recv_size = 1024 * 1024; + + /* The maximum single-message size which can be received */ +-static int smb_direct_max_receive_size = 8192; ++static int smb_direct_max_receive_size = 1364; + + static int smb_direct_max_read_write_size = SMBD_DEFAULT_IOSIZE; + diff --git a/queue-5.15/ksmbd-register-ksmbd-ib-client-with-ib_register_client.patch b/queue-5.15/ksmbd-register-ksmbd-ib-client-with-ib_register_client.patch new file mode 100644 index 00000000000..db6ff593f86 --- /dev/null +++ b/queue-5.15/ksmbd-register-ksmbd-ib-client-with-ib_register_client.patch @@ -0,0 +1,186 @@ +From stable+bounces-7645-greg=kroah.com@vger.kernel.org Mon Dec 18 16:37:48 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:32:36 +0900 +Subject: ksmbd: register ksmbd ib client with ib_register_client() +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Hyunchul Lee , Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-17-linkinjeon@kernel.org> + +From: Hyunchul Lee + +[ Upstream commit 31928a001bed0d9642711d2eba520fc46d41c376 ] + +Register ksmbd ib client with ib_register_client() to find the rdma capable +network adapter. If ops.get_netdev(Chelsio NICs) is NULL, ksmbd will find +it using ib_device_get_by_netdev in old way. + +Signed-off-by: Hyunchul Lee +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/transport_rdma.c | 107 +++++++++++++++++++++++++++++++++++++++++----- + fs/ksmbd/transport_rdma.h | 2 + 2 files changed, 98 insertions(+), 11 deletions(-) + +--- a/fs/ksmbd/transport_rdma.c ++++ b/fs/ksmbd/transport_rdma.c +@@ -79,6 +79,14 @@ static int smb_direct_max_read_write_siz + + static int smb_direct_max_outstanding_rw_ops = 8; + ++static LIST_HEAD(smb_direct_device_list); ++static DEFINE_RWLOCK(smb_direct_device_lock); ++ ++struct smb_direct_device { ++ struct ib_device *ib_dev; ++ struct list_head list; ++}; ++ + static struct smb_direct_listener { + struct rdma_cm_id *cm_id; + } smb_direct_listener; +@@ -2013,12 +2021,61 @@ err: + return ret; + } + ++static int smb_direct_ib_client_add(struct ib_device *ib_dev) ++{ ++ struct smb_direct_device *smb_dev; ++ ++ if (!ib_dev->ops.get_netdev || ++ !rdma_frwr_is_supported(&ib_dev->attrs)) ++ return 0; ++ ++ smb_dev = kzalloc(sizeof(*smb_dev), GFP_KERNEL); ++ if (!smb_dev) ++ return -ENOMEM; ++ smb_dev->ib_dev = ib_dev; ++ ++ write_lock(&smb_direct_device_lock); ++ list_add(&smb_dev->list, &smb_direct_device_list); ++ write_unlock(&smb_direct_device_lock); ++ ++ ksmbd_debug(RDMA, "ib device added: name %s\n", ib_dev->name); ++ return 0; ++} ++ ++static void smb_direct_ib_client_remove(struct ib_device *ib_dev, ++ void *client_data) ++{ ++ struct smb_direct_device *smb_dev, *tmp; ++ ++ write_lock(&smb_direct_device_lock); ++ list_for_each_entry_safe(smb_dev, tmp, &smb_direct_device_list, list) { ++ if (smb_dev->ib_dev == ib_dev) { ++ list_del(&smb_dev->list); ++ kfree(smb_dev); ++ break; ++ } ++ } ++ write_unlock(&smb_direct_device_lock); ++} ++ ++static struct ib_client smb_direct_ib_client = { ++ .name = "ksmbd_smb_direct_ib", ++ .add = smb_direct_ib_client_add, ++ .remove = smb_direct_ib_client_remove, ++}; ++ + int ksmbd_rdma_init(void) + { + int ret; + + smb_direct_listener.cm_id = NULL; + ++ ret = ib_register_client(&smb_direct_ib_client); ++ if (ret) { ++ pr_err("failed to ib_register_client\n"); ++ return ret; ++ } ++ + /* When a client is running out of send credits, the credits are + * granted by the server's sending a packet using this queue. + * This avoids the situation that a clients cannot send packets +@@ -2042,30 +2099,60 @@ int ksmbd_rdma_init(void) + return 0; + } + +-int ksmbd_rdma_destroy(void) ++void ksmbd_rdma_destroy(void) + { +- if (smb_direct_listener.cm_id) +- rdma_destroy_id(smb_direct_listener.cm_id); ++ if (!smb_direct_listener.cm_id) ++ return; ++ ++ ib_unregister_client(&smb_direct_ib_client); ++ rdma_destroy_id(smb_direct_listener.cm_id); ++ + smb_direct_listener.cm_id = NULL; + + if (smb_direct_wq) { + destroy_workqueue(smb_direct_wq); + smb_direct_wq = NULL; + } +- return 0; + } + + bool ksmbd_rdma_capable_netdev(struct net_device *netdev) + { +- struct ib_device *ibdev; ++ struct smb_direct_device *smb_dev; ++ int i; + bool rdma_capable = false; + +- ibdev = ib_device_get_by_netdev(netdev, RDMA_DRIVER_UNKNOWN); +- if (ibdev) { +- if (rdma_frwr_is_supported(&ibdev->attrs)) +- rdma_capable = true; +- ib_device_put(ibdev); ++ read_lock(&smb_direct_device_lock); ++ list_for_each_entry(smb_dev, &smb_direct_device_list, list) { ++ for (i = 0; i < smb_dev->ib_dev->phys_port_cnt; i++) { ++ struct net_device *ndev; ++ ++ ndev = smb_dev->ib_dev->ops.get_netdev(smb_dev->ib_dev, ++ i + 1); ++ if (!ndev) ++ continue; ++ ++ if (ndev == netdev) { ++ dev_put(ndev); ++ rdma_capable = true; ++ goto out; ++ } ++ dev_put(ndev); ++ } + } ++out: ++ read_unlock(&smb_direct_device_lock); ++ ++ if (rdma_capable == false) { ++ struct ib_device *ibdev; ++ ++ ibdev = ib_device_get_by_netdev(netdev, RDMA_DRIVER_UNKNOWN); ++ if (ibdev) { ++ if (rdma_frwr_is_supported(&ibdev->attrs)) ++ rdma_capable = true; ++ ib_device_put(ibdev); ++ } ++ } ++ + return rdma_capable; + } + +--- a/fs/ksmbd/transport_rdma.h ++++ b/fs/ksmbd/transport_rdma.h +@@ -56,7 +56,7 @@ struct smb_direct_data_transfer { + + #ifdef CONFIG_SMB_SERVER_SMBDIRECT + int ksmbd_rdma_init(void); +-int ksmbd_rdma_destroy(void); ++void ksmbd_rdma_destroy(void); + bool ksmbd_rdma_capable_netdev(struct net_device *netdev); + void init_smbd_max_io_size(unsigned int sz); + #else diff --git a/queue-5.15/ksmbd-release-interim-response-after-sending-status-pending-response.patch b/queue-5.15/ksmbd-release-interim-response-after-sending-status-pending-response.patch new file mode 100644 index 00000000000..84422fd8a1d --- /dev/null +++ b/queue-5.15/ksmbd-release-interim-response-after-sending-status-pending-response.patch @@ -0,0 +1,47 @@ +From linkinjeon@gmail.com Mon Dec 18 16:43:35 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:34:52 +0900 +Subject: ksmbd: release interim response after sending status pending response +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-153-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit 2a3f7857ec742e212d6cee7fbbf7b0e2ae7f5161 ] + +Add missing release async id and delete interim response entry after +sending status pending response. This only cause when smb2 lease is enable. + +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/ksmbd_work.c | 3 +++ + fs/ksmbd/oplock.c | 3 ++- + 2 files changed, 5 insertions(+), 1 deletion(-) + +--- a/fs/ksmbd/ksmbd_work.c ++++ b/fs/ksmbd/ksmbd_work.c +@@ -56,6 +56,9 @@ void ksmbd_free_work_struct(struct ksmbd + kfree(work->tr_buf); + kvfree(work->request_buf); + kfree(work->iov); ++ if (!list_empty(&work->interim_entry)) ++ list_del(&work->interim_entry); ++ + if (work->async_id) + ksmbd_release_id(&work->conn->async_ida, work->async_id); + kmem_cache_free(work_cache, work); +--- a/fs/ksmbd/oplock.c ++++ b/fs/ksmbd/oplock.c +@@ -833,7 +833,8 @@ static int smb2_lease_break_noti(struct + interim_entry); + setup_async_work(in_work, NULL, NULL); + smb2_send_interim_resp(in_work, STATUS_PENDING); +- list_del(&in_work->interim_entry); ++ list_del_init(&in_work->interim_entry); ++ release_async_work(in_work); + } + INIT_WORK(&work->work, __smb2_lease_break_noti); + ksmbd_queue_work(work); diff --git a/queue-5.15/ksmbd-remove-a-redundant-zeroing-of-memory.patch b/queue-5.15/ksmbd-remove-a-redundant-zeroing-of-memory.patch new file mode 100644 index 00000000000..9984e9fe2f4 --- /dev/null +++ b/queue-5.15/ksmbd-remove-a-redundant-zeroing-of-memory.patch @@ -0,0 +1,40 @@ +From linkinjeon@gmail.com Mon Dec 18 16:36:54 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:32:48 +0900 +Subject: ksmbd: Remove a redundant zeroing of memory +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Christophe JAILLET , Hyunchul Lee , Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-29-linkinjeon@kernel.org> + +From: Christophe JAILLET + +[ Upstream commit 56b401fb0c506120f25c1b4feeb96d9117efe171 ] + +fill_transform_hdr() has only one caller that already clears tr_buf (it is +kzalloc'ed). + +So there is no need to clear it another time here. + +Remove the superfluous memset() and add a comment to remind that the caller +must clear the buffer. + +Signed-off-by: Christophe JAILLET +Acked-by: Hyunchul Lee +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/smb2pdu.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -8602,7 +8602,7 @@ static void fill_transform_hdr(void *tr_ + struct smb2_hdr *hdr = smb2_get_msg(old_buf); + unsigned int orig_len = get_rfc1002_len(old_buf); + +- memset(tr_buf, 0, sizeof(struct smb2_transform_hdr) + 4); ++ /* tr_buf must be cleared by the caller */ + tr_hdr->ProtocolId = SMB2_TRANSFORM_PROTO_NUM; + tr_hdr->OriginalMessageSize = cpu_to_le32(orig_len); + tr_hdr->Flags = cpu_to_le16(0x01); diff --git a/queue-5.15/ksmbd-remove-duplicate-flag-set-in-smb2_write.patch b/queue-5.15/ksmbd-remove-duplicate-flag-set-in-smb2_write.patch new file mode 100644 index 00000000000..4ec312b3b57 --- /dev/null +++ b/queue-5.15/ksmbd-remove-duplicate-flag-set-in-smb2_write.patch @@ -0,0 +1,43 @@ +From linkinjeon@gmail.com Mon Dec 18 16:37:42 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:33:03 +0900 +Subject: ksmbd: remove duplicate flag set in smb2_write +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Hyunchul Lee , Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-44-linkinjeon@kernel.org> + +From: Hyunchul Lee + +[ Upstream commit 745bbc0995c25917dfafb645b8efb29813ef9e0b ] + +The writethrough flag is set again if is_rdma_channel is false. + +Signed-off-by: Hyunchul Lee +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/smb2pdu.c | 5 +---- + 1 file changed, 1 insertion(+), 4 deletions(-) + +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -6564,6 +6564,7 @@ int smb2_write(struct ksmbd_work *work) + goto out; + } + ++ ksmbd_debug(SMB, "flags %u\n", le32_to_cpu(req->Flags)); + if (le32_to_cpu(req->Flags) & SMB2_WRITEFLAG_WRITE_THROUGH) + writethrough = true; + +@@ -6577,10 +6578,6 @@ int smb2_write(struct ksmbd_work *work) + data_buf = (char *)(((char *)&req->hdr.ProtocolId) + + le16_to_cpu(req->DataOffset)); + +- ksmbd_debug(SMB, "flags %u\n", le32_to_cpu(req->Flags)); +- if (le32_to_cpu(req->Flags) & SMB2_WRITEFLAG_WRITE_THROUGH) +- writethrough = true; +- + ksmbd_debug(SMB, "filename %pd, offset %lld, len %zu\n", + fp->filp->f_path.dentry, offset, length); + err = ksmbd_vfs_write(work, fp, data_buf, length, &offset, diff --git a/queue-5.15/ksmbd-remove-duplicated-codes.patch b/queue-5.15/ksmbd-remove-duplicated-codes.patch new file mode 100644 index 00000000000..aeecdf9eab0 --- /dev/null +++ b/queue-5.15/ksmbd-remove-duplicated-codes.patch @@ -0,0 +1,64 @@ +From linkinjeon@gmail.com Mon Dec 18 16:39:17 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:33:33 +0900 +Subject: ksmbd: Remove duplicated codes +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Dawei Li , Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-74-linkinjeon@kernel.org> + +From: Dawei Li + +[ Upstream commit 7010357004096e54c884813e702d71147dc081f8 ] + +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 +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/asn1.c | 23 +++++++++++------------ + 1 file changed, 11 insertions(+), 12 deletions(-) + +--- a/fs/ksmbd/asn1.c ++++ b/fs/ksmbd/asn1.c +@@ -208,9 +208,9 @@ int ksmbd_neg_token_init_mech_type(void + 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 + 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); + } diff --git a/queue-5.15/ksmbd-remove-experimental-warning.patch b/queue-5.15/ksmbd-remove-experimental-warning.patch new file mode 100644 index 00000000000..75229de7788 --- /dev/null +++ b/queue-5.15/ksmbd-remove-experimental-warning.patch @@ -0,0 +1,44 @@ +From linkinjeon@gmail.com Mon Dec 18 16:42:07 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:34:26 +0900 +Subject: ksmbd: remove experimental warning +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Steve French , Namjae Jeon +Message-ID: <20231218153454.8090-127-linkinjeon@kernel.org> + +From: Steve French + +[ Upstream commit f5069159f32c8c943e047f22731317463c8e9b84 ] + +ksmbd has made significant improvements over the past two +years and is regularly tested and used. Remove the experimental +warning. + +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/Kconfig | 2 +- + fs/ksmbd/server.c | 2 -- + 2 files changed, 1 insertion(+), 3 deletions(-) + +--- a/fs/ksmbd/Kconfig ++++ b/fs/ksmbd/Kconfig +@@ -1,5 +1,5 @@ + config SMB_SERVER +- tristate "SMB3 server support (EXPERIMENTAL)" ++ tristate "SMB3 server support" + depends on INET + depends on MULTIUSER + depends on FILE_LOCKING +--- a/fs/ksmbd/server.c ++++ b/fs/ksmbd/server.c +@@ -591,8 +591,6 @@ static int __init ksmbd_server_init(void + if (ret) + goto err_crypto_destroy; + +- pr_warn_once("The ksmbd server is experimental\n"); +- + return 0; + + err_crypto_destroy: diff --git a/queue-5.15/ksmbd-remove-filename-in-ksmbd_file.patch b/queue-5.15/ksmbd-remove-filename-in-ksmbd_file.patch new file mode 100644 index 00000000000..41baf20e3c5 --- /dev/null +++ b/queue-5.15/ksmbd-remove-filename-in-ksmbd_file.patch @@ -0,0 +1,256 @@ +From linkinjeon@gmail.com Mon Dec 18 16:37:03 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:32:51 +0900 +Subject: ksmbd: remove filename in ksmbd_file +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , Hyunchul Lee , Steve French +Message-ID: <20231218153454.8090-32-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit 50f500b7f6335404b18bbffa93e3a905a08d061a ] + +If the filename is change by underlying rename the server, fp->filename +and real filename can be different. This patch remove the uses of +fp->filename in ksmbd and replace it with d_path(). + +Signed-off-by: Namjae Jeon +Reviewed-by: Hyunchul Lee +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/misc.c | 40 +++++++++++++++++++++++++++++++--------- + fs/ksmbd/misc.h | 3 ++- + fs/ksmbd/oplock.c | 30 ------------------------------ + fs/ksmbd/oplock.h | 2 -- + fs/ksmbd/smb2pdu.c | 21 +++++++-------------- + fs/ksmbd/vfs.c | 6 ++---- + fs/ksmbd/vfs_cache.c | 1 - + fs/ksmbd/vfs_cache.h | 1 - + 8 files changed, 42 insertions(+), 62 deletions(-) + +--- a/fs/ksmbd/misc.c ++++ b/fs/ksmbd/misc.c +@@ -158,19 +158,41 @@ out: + * Return : windows path string or error + */ + +-char *convert_to_nt_pathname(char *filename) ++char *convert_to_nt_pathname(struct ksmbd_share_config *share, ++ struct path *path) + { +- char *ab_pathname; ++ char *pathname, *ab_pathname, *nt_pathname; ++ int share_path_len = share->path_sz; + +- if (strlen(filename) == 0) +- filename = "\\"; ++ pathname = kmalloc(PATH_MAX, GFP_KERNEL); ++ if (!pathname) ++ return ERR_PTR(-EACCES); + +- ab_pathname = kstrdup(filename, GFP_KERNEL); +- if (!ab_pathname) +- return NULL; ++ ab_pathname = d_path(path, pathname, PATH_MAX); ++ if (IS_ERR(ab_pathname)) { ++ nt_pathname = ERR_PTR(-EACCES); ++ goto free_pathname; ++ } + +- ksmbd_conv_path_to_windows(ab_pathname); +- return ab_pathname; ++ if (strncmp(ab_pathname, share->path, share_path_len)) { ++ nt_pathname = ERR_PTR(-EACCES); ++ goto free_pathname; ++ } ++ ++ nt_pathname = kzalloc(strlen(&ab_pathname[share_path_len]) + 2, GFP_KERNEL); ++ if (!nt_pathname) { ++ nt_pathname = ERR_PTR(-ENOMEM); ++ goto free_pathname; ++ } ++ if (ab_pathname[share_path_len] == '\0') ++ strcpy(nt_pathname, "/"); ++ strcat(nt_pathname, &ab_pathname[share_path_len]); ++ ++ ksmbd_conv_path_to_windows(nt_pathname); ++ ++free_pathname: ++ kfree(pathname); ++ return nt_pathname; + } + + int get_nlink(struct kstat *st) +--- a/fs/ksmbd/misc.h ++++ b/fs/ksmbd/misc.h +@@ -14,7 +14,8 @@ struct ksmbd_file; + int match_pattern(const char *str, size_t len, const char *pattern); + int ksmbd_validate_filename(char *filename); + int parse_stream_name(char *filename, char **stream_name, int *s_type); +-char *convert_to_nt_pathname(char *filename); ++char *convert_to_nt_pathname(struct ksmbd_share_config *share, ++ struct path *path); + int get_nlink(struct kstat *st); + void ksmbd_conv_path_to_unix(char *path); + void ksmbd_strip_last_slash(char *path); +--- a/fs/ksmbd/oplock.c ++++ b/fs/ksmbd/oplock.c +@@ -1696,33 +1696,3 @@ out: + read_unlock(&lease_list_lock); + return ret_op; + } +- +-int smb2_check_durable_oplock(struct ksmbd_file *fp, +- struct lease_ctx_info *lctx, char *name) +-{ +- struct oplock_info *opinfo = opinfo_get(fp); +- int ret = 0; +- +- if (opinfo && opinfo->is_lease) { +- if (!lctx) { +- pr_err("open does not include lease\n"); +- ret = -EBADF; +- goto out; +- } +- if (memcmp(opinfo->o_lease->lease_key, lctx->lease_key, +- SMB2_LEASE_KEY_SIZE)) { +- pr_err("invalid lease key\n"); +- ret = -EBADF; +- goto out; +- } +- if (name && strcmp(fp->filename, name)) { +- pr_err("invalid name reconnect %s\n", name); +- ret = -EINVAL; +- goto out; +- } +- } +-out: +- if (opinfo) +- opinfo_put(opinfo); +- return ret; +-} +--- a/fs/ksmbd/oplock.h ++++ b/fs/ksmbd/oplock.h +@@ -124,6 +124,4 @@ struct oplock_info *lookup_lease_in_tabl + int find_same_lease_key(struct ksmbd_session *sess, struct ksmbd_inode *ci, + struct lease_ctx_info *lctx); + void destroy_lease_table(struct ksmbd_conn *conn); +-int smb2_check_durable_oplock(struct ksmbd_file *fp, +- struct lease_ctx_info *lctx, char *name); + #endif /* __KSMBD_OPLOCK_H */ +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -2988,7 +2988,6 @@ int smb2_open(struct ksmbd_work *work) + goto err_out; + } + +- fp->filename = name; + fp->cdoption = req->CreateDisposition; + fp->daccess = daccess; + fp->saccess = req->ShareAccess; +@@ -3343,14 +3342,13 @@ err_out1: + if (!rsp->hdr.Status) + rsp->hdr.Status = STATUS_UNEXPECTED_IO_ERROR; + +- if (!fp || !fp->filename) +- kfree(name); + if (fp) + ksmbd_fd_put(work, fp); + smb2_set_err_rsp(work); + ksmbd_debug(SMB, "Error response: %x\n", rsp->hdr.Status); + } + ++ kfree(name); + kfree(lc); + + return 0; +@@ -3969,8 +3967,6 @@ int smb2_query_dir(struct ksmbd_work *wo + ksmbd_debug(SMB, "Search pattern is %s\n", srch_ptr); + } + +- ksmbd_debug(SMB, "Directory name is %s\n", dir_fp->filename); +- + if (srch_flag & SMB2_REOPEN || srch_flag & SMB2_RESTART_SCANS) { + ksmbd_debug(SMB, "Restart directory scan\n"); + generic_file_llseek(dir_fp->filp, 0, SEEK_SET); +@@ -4456,9 +4452,9 @@ static int get_file_all_info(struct ksmb + return -EACCES; + } + +- filename = convert_to_nt_pathname(fp->filename); +- if (!filename) +- return -ENOMEM; ++ filename = convert_to_nt_pathname(work->tcon->share_conf, &fp->filp->f_path); ++ if (IS_ERR(filename)) ++ return PTR_ERR(filename); + + inode = file_inode(fp->filp); + generic_fillattr(file_mnt_user_ns(fp->filp), inode, &stat); +@@ -5761,8 +5757,7 @@ static int set_file_allocation_info(stru + size = i_size_read(inode); + rc = ksmbd_vfs_truncate(work, fp, alloc_blks * 512); + if (rc) { +- pr_err("truncate failed! filename : %s, err %d\n", +- fp->filename, rc); ++ pr_err("truncate failed!, err %d\n", rc); + return rc; + } + if (size < alloc_blks * 512) +@@ -5792,12 +5787,10 @@ static int set_end_of_file_info(struct k + * truncated range. + */ + if (inode->i_sb->s_magic != MSDOS_SUPER_MAGIC) { +- ksmbd_debug(SMB, "filename : %s truncated to newsize %lld\n", +- fp->filename, newsize); ++ ksmbd_debug(SMB, "truncated to newsize %lld\n", newsize); + rc = ksmbd_vfs_truncate(work, fp, newsize); + if (rc) { +- ksmbd_debug(SMB, "truncate failed! filename : %s err %d\n", +- fp->filename, rc); ++ ksmbd_debug(SMB, "truncate failed!, err %d\n", rc); + if (rc != -EAGAIN) + rc = -EBADF; + return rc; +--- a/fs/ksmbd/vfs.c ++++ b/fs/ksmbd/vfs.c +@@ -397,8 +397,7 @@ int ksmbd_vfs_read(struct ksmbd_work *wo + + nbytes = kernel_read(filp, rbuf, count, pos); + if (nbytes < 0) { +- pr_err("smb read failed for (%s), err = %zd\n", +- fp->filename, nbytes); ++ pr_err("smb read failed, err = %zd\n", nbytes); + return nbytes; + } + +@@ -873,8 +872,7 @@ int ksmbd_vfs_truncate(struct ksmbd_work + + err = vfs_truncate(&filp->f_path, size); + if (err) +- pr_err("truncate failed for filename : %s err %d\n", +- fp->filename, err); ++ pr_err("truncate failed, err %d\n", err); + return err; + } + +--- a/fs/ksmbd/vfs_cache.c ++++ b/fs/ksmbd/vfs_cache.c +@@ -328,7 +328,6 @@ static void __ksmbd_close_fd(struct ksmb + kfree(smb_lock); + } + +- kfree(fp->filename); + if (ksmbd_stream_fd(fp)) + kfree(fp->stream.name); + kmem_cache_free(filp_cache, fp); +--- a/fs/ksmbd/vfs_cache.h ++++ b/fs/ksmbd/vfs_cache.h +@@ -62,7 +62,6 @@ struct ksmbd_inode { + + struct ksmbd_file { + struct file *filp; +- char *filename; + u64 persistent_id; + u64 volatile_id; + diff --git a/queue-5.15/ksmbd-remove-generic_fillattr-use-in-smb2_open.patch b/queue-5.15/ksmbd-remove-generic_fillattr-use-in-smb2_open.patch new file mode 100644 index 00000000000..d339e740d46 --- /dev/null +++ b/queue-5.15/ksmbd-remove-generic_fillattr-use-in-smb2_open.patch @@ -0,0 +1,61 @@ +From linkinjeon@gmail.com Mon Dec 18 16:38:10 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:33:11 +0900 +Subject: ksmbd: remove generic_fillattr use in smb2_open() +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , Hyunchul Lee , Steve French +Message-ID: <20231218153454.8090-52-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit 823d0d3e2b05791ba8cbab22574b947c21f89c18 ] + +Removed the use of unneeded generic_fillattr() in smb2_open(). + +Reviewed-by: Hyunchul Lee +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/smb2pdu.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -2809,7 +2809,6 @@ int smb2_open(struct ksmbd_work *work) + } else { + file_present = true; + user_ns = mnt_user_ns(path.mnt); +- generic_fillattr(user_ns, d_inode(path.dentry), &stat); + } + if (stream_name) { + if (req->CreateOptions & FILE_DIRECTORY_FILE_LE) { +@@ -2818,7 +2817,8 @@ int smb2_open(struct ksmbd_work *work) + rsp->hdr.Status = STATUS_NOT_A_DIRECTORY; + } + } else { +- if (S_ISDIR(stat.mode) && s_type == DATA_STREAM) { ++ if (file_present && S_ISDIR(d_inode(path.dentry)->i_mode) && ++ s_type == DATA_STREAM) { + rc = -EIO; + rsp->hdr.Status = STATUS_FILE_IS_A_DIRECTORY; + } +@@ -2835,7 +2835,8 @@ int smb2_open(struct ksmbd_work *work) + } + + if (file_present && req->CreateOptions & FILE_NON_DIRECTORY_FILE_LE && +- S_ISDIR(stat.mode) && !(req->CreateOptions & FILE_DELETE_ON_CLOSE_LE)) { ++ S_ISDIR(d_inode(path.dentry)->i_mode) && ++ !(req->CreateOptions & FILE_DELETE_ON_CLOSE_LE)) { + ksmbd_debug(SMB, "open() argument is a directory: %s, %x\n", + name, req->CreateOptions); + rsp->hdr.Status = STATUS_FILE_IS_A_DIRECTORY; +@@ -2845,7 +2846,7 @@ int smb2_open(struct ksmbd_work *work) + + if (file_present && (req->CreateOptions & FILE_DIRECTORY_FILE_LE) && + !(req->CreateDisposition == FILE_CREATE_LE) && +- !S_ISDIR(stat.mode)) { ++ !S_ISDIR(d_inode(path.dentry)->i_mode)) { + rsp->hdr.Status = STATUS_NOT_A_DIRECTORY; + rc = -EIO; + goto err_out; diff --git a/queue-5.15/ksmbd-remove-md4-leftovers.patch b/queue-5.15/ksmbd-remove-md4-leftovers.patch new file mode 100644 index 00000000000..358072b79e0 --- /dev/null +++ b/queue-5.15/ksmbd-remove-md4-leftovers.patch @@ -0,0 +1,44 @@ +From stable+bounces-7633-greg=kroah.com@vger.kernel.org Mon Dec 18 16:35:38 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:32:24 +0900 +Subject: ksmbd: remove md4 leftovers +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , Hyunchul Lee , Steve French +Message-ID: <20231218153454.8090-5-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit 561a1cf57535154f094f31167a9170197caae686 ] + +As NTLM authentication is removed, md4 is no longer used. +ksmbd remove md4 leftovers, i.e. select CRYPTO_MD4, MODULE_SOFTDEP md4. + +Acked-by: Hyunchul Lee +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/Kconfig | 1 - + fs/ksmbd/server.c | 1 - + 2 files changed, 2 deletions(-) + +--- a/fs/ksmbd/Kconfig ++++ b/fs/ksmbd/Kconfig +@@ -6,7 +6,6 @@ config SMB_SERVER + select NLS + select NLS_UTF8 + select CRYPTO +- select CRYPTO_MD4 + select CRYPTO_MD5 + select CRYPTO_HMAC + select CRYPTO_ECB +--- a/fs/ksmbd/server.c ++++ b/fs/ksmbd/server.c +@@ -628,7 +628,6 @@ MODULE_DESCRIPTION("Linux kernel CIFS/SM + MODULE_LICENSE("GPL"); + MODULE_SOFTDEP("pre: ecb"); + MODULE_SOFTDEP("pre: hmac"); +-MODULE_SOFTDEP("pre: md4"); + MODULE_SOFTDEP("pre: md5"); + MODULE_SOFTDEP("pre: nls"); + MODULE_SOFTDEP("pre: aes"); diff --git a/queue-5.15/ksmbd-remove-redundant-flush_workqueue-calls.patch b/queue-5.15/ksmbd-remove-redundant-flush_workqueue-calls.patch new file mode 100644 index 00000000000..e77c83b99e9 --- /dev/null +++ b/queue-5.15/ksmbd-remove-redundant-flush_workqueue-calls.patch @@ -0,0 +1,54 @@ +From stable+bounces-7632-greg=kroah.com@vger.kernel.org Mon Dec 18 16:35:37 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:32:23 +0900 +Subject: ksmbd: Remove redundant 'flush_workqueue()' calls +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Christophe JAILLET , Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-4-linkinjeon@kernel.org> + +From: Christophe JAILLET + +[ Upstream commit e8d585b2f68c0b10c966ee55146de043429085a3 ] + +'destroy_workqueue()' already drains the queue before destroying it, so +there is no need to flush it explicitly. + +Remove the redundant 'flush_workqueue()' calls. + +This was generated with coccinelle: + +@@ +expression E; +@@ +- flush_workqueue(E); + destroy_workqueue(E); + +Acked-by: Namjae Jeon +Signed-off-by: Christophe JAILLET +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/ksmbd_work.c | 1 - + fs/ksmbd/transport_rdma.c | 1 - + 2 files changed, 2 deletions(-) + +--- a/fs/ksmbd/ksmbd_work.c ++++ b/fs/ksmbd/ksmbd_work.c +@@ -69,7 +69,6 @@ int ksmbd_workqueue_init(void) + + void ksmbd_workqueue_destroy(void) + { +- flush_workqueue(ksmbd_wq); + destroy_workqueue(ksmbd_wq); + ksmbd_wq = NULL; + } +--- a/fs/ksmbd/transport_rdma.c ++++ b/fs/ksmbd/transport_rdma.c +@@ -2049,7 +2049,6 @@ int ksmbd_rdma_destroy(void) + smb_direct_listener.cm_id = NULL; + + if (smb_direct_wq) { +- flush_workqueue(smb_direct_wq); + destroy_workqueue(smb_direct_wq); + smb_direct_wq = NULL; + } diff --git a/queue-5.15/ksmbd-remove-smb2_buf_length-in-smb2_hdr.patch b/queue-5.15/ksmbd-remove-smb2_buf_length-in-smb2_hdr.patch new file mode 100644 index 00000000000..3342780d2de --- /dev/null +++ b/queue-5.15/ksmbd-remove-smb2_buf_length-in-smb2_hdr.patch @@ -0,0 +1,1833 @@ +From stable+bounces-7634-greg=kroah.com@vger.kernel.org Mon Dec 18 16:35:40 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:32:25 +0900 +Subject: ksmbd: remove smb2_buf_length in smb2_hdr +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , Ronnie Sahlberg , Steve French +Message-ID: <20231218153454.8090-6-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit cb4517201b8acdb5fd5314494aaf86c267f22345 ] + +To move smb2_hdr to smbfs_common, This patch remove smb2_buf_length +variable in smb2_hdr. Also, declare smb2_get_msg function to get smb2 +request/response from ->request/response_buf. + +Cc: Ronnie Sahlberg +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/auth.c | 4 + fs/ksmbd/connection.c | 9 + fs/ksmbd/ksmbd_work.h | 4 + fs/ksmbd/oplock.c | 24 +- + fs/ksmbd/smb2pdu.c | 435 ++++++++++++++++++++++------------------------ + fs/ksmbd/smb2pdu.h | 20 +- + fs/ksmbd/smb_common.c | 11 - + fs/ksmbd/smb_common.h | 6 + fs/ksmbd/transport_rdma.c | 2 + 9 files changed, 256 insertions(+), 259 deletions(-) + +--- a/fs/ksmbd/auth.c ++++ b/fs/ksmbd/auth.c +@@ -884,9 +884,9 @@ int ksmbd_gen_preauth_integrity_hash(str + __u8 *pi_hash) + { + int rc; +- struct smb2_hdr *rcv_hdr = (struct smb2_hdr *)buf; ++ struct smb2_hdr *rcv_hdr = smb2_get_msg(buf); + char *all_bytes_msg = (char *)&rcv_hdr->ProtocolId; +- int msg_size = be32_to_cpu(rcv_hdr->smb2_buf_length); ++ int msg_size = get_rfc1002_len(buf); + struct ksmbd_crypto_ctx *ctx = NULL; + + if (conn->preauth_info->Preauth_HashId != +--- a/fs/ksmbd/connection.c ++++ b/fs/ksmbd/connection.c +@@ -160,14 +160,13 @@ void ksmbd_conn_wait_idle(struct ksmbd_c + int ksmbd_conn_write(struct ksmbd_work *work) + { + struct ksmbd_conn *conn = work->conn; +- struct smb_hdr *rsp_hdr = work->response_buf; + size_t len = 0; + int sent; + struct kvec iov[3]; + int iov_idx = 0; + + ksmbd_conn_try_dequeue_request(work); +- if (!rsp_hdr) { ++ if (!work->response_buf) { + pr_err("NULL response header\n"); + return -EINVAL; + } +@@ -179,7 +178,7 @@ int ksmbd_conn_write(struct ksmbd_work * + } + + if (work->aux_payload_sz) { +- iov[iov_idx] = (struct kvec) { rsp_hdr, work->resp_hdr_sz }; ++ iov[iov_idx] = (struct kvec) { work->response_buf, work->resp_hdr_sz }; + len += iov[iov_idx++].iov_len; + iov[iov_idx] = (struct kvec) { work->aux_payload_buf, work->aux_payload_sz }; + len += iov[iov_idx++].iov_len; +@@ -187,8 +186,8 @@ int ksmbd_conn_write(struct ksmbd_work * + if (work->tr_buf) + iov[iov_idx].iov_len = work->resp_hdr_sz; + else +- iov[iov_idx].iov_len = get_rfc1002_len(rsp_hdr) + 4; +- iov[iov_idx].iov_base = rsp_hdr; ++ iov[iov_idx].iov_len = get_rfc1002_len(work->response_buf) + 4; ++ iov[iov_idx].iov_base = work->response_buf; + len += iov[iov_idx++].iov_len; + } + +--- a/fs/ksmbd/ksmbd_work.h ++++ b/fs/ksmbd/ksmbd_work.h +@@ -92,7 +92,7 @@ struct ksmbd_work { + */ + static inline void *ksmbd_resp_buf_next(struct ksmbd_work *work) + { +- return work->response_buf + work->next_smb2_rsp_hdr_off; ++ return work->response_buf + work->next_smb2_rsp_hdr_off + 4; + } + + /** +@@ -101,7 +101,7 @@ static inline void *ksmbd_resp_buf_next( + */ + static inline void *ksmbd_req_buf_next(struct ksmbd_work *work) + { +- return work->request_buf + work->next_smb2_rcv_hdr_off; ++ return work->request_buf + work->next_smb2_rcv_hdr_off + 4; + } + + struct ksmbd_work *ksmbd_alloc_work_struct(void); +--- a/fs/ksmbd/oplock.c ++++ b/fs/ksmbd/oplock.c +@@ -630,10 +630,10 @@ static void __smb2_oplock_break_noti(str + return; + } + +- rsp_hdr = work->response_buf; ++ rsp_hdr = smb2_get_msg(work->response_buf); + memset(rsp_hdr, 0, sizeof(struct smb2_hdr) + 2); +- rsp_hdr->smb2_buf_length = +- cpu_to_be32(smb2_hdr_size_no_buflen(conn->vals)); ++ *(__be32 *)work->response_buf = ++ cpu_to_be32(conn->vals->header_size); + rsp_hdr->ProtocolId = SMB2_PROTO_NUMBER; + rsp_hdr->StructureSize = SMB2_HEADER_STRUCTURE_SIZE; + rsp_hdr->CreditRequest = cpu_to_le16(0); +@@ -646,7 +646,7 @@ static void __smb2_oplock_break_noti(str + rsp_hdr->SessionId = 0; + memset(rsp_hdr->Signature, 0, 16); + +- rsp = work->response_buf; ++ rsp = smb2_get_msg(work->response_buf); + + rsp->StructureSize = cpu_to_le16(24); + if (!br_info->open_trunc && +@@ -660,7 +660,7 @@ static void __smb2_oplock_break_noti(str + rsp->PersistentFid = cpu_to_le64(fp->persistent_id); + rsp->VolatileFid = cpu_to_le64(fp->volatile_id); + +- inc_rfc1001_len(rsp, 24); ++ inc_rfc1001_len(work->response_buf, 24); + + ksmbd_debug(OPLOCK, + "sending oplock break v_id %llu p_id = %llu lock level = %d\n", +@@ -737,10 +737,10 @@ static void __smb2_lease_break_noti(stru + return; + } + +- rsp_hdr = work->response_buf; ++ rsp_hdr = smb2_get_msg(work->response_buf); + memset(rsp_hdr, 0, sizeof(struct smb2_hdr) + 2); +- rsp_hdr->smb2_buf_length = +- cpu_to_be32(smb2_hdr_size_no_buflen(conn->vals)); ++ *(__be32 *)work->response_buf = ++ cpu_to_be32(conn->vals->header_size); + rsp_hdr->ProtocolId = SMB2_PROTO_NUMBER; + rsp_hdr->StructureSize = SMB2_HEADER_STRUCTURE_SIZE; + rsp_hdr->CreditRequest = cpu_to_le16(0); +@@ -753,7 +753,7 @@ static void __smb2_lease_break_noti(stru + rsp_hdr->SessionId = 0; + memset(rsp_hdr->Signature, 0, 16); + +- rsp = work->response_buf; ++ rsp = smb2_get_msg(work->response_buf); + rsp->StructureSize = cpu_to_le16(44); + rsp->Epoch = br_info->epoch; + rsp->Flags = 0; +@@ -769,7 +769,7 @@ static void __smb2_lease_break_noti(stru + rsp->AccessMaskHint = 0; + rsp->ShareMaskHint = 0; + +- inc_rfc1001_len(rsp, 44); ++ inc_rfc1001_len(work->response_buf, 44); + + ksmbd_conn_write(work); + ksmbd_free_work_struct(work); +@@ -1399,7 +1399,7 @@ struct lease_ctx_info *parse_lease_state + if (!lreq) + return NULL; + +- data_offset = (char *)req + 4 + le32_to_cpu(req->CreateContextsOffset); ++ data_offset = (char *)req + le32_to_cpu(req->CreateContextsOffset); + cc = (struct create_context *)data_offset; + do { + cc = (struct create_context *)((char *)cc + next); +@@ -1464,7 +1464,7 @@ struct create_context *smb2_find_context + * CreateContextsOffset and CreateContextsLength are guaranteed to + * be valid because of ksmbd_smb2_check_message(). + */ +- cc = (struct create_context *)((char *)req + 4 + ++ cc = (struct create_context *)((char *)req + + le32_to_cpu(req->CreateContextsOffset)); + remain_len = le32_to_cpu(req->CreateContextsLength); + do { +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -45,8 +45,8 @@ static void __wbuf(struct ksmbd_work *wo + *req = ksmbd_req_buf_next(work); + *rsp = ksmbd_resp_buf_next(work); + } else { +- *req = work->request_buf; +- *rsp = work->response_buf; ++ *req = smb2_get_msg(work->request_buf); ++ *rsp = smb2_get_msg(work->response_buf); + } + } + +@@ -94,7 +94,7 @@ struct channel *lookup_chann_list(struct + */ + int smb2_get_ksmbd_tcon(struct ksmbd_work *work) + { +- struct smb2_hdr *req_hdr = work->request_buf; ++ struct smb2_hdr *req_hdr = smb2_get_msg(work->request_buf); + unsigned int cmd = le16_to_cpu(req_hdr->Command); + int tree_id; + +@@ -149,7 +149,7 @@ void smb2_set_err_rsp(struct ksmbd_work + if (work->next_smb2_rcv_hdr_off) + err_rsp = ksmbd_resp_buf_next(work); + else +- err_rsp = work->response_buf; ++ err_rsp = smb2_get_msg(work->response_buf); + + if (err_rsp->hdr.Status != STATUS_STOPPED_ON_SYMLINK) { + err_rsp->StructureSize = SMB2_ERROR_STRUCTURE_SIZE2_LE; +@@ -169,7 +169,7 @@ void smb2_set_err_rsp(struct ksmbd_work + */ + bool is_smb2_neg_cmd(struct ksmbd_work *work) + { +- struct smb2_hdr *hdr = work->request_buf; ++ struct smb2_hdr *hdr = smb2_get_msg(work->request_buf); + + /* is it SMB2 header ? */ + if (hdr->ProtocolId != SMB2_PROTO_NUMBER) +@@ -193,7 +193,7 @@ bool is_smb2_neg_cmd(struct ksmbd_work * + */ + bool is_smb2_rsp(struct ksmbd_work *work) + { +- struct smb2_hdr *hdr = work->response_buf; ++ struct smb2_hdr *hdr = smb2_get_msg(work->response_buf); + + /* is it SMB2 header ? */ + if (hdr->ProtocolId != SMB2_PROTO_NUMBER) +@@ -219,7 +219,7 @@ u16 get_smb2_cmd_val(struct ksmbd_work * + if (work->next_smb2_rcv_hdr_off) + rcv_hdr = ksmbd_req_buf_next(work); + else +- rcv_hdr = work->request_buf; ++ rcv_hdr = smb2_get_msg(work->request_buf); + return le16_to_cpu(rcv_hdr->Command); + } + +@@ -235,7 +235,7 @@ void set_smb2_rsp_status(struct ksmbd_wo + if (work->next_smb2_rcv_hdr_off) + rsp_hdr = ksmbd_resp_buf_next(work); + else +- rsp_hdr = work->response_buf; ++ rsp_hdr = smb2_get_msg(work->response_buf); + rsp_hdr->Status = err; + smb2_set_err_rsp(work); + } +@@ -256,13 +256,11 @@ int init_smb2_neg_rsp(struct ksmbd_work + if (conn->need_neg == false) + return -EINVAL; + +- rsp_hdr = work->response_buf; ++ *(__be32 *)work->response_buf = ++ cpu_to_be32(conn->vals->header_size); + ++ rsp_hdr = smb2_get_msg(work->response_buf); + memset(rsp_hdr, 0, sizeof(struct smb2_hdr) + 2); +- +- rsp_hdr->smb2_buf_length = +- cpu_to_be32(smb2_hdr_size_no_buflen(conn->vals)); +- + rsp_hdr->ProtocolId = SMB2_PROTO_NUMBER; + rsp_hdr->StructureSize = SMB2_HEADER_STRUCTURE_SIZE; + rsp_hdr->CreditRequest = cpu_to_le16(2); +@@ -275,7 +273,7 @@ int init_smb2_neg_rsp(struct ksmbd_work + rsp_hdr->SessionId = 0; + memset(rsp_hdr->Signature, 0, 16); + +- rsp = work->response_buf; ++ rsp = smb2_get_msg(work->response_buf); + + WARN_ON(ksmbd_conn_good(work)); + +@@ -296,12 +294,12 @@ int init_smb2_neg_rsp(struct ksmbd_work + + rsp->SecurityBufferOffset = cpu_to_le16(128); + rsp->SecurityBufferLength = cpu_to_le16(AUTH_GSS_LENGTH); +- ksmbd_copy_gss_neg_header(((char *)(&rsp->hdr) + +- sizeof(rsp->hdr.smb2_buf_length)) + ++ ksmbd_copy_gss_neg_header((char *)(&rsp->hdr) + + le16_to_cpu(rsp->SecurityBufferOffset)); +- inc_rfc1001_len(rsp, sizeof(struct smb2_negotiate_rsp) - +- sizeof(struct smb2_hdr) - sizeof(rsp->Buffer) + +- AUTH_GSS_LENGTH); ++ inc_rfc1001_len(work->response_buf, ++ sizeof(struct smb2_negotiate_rsp) - ++ sizeof(struct smb2_hdr) - sizeof(rsp->Buffer) + ++ AUTH_GSS_LENGTH); + rsp->SecurityMode = SMB2_NEGOTIATE_SIGNING_ENABLED_LE; + if (server_conf.signing == KSMBD_CONFIG_OPT_MANDATORY) + rsp->SecurityMode |= SMB2_NEGOTIATE_SIGNING_REQUIRED_LE; +@@ -407,8 +405,8 @@ static void init_chained_smb2_rsp(struct + next_hdr_offset = le32_to_cpu(req->NextCommand); + + new_len = ALIGN(len, 8); +- inc_rfc1001_len(work->response_buf, ((sizeof(struct smb2_hdr) - 4) +- + new_len - len)); ++ inc_rfc1001_len(work->response_buf, ++ sizeof(struct smb2_hdr) + new_len - len); + rsp->NextCommand = cpu_to_le32(new_len); + + work->next_smb2_rcv_hdr_off += next_hdr_offset; +@@ -426,7 +424,7 @@ static void init_chained_smb2_rsp(struct + work->compound_fid = KSMBD_NO_FID; + work->compound_pfid = KSMBD_NO_FID; + } +- memset((char *)rsp_hdr + 4, 0, sizeof(struct smb2_hdr) + 2); ++ memset((char *)rsp_hdr, 0, sizeof(struct smb2_hdr) + 2); + rsp_hdr->ProtocolId = SMB2_PROTO_NUMBER; + rsp_hdr->StructureSize = SMB2_HEADER_STRUCTURE_SIZE; + rsp_hdr->Command = rcv_hdr->Command; +@@ -452,7 +450,7 @@ static void init_chained_smb2_rsp(struct + */ + bool is_chained_smb2_message(struct ksmbd_work *work) + { +- struct smb2_hdr *hdr = work->request_buf; ++ struct smb2_hdr *hdr = smb2_get_msg(work->request_buf); + unsigned int len, next_cmd; + + if (hdr->ProtocolId != SMB2_PROTO_NUMBER) +@@ -503,13 +501,13 @@ bool is_chained_smb2_message(struct ksmb + */ + int init_smb2_rsp_hdr(struct ksmbd_work *work) + { +- struct smb2_hdr *rsp_hdr = work->response_buf; +- struct smb2_hdr *rcv_hdr = work->request_buf; ++ struct smb2_hdr *rsp_hdr = smb2_get_msg(work->response_buf); ++ struct smb2_hdr *rcv_hdr = smb2_get_msg(work->request_buf); + struct ksmbd_conn *conn = work->conn; + + memset(rsp_hdr, 0, sizeof(struct smb2_hdr) + 2); +- rsp_hdr->smb2_buf_length = +- cpu_to_be32(smb2_hdr_size_no_buflen(conn->vals)); ++ *(__be32 *)work->response_buf = ++ cpu_to_be32(conn->vals->header_size); + rsp_hdr->ProtocolId = rcv_hdr->ProtocolId; + rsp_hdr->StructureSize = SMB2_HEADER_STRUCTURE_SIZE; + rsp_hdr->Command = rcv_hdr->Command; +@@ -542,7 +540,7 @@ int init_smb2_rsp_hdr(struct ksmbd_work + */ + int smb2_allocate_rsp_buf(struct ksmbd_work *work) + { +- struct smb2_hdr *hdr = work->request_buf; ++ struct smb2_hdr *hdr = smb2_get_msg(work->request_buf); + size_t small_sz = MAX_CIFS_SMALL_BUFFER_SIZE; + size_t large_sz = small_sz + work->conn->vals->max_trans_size; + size_t sz = small_sz; +@@ -554,7 +552,7 @@ int smb2_allocate_rsp_buf(struct ksmbd_w + if (cmd == SMB2_QUERY_INFO_HE) { + struct smb2_query_info_req *req; + +- req = work->request_buf; ++ req = smb2_get_msg(work->request_buf); + if ((req->InfoType == SMB2_O_INFO_FILE && + (req->FileInfoClass == FILE_FULL_EA_INFORMATION || + req->FileInfoClass == FILE_ALL_INFORMATION)) || +@@ -582,7 +580,7 @@ int smb2_allocate_rsp_buf(struct ksmbd_w + */ + int smb2_check_user_session(struct ksmbd_work *work) + { +- struct smb2_hdr *req_hdr = work->request_buf; ++ struct smb2_hdr *req_hdr = smb2_get_msg(work->request_buf); + struct ksmbd_conn *conn = work->conn; + unsigned int cmd = conn->ops->get_cmd_val(work); + unsigned long long sess_id; +@@ -683,7 +681,7 @@ int setup_async_work(struct ksmbd_work * + struct ksmbd_conn *conn = work->conn; + int id; + +- rsp_hdr = work->response_buf; ++ rsp_hdr = smb2_get_msg(work->response_buf); + rsp_hdr->Flags |= SMB2_FLAGS_ASYNC_COMMAND; + + id = ksmbd_acquire_async_msg_id(&conn->async_ida); +@@ -715,7 +713,7 @@ void smb2_send_interim_resp(struct ksmbd + { + struct smb2_hdr *rsp_hdr; + +- rsp_hdr = work->response_buf; ++ rsp_hdr = smb2_get_msg(work->response_buf); + smb2_set_err_rsp(work); + rsp_hdr->Status = status; + +@@ -843,11 +841,11 @@ static void build_posix_ctxt(struct smb2 + } + + static void assemble_neg_contexts(struct ksmbd_conn *conn, +- struct smb2_negotiate_rsp *rsp) ++ struct smb2_negotiate_rsp *rsp, ++ void *smb2_buf_len) + { +- /* +4 is to account for the RFC1001 len field */ + char *pneg_ctxt = (char *)rsp + +- le32_to_cpu(rsp->NegotiateContextOffset) + 4; ++ le32_to_cpu(rsp->NegotiateContextOffset); + int neg_ctxt_cnt = 1; + int ctxt_size; + +@@ -856,7 +854,7 @@ static void assemble_neg_contexts(struct + build_preauth_ctxt((struct smb2_preauth_neg_context *)pneg_ctxt, + conn->preauth_info->Preauth_HashId); + rsp->NegotiateContextCount = cpu_to_le16(neg_ctxt_cnt); +- inc_rfc1001_len(rsp, AUTH_GSS_PADDING); ++ inc_rfc1001_len(smb2_buf_len, AUTH_GSS_PADDING); + ctxt_size = sizeof(struct smb2_preauth_neg_context); + /* Round to 8 byte boundary */ + pneg_ctxt += round_up(sizeof(struct smb2_preauth_neg_context), 8); +@@ -910,7 +908,7 @@ static void assemble_neg_contexts(struct + ctxt_size += sizeof(struct smb2_signing_capabilities) + 2; + } + +- inc_rfc1001_len(rsp, ctxt_size); ++ inc_rfc1001_len(smb2_buf_len, ctxt_size); + } + + static __le32 decode_preauth_ctxt(struct ksmbd_conn *conn, +@@ -1012,14 +1010,14 @@ static void decode_sign_cap_ctxt(struct + } + + static __le32 deassemble_neg_contexts(struct ksmbd_conn *conn, +- struct smb2_negotiate_req *req) ++ struct smb2_negotiate_req *req, ++ int len_of_smb) + { + /* +4 is to account for the RFC1001 len field */ +- struct smb2_neg_context *pctx = (struct smb2_neg_context *)((char *)req + 4); ++ struct smb2_neg_context *pctx = (struct smb2_neg_context *)req; + int i = 0, len_of_ctxts; + int offset = le32_to_cpu(req->NegotiateContextOffset); + int neg_ctxt_cnt = le16_to_cpu(req->NegotiateContextCount); +- int len_of_smb = be32_to_cpu(req->hdr.smb2_buf_length); + __le32 status = STATUS_INVALID_PARAMETER; + + ksmbd_debug(SMB, "decoding %d negotiate contexts\n", neg_ctxt_cnt); +@@ -1104,8 +1102,8 @@ static __le32 deassemble_neg_contexts(st + int smb2_handle_negotiate(struct ksmbd_work *work) + { + struct ksmbd_conn *conn = work->conn; +- struct smb2_negotiate_req *req = work->request_buf; +- struct smb2_negotiate_rsp *rsp = work->response_buf; ++ struct smb2_negotiate_req *req = smb2_get_msg(work->request_buf); ++ struct smb2_negotiate_rsp *rsp = smb2_get_msg(work->response_buf); + int rc = 0; + unsigned int smb2_buf_len, smb2_neg_size; + __le32 status; +@@ -1119,7 +1117,7 @@ int smb2_handle_negotiate(struct ksmbd_w + } + + smb2_buf_len = get_rfc1002_len(work->request_buf); +- smb2_neg_size = offsetof(struct smb2_negotiate_req, Dialects) - 4; ++ smb2_neg_size = offsetof(struct smb2_negotiate_req, Dialects); + if (smb2_neg_size > smb2_buf_len) { + rsp->hdr.Status = STATUS_INVALID_PARAMETER; + rc = -EINVAL; +@@ -1175,7 +1173,8 @@ int smb2_handle_negotiate(struct ksmbd_w + goto err_out; + } + +- status = deassemble_neg_contexts(conn, req); ++ status = deassemble_neg_contexts(conn, req, ++ get_rfc1002_len(work->request_buf)); + if (status != STATUS_SUCCESS) { + pr_err("deassemble_neg_contexts error(0x%x)\n", + status); +@@ -1199,7 +1198,7 @@ int smb2_handle_negotiate(struct ksmbd_w + conn->preauth_info->Preauth_HashValue); + rsp->NegotiateContextOffset = + cpu_to_le32(OFFSET_OF_NEG_CONTEXT); +- assemble_neg_contexts(conn, rsp); ++ assemble_neg_contexts(conn, rsp, work->response_buf); + break; + case SMB302_PROT_ID: + init_smb3_02_server(conn); +@@ -1247,10 +1246,9 @@ int smb2_handle_negotiate(struct ksmbd_w + + rsp->SecurityBufferOffset = cpu_to_le16(128); + rsp->SecurityBufferLength = cpu_to_le16(AUTH_GSS_LENGTH); +- ksmbd_copy_gss_neg_header(((char *)(&rsp->hdr) + +- sizeof(rsp->hdr.smb2_buf_length)) + +- le16_to_cpu(rsp->SecurityBufferOffset)); +- inc_rfc1001_len(rsp, sizeof(struct smb2_negotiate_rsp) - ++ ksmbd_copy_gss_neg_header((char *)(&rsp->hdr) + ++ le16_to_cpu(rsp->SecurityBufferOffset)); ++ inc_rfc1001_len(work->response_buf, sizeof(struct smb2_negotiate_rsp) - + sizeof(struct smb2_hdr) - sizeof(rsp->Buffer) + + AUTH_GSS_LENGTH); + rsp->SecurityMode = SMB2_NEGOTIATE_SIGNING_ENABLED_LE; +@@ -1342,7 +1340,7 @@ static int ntlm_negotiate(struct ksmbd_w + struct negotiate_message *negblob, + size_t negblob_len) + { +- struct smb2_sess_setup_rsp *rsp = work->response_buf; ++ struct smb2_sess_setup_rsp *rsp = smb2_get_msg(work->response_buf); + struct challenge_message *chgblob; + unsigned char *spnego_blob = NULL; + u16 spnego_blob_len; +@@ -1449,8 +1447,8 @@ static struct ksmbd_user *session_user(s + + static int ntlm_authenticate(struct ksmbd_work *work) + { +- struct smb2_sess_setup_req *req = work->request_buf; +- struct smb2_sess_setup_rsp *rsp = work->response_buf; ++ struct smb2_sess_setup_req *req = smb2_get_msg(work->request_buf); ++ struct smb2_sess_setup_rsp *rsp = smb2_get_msg(work->response_buf); + struct ksmbd_conn *conn = work->conn; + struct ksmbd_session *sess = work->sess; + struct channel *chann = NULL; +@@ -1473,7 +1471,7 @@ static int ntlm_authenticate(struct ksmb + memcpy((char *)&rsp->hdr.ProtocolId + sz, spnego_blob, spnego_blob_len); + rsp->SecurityBufferLength = cpu_to_le16(spnego_blob_len); + kfree(spnego_blob); +- inc_rfc1001_len(rsp, spnego_blob_len - 1); ++ inc_rfc1001_len(work->response_buf, spnego_blob_len - 1); + } + + user = session_user(conn, req); +@@ -1590,8 +1588,8 @@ binding_session: + #ifdef CONFIG_SMB_SERVER_KERBEROS5 + static int krb5_authenticate(struct ksmbd_work *work) + { +- struct smb2_sess_setup_req *req = work->request_buf; +- struct smb2_sess_setup_rsp *rsp = work->response_buf; ++ struct smb2_sess_setup_req *req = smb2_get_msg(work->request_buf); ++ struct smb2_sess_setup_rsp *rsp = smb2_get_msg(work->response_buf); + struct ksmbd_conn *conn = work->conn; + struct ksmbd_session *sess = work->sess; + char *in_blob, *out_blob; +@@ -1606,8 +1604,7 @@ static int krb5_authenticate(struct ksmb + out_blob = (char *)&rsp->hdr.ProtocolId + + le16_to_cpu(rsp->SecurityBufferOffset); + out_len = work->response_sz - +- offsetof(struct smb2_hdr, smb2_buf_length) - +- le16_to_cpu(rsp->SecurityBufferOffset); ++ (le16_to_cpu(rsp->SecurityBufferOffset) + 4); + + /* Check previous session */ + prev_sess_id = le64_to_cpu(req->PreviousSessionId); +@@ -1624,7 +1621,7 @@ static int krb5_authenticate(struct ksmb + return -EINVAL; + } + rsp->SecurityBufferLength = cpu_to_le16(out_len); +- inc_rfc1001_len(rsp, out_len - 1); ++ inc_rfc1001_len(work->response_buf, out_len - 1); + + if ((conn->sign || server_conf.enforced_signing) || + (req->SecurityMode & SMB2_NEGOTIATE_SIGNING_REQUIRED)) +@@ -1683,8 +1680,8 @@ static int krb5_authenticate(struct ksmb + int smb2_sess_setup(struct ksmbd_work *work) + { + struct ksmbd_conn *conn = work->conn; +- struct smb2_sess_setup_req *req = work->request_buf; +- struct smb2_sess_setup_rsp *rsp = work->response_buf; ++ struct smb2_sess_setup_req *req = smb2_get_msg(work->request_buf); ++ struct smb2_sess_setup_rsp *rsp = smb2_get_msg(work->response_buf); + struct ksmbd_session *sess; + struct negotiate_message *negblob; + unsigned int negblob_len, negblob_off; +@@ -1696,7 +1693,7 @@ int smb2_sess_setup(struct ksmbd_work *w + rsp->SessionFlags = 0; + rsp->SecurityBufferOffset = cpu_to_le16(72); + rsp->SecurityBufferLength = 0; +- inc_rfc1001_len(rsp, 9); ++ inc_rfc1001_len(work->response_buf, 9); + + if (!req->hdr.SessionId) { + sess = ksmbd_smb2_session_create(); +@@ -1777,7 +1774,7 @@ int smb2_sess_setup(struct ksmbd_work *w + + negblob_off = le16_to_cpu(req->SecurityBufferOffset); + negblob_len = le16_to_cpu(req->SecurityBufferLength); +- if (negblob_off < (offsetof(struct smb2_sess_setup_req, Buffer) - 4) || ++ if (negblob_off < offsetof(struct smb2_sess_setup_req, Buffer) || + negblob_len < offsetof(struct negotiate_message, NegotiateFlags)) { + rc = -EINVAL; + goto out_err; +@@ -1819,7 +1816,8 @@ int smb2_sess_setup(struct ksmbd_work *w + * Note: here total size -1 is done as an + * adjustment for 0 size blob + */ +- inc_rfc1001_len(rsp, le16_to_cpu(rsp->SecurityBufferLength) - 1); ++ inc_rfc1001_len(work->response_buf, ++ le16_to_cpu(rsp->SecurityBufferLength) - 1); + + } else if (negblob->MessageType == NtLmAuthenticate) { + rc = ntlm_authenticate(work); +@@ -1915,8 +1913,8 @@ out_err: + int smb2_tree_connect(struct ksmbd_work *work) + { + struct ksmbd_conn *conn = work->conn; +- struct smb2_tree_connect_req *req = work->request_buf; +- struct smb2_tree_connect_rsp *rsp = work->response_buf; ++ struct smb2_tree_connect_req *req = smb2_get_msg(work->request_buf); ++ struct smb2_tree_connect_rsp *rsp = smb2_get_msg(work->response_buf); + struct ksmbd_session *sess = work->sess; + char *treename = NULL, *name = NULL; + struct ksmbd_tree_conn_status status; +@@ -1981,7 +1979,7 @@ out_err1: + rsp->Reserved = 0; + /* default manual caching */ + rsp->ShareFlags = SMB2_SHAREFLAG_MANUAL_CACHING; +- inc_rfc1001_len(rsp, 16); ++ inc_rfc1001_len(work->response_buf, 16); + + if (!IS_ERR(treename)) + kfree(treename); +@@ -2087,17 +2085,18 @@ static int smb2_create_open_flags(bool f + */ + int smb2_tree_disconnect(struct ksmbd_work *work) + { +- struct smb2_tree_disconnect_rsp *rsp = work->response_buf; ++ struct smb2_tree_disconnect_rsp *rsp = smb2_get_msg(work->response_buf); + struct ksmbd_session *sess = work->sess; + struct ksmbd_tree_connect *tcon = work->tcon; + + rsp->StructureSize = cpu_to_le16(4); +- inc_rfc1001_len(rsp, 4); ++ inc_rfc1001_len(work->response_buf, 4); + + ksmbd_debug(SMB, "request\n"); + + if (!tcon) { +- struct smb2_tree_disconnect_req *req = work->request_buf; ++ struct smb2_tree_disconnect_req *req = ++ smb2_get_msg(work->request_buf); + + ksmbd_debug(SMB, "Invalid tid %d\n", req->hdr.Id.SyncId.TreeId); + rsp->hdr.Status = STATUS_NETWORK_NAME_DELETED; +@@ -2120,11 +2119,11 @@ int smb2_tree_disconnect(struct ksmbd_wo + int smb2_session_logoff(struct ksmbd_work *work) + { + struct ksmbd_conn *conn = work->conn; +- struct smb2_logoff_rsp *rsp = work->response_buf; ++ struct smb2_logoff_rsp *rsp = smb2_get_msg(work->response_buf); + struct ksmbd_session *sess = work->sess; + + rsp->StructureSize = cpu_to_le16(4); +- inc_rfc1001_len(rsp, 4); ++ inc_rfc1001_len(work->response_buf, 4); + + ksmbd_debug(SMB, "request\n"); + +@@ -2134,7 +2133,7 @@ int smb2_session_logoff(struct ksmbd_wor + ksmbd_conn_wait_idle(conn); + + if (ksmbd_tree_conn_session_logoff(sess)) { +- struct smb2_logoff_req *req = work->request_buf; ++ struct smb2_logoff_req *req = smb2_get_msg(work->request_buf); + + ksmbd_debug(SMB, "Invalid tid %d\n", req->hdr.Id.SyncId.TreeId); + rsp->hdr.Status = STATUS_NETWORK_NAME_DELETED; +@@ -2161,8 +2160,8 @@ int smb2_session_logoff(struct ksmbd_wor + */ + static noinline int create_smb2_pipe(struct ksmbd_work *work) + { +- struct smb2_create_rsp *rsp = work->response_buf; +- struct smb2_create_req *req = work->request_buf; ++ struct smb2_create_rsp *rsp = smb2_get_msg(work->response_buf); ++ struct smb2_create_req *req = smb2_get_msg(work->request_buf); + int id; + int err; + char *name; +@@ -2200,7 +2199,7 @@ static noinline int create_smb2_pipe(str + rsp->CreateContextsOffset = 0; + rsp->CreateContextsLength = 0; + +- inc_rfc1001_len(rsp, 88); /* StructureSize - 1*/ ++ inc_rfc1001_len(work->response_buf, 88); /* StructureSize - 1*/ + kfree(name); + return 0; + +@@ -2556,7 +2555,7 @@ int smb2_open(struct ksmbd_work *work) + struct ksmbd_session *sess = work->sess; + struct ksmbd_tree_connect *tcon = work->tcon; + struct smb2_create_req *req; +- struct smb2_create_rsp *rsp, *rsp_org; ++ struct smb2_create_rsp *rsp; + struct path path; + struct ksmbd_share_config *share = tcon->share_conf; + struct ksmbd_file *fp = NULL; +@@ -2582,7 +2581,6 @@ int smb2_open(struct ksmbd_work *work) + umode_t posix_mode = 0; + __le32 daccess, maximal_access = 0; + +- rsp_org = work->response_buf; + WORK_BUFFERS(work, req, rsp); + + if (req->hdr.NextCommand && !work->next_smb2_rcv_hdr_off && +@@ -3240,7 +3238,7 @@ int smb2_open(struct ksmbd_work *work) + + rsp->CreateContextsOffset = 0; + rsp->CreateContextsLength = 0; +- inc_rfc1001_len(rsp_org, 88); /* StructureSize - 1*/ ++ inc_rfc1001_len(work->response_buf, 88); /* StructureSize - 1*/ + + /* If lease is request send lease context response */ + if (opinfo && opinfo->is_lease) { +@@ -3255,7 +3253,8 @@ int smb2_open(struct ksmbd_work *work) + create_lease_buf(rsp->Buffer, opinfo->o_lease); + le32_add_cpu(&rsp->CreateContextsLength, + conn->vals->create_lease_size); +- inc_rfc1001_len(rsp_org, conn->vals->create_lease_size); ++ inc_rfc1001_len(work->response_buf, ++ conn->vals->create_lease_size); + next_ptr = &lease_ccontext->Next; + next_off = conn->vals->create_lease_size; + } +@@ -3275,7 +3274,8 @@ int smb2_open(struct ksmbd_work *work) + le32_to_cpu(maximal_access)); + le32_add_cpu(&rsp->CreateContextsLength, + conn->vals->create_mxac_size); +- inc_rfc1001_len(rsp_org, conn->vals->create_mxac_size); ++ inc_rfc1001_len(work->response_buf, ++ conn->vals->create_mxac_size); + if (next_ptr) + *next_ptr = cpu_to_le32(next_off); + next_ptr = &mxac_ccontext->Next; +@@ -3293,7 +3293,8 @@ int smb2_open(struct ksmbd_work *work) + stat.ino, tcon->id); + le32_add_cpu(&rsp->CreateContextsLength, + conn->vals->create_disk_id_size); +- inc_rfc1001_len(rsp_org, conn->vals->create_disk_id_size); ++ inc_rfc1001_len(work->response_buf, ++ conn->vals->create_disk_id_size); + if (next_ptr) + *next_ptr = cpu_to_le32(next_off); + next_ptr = &disk_id_ccontext->Next; +@@ -3307,15 +3308,15 @@ int smb2_open(struct ksmbd_work *work) + fp); + le32_add_cpu(&rsp->CreateContextsLength, + conn->vals->create_posix_size); +- inc_rfc1001_len(rsp_org, conn->vals->create_posix_size); ++ inc_rfc1001_len(work->response_buf, ++ conn->vals->create_posix_size); + if (next_ptr) + *next_ptr = cpu_to_le32(next_off); + } + + if (contxt_cnt > 0) { + rsp->CreateContextsOffset = +- cpu_to_le32(offsetof(struct smb2_create_rsp, Buffer) +- - 4); ++ cpu_to_le32(offsetof(struct smb2_create_rsp, Buffer)); + } + + err_out: +@@ -3918,7 +3919,7 @@ int smb2_query_dir(struct ksmbd_work *wo + { + struct ksmbd_conn *conn = work->conn; + struct smb2_query_directory_req *req; +- struct smb2_query_directory_rsp *rsp, *rsp_org; ++ struct smb2_query_directory_rsp *rsp; + struct ksmbd_share_config *share = work->tcon->share_conf; + struct ksmbd_file *dir_fp = NULL; + struct ksmbd_dir_info d_info; +@@ -3928,7 +3929,6 @@ int smb2_query_dir(struct ksmbd_work *wo + int buffer_sz; + struct smb2_query_dir_private query_dir_private = {NULL, }; + +- rsp_org = work->response_buf; + WORK_BUFFERS(work, req, rsp); + + if (ksmbd_override_fsids(work)) { +@@ -4052,7 +4052,7 @@ int smb2_query_dir(struct ksmbd_work *wo + rsp->OutputBufferOffset = cpu_to_le16(0); + rsp->OutputBufferLength = cpu_to_le32(0); + rsp->Buffer[0] = 0; +- inc_rfc1001_len(rsp_org, 9); ++ inc_rfc1001_len(work->response_buf, 9); + } else { + no_buf_len: + ((struct file_directory_info *) +@@ -4064,7 +4064,7 @@ no_buf_len: + rsp->StructureSize = cpu_to_le16(9); + rsp->OutputBufferOffset = cpu_to_le16(72); + rsp->OutputBufferLength = cpu_to_le32(d_info.data_count); +- inc_rfc1001_len(rsp_org, 8 + d_info.data_count); ++ inc_rfc1001_len(work->response_buf, 8 + d_info.data_count); + } + + kfree(srch_ptr); +@@ -4109,26 +4109,28 @@ err_out2: + * Return: 0 on success, otherwise error + */ + static int buffer_check_err(int reqOutputBufferLength, +- struct smb2_query_info_rsp *rsp, int infoclass_size) ++ struct smb2_query_info_rsp *rsp, ++ void *rsp_org, int infoclass_size) + { + if (reqOutputBufferLength < le32_to_cpu(rsp->OutputBufferLength)) { + if (reqOutputBufferLength < infoclass_size) { + pr_err("Invalid Buffer Size Requested\n"); + rsp->hdr.Status = STATUS_INFO_LENGTH_MISMATCH; +- rsp->hdr.smb2_buf_length = cpu_to_be32(sizeof(struct smb2_hdr) - 4); ++ *(__be32 *)rsp_org = cpu_to_be32(sizeof(struct smb2_hdr)); + return -EINVAL; + } + + ksmbd_debug(SMB, "Buffer Overflow\n"); + rsp->hdr.Status = STATUS_BUFFER_OVERFLOW; +- rsp->hdr.smb2_buf_length = cpu_to_be32(sizeof(struct smb2_hdr) - 4 + ++ *(__be32 *)rsp_org = cpu_to_be32(sizeof(struct smb2_hdr) + + reqOutputBufferLength); + rsp->OutputBufferLength = cpu_to_le32(reqOutputBufferLength); + } + return 0; + } + +-static void get_standard_info_pipe(struct smb2_query_info_rsp *rsp) ++static void get_standard_info_pipe(struct smb2_query_info_rsp *rsp, ++ void *rsp_org) + { + struct smb2_file_standard_info *sinfo; + +@@ -4141,10 +4143,11 @@ static void get_standard_info_pipe(struc + sinfo->Directory = 0; + rsp->OutputBufferLength = + cpu_to_le32(sizeof(struct smb2_file_standard_info)); +- inc_rfc1001_len(rsp, sizeof(struct smb2_file_standard_info)); ++ inc_rfc1001_len(rsp_org, sizeof(struct smb2_file_standard_info)); + } + +-static void get_internal_info_pipe(struct smb2_query_info_rsp *rsp, u64 num) ++static void get_internal_info_pipe(struct smb2_query_info_rsp *rsp, u64 num, ++ void *rsp_org) + { + struct smb2_file_internal_info *file_info; + +@@ -4154,12 +4157,13 @@ static void get_internal_info_pipe(struc + file_info->IndexNumber = cpu_to_le64(num | (1ULL << 63)); + rsp->OutputBufferLength = + cpu_to_le32(sizeof(struct smb2_file_internal_info)); +- inc_rfc1001_len(rsp, sizeof(struct smb2_file_internal_info)); ++ inc_rfc1001_len(rsp_org, sizeof(struct smb2_file_internal_info)); + } + + static int smb2_get_info_file_pipe(struct ksmbd_session *sess, + struct smb2_query_info_req *req, +- struct smb2_query_info_rsp *rsp) ++ struct smb2_query_info_rsp *rsp, ++ void *rsp_org) + { + u64 id; + int rc; +@@ -4177,14 +4181,16 @@ static int smb2_get_info_file_pipe(struc + + switch (req->FileInfoClass) { + case FILE_STANDARD_INFORMATION: +- get_standard_info_pipe(rsp); ++ get_standard_info_pipe(rsp, rsp_org); + rc = buffer_check_err(le32_to_cpu(req->OutputBufferLength), +- rsp, FILE_STANDARD_INFORMATION_SIZE); ++ rsp, rsp_org, ++ FILE_STANDARD_INFORMATION_SIZE); + break; + case FILE_INTERNAL_INFORMATION: +- get_internal_info_pipe(rsp, id); ++ get_internal_info_pipe(rsp, id, rsp_org); + rc = buffer_check_err(le32_to_cpu(req->OutputBufferLength), +- rsp, FILE_INTERNAL_INFORMATION_SIZE); ++ rsp, rsp_org, ++ FILE_INTERNAL_INFORMATION_SIZE); + break; + default: + ksmbd_debug(SMB, "smb2_info_file_pipe for %u not supported\n", +@@ -4785,7 +4791,7 @@ static int find_file_posix_info(struct s + + static int smb2_get_info_file(struct ksmbd_work *work, + struct smb2_query_info_req *req, +- struct smb2_query_info_rsp *rsp, void *rsp_org) ++ struct smb2_query_info_rsp *rsp) + { + struct ksmbd_file *fp; + int fileinfoclass = 0; +@@ -4796,7 +4802,8 @@ static int smb2_get_info_file(struct ksm + if (test_share_config_flag(work->tcon->share_conf, + KSMBD_SHARE_FLAG_PIPE)) { + /* smb2 info file called for pipe */ +- return smb2_get_info_file_pipe(work->sess, req, rsp); ++ return smb2_get_info_file_pipe(work->sess, req, rsp, ++ work->response_buf); + } + + if (work->next_smb2_rcv_hdr_off) { +@@ -4821,77 +4828,77 @@ static int smb2_get_info_file(struct ksm + + switch (fileinfoclass) { + case FILE_ACCESS_INFORMATION: +- get_file_access_info(rsp, fp, rsp_org); ++ get_file_access_info(rsp, fp, work->response_buf); + file_infoclass_size = FILE_ACCESS_INFORMATION_SIZE; + break; + + case FILE_BASIC_INFORMATION: +- rc = get_file_basic_info(rsp, fp, rsp_org); ++ rc = get_file_basic_info(rsp, fp, work->response_buf); + file_infoclass_size = FILE_BASIC_INFORMATION_SIZE; + break; + + case FILE_STANDARD_INFORMATION: +- get_file_standard_info(rsp, fp, rsp_org); ++ get_file_standard_info(rsp, fp, work->response_buf); + file_infoclass_size = FILE_STANDARD_INFORMATION_SIZE; + break; + + case FILE_ALIGNMENT_INFORMATION: +- get_file_alignment_info(rsp, rsp_org); ++ get_file_alignment_info(rsp, work->response_buf); + file_infoclass_size = FILE_ALIGNMENT_INFORMATION_SIZE; + break; + + case FILE_ALL_INFORMATION: +- rc = get_file_all_info(work, rsp, fp, rsp_org); ++ rc = get_file_all_info(work, rsp, fp, work->response_buf); + file_infoclass_size = FILE_ALL_INFORMATION_SIZE; + break; + + case FILE_ALTERNATE_NAME_INFORMATION: +- get_file_alternate_info(work, rsp, fp, rsp_org); ++ get_file_alternate_info(work, rsp, fp, work->response_buf); + file_infoclass_size = FILE_ALTERNATE_NAME_INFORMATION_SIZE; + break; + + case FILE_STREAM_INFORMATION: +- get_file_stream_info(work, rsp, fp, rsp_org); ++ get_file_stream_info(work, rsp, fp, work->response_buf); + file_infoclass_size = FILE_STREAM_INFORMATION_SIZE; + break; + + case FILE_INTERNAL_INFORMATION: +- get_file_internal_info(rsp, fp, rsp_org); ++ get_file_internal_info(rsp, fp, work->response_buf); + file_infoclass_size = FILE_INTERNAL_INFORMATION_SIZE; + break; + + case FILE_NETWORK_OPEN_INFORMATION: +- rc = get_file_network_open_info(rsp, fp, rsp_org); ++ rc = get_file_network_open_info(rsp, fp, work->response_buf); + file_infoclass_size = FILE_NETWORK_OPEN_INFORMATION_SIZE; + break; + + case FILE_EA_INFORMATION: +- get_file_ea_info(rsp, rsp_org); ++ get_file_ea_info(rsp, work->response_buf); + file_infoclass_size = FILE_EA_INFORMATION_SIZE; + break; + + case FILE_FULL_EA_INFORMATION: +- rc = smb2_get_ea(work, fp, req, rsp, rsp_org); ++ rc = smb2_get_ea(work, fp, req, rsp, work->response_buf); + file_infoclass_size = FILE_FULL_EA_INFORMATION_SIZE; + break; + + case FILE_POSITION_INFORMATION: +- get_file_position_info(rsp, fp, rsp_org); ++ get_file_position_info(rsp, fp, work->response_buf); + file_infoclass_size = FILE_POSITION_INFORMATION_SIZE; + break; + + case FILE_MODE_INFORMATION: +- get_file_mode_info(rsp, fp, rsp_org); ++ get_file_mode_info(rsp, fp, work->response_buf); + file_infoclass_size = FILE_MODE_INFORMATION_SIZE; + break; + + case FILE_COMPRESSION_INFORMATION: +- get_file_compression_info(rsp, fp, rsp_org); ++ get_file_compression_info(rsp, fp, work->response_buf); + file_infoclass_size = FILE_COMPRESSION_INFORMATION_SIZE; + break; + + case FILE_ATTRIBUTE_TAG_INFORMATION: +- rc = get_file_attribute_tag_info(rsp, fp, rsp_org); ++ rc = get_file_attribute_tag_info(rsp, fp, work->response_buf); + file_infoclass_size = FILE_ATTRIBUTE_TAG_INFORMATION_SIZE; + break; + case SMB_FIND_FILE_POSIX_INFO: +@@ -4899,7 +4906,7 @@ static int smb2_get_info_file(struct ksm + pr_err("client doesn't negotiate with SMB3.1.1 POSIX Extensions\n"); + rc = -EOPNOTSUPP; + } else { +- rc = find_file_posix_info(rsp, fp, rsp_org); ++ rc = find_file_posix_info(rsp, fp, work->response_buf); + file_infoclass_size = sizeof(struct smb311_posix_qinfo); + } + break; +@@ -4910,7 +4917,7 @@ static int smb2_get_info_file(struct ksm + } + if (!rc) + rc = buffer_check_err(le32_to_cpu(req->OutputBufferLength), +- rsp, ++ rsp, work->response_buf, + file_infoclass_size); + ksmbd_fd_put(work, fp); + return rc; +@@ -4918,7 +4925,7 @@ static int smb2_get_info_file(struct ksm + + static int smb2_get_info_filesystem(struct ksmbd_work *work, + struct smb2_query_info_req *req, +- struct smb2_query_info_rsp *rsp, void *rsp_org) ++ struct smb2_query_info_rsp *rsp) + { + struct ksmbd_session *sess = work->sess; + struct ksmbd_conn *conn = work->conn; +@@ -4957,7 +4964,7 @@ static int smb2_get_info_filesystem(stru + info->DeviceType = cpu_to_le32(stfs.f_type); + info->DeviceCharacteristics = cpu_to_le32(0x00000020); + rsp->OutputBufferLength = cpu_to_le32(8); +- inc_rfc1001_len(rsp_org, 8); ++ inc_rfc1001_len(work->response_buf, 8); + fs_infoclass_size = FS_DEVICE_INFORMATION_SIZE; + break; + } +@@ -4987,7 +4994,7 @@ static int smb2_get_info_filesystem(stru + info->FileSystemNameLen = cpu_to_le32(len); + sz = sizeof(struct filesystem_attribute_info) - 2 + len; + rsp->OutputBufferLength = cpu_to_le32(sz); +- inc_rfc1001_len(rsp_org, sz); ++ inc_rfc1001_len(work->response_buf, sz); + fs_infoclass_size = FS_ATTRIBUTE_INFORMATION_SIZE; + break; + } +@@ -5015,7 +5022,7 @@ static int smb2_get_info_filesystem(stru + info->Reserved = 0; + sz = sizeof(struct filesystem_vol_info) - 2 + len; + rsp->OutputBufferLength = cpu_to_le32(sz); +- inc_rfc1001_len(rsp_org, sz); ++ inc_rfc1001_len(work->response_buf, sz); + fs_infoclass_size = FS_VOLUME_INFORMATION_SIZE; + break; + } +@@ -5029,7 +5036,7 @@ static int smb2_get_info_filesystem(stru + info->SectorsPerAllocationUnit = cpu_to_le32(1); + info->BytesPerSector = cpu_to_le32(stfs.f_bsize); + rsp->OutputBufferLength = cpu_to_le32(24); +- inc_rfc1001_len(rsp_org, 24); ++ inc_rfc1001_len(work->response_buf, 24); + fs_infoclass_size = FS_SIZE_INFORMATION_SIZE; + break; + } +@@ -5046,7 +5053,7 @@ static int smb2_get_info_filesystem(stru + info->SectorsPerAllocationUnit = cpu_to_le32(1); + info->BytesPerSector = cpu_to_le32(stfs.f_bsize); + rsp->OutputBufferLength = cpu_to_le32(32); +- inc_rfc1001_len(rsp_org, 32); ++ inc_rfc1001_len(work->response_buf, 32); + fs_infoclass_size = FS_FULL_SIZE_INFORMATION_SIZE; + break; + } +@@ -5067,7 +5074,7 @@ static int smb2_get_info_filesystem(stru + info->extended_info.rel_date = 0; + memcpy(info->extended_info.version_string, "1.1.0", strlen("1.1.0")); + rsp->OutputBufferLength = cpu_to_le32(64); +- inc_rfc1001_len(rsp_org, 64); ++ inc_rfc1001_len(work->response_buf, 64); + fs_infoclass_size = FS_OBJECT_ID_INFORMATION_SIZE; + break; + } +@@ -5090,7 +5097,7 @@ static int smb2_get_info_filesystem(stru + info->ByteOffsetForSectorAlignment = 0; + info->ByteOffsetForPartitionAlignment = 0; + rsp->OutputBufferLength = cpu_to_le32(28); +- inc_rfc1001_len(rsp_org, 28); ++ inc_rfc1001_len(work->response_buf, 28); + fs_infoclass_size = FS_SECTOR_SIZE_INFORMATION_SIZE; + break; + } +@@ -5112,7 +5119,7 @@ static int smb2_get_info_filesystem(stru + info->DefaultQuotaLimit = cpu_to_le64(SMB2_NO_FID); + info->Padding = 0; + rsp->OutputBufferLength = cpu_to_le32(48); +- inc_rfc1001_len(rsp_org, 48); ++ inc_rfc1001_len(work->response_buf, 48); + fs_infoclass_size = FS_CONTROL_INFORMATION_SIZE; + break; + } +@@ -5133,7 +5140,7 @@ static int smb2_get_info_filesystem(stru + info->TotalFileNodes = cpu_to_le64(stfs.f_files); + info->FreeFileNodes = cpu_to_le64(stfs.f_ffree); + rsp->OutputBufferLength = cpu_to_le32(56); +- inc_rfc1001_len(rsp_org, 56); ++ inc_rfc1001_len(work->response_buf, 56); + fs_infoclass_size = FS_POSIX_INFORMATION_SIZE; + } + break; +@@ -5143,7 +5150,7 @@ static int smb2_get_info_filesystem(stru + return -EOPNOTSUPP; + } + rc = buffer_check_err(le32_to_cpu(req->OutputBufferLength), +- rsp, ++ rsp, work->response_buf, + fs_infoclass_size); + path_put(&path); + return rc; +@@ -5151,7 +5158,7 @@ static int smb2_get_info_filesystem(stru + + static int smb2_get_info_sec(struct ksmbd_work *work, + struct smb2_query_info_req *req, +- struct smb2_query_info_rsp *rsp, void *rsp_org) ++ struct smb2_query_info_rsp *rsp) + { + struct ksmbd_file *fp; + struct user_namespace *user_ns; +@@ -5178,7 +5185,7 @@ static int smb2_get_info_sec(struct ksmb + + secdesclen = sizeof(struct smb_ntsd); + rsp->OutputBufferLength = cpu_to_le32(secdesclen); +- inc_rfc1001_len(rsp_org, secdesclen); ++ inc_rfc1001_len(work->response_buf, secdesclen); + + return 0; + } +@@ -5223,7 +5230,7 @@ static int smb2_get_info_sec(struct ksmb + return rc; + + rsp->OutputBufferLength = cpu_to_le32(secdesclen); +- inc_rfc1001_len(rsp_org, secdesclen); ++ inc_rfc1001_len(work->response_buf, secdesclen); + return 0; + } + +@@ -5236,10 +5243,9 @@ static int smb2_get_info_sec(struct ksmb + int smb2_query_info(struct ksmbd_work *work) + { + struct smb2_query_info_req *req; +- struct smb2_query_info_rsp *rsp, *rsp_org; ++ struct smb2_query_info_rsp *rsp; + int rc = 0; + +- rsp_org = work->response_buf; + WORK_BUFFERS(work, req, rsp); + + ksmbd_debug(SMB, "GOT query info request\n"); +@@ -5247,15 +5253,15 @@ int smb2_query_info(struct ksmbd_work *w + switch (req->InfoType) { + case SMB2_O_INFO_FILE: + ksmbd_debug(SMB, "GOT SMB2_O_INFO_FILE\n"); +- rc = smb2_get_info_file(work, req, rsp, (void *)rsp_org); ++ rc = smb2_get_info_file(work, req, rsp); + break; + case SMB2_O_INFO_FILESYSTEM: + ksmbd_debug(SMB, "GOT SMB2_O_INFO_FILESYSTEM\n"); +- rc = smb2_get_info_filesystem(work, req, rsp, (void *)rsp_org); ++ rc = smb2_get_info_filesystem(work, req, rsp); + break; + case SMB2_O_INFO_SECURITY: + ksmbd_debug(SMB, "GOT SMB2_O_INFO_SECURITY\n"); +- rc = smb2_get_info_sec(work, req, rsp, (void *)rsp_org); ++ rc = smb2_get_info_sec(work, req, rsp); + break; + default: + ksmbd_debug(SMB, "InfoType %d not supported yet\n", +@@ -5280,7 +5286,7 @@ int smb2_query_info(struct ksmbd_work *w + } + rsp->StructureSize = cpu_to_le16(9); + rsp->OutputBufferOffset = cpu_to_le16(72); +- inc_rfc1001_len(rsp_org, 8); ++ inc_rfc1001_len(work->response_buf, 8); + return 0; + } + +@@ -5293,8 +5299,8 @@ int smb2_query_info(struct ksmbd_work *w + static noinline int smb2_close_pipe(struct ksmbd_work *work) + { + u64 id; +- struct smb2_close_req *req = work->request_buf; +- struct smb2_close_rsp *rsp = work->response_buf; ++ struct smb2_close_req *req = smb2_get_msg(work->request_buf); ++ struct smb2_close_rsp *rsp = smb2_get_msg(work->response_buf); + + id = le64_to_cpu(req->VolatileFileId); + ksmbd_session_rpc_close(work->sess, id); +@@ -5309,7 +5315,7 @@ static noinline int smb2_close_pipe(stru + rsp->AllocationSize = 0; + rsp->EndOfFile = 0; + rsp->Attributes = 0; +- inc_rfc1001_len(rsp, 60); ++ inc_rfc1001_len(work->response_buf, 60); + return 0; + } + +@@ -5325,14 +5331,12 @@ int smb2_close(struct ksmbd_work *work) + u64 sess_id; + struct smb2_close_req *req; + struct smb2_close_rsp *rsp; +- struct smb2_close_rsp *rsp_org; + struct ksmbd_conn *conn = work->conn; + struct ksmbd_file *fp; + struct inode *inode; + u64 time; + int err = 0; + +- rsp_org = work->response_buf; + WORK_BUFFERS(work, req, rsp); + + if (test_share_config_flag(work->tcon->share_conf, +@@ -5422,7 +5426,7 @@ out: + rsp->hdr.Status = STATUS_FILE_CLOSED; + smb2_set_err_rsp(work); + } else { +- inc_rfc1001_len(rsp_org, 60); ++ inc_rfc1001_len(work->response_buf, 60); + } + + return 0; +@@ -5436,11 +5440,11 @@ out: + */ + int smb2_echo(struct ksmbd_work *work) + { +- struct smb2_echo_rsp *rsp = work->response_buf; ++ struct smb2_echo_rsp *rsp = smb2_get_msg(work->response_buf); + + rsp->StructureSize = cpu_to_le16(4); + rsp->Reserved = 0; +- inc_rfc1001_len(rsp, 4); ++ inc_rfc1001_len(work->response_buf, 4); + return 0; + } + +@@ -6061,14 +6065,13 @@ static int smb2_set_info_sec(struct ksmb + int smb2_set_info(struct ksmbd_work *work) + { + struct smb2_set_info_req *req; +- struct smb2_set_info_rsp *rsp, *rsp_org; ++ struct smb2_set_info_rsp *rsp; + struct ksmbd_file *fp; + int rc = 0; + unsigned int id = KSMBD_NO_FID, pid = KSMBD_NO_FID; + + ksmbd_debug(SMB, "Received set info request\n"); + +- rsp_org = work->response_buf; + if (work->next_smb2_rcv_hdr_off) { + req = ksmbd_req_buf_next(work); + rsp = ksmbd_resp_buf_next(work); +@@ -6079,8 +6082,8 @@ int smb2_set_info(struct ksmbd_work *wor + pid = work->compound_pfid; + } + } else { +- req = work->request_buf; +- rsp = work->response_buf; ++ req = smb2_get_msg(work->request_buf); ++ rsp = smb2_get_msg(work->response_buf); + } + + if (!has_file_id(id)) { +@@ -6120,7 +6123,7 @@ int smb2_set_info(struct ksmbd_work *wor + goto err_out; + + rsp->StructureSize = cpu_to_le16(2); +- inc_rfc1001_len(rsp_org, 2); ++ inc_rfc1001_len(work->response_buf, 2); + ksmbd_fd_put(work, fp); + return 0; + +@@ -6160,12 +6163,12 @@ static noinline int smb2_read_pipe(struc + int nbytes = 0, err; + u64 id; + struct ksmbd_rpc_command *rpc_resp; +- struct smb2_read_req *req = work->request_buf; +- struct smb2_read_rsp *rsp = work->response_buf; ++ struct smb2_read_req *req = smb2_get_msg(work->request_buf); ++ struct smb2_read_rsp *rsp = smb2_get_msg(work->response_buf); + + id = le64_to_cpu(req->VolatileFileId); + +- inc_rfc1001_len(rsp, 16); ++ inc_rfc1001_len(work->response_buf, 16); + rpc_resp = ksmbd_rpc_read(work->sess, id); + if (rpc_resp) { + if (rpc_resp->flags != KSMBD_RPC_OK) { +@@ -6184,7 +6187,7 @@ static noinline int smb2_read_pipe(struc + rpc_resp->payload_sz); + + nbytes = rpc_resp->payload_sz; +- work->resp_hdr_sz = get_rfc1002_len(rsp) + 4; ++ work->resp_hdr_sz = get_rfc1002_len(work->response_buf) + 4; + work->aux_payload_sz = nbytes; + kvfree(rpc_resp); + } +@@ -6195,7 +6198,7 @@ static noinline int smb2_read_pipe(struc + rsp->DataLength = cpu_to_le32(nbytes); + rsp->DataRemaining = 0; + rsp->Reserved2 = 0; +- inc_rfc1001_len(rsp, nbytes); ++ inc_rfc1001_len(work->response_buf, nbytes); + return 0; + + out: +@@ -6245,14 +6248,13 @@ int smb2_read(struct ksmbd_work *work) + { + struct ksmbd_conn *conn = work->conn; + struct smb2_read_req *req; +- struct smb2_read_rsp *rsp, *rsp_org; ++ struct smb2_read_rsp *rsp; + struct ksmbd_file *fp = NULL; + loff_t offset; + size_t length, mincount; + ssize_t nbytes = 0, remain_bytes = 0; + int err = 0; + +- rsp_org = work->response_buf; + WORK_BUFFERS(work, req, rsp); + if (work->next_smb2_rcv_hdr_off) { + work->send_no_response = 1; +@@ -6339,10 +6341,10 @@ int smb2_read(struct ksmbd_work *work) + rsp->DataLength = cpu_to_le32(nbytes); + rsp->DataRemaining = cpu_to_le32(remain_bytes); + rsp->Reserved2 = 0; +- inc_rfc1001_len(rsp_org, 16); +- work->resp_hdr_sz = get_rfc1002_len(rsp_org) + 4; ++ inc_rfc1001_len(work->response_buf, 16); ++ work->resp_hdr_sz = get_rfc1002_len(work->response_buf) + 4; + work->aux_payload_sz = nbytes; +- inc_rfc1001_len(rsp_org, nbytes); ++ inc_rfc1001_len(work->response_buf, nbytes); + ksmbd_fd_put(work, fp); + return 0; + +@@ -6377,8 +6379,8 @@ out: + */ + static noinline int smb2_write_pipe(struct ksmbd_work *work) + { +- struct smb2_write_req *req = work->request_buf; +- struct smb2_write_rsp *rsp = work->response_buf; ++ struct smb2_write_req *req = smb2_get_msg(work->request_buf); ++ struct smb2_write_rsp *rsp = smb2_get_msg(work->response_buf); + struct ksmbd_rpc_command *rpc_resp; + u64 id = 0; + int err = 0, ret = 0; +@@ -6389,13 +6391,14 @@ static noinline int smb2_write_pipe(stru + id = le64_to_cpu(req->VolatileFileId); + + if (le16_to_cpu(req->DataOffset) == +- (offsetof(struct smb2_write_req, Buffer) - 4)) { ++ offsetof(struct smb2_write_req, Buffer)) { + data_buf = (char *)&req->Buffer[0]; + } else { +- if ((u64)le16_to_cpu(req->DataOffset) + length > get_rfc1002_len(req)) { ++ if ((u64)le16_to_cpu(req->DataOffset) + length > ++ get_rfc1002_len(work->request_buf)) { + pr_err("invalid write data offset %u, smb_len %u\n", + le16_to_cpu(req->DataOffset), +- get_rfc1002_len(req)); ++ get_rfc1002_len(work->request_buf)); + err = -EINVAL; + goto out; + } +@@ -6427,7 +6430,7 @@ static noinline int smb2_write_pipe(stru + rsp->DataLength = cpu_to_le32(length); + rsp->DataRemaining = 0; + rsp->Reserved2 = 0; +- inc_rfc1001_len(rsp, 16); ++ inc_rfc1001_len(work->response_buf, 16); + return 0; + out: + if (err) { +@@ -6495,7 +6498,7 @@ static ssize_t smb2_write_rdma_channel(s + int smb2_write(struct ksmbd_work *work) + { + struct smb2_write_req *req; +- struct smb2_write_rsp *rsp, *rsp_org; ++ struct smb2_write_rsp *rsp; + struct ksmbd_file *fp = NULL; + loff_t offset; + size_t length; +@@ -6504,7 +6507,6 @@ int smb2_write(struct ksmbd_work *work) + bool writethrough = false; + int err = 0; + +- rsp_org = work->response_buf; + WORK_BUFFERS(work, req, rsp); + + if (test_share_config_flag(work->tcon->share_conf, KSMBD_SHARE_FLAG_PIPE)) { +@@ -6547,7 +6549,7 @@ int smb2_write(struct ksmbd_work *work) + if (req->Channel != SMB2_CHANNEL_RDMA_V1 && + req->Channel != SMB2_CHANNEL_RDMA_V1_INVALIDATE) { + if (le16_to_cpu(req->DataOffset) == +- (offsetof(struct smb2_write_req, Buffer) - 4)) { ++ offsetof(struct smb2_write_req, Buffer)) { + data_buf = (char *)&req->Buffer[0]; + } else { + if (le16_to_cpu(req->DataOffset) < +@@ -6589,7 +6591,7 @@ int smb2_write(struct ksmbd_work *work) + rsp->DataLength = cpu_to_le32(nbytes); + rsp->DataRemaining = 0; + rsp->Reserved2 = 0; +- inc_rfc1001_len(rsp_org, 16); ++ inc_rfc1001_len(work->response_buf, 16); + ksmbd_fd_put(work, fp); + return 0; + +@@ -6623,10 +6625,9 @@ out: + int smb2_flush(struct ksmbd_work *work) + { + struct smb2_flush_req *req; +- struct smb2_flush_rsp *rsp, *rsp_org; ++ struct smb2_flush_rsp *rsp; + int err; + +- rsp_org = work->response_buf; + WORK_BUFFERS(work, req, rsp); + + ksmbd_debug(SMB, "SMB2_FLUSH called for fid %llu\n", +@@ -6640,7 +6641,7 @@ int smb2_flush(struct ksmbd_work *work) + + rsp->StructureSize = cpu_to_le16(4); + rsp->Reserved = 0; +- inc_rfc1001_len(rsp_org, 4); ++ inc_rfc1001_len(work->response_buf, 4); + return 0; + + out: +@@ -6661,7 +6662,7 @@ out: + int smb2_cancel(struct ksmbd_work *work) + { + struct ksmbd_conn *conn = work->conn; +- struct smb2_hdr *hdr = work->request_buf; ++ struct smb2_hdr *hdr = smb2_get_msg(work->request_buf); + struct smb2_hdr *chdr; + struct ksmbd_work *cancel_work = NULL; + int canceled = 0; +@@ -6676,7 +6677,7 @@ int smb2_cancel(struct ksmbd_work *work) + spin_lock(&conn->request_lock); + list_for_each_entry(cancel_work, command_list, + async_request_entry) { +- chdr = cancel_work->request_buf; ++ chdr = smb2_get_msg(cancel_work->request_buf); + + if (cancel_work->async_id != + le64_to_cpu(hdr->Id.AsyncId)) +@@ -6695,7 +6696,7 @@ int smb2_cancel(struct ksmbd_work *work) + + spin_lock(&conn->request_lock); + list_for_each_entry(cancel_work, command_list, request_entry) { +- chdr = cancel_work->request_buf; ++ chdr = smb2_get_msg(cancel_work->request_buf); + + if (chdr->MessageId != hdr->MessageId || + cancel_work == work) +@@ -6830,8 +6831,8 @@ static inline bool lock_defer_pending(st + */ + int smb2_lock(struct ksmbd_work *work) + { +- struct smb2_lock_req *req = work->request_buf; +- struct smb2_lock_rsp *rsp = work->response_buf; ++ struct smb2_lock_req *req = smb2_get_msg(work->request_buf); ++ struct smb2_lock_rsp *rsp = smb2_get_msg(work->response_buf); + struct smb2_lock_element *lock_ele; + struct ksmbd_file *fp = NULL; + struct file_lock *flock = NULL; +@@ -7139,7 +7140,7 @@ skip: + ksmbd_debug(SMB, "successful in taking lock\n"); + rsp->hdr.Status = STATUS_SUCCESS; + rsp->Reserved = 0; +- inc_rfc1001_len(rsp, 4); ++ inc_rfc1001_len(work->response_buf, 4); + ksmbd_fd_put(work, fp); + return 0; + +@@ -7617,13 +7618,12 @@ static int fsctl_request_resume_key(stru + int smb2_ioctl(struct ksmbd_work *work) + { + struct smb2_ioctl_req *req; +- struct smb2_ioctl_rsp *rsp, *rsp_org; ++ struct smb2_ioctl_rsp *rsp; + unsigned int cnt_code, nbytes = 0, out_buf_len, in_buf_len; + u64 id = KSMBD_NO_FID; + struct ksmbd_conn *conn = work->conn; + int ret = 0; + +- rsp_org = work->response_buf; + if (work->next_smb2_rcv_hdr_off) { + req = ksmbd_req_buf_next(work); + rsp = ksmbd_resp_buf_next(work); +@@ -7633,8 +7633,8 @@ int smb2_ioctl(struct ksmbd_work *work) + id = work->compound_fid; + } + } else { +- req = work->request_buf; +- rsp = work->response_buf; ++ req = smb2_get_msg(work->request_buf); ++ rsp = smb2_get_msg(work->response_buf); + } + + if (!has_file_id(id)) +@@ -7936,7 +7936,7 @@ dup_ext_out: + rsp->Reserved = cpu_to_le16(0); + rsp->Flags = cpu_to_le32(0); + rsp->Reserved2 = cpu_to_le32(0); +- inc_rfc1001_len(rsp_org, 48 + nbytes); ++ inc_rfc1001_len(work->response_buf, 48 + nbytes); + + return 0; + +@@ -7963,8 +7963,8 @@ out: + */ + static void smb20_oplock_break_ack(struct ksmbd_work *work) + { +- struct smb2_oplock_break *req = work->request_buf; +- struct smb2_oplock_break *rsp = work->response_buf; ++ struct smb2_oplock_break *req = smb2_get_msg(work->request_buf); ++ struct smb2_oplock_break *rsp = smb2_get_msg(work->response_buf); + struct ksmbd_file *fp; + struct oplock_info *opinfo = NULL; + __le32 err = 0; +@@ -8071,7 +8071,7 @@ static void smb20_oplock_break_ack(struc + rsp->Reserved2 = 0; + rsp->VolatileFid = cpu_to_le64(volatile_id); + rsp->PersistentFid = cpu_to_le64(persistent_id); +- inc_rfc1001_len(rsp, 24); ++ inc_rfc1001_len(work->response_buf, 24); + return; + + err_out: +@@ -8107,8 +8107,8 @@ static int check_lease_state(struct leas + static void smb21_lease_break_ack(struct ksmbd_work *work) + { + struct ksmbd_conn *conn = work->conn; +- struct smb2_lease_ack *req = work->request_buf; +- struct smb2_lease_ack *rsp = work->response_buf; ++ struct smb2_lease_ack *req = smb2_get_msg(work->request_buf); ++ struct smb2_lease_ack *rsp = smb2_get_msg(work->response_buf); + struct oplock_info *opinfo; + __le32 err = 0; + int ret = 0; +@@ -8220,7 +8220,7 @@ static void smb21_lease_break_ack(struct + memcpy(rsp->LeaseKey, req->LeaseKey, 16); + rsp->LeaseState = lease_state; + rsp->LeaseDuration = 0; +- inc_rfc1001_len(rsp, 36); ++ inc_rfc1001_len(work->response_buf, 36); + return; + + err_out: +@@ -8241,8 +8241,8 @@ err_out: + */ + int smb2_oplock_break(struct ksmbd_work *work) + { +- struct smb2_oplock_break *req = work->request_buf; +- struct smb2_oplock_break *rsp = work->response_buf; ++ struct smb2_oplock_break *req = smb2_get_msg(work->request_buf); ++ struct smb2_oplock_break *rsp = smb2_get_msg(work->response_buf); + + switch (le16_to_cpu(req->StructureSize)) { + case OP_BREAK_STRUCT_SIZE_20: +@@ -8294,7 +8294,7 @@ int smb2_notify(struct ksmbd_work *work) + */ + bool smb2_is_sign_req(struct ksmbd_work *work, unsigned int command) + { +- struct smb2_hdr *rcv_hdr2 = work->request_buf; ++ struct smb2_hdr *rcv_hdr2 = smb2_get_msg(work->request_buf); + + if ((rcv_hdr2->Flags & SMB2_FLAGS_SIGNED) && + command != SMB2_NEGOTIATE_HE && +@@ -8313,22 +8313,22 @@ bool smb2_is_sign_req(struct ksmbd_work + */ + int smb2_check_sign_req(struct ksmbd_work *work) + { +- struct smb2_hdr *hdr, *hdr_org; ++ struct smb2_hdr *hdr; + char signature_req[SMB2_SIGNATURE_SIZE]; + char signature[SMB2_HMACSHA256_SIZE]; + struct kvec iov[1]; + size_t len; + +- hdr_org = hdr = work->request_buf; ++ hdr = smb2_get_msg(work->request_buf); + if (work->next_smb2_rcv_hdr_off) + hdr = ksmbd_req_buf_next(work); + + if (!hdr->NextCommand && !work->next_smb2_rcv_hdr_off) +- len = be32_to_cpu(hdr_org->smb2_buf_length); ++ len = get_rfc1002_len(work->request_buf); + else if (hdr->NextCommand) + len = le32_to_cpu(hdr->NextCommand); + else +- len = be32_to_cpu(hdr_org->smb2_buf_length) - ++ len = get_rfc1002_len(work->request_buf) - + work->next_smb2_rcv_hdr_off; + + memcpy(signature_req, hdr->Signature, SMB2_SIGNATURE_SIZE); +@@ -8356,25 +8356,26 @@ int smb2_check_sign_req(struct ksmbd_wor + */ + void smb2_set_sign_rsp(struct ksmbd_work *work) + { +- struct smb2_hdr *hdr, *hdr_org; ++ struct smb2_hdr *hdr; + struct smb2_hdr *req_hdr; + char signature[SMB2_HMACSHA256_SIZE]; + struct kvec iov[2]; + size_t len; + int n_vec = 1; + +- hdr_org = hdr = work->response_buf; ++ hdr = smb2_get_msg(work->response_buf); + if (work->next_smb2_rsp_hdr_off) + hdr = ksmbd_resp_buf_next(work); + + req_hdr = ksmbd_req_buf_next(work); + + if (!work->next_smb2_rsp_hdr_off) { +- len = get_rfc1002_len(hdr_org); ++ len = get_rfc1002_len(work->response_buf); + if (req_hdr->NextCommand) + len = ALIGN(len, 8); + } else { +- len = get_rfc1002_len(hdr_org) - work->next_smb2_rsp_hdr_off; ++ len = get_rfc1002_len(work->response_buf) - ++ work->next_smb2_rsp_hdr_off; + len = ALIGN(len, 8); + } + +@@ -8410,23 +8411,23 @@ int smb3_check_sign_req(struct ksmbd_wor + { + struct ksmbd_conn *conn = work->conn; + char *signing_key; +- struct smb2_hdr *hdr, *hdr_org; ++ struct smb2_hdr *hdr; + struct channel *chann; + char signature_req[SMB2_SIGNATURE_SIZE]; + char signature[SMB2_CMACAES_SIZE]; + struct kvec iov[1]; + size_t len; + +- hdr_org = hdr = work->request_buf; ++ hdr = smb2_get_msg(work->request_buf); + if (work->next_smb2_rcv_hdr_off) + hdr = ksmbd_req_buf_next(work); + + if (!hdr->NextCommand && !work->next_smb2_rcv_hdr_off) +- len = be32_to_cpu(hdr_org->smb2_buf_length); ++ len = get_rfc1002_len(work->request_buf); + else if (hdr->NextCommand) + len = le32_to_cpu(hdr->NextCommand); + else +- len = be32_to_cpu(hdr_org->smb2_buf_length) - ++ len = get_rfc1002_len(work->request_buf) - + work->next_smb2_rcv_hdr_off; + + if (le16_to_cpu(hdr->Command) == SMB2_SESSION_SETUP_HE) { +@@ -8471,8 +8472,7 @@ int smb3_check_sign_req(struct ksmbd_wor + void smb3_set_sign_rsp(struct ksmbd_work *work) + { + struct ksmbd_conn *conn = work->conn; +- struct smb2_hdr *req_hdr; +- struct smb2_hdr *hdr, *hdr_org; ++ struct smb2_hdr *req_hdr, *hdr; + struct channel *chann; + char signature[SMB2_CMACAES_SIZE]; + struct kvec iov[2]; +@@ -8480,18 +8480,19 @@ void smb3_set_sign_rsp(struct ksmbd_work + size_t len; + char *signing_key; + +- hdr_org = hdr = work->response_buf; ++ hdr = smb2_get_msg(work->response_buf); + if (work->next_smb2_rsp_hdr_off) + hdr = ksmbd_resp_buf_next(work); + + req_hdr = ksmbd_req_buf_next(work); + + if (!work->next_smb2_rsp_hdr_off) { +- len = get_rfc1002_len(hdr_org); ++ len = get_rfc1002_len(work->response_buf); + if (req_hdr->NextCommand) + len = ALIGN(len, 8); + } else { +- len = get_rfc1002_len(hdr_org) - work->next_smb2_rsp_hdr_off; ++ len = get_rfc1002_len(work->response_buf) - ++ work->next_smb2_rsp_hdr_off; + len = ALIGN(len, 8); + } + +@@ -8548,7 +8549,7 @@ void smb3_preauth_hash_rsp(struct ksmbd_ + + if (le16_to_cpu(req->Command) == SMB2_NEGOTIATE_HE && + conn->preauth_info) +- ksmbd_gen_preauth_integrity_hash(conn, (char *)rsp, ++ ksmbd_gen_preauth_integrity_hash(conn, work->response_buf, + conn->preauth_info->Preauth_HashValue); + + if (le16_to_cpu(rsp->Command) == SMB2_SESSION_SETUP_HE && sess) { +@@ -8566,7 +8567,7 @@ void smb3_preauth_hash_rsp(struct ksmbd_ + if (!hash_value) + return; + } +- ksmbd_gen_preauth_integrity_hash(conn, (char *)rsp, ++ ksmbd_gen_preauth_integrity_hash(conn, work->response_buf, + hash_value); + } + } +@@ -8648,7 +8649,6 @@ int smb3_decrypt_req(struct ksmbd_work * + struct ksmbd_conn *conn = work->conn; + struct ksmbd_session *sess; + char *buf = work->request_buf; +- struct smb2_hdr *hdr; + unsigned int pdu_length = get_rfc1002_len(buf); + struct kvec iov[2]; + int buf_data_size = pdu_length + 4 - +@@ -8684,8 +8684,7 @@ int smb3_decrypt_req(struct ksmbd_work * + return rc; + + memmove(buf + 4, iov[1].iov_base, buf_data_size); +- hdr = (struct smb2_hdr *)buf; +- hdr->smb2_buf_length = cpu_to_be32(buf_data_size); ++ *(__be32 *)buf = cpu_to_be32(buf_data_size); + + return rc; + } +@@ -8694,7 +8693,7 @@ bool smb3_11_final_sess_setup_resp(struc + { + struct ksmbd_conn *conn = work->conn; + struct ksmbd_session *sess = work->sess; +- struct smb2_hdr *rsp = work->response_buf; ++ struct smb2_hdr *rsp = smb2_get_msg(work->response_buf); + + if (conn->dialect < SMB30_PROT_ID) + return false; +--- a/fs/ksmbd/smb2pdu.h ++++ b/fs/ksmbd/smb2pdu.h +@@ -131,11 +131,6 @@ + cpu_to_le16(__SMB2_HEADER_STRUCTURE_SIZE) + + struct smb2_hdr { +- __be32 smb2_buf_length; /* big endian on wire */ +- /* +- * length is only two or three bytes - with +- * one or two byte type preceding it that MBZ +- */ + __le32 ProtocolId; /* 0xFE 'S' 'M' 'B' */ + __le16 StructureSize; /* 64 */ + __le16 CreditCharge; /* MBZ */ +@@ -254,14 +249,14 @@ struct preauth_integrity_info { + __u8 Preauth_HashValue[PREAUTH_HASHVALUE_SIZE]; + }; + +-/* offset is sizeof smb2_negotiate_rsp - 4 but rounded up to 8 bytes. */ ++/* offset is sizeof smb2_negotiate_rsp but rounded up to 8 bytes. */ + #ifdef CONFIG_SMB_SERVER_KERBEROS5 +-/* sizeof(struct smb2_negotiate_rsp) - 4 = ++/* sizeof(struct smb2_negotiate_rsp) = + * header(64) + response(64) + GSS_LENGTH(96) + GSS_PADDING(0) + */ + #define OFFSET_OF_NEG_CONTEXT 0xe0 + #else +-/* sizeof(struct smb2_negotiate_rsp) - 4 = ++/* sizeof(struct smb2_negotiate_rsp) = + * header(64) + response(64) + GSS_LENGTH(74) + GSS_PADDING(6) + */ + #define OFFSET_OF_NEG_CONTEXT 0xd0 +@@ -1707,4 +1702,13 @@ int smb2_ioctl(struct ksmbd_work *work); + int smb2_oplock_break(struct ksmbd_work *work); + int smb2_notify(struct ksmbd_work *ksmbd_work); + ++/* ++ * Get the body of the smb2 message excluding the 4 byte rfc1002 headers ++ * from request/response buffer. ++ */ ++static inline void *smb2_get_msg(void *buf) ++{ ++ return buf + 4; ++} ++ + #endif /* _SMB2PDU_H */ +--- a/fs/ksmbd/smb_common.c ++++ b/fs/ksmbd/smb_common.c +@@ -243,14 +243,14 @@ int ksmbd_lookup_dialect_by_id(__le16 *c + static int ksmbd_negotiate_smb_dialect(void *buf) + { + int smb_buf_length = get_rfc1002_len(buf); +- __le32 proto = ((struct smb2_hdr *)buf)->ProtocolId; ++ __le32 proto = ((struct smb2_hdr *)smb2_get_msg(buf))->ProtocolId; + + if (proto == SMB2_PROTO_NUMBER) { + struct smb2_negotiate_req *req; + int smb2_neg_size = +- offsetof(struct smb2_negotiate_req, Dialects) - 4; ++ offsetof(struct smb2_negotiate_req, Dialects); + +- req = (struct smb2_negotiate_req *)buf; ++ req = (struct smb2_negotiate_req *)smb2_get_msg(buf); + if (smb2_neg_size > smb_buf_length) + goto err_out; + +@@ -469,11 +469,12 @@ int ksmbd_smb_negotiate_common(struct ks + struct ksmbd_conn *conn = work->conn; + int ret; + +- conn->dialect = ksmbd_negotiate_smb_dialect(work->request_buf); ++ conn->dialect = ++ ksmbd_negotiate_smb_dialect(work->request_buf); + ksmbd_debug(SMB, "conn->dialect 0x%x\n", conn->dialect); + + if (command == SMB2_NEGOTIATE_HE) { +- struct smb2_hdr *smb2_hdr = work->request_buf; ++ struct smb2_hdr *smb2_hdr = smb2_get_msg(work->request_buf); + + if (smb2_hdr->ProtocolId != SMB2_PROTO_NUMBER) { + ksmbd_debug(SMB, "Downgrade to SMB1 negotiation\n"); +--- a/fs/ksmbd/smb_common.h ++++ b/fs/ksmbd/smb_common.h +@@ -464,12 +464,6 @@ struct smb_version_cmds { + int (*proc)(struct ksmbd_work *swork); + }; + +-static inline size_t +-smb2_hdr_size_no_buflen(struct smb_version_values *vals) +-{ +- return vals->header_size - 4; +-} +- + int ksmbd_min_protocol(void); + int ksmbd_max_protocol(void); + +--- a/fs/ksmbd/transport_rdma.c ++++ b/fs/ksmbd/transport_rdma.c +@@ -490,7 +490,7 @@ static int smb_direct_check_recvmsg(stru + struct smb_direct_data_transfer *req = + (struct smb_direct_data_transfer *)recvmsg->packet; + struct smb2_hdr *hdr = (struct smb2_hdr *)(recvmsg->packet +- + le32_to_cpu(req->data_offset) - 4); ++ + le32_to_cpu(req->data_offset)); + ksmbd_debug(RDMA, + "CreditGranted: %u, CreditRequested: %u, DataLength: %u, RemainingDataLength: %u, SMB: %x, Command: %u\n", + le16_to_cpu(req->credits_granted), diff --git a/queue-5.15/ksmbd-remove-smb2_buf_length-in-smb2_transform_hdr.patch b/queue-5.15/ksmbd-remove-smb2_buf_length-in-smb2_transform_hdr.patch new file mode 100644 index 00000000000..760665afacd --- /dev/null +++ b/queue-5.15/ksmbd-remove-smb2_buf_length-in-smb2_transform_hdr.patch @@ -0,0 +1,173 @@ +From stable+bounces-7635-greg=kroah.com@vger.kernel.org Mon Dec 18 16:35:41 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:32:26 +0900 +Subject: ksmbd: remove smb2_buf_length in smb2_transform_hdr +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , Ronnie Sahlberg , Steve French +Message-ID: <20231218153454.8090-7-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit 2dd9129f7dec1de369e4447a54ea2edf695f765b ] + +To move smb2_transform_hdr to smbfs_common, This patch remove +smb2_buf_length variable in smb2_transform_hdr. + +Cc: Ronnie Sahlberg +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/auth.c | 7 +++---- + fs/ksmbd/connection.c | 2 +- + fs/ksmbd/smb2pdu.c | 37 +++++++++++++++++-------------------- + fs/ksmbd/smb2pdu.h | 5 ----- + 4 files changed, 21 insertions(+), 30 deletions(-) + +--- a/fs/ksmbd/auth.c ++++ b/fs/ksmbd/auth.c +@@ -994,7 +994,7 @@ static struct scatterlist *ksmbd_init_sg + u8 *sign) + { + struct scatterlist *sg; +- unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 24; ++ unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 20; + int i, nr_entries[3] = {0}, total_entries = 0, sg_idx = 0; + + if (!nvec) +@@ -1058,9 +1058,8 @@ static struct scatterlist *ksmbd_init_sg + int ksmbd_crypt_message(struct ksmbd_conn *conn, struct kvec *iov, + unsigned int nvec, int enc) + { +- struct smb2_transform_hdr *tr_hdr = +- (struct smb2_transform_hdr *)iov[0].iov_base; +- unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 24; ++ struct smb2_transform_hdr *tr_hdr = smb2_get_msg(iov[0].iov_base); ++ unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 20; + int rc; + struct scatterlist *sg; + u8 sign[SMB2_SIGNATURE_SIZE] = {}; +--- a/fs/ksmbd/connection.c ++++ b/fs/ksmbd/connection.c +@@ -173,7 +173,7 @@ int ksmbd_conn_write(struct ksmbd_work * + + if (work->tr_buf) { + iov[iov_idx] = (struct kvec) { work->tr_buf, +- sizeof(struct smb2_transform_hdr) }; ++ sizeof(struct smb2_transform_hdr) + 4 }; + len += iov[iov_idx++].iov_len; + } + +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -8572,13 +8572,13 @@ void smb3_preauth_hash_rsp(struct ksmbd_ + } + } + +-static void fill_transform_hdr(struct smb2_transform_hdr *tr_hdr, char *old_buf, +- __le16 cipher_type) ++static void fill_transform_hdr(void *tr_buf, char *old_buf, __le16 cipher_type) + { +- struct smb2_hdr *hdr = (struct smb2_hdr *)old_buf; ++ struct smb2_transform_hdr *tr_hdr = tr_buf + 4; ++ struct smb2_hdr *hdr = smb2_get_msg(old_buf); + unsigned int orig_len = get_rfc1002_len(old_buf); + +- memset(tr_hdr, 0, sizeof(struct smb2_transform_hdr)); ++ memset(tr_buf, 0, sizeof(struct smb2_transform_hdr) + 4); + tr_hdr->ProtocolId = SMB2_TRANSFORM_PROTO_NUM; + tr_hdr->OriginalMessageSize = cpu_to_le32(orig_len); + tr_hdr->Flags = cpu_to_le16(0x01); +@@ -8588,14 +8588,13 @@ static void fill_transform_hdr(struct sm + else + get_random_bytes(&tr_hdr->Nonce, SMB3_AES_CCM_NONCE); + memcpy(&tr_hdr->SessionId, &hdr->SessionId, 8); +- inc_rfc1001_len(tr_hdr, sizeof(struct smb2_transform_hdr) - 4); +- inc_rfc1001_len(tr_hdr, orig_len); ++ inc_rfc1001_len(tr_buf, sizeof(struct smb2_transform_hdr)); ++ inc_rfc1001_len(tr_buf, orig_len); + } + + int smb3_encrypt_resp(struct ksmbd_work *work) + { + char *buf = work->response_buf; +- struct smb2_transform_hdr *tr_hdr; + struct kvec iov[3]; + int rc = -ENOMEM; + int buf_size = 0, rq_nvec = 2 + (work->aux_payload_sz ? 1 : 0); +@@ -8603,15 +8602,15 @@ int smb3_encrypt_resp(struct ksmbd_work + if (ARRAY_SIZE(iov) < rq_nvec) + return -ENOMEM; + +- tr_hdr = kzalloc(sizeof(struct smb2_transform_hdr), GFP_KERNEL); +- if (!tr_hdr) ++ work->tr_buf = kzalloc(sizeof(struct smb2_transform_hdr) + 4, GFP_KERNEL); ++ if (!work->tr_buf) + return rc; + + /* fill transform header */ +- fill_transform_hdr(tr_hdr, buf, work->conn->cipher_type); ++ fill_transform_hdr(work->tr_buf, buf, work->conn->cipher_type); + +- iov[0].iov_base = tr_hdr; +- iov[0].iov_len = sizeof(struct smb2_transform_hdr); ++ iov[0].iov_base = work->tr_buf; ++ iov[0].iov_len = sizeof(struct smb2_transform_hdr) + 4; + buf_size += iov[0].iov_len - 4; + + iov[1].iov_base = buf + 4; +@@ -8631,15 +8630,14 @@ int smb3_encrypt_resp(struct ksmbd_work + return rc; + + memmove(buf, iov[1].iov_base, iov[1].iov_len); +- tr_hdr->smb2_buf_length = cpu_to_be32(buf_size); +- work->tr_buf = tr_hdr; ++ *(__be32 *)work->tr_buf = cpu_to_be32(buf_size); + + return rc; + } + + bool smb3_is_transform_hdr(void *buf) + { +- struct smb2_transform_hdr *trhdr = buf; ++ struct smb2_transform_hdr *trhdr = smb2_get_msg(buf); + + return trhdr->ProtocolId == SMB2_TRANSFORM_PROTO_NUM; + } +@@ -8651,9 +8649,8 @@ int smb3_decrypt_req(struct ksmbd_work * + char *buf = work->request_buf; + unsigned int pdu_length = get_rfc1002_len(buf); + struct kvec iov[2]; +- int buf_data_size = pdu_length + 4 - +- sizeof(struct smb2_transform_hdr); +- struct smb2_transform_hdr *tr_hdr = (struct smb2_transform_hdr *)buf; ++ int buf_data_size = pdu_length - sizeof(struct smb2_transform_hdr); ++ struct smb2_transform_hdr *tr_hdr = smb2_get_msg(buf); + int rc = 0; + + if (pdu_length < sizeof(struct smb2_transform_hdr) || +@@ -8676,8 +8673,8 @@ int smb3_decrypt_req(struct ksmbd_work * + } + + iov[0].iov_base = buf; +- iov[0].iov_len = sizeof(struct smb2_transform_hdr); +- iov[1].iov_base = buf + sizeof(struct smb2_transform_hdr); ++ iov[0].iov_len = sizeof(struct smb2_transform_hdr) + 4; ++ iov[1].iov_base = buf + sizeof(struct smb2_transform_hdr) + 4; + iov[1].iov_len = buf_data_size; + rc = ksmbd_crypt_message(conn, iov, 2, 0); + if (rc) +--- a/fs/ksmbd/smb2pdu.h ++++ b/fs/ksmbd/smb2pdu.h +@@ -160,11 +160,6 @@ struct smb2_pdu { + #define SMB3_AES_GCM_NONCE 12 + + struct smb2_transform_hdr { +- __be32 smb2_buf_length; /* big endian on wire */ +- /* +- * length is only two or three bytes - with +- * one or two byte type preceding it that MBZ +- */ + __le32 ProtocolId; /* 0xFD 'S' 'M' 'B' */ + __u8 Signature[16]; + __u8 Nonce[16]; diff --git a/queue-5.15/ksmbd-remove-unnecessary-generic_fillattr-in-smb2_open.patch b/queue-5.15/ksmbd-remove-unnecessary-generic_fillattr-in-smb2_open.patch new file mode 100644 index 00000000000..448e5f47f99 --- /dev/null +++ b/queue-5.15/ksmbd-remove-unnecessary-generic_fillattr-in-smb2_open.patch @@ -0,0 +1,76 @@ +From linkinjeon@gmail.com Mon Dec 18 16:37:57 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:33:07 +0900 +Subject: ksmbd: remove unnecessary generic_fillattr in smb2_open +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Hyunchul Lee , Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-48-linkinjeon@kernel.org> + +From: Hyunchul Lee + +[ Upstream commit c90b31eaf9e77269d3803ed9223a2e0168b519ac ] + +Remove unnecessary generic_fillattr to fix wrong +AllocationSize of SMB2_CREATE response, And +Move the call of ksmbd_vfs_getattr above the place +where stat is needed because of truncate. + +This patch fixes wrong AllocationSize of SMB2_CREATE +response. Because ext4 updates inode->i_blocks only +when disk space is allocated, generic_fillattr does +not set stat.blocks properly for delayed allocation. +But ext4 returns the blocks that include the delayed +allocation blocks when getattr is called. + +The issue can be reproduced with commands below: + +touch ${FILENAME} +xfs_io -c "pwrite -S 0xAB 0 40k" ${FILENAME} +xfs_io -c "stat" ${FILENAME} + +40KB are written, but the count of blocks is 8. + +Signed-off-by: Hyunchul Lee +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/smb2pdu.c | 13 ++++--------- + 1 file changed, 4 insertions(+), 9 deletions(-) + +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -3095,12 +3095,6 @@ int smb2_open(struct ksmbd_work *work) + list_add(&fp->node, &fp->f_ci->m_fp_list); + write_unlock(&fp->f_ci->m_lock); + +- rc = ksmbd_vfs_getattr(&path, &stat); +- if (rc) { +- generic_fillattr(user_ns, d_inode(path.dentry), &stat); +- rc = 0; +- } +- + /* Check delete pending among previous fp before oplock break */ + if (ksmbd_inode_pending_delete(fp)) { + rc = -EBUSY; +@@ -3187,6 +3181,10 @@ int smb2_open(struct ksmbd_work *work) + } + } + ++ rc = ksmbd_vfs_getattr(&path, &stat); ++ if (rc) ++ goto err_out; ++ + if (stat.result_mask & STATX_BTIME) + fp->create_time = ksmbd_UnixTimeToNT(stat.btime); + else +@@ -3202,9 +3200,6 @@ int smb2_open(struct ksmbd_work *work) + + memcpy(fp->client_guid, conn->ClientGUID, SMB2_CLIENT_GUID_SIZE); + +- generic_fillattr(user_ns, file_inode(fp->filp), +- &stat); +- + rsp->StructureSize = cpu_to_le16(89); + rcu_read_lock(); + opinfo = rcu_dereference(fp->f_opinfo); diff --git a/queue-5.15/ksmbd-remove-unneeded-mark_inode_dirty-in-set_info_sec.patch b/queue-5.15/ksmbd-remove-unneeded-mark_inode_dirty-in-set_info_sec.patch new file mode 100644 index 00000000000..ba75e5718eb --- /dev/null +++ b/queue-5.15/ksmbd-remove-unneeded-mark_inode_dirty-in-set_info_sec.patch @@ -0,0 +1,32 @@ +From linkinjeon@gmail.com Mon Dec 18 16:42:10 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:34:27 +0900 +Subject: ksmbd: remove unneeded mark_inode_dirty in set_info_sec() +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-128-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit e4e14095cc68a2efefba6f77d95efe1137e751d4 ] + +mark_inode_dirty will be called in notify_change(). +This patch remove unneeded mark_inode_dirty in set_info_sec(). + +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/smbacl.c | 1 - + 1 file changed, 1 deletion(-) + +--- a/fs/ksmbd/smbacl.c ++++ b/fs/ksmbd/smbacl.c +@@ -1441,7 +1441,6 @@ int set_info_sec(struct ksmbd_conn *conn + out: + posix_acl_release(fattr.cf_acls); + posix_acl_release(fattr.cf_dacls); +- mark_inode_dirty(inode); + return rc; + } + diff --git a/queue-5.15/ksmbd-remove-unused-compression-negotiate-ctx-packing.patch b/queue-5.15/ksmbd-remove-unused-compression-negotiate-ctx-packing.patch new file mode 100644 index 00000000000..55821b71de8 --- /dev/null +++ b/queue-5.15/ksmbd-remove-unused-compression-negotiate-ctx-packing.patch @@ -0,0 +1,79 @@ +From linkinjeon@gmail.com Mon Dec 18 16:39:55 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:33:45 +0900 +Subject: ksmbd: remove unused compression negotiate ctx packing +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, David Disseldorp , Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-86-linkinjeon@kernel.org> + +From: David Disseldorp + +[ Upstream commit af36c51e0e111de4e908328d49cba49de758f66e ] + +build_compression_ctxt() is currently unreachable due to +conn.compress_algorithm remaining zero (SMB3_COMPRESS_NONE). + +It appears to have been broken in a couple of subtle ways over the +years: +- prior to d6c9ad23b421 ("ksmbd: use the common definitions for + NEGOTIATE_PROTOCOL") smb2_compression_ctx.DataLength was set to 8, + which didn't account for the single CompressionAlgorithms flexible + array member. +- post d6c9ad23b421 smb2_compression_capabilities_context + CompressionAlgorithms is a three member array, while + CompressionAlgorithmCount is set to indicate only one member. + assemble_neg_contexts() ctxt_size is also incorrectly incremented by + sizeof(struct smb2_compression_capabilities_context) + 2, which + assumes one flexible array member. + +Signed-off-by: David Disseldorp +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/smb2pdu.c | 27 ++------------------------- + 1 file changed, 2 insertions(+), 25 deletions(-) + +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -787,19 +787,6 @@ static void build_encrypt_ctxt(struct sm + pneg_ctxt->Ciphers[0] = cipher_type; + } + +-static void build_compression_ctxt(struct smb2_compression_ctx *pneg_ctxt, +- __le16 comp_algo) +-{ +- pneg_ctxt->ContextType = SMB2_COMPRESSION_CAPABILITIES; +- pneg_ctxt->DataLength = +- cpu_to_le16(sizeof(struct smb2_compression_ctx) +- - sizeof(struct smb2_neg_context)); +- pneg_ctxt->Reserved = cpu_to_le32(0); +- pneg_ctxt->CompressionAlgorithmCount = cpu_to_le16(1); +- pneg_ctxt->Reserved1 = cpu_to_le32(0); +- pneg_ctxt->CompressionAlgorithms[0] = comp_algo; +-} +- + static void build_sign_cap_ctxt(struct smb2_signing_capabilities *pneg_ctxt, + __le16 sign_algo) + { +@@ -862,18 +849,8 @@ static void assemble_neg_contexts(struct + neg_ctxt_cnt++; + ctxt_size += sizeof(struct smb2_encryption_neg_context) + 2; + } +- +- if (conn->compress_algorithm) { +- ctxt_size = round_up(ctxt_size, 8); +- ksmbd_debug(SMB, +- "assemble SMB2_COMPRESSION_CAPABILITIES context\n"); +- /* Temporarily set to SMB3_COMPRESS_NONE */ +- build_compression_ctxt((struct smb2_compression_ctx *) +- (pneg_ctxt + ctxt_size), +- conn->compress_algorithm); +- neg_ctxt_cnt++; +- ctxt_size += sizeof(struct smb2_compression_ctx) + 2; +- } ++ /* compression context not yet supported */ ++ WARN_ON(conn->compress_algorithm != SMB3_COMPRESS_NONE); + + if (conn->posix_ext_supported) { + ctxt_size = round_up(ctxt_size, 8); diff --git a/queue-5.15/ksmbd-remove-unused-field-in-ksmbd_user-struct.patch b/queue-5.15/ksmbd-remove-unused-field-in-ksmbd_user-struct.patch new file mode 100644 index 00000000000..76f7b694215 --- /dev/null +++ b/queue-5.15/ksmbd-remove-unused-field-in-ksmbd_user-struct.patch @@ -0,0 +1,32 @@ +From linkinjeon@gmail.com Mon Dec 18 16:42:49 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:34:39 +0900 +Subject: ksmbd: Remove unused field in ksmbd_user struct +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Cheng-Han Wu , Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-140-linkinjeon@kernel.org> + +From: Cheng-Han Wu + +[ Upstream commit eacc655e18d1dec9b50660d16a1ddeeb4d6c48f2 ] + +fs/smb/server/mgmt/user_config.h:21: Remove the unused field 'failed_login_count' from the ksmbd_user struct. + +Signed-off-by: Cheng-Han Wu +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/mgmt/user_config.h | 1 - + 1 file changed, 1 deletion(-) + +--- a/fs/ksmbd/mgmt/user_config.h ++++ b/fs/ksmbd/mgmt/user_config.h +@@ -18,7 +18,6 @@ struct ksmbd_user { + + size_t passkey_sz; + char *passkey; +- unsigned int failed_login_count; + }; + + static inline bool user_guest(struct ksmbd_user *user) diff --git a/queue-5.15/ksmbd-remove-unused-fields-from-ksmbd_file-struct-definition.patch b/queue-5.15/ksmbd-remove-unused-fields-from-ksmbd_file-struct-definition.patch new file mode 100644 index 00000000000..ffde24d44ee --- /dev/null +++ b/queue-5.15/ksmbd-remove-unused-fields-from-ksmbd_file-struct-definition.patch @@ -0,0 +1,41 @@ +From stable+bounces-7639-greg=kroah.com@vger.kernel.org Mon Dec 18 16:36:10 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:32:30 +0900 +Subject: ksmbd: Remove unused fields from ksmbd_file struct definition +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Marios Makassikis , Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-11-linkinjeon@kernel.org> + +From: Marios Makassikis + +[ Upstream commit 305f8bda15ebbe4004681286a5c67d0dc296c771 ] + +These fields are remnants of the not upstreamed SMB1 code. + +Acked-by: Namjae Jeon +Signed-off-by: Marios Makassikis +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/vfs_cache.h | 10 ---------- + 1 file changed, 10 deletions(-) + +--- a/fs/ksmbd/vfs_cache.h ++++ b/fs/ksmbd/vfs_cache.h +@@ -96,16 +96,6 @@ struct ksmbd_file { + + int durable_timeout; + +- /* for SMB1 */ +- int pid; +- +- /* conflict lock fail count for SMB1 */ +- unsigned int cflock_cnt; +- /* last lock failure start offset for SMB1 */ +- unsigned long long llock_fstart; +- +- int dirent_offset; +- + /* if ls is happening on directory, below is valid*/ + struct ksmbd_readdir_data readdir_data; + int dot_dotdot[2]; diff --git a/queue-5.15/ksmbd-remove-unused-is_char_allowed-function.patch b/queue-5.15/ksmbd-remove-unused-is_char_allowed-function.patch new file mode 100644 index 00000000000..b5975de206e --- /dev/null +++ b/queue-5.15/ksmbd-remove-unused-is_char_allowed-function.patch @@ -0,0 +1,55 @@ +From linkinjeon@gmail.com Mon Dec 18 16:39:36 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:33:39 +0900 +Subject: ksmbd: remove unused is_char_allowed function +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Tom Rix , Sergey Senozhatsky , Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-80-linkinjeon@kernel.org> + +From: Tom Rix + +[ Upstream commit 2824861773eb512b37547516d81ef78108032cb2 ] + +clang with W=1 reports +fs/ksmbd/unicode.c:122:19: error: unused function + 'is_char_allowed' [-Werror,-Wunused-function] +static inline int is_char_allowed(char *ch) + ^ +This function is not used so remove it. + +Signed-off-by: Tom Rix +Reviewed-by: Sergey Senozhatsky +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/unicode.c | 18 ------------------ + 1 file changed, 18 deletions(-) + +--- a/fs/ksmbd/unicode.c ++++ b/fs/ksmbd/unicode.c +@@ -114,24 +114,6 @@ cp_convert: + } + + /* +- * is_char_allowed() - check for valid character +- * @ch: input character to be checked +- * +- * Return: 1 if char is allowed, otherwise 0 +- */ +-static inline int is_char_allowed(char *ch) +-{ +- /* check for control chars, wildcards etc. */ +- if (!(*ch & 0x80) && +- (*ch <= 0x1f || +- *ch == '?' || *ch == '"' || *ch == '<' || +- *ch == '>' || *ch == '|')) +- return 0; +- +- return 1; +-} +- +-/* + * smb_from_utf16() - convert utf16le string to local charset + * @to: destination buffer + * @from: source buffer diff --git a/queue-5.15/ksmbd-remove-unused-ksmbd_share_configs_cleanup-function.patch b/queue-5.15/ksmbd-remove-unused-ksmbd_share_configs_cleanup-function.patch new file mode 100644 index 00000000000..28b15d9779f --- /dev/null +++ b/queue-5.15/ksmbd-remove-unused-ksmbd_share_configs_cleanup-function.patch @@ -0,0 +1,51 @@ +From linkinjeon@gmail.com Mon Dec 18 16:37:45 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:33:04 +0900 +Subject: ksmbd: remove unused ksmbd_share_configs_cleanup function +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-45-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit 1c90b54718fdea4f89e7e0c2415803f33f6d0b00 ] + +remove unused ksmbd_share_configs_cleanup function. + +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/mgmt/share_config.c | 14 -------------- + fs/ksmbd/mgmt/share_config.h | 2 -- + 2 files changed, 16 deletions(-) + +--- a/fs/ksmbd/mgmt/share_config.c ++++ b/fs/ksmbd/mgmt/share_config.c +@@ -222,17 +222,3 @@ bool ksmbd_share_veto_filename(struct ks + } + return false; + } +- +-void ksmbd_share_configs_cleanup(void) +-{ +- struct ksmbd_share_config *share; +- struct hlist_node *tmp; +- int i; +- +- down_write(&shares_table_lock); +- hash_for_each_safe(shares_table, i, tmp, share, hlist) { +- hash_del(&share->hlist); +- kill_share(share); +- } +- up_write(&shares_table_lock); +-} +--- a/fs/ksmbd/mgmt/share_config.h ++++ b/fs/ksmbd/mgmt/share_config.h +@@ -76,6 +76,4 @@ static inline void ksmbd_share_config_pu + struct ksmbd_share_config *ksmbd_share_config_get(char *name); + bool ksmbd_share_veto_filename(struct ksmbd_share_config *share, + const char *filename); +-void ksmbd_share_configs_cleanup(void); +- + #endif /* __SHARE_CONFIG_MANAGEMENT_H__ */ diff --git a/queue-5.15/ksmbd-remove-unused-ksmbd_tree_conn_share-function.patch b/queue-5.15/ksmbd-remove-unused-ksmbd_tree_conn_share-function.patch new file mode 100644 index 00000000000..d772f748b9d --- /dev/null +++ b/queue-5.15/ksmbd-remove-unused-ksmbd_tree_conn_share-function.patch @@ -0,0 +1,55 @@ +From linkinjeon@gmail.com Mon Dec 18 16:40:55 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:34:04 +0900 +Subject: ksmbd: remove unused ksmbd_tree_conn_share function +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , Sergey Senozhatsky , Steve French +Message-ID: <20231218153454.8090-105-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit 7bd9f0876fdef00f4e155be35e6b304981a53f80 ] + +Remove unused ksmbd_tree_conn_share function. + +Signed-off-by: Namjae Jeon +Reviewed-by: Sergey Senozhatsky +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/mgmt/tree_connect.c | 11 ----------- + fs/ksmbd/mgmt/tree_connect.h | 3 --- + 2 files changed, 14 deletions(-) + +--- a/fs/ksmbd/mgmt/tree_connect.c ++++ b/fs/ksmbd/mgmt/tree_connect.c +@@ -120,17 +120,6 @@ struct ksmbd_tree_connect *ksmbd_tree_co + return tcon; + } + +-struct ksmbd_share_config *ksmbd_tree_conn_share(struct ksmbd_session *sess, +- unsigned int id) +-{ +- struct ksmbd_tree_connect *tc; +- +- tc = ksmbd_tree_conn_lookup(sess, id); +- if (tc) +- return tc->share_conf; +- return NULL; +-} +- + int ksmbd_tree_conn_session_logoff(struct ksmbd_session *sess) + { + int ret = 0; +--- a/fs/ksmbd/mgmt/tree_connect.h ++++ b/fs/ksmbd/mgmt/tree_connect.h +@@ -53,9 +53,6 @@ int ksmbd_tree_conn_disconnect(struct ks + struct ksmbd_tree_connect *ksmbd_tree_conn_lookup(struct ksmbd_session *sess, + unsigned int id); + +-struct ksmbd_share_config *ksmbd_tree_conn_share(struct ksmbd_session *sess, +- unsigned int id); +- + int ksmbd_tree_conn_session_logoff(struct ksmbd_session *sess); + + #endif /* __TREE_CONNECT_MANAGEMENT_H__ */ diff --git a/queue-5.15/ksmbd-remove-unused-parameter-from-smb2_get_name.patch b/queue-5.15/ksmbd-remove-unused-parameter-from-smb2_get_name.patch new file mode 100644 index 00000000000..3e83c04f6ac --- /dev/null +++ b/queue-5.15/ksmbd-remove-unused-parameter-from-smb2_get_name.patch @@ -0,0 +1,74 @@ +From stable+bounces-7638-greg=kroah.com@vger.kernel.org Mon Dec 18 16:36:08 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:32:29 +0900 +Subject: ksmbd: Remove unused parameter from smb2_get_name() +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Marios Makassikis , Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-10-linkinjeon@kernel.org> + +From: Marios Makassikis + +[ Upstream commit 80917f17e3f99027661a45262c310139e53a9faa ] + +The 'share' parameter is no longer used by smb2_get_name() since +commit 265fd1991c1d ("ksmbd: use LOOKUP_BENEATH to prevent the out of +share access"). + +Acked-by: Namjae Jeon +Signed-off-by: Marios Makassikis +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/smb2pdu.c | 13 ++++--------- + 1 file changed, 4 insertions(+), 9 deletions(-) + +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -651,7 +651,6 @@ static void destroy_previous_session(str + + /** + * smb2_get_name() - get filename string from on the wire smb format +- * @share: ksmbd_share_config pointer + * @src: source buffer + * @maxlen: maxlen of source string + * @nls_table: nls_table pointer +@@ -659,8 +658,7 @@ static void destroy_previous_session(str + * Return: matching converted filename on success, otherwise error ptr + */ + static char * +-smb2_get_name(struct ksmbd_share_config *share, const char *src, +- const int maxlen, struct nls_table *local_nls) ++smb2_get_name(const char *src, const int maxlen, struct nls_table *local_nls) + { + char *name; + +@@ -2604,8 +2602,7 @@ int smb2_open(struct ksmbd_work *work) + goto err_out1; + } + +- name = smb2_get_name(share, +- req->Buffer, ++ name = smb2_get_name(req->Buffer, + le16_to_cpu(req->NameLength), + work->conn->local_nls); + if (IS_ERR(name)) { +@@ -5481,8 +5478,7 @@ static int smb2_rename(struct ksmbd_work + goto out; + } + +- new_name = smb2_get_name(share, +- file_info->FileName, ++ new_name = smb2_get_name(file_info->FileName, + le32_to_cpu(file_info->FileNameLength), + local_nls); + if (IS_ERR(new_name)) { +@@ -5593,8 +5589,7 @@ static int smb2_create_link(struct ksmbd + if (!pathname) + return -ENOMEM; + +- link_name = smb2_get_name(share, +- file_info->FileName, ++ link_name = smb2_get_name(file_info->FileName, + le32_to_cpu(file_info->FileNameLength), + local_nls); + if (IS_ERR(link_name) || S_ISDIR(file_inode(filp)->i_mode)) { diff --git a/queue-5.15/ksmbd-reorganize-ksmbd_iov_pin_rsp.patch b/queue-5.15/ksmbd-reorganize-ksmbd_iov_pin_rsp.patch new file mode 100644 index 00000000000..efcf37b7549 --- /dev/null +++ b/queue-5.15/ksmbd-reorganize-ksmbd_iov_pin_rsp.patch @@ -0,0 +1,97 @@ +From linkinjeon@gmail.com Mon Dec 18 16:42:52 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:34:40 +0900 +Subject: ksmbd: reorganize ksmbd_iov_pin_rsp() +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-141-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit 1819a904299942b309f687cc0f08b123500aa178 ] + +If ksmbd_iov_pin_rsp fail, io vertor should be rollback. +This patch moves memory allocations to before setting the io vector +to avoid rollbacks. + +Fixes: e2b76ab8b5c9 ("ksmbd: add support for read compound") +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/ksmbd_work.c | 43 ++++++++++++++++++++++--------------------- + 1 file changed, 22 insertions(+), 21 deletions(-) + +--- a/fs/ksmbd/ksmbd_work.c ++++ b/fs/ksmbd/ksmbd_work.c +@@ -95,11 +95,28 @@ bool ksmbd_queue_work(struct ksmbd_work + return queue_work(ksmbd_wq, &work->work); + } + +-static int ksmbd_realloc_iov_pin(struct ksmbd_work *work, void *ib, +- unsigned int ib_len) ++static inline void __ksmbd_iov_pin(struct ksmbd_work *work, void *ib, ++ unsigned int ib_len) + { ++ work->iov[++work->iov_idx].iov_base = ib; ++ work->iov[work->iov_idx].iov_len = ib_len; ++ work->iov_cnt++; ++} ++ ++static int __ksmbd_iov_pin_rsp(struct ksmbd_work *work, void *ib, int len, ++ void *aux_buf, unsigned int aux_size) ++{ ++ struct aux_read *ar; ++ int need_iov_cnt = 1; ++ ++ if (aux_size) { ++ need_iov_cnt++; ++ ar = kmalloc(sizeof(struct aux_read), GFP_KERNEL); ++ if (!ar) ++ return -ENOMEM; ++ } + +- if (work->iov_alloc_cnt <= work->iov_cnt) { ++ if (work->iov_alloc_cnt < work->iov_cnt + need_iov_cnt) { + struct kvec *new; + + work->iov_alloc_cnt += 4; +@@ -111,16 +128,6 @@ static int ksmbd_realloc_iov_pin(struct + work->iov = new; + } + +- work->iov[++work->iov_idx].iov_base = ib; +- work->iov[work->iov_idx].iov_len = ib_len; +- work->iov_cnt++; +- +- return 0; +-} +- +-static int __ksmbd_iov_pin_rsp(struct ksmbd_work *work, void *ib, int len, +- void *aux_buf, unsigned int aux_size) +-{ + /* Plus rfc_length size on first iov */ + if (!work->iov_idx) { + work->iov[work->iov_idx].iov_base = work->response_buf; +@@ -129,19 +136,13 @@ static int __ksmbd_iov_pin_rsp(struct ks + work->iov_cnt++; + } + +- ksmbd_realloc_iov_pin(work, ib, len); ++ __ksmbd_iov_pin(work, ib, len); + inc_rfc1001_len(work->iov[0].iov_base, len); + + if (aux_size) { +- struct aux_read *ar; +- +- ksmbd_realloc_iov_pin(work, aux_buf, aux_size); ++ __ksmbd_iov_pin(work, aux_buf, aux_size); + inc_rfc1001_len(work->iov[0].iov_base, aux_size); + +- ar = kmalloc(sizeof(struct aux_read), GFP_KERNEL); +- if (!ar) +- return -ENOMEM; +- + ar->buf = aux_buf; + list_add(&ar->entry, &work->aux_read_list); + } diff --git a/queue-5.15/ksmbd-replace-one-element-array-with-flexible-array-member.patch b/queue-5.15/ksmbd-replace-one-element-array-with-flexible-array-member.patch new file mode 100644 index 00000000000..2904839bdbf --- /dev/null +++ b/queue-5.15/ksmbd-replace-one-element-array-with-flexible-array-member.patch @@ -0,0 +1,41 @@ +From linkinjeon@gmail.com Mon Dec 18 16:41:26 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:34:13 +0900 +Subject: ksmbd: Replace one-element array with flexible-array member +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, "Gustavo A. R. Silva" , Kees Cook , Namjae Jeon , Sergey Senozhatsky , Steve French +Message-ID: <20231218153454.8090-114-linkinjeon@kernel.org> + +From: "Gustavo A. R. Silva" + +[ Upstream commit 11d5e2061e973a8d4ff2b95a114b4b8ef8652633 ] + +One-element arrays are deprecated, and we are replacing them with flexible +array members instead. So, replace one-element array with flexible-array +member in struct smb_negotiate_req. + +This results in no differences in binary output. + +Link: https://github.com/KSPP/linux/issues/79 +Link: https://github.com/KSPP/linux/issues/317 +Signed-off-by: Gustavo A. R. Silva +Reviewed-by: Kees Cook +Acked-by: Namjae Jeon +Reviewed-by: Sergey Senozhatsky +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/smb_common.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/fs/ksmbd/smb_common.h ++++ b/fs/ksmbd/smb_common.h +@@ -247,7 +247,7 @@ struct smb_hdr { + struct smb_negotiate_req { + struct smb_hdr hdr; /* wct = 0 */ + __le16 ByteCount; +- unsigned char DialectsArray[1]; ++ unsigned char DialectsArray[]; + } __packed; + + struct smb_negotiate_rsp { diff --git a/queue-5.15/ksmbd-replace-one-element-arrays-with-flexible-array-members.patch b/queue-5.15/ksmbd-replace-one-element-arrays-with-flexible-array-members.patch new file mode 100644 index 00000000000..d693f0cd5c6 --- /dev/null +++ b/queue-5.15/ksmbd-replace-one-element-arrays-with-flexible-array-members.patch @@ -0,0 +1,126 @@ +From linkinjeon@gmail.com Mon Dec 18 16:38:49 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:33:24 +0900 +Subject: ksmbd: replace one-element arrays with flexible-array members +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, "Gustavo A. R. Silva" , Sergey Senozhatsky , Namjae Jeon , Kees Cook +Message-ID: <20231218153454.8090-65-linkinjeon@kernel.org> + +From: "Gustavo A. R. Silva" + +[ Upstream commit d272e01fa0a2f15c5c331a37cd99c6875c7b7186 ] + +One-element arrays are deprecated, and we are replacing them with flexible +array members instead. So, replace one-element arrays with flexible-array +members in multiple structs in fs/ksmbd/smb_common.h and one in +fs/ksmbd/smb2pdu.h. + +Important to mention is that doing a build before/after this patch results +in no binary output differences. + +This helps with the ongoing efforts to tighten the FORTIFY_SOURCE routines +on memcpy() and help us make progress towards globally enabling +-fstrict-flex-arrays=3 [1]. + +Link: https://github.com/KSPP/linux/issues/242 +Link: https://github.com/KSPP/linux/issues/79 +Link: https://gcc.gnu.org/pipermail/gcc-patches/2022-October/602902.html [1] +Signed-off-by: Gustavo A. R. Silva +Reviewed-by: Sergey Senozhatsky +Acked-by: Namjae Jeon +Reviewed-by: Kees Cook +Signed-off-by: Kees Cook +Link: https://lore.kernel.org/r/Y3OxronfaPYv9qGP@work +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/smb2pdu.c | 4 ++-- + fs/ksmbd/smb2pdu.h | 2 +- + fs/ksmbd/smb_common.h | 12 ++++++------ + 3 files changed, 9 insertions(+), 9 deletions(-) + +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -3486,7 +3486,7 @@ static int smb2_populate_readdir_entry(s + goto free_conv_name; + } + +- struct_sz = readdir_info_level_struct_sz(info_level) - 1 + conv_len; ++ struct_sz = readdir_info_level_struct_sz(info_level) + conv_len; + next_entry_offset = ALIGN(struct_sz, KSMBD_DIR_INFO_ALIGNMENT); + d_info->last_entry_off_align = next_entry_offset - struct_sz; + +@@ -3737,7 +3737,7 @@ static int reserve_populate_dentry(struc + return -EOPNOTSUPP; + + conv_len = (d_info->name_len + 1) * 2; +- next_entry_offset = ALIGN(struct_sz - 1 + conv_len, ++ next_entry_offset = ALIGN(struct_sz + conv_len, + KSMBD_DIR_INFO_ALIGNMENT); + + if (next_entry_offset > d_info->out_buf_len) { +--- a/fs/ksmbd/smb2pdu.h ++++ b/fs/ksmbd/smb2pdu.h +@@ -1621,7 +1621,7 @@ struct smb2_posix_info { + /* SidBuffer contain two sids (UNIX user sid(16), UNIX group sid(16)) */ + u8 SidBuffer[32]; + __le32 name_len; +- u8 name[1]; ++ u8 name[]; + /* + * var sized owner SID + * var sized group SID +--- a/fs/ksmbd/smb_common.h ++++ b/fs/ksmbd/smb_common.h +@@ -310,14 +310,14 @@ struct file_directory_info { + __le64 AllocationSize; + __le32 ExtFileAttributes; + __le32 FileNameLength; +- char FileName[1]; ++ char FileName[]; + } __packed; /* level 0x101 FF resp data */ + + struct file_names_info { + __le32 NextEntryOffset; + __u32 FileIndex; + __le32 FileNameLength; +- char FileName[1]; ++ char FileName[]; + } __packed; /* level 0xc FF resp data */ + + struct file_full_directory_info { +@@ -332,7 +332,7 @@ struct file_full_directory_info { + __le32 ExtFileAttributes; + __le32 FileNameLength; + __le32 EaSize; +- char FileName[1]; ++ char FileName[]; + } __packed; /* level 0x102 FF resp */ + + struct file_both_directory_info { +@@ -350,7 +350,7 @@ struct file_both_directory_info { + __u8 ShortNameLength; + __u8 Reserved; + __u8 ShortName[24]; +- char FileName[1]; ++ char FileName[]; + } __packed; /* level 0x104 FFrsp data */ + + struct file_id_both_directory_info { +@@ -370,7 +370,7 @@ struct file_id_both_directory_info { + __u8 ShortName[24]; + __le16 Reserved2; + __le64 UniqueId; +- char FileName[1]; ++ char FileName[]; + } __packed; + + struct file_id_full_dir_info { +@@ -387,7 +387,7 @@ struct file_id_full_dir_info { + __le32 EaSize; /* EA size */ + __le32 Reserved; + __le64 UniqueId; /* inode num - le since Samba puts ino in low 32 bit*/ +- char FileName[1]; ++ char FileName[]; + } __packed; /* level 0x105 FF rsp data */ + + struct smb_version_values { diff --git a/queue-5.15/ksmbd-replace-the-ternary-conditional-operator-with-min.patch b/queue-5.15/ksmbd-replace-the-ternary-conditional-operator-with-min.patch new file mode 100644 index 00000000000..6f2f3baec15 --- /dev/null +++ b/queue-5.15/ksmbd-replace-the-ternary-conditional-operator-with-min.patch @@ -0,0 +1,34 @@ +From linkinjeon@gmail.com Mon Dec 18 16:41:11 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:34:09 +0900 +Subject: ksmbd: Replace the ternary conditional operator with min() +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Lu Hongfei , Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-110-linkinjeon@kernel.org> + +From: Lu Hongfei + +[ Upstream commit f65fadb0422537d73f9a6472861852dc2f7a6a5b ] + +It would be better to replace the traditional ternary conditional +operator with min() in compare_sids. + +Signed-off-by: Lu Hongfei +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/smbacl.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/fs/ksmbd/smbacl.c ++++ b/fs/ksmbd/smbacl.c +@@ -97,7 +97,7 @@ int compare_sids(const struct smb_sid *c + /* compare all of the subauth values if any */ + num_sat = ctsid->num_subauth; + num_saw = cwsid->num_subauth; +- num_subauth = num_sat < num_saw ? num_sat : num_saw; ++ num_subauth = min(num_sat, num_saw); + if (num_subauth) { + for (i = 0; i < num_subauth; ++i) { + if (ctsid->sub_auth[i] != cwsid->sub_auth[i]) { diff --git a/queue-5.15/ksmbd-replace-usage-of-found-with-dedicated-list-iterator-variable.patch b/queue-5.15/ksmbd-replace-usage-of-found-with-dedicated-list-iterator-variable.patch new file mode 100644 index 00000000000..a6f8fdbfefb --- /dev/null +++ b/queue-5.15/ksmbd-replace-usage-of-found-with-dedicated-list-iterator-variable.patch @@ -0,0 +1,99 @@ +From linkinjeon@gmail.com Mon Dec 18 16:36:57 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:32:49 +0900 +Subject: ksmbd: replace usage of found with dedicated list iterator variable +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Jakob Koschel , Hyunchul Lee , Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-30-linkinjeon@kernel.org> + +From: Jakob Koschel + +[ Upstream commit edf5f0548fbb77e20b898460dc25281b0f4d974d ] + +To move the list iterator variable into the list_for_each_entry_*() +macro in the future it should be avoided to use the list iterator +variable after the loop body. + +To *never* use the list iterator variable after the loop it was +concluded to use a separate iterator variable instead of a +found boolean [1]. + +This removes the need to use a found variable and simply checking if +the variable was set, can determine if the break/goto was hit. + +Link: https://lore.kernel.org/all/CAHk-=wgRr_D8CB-D9Kg-c=EHreAsk5SqXPwr9Y7k9sA6cWXJ6w@mail.gmail.com/ +Signed-off-by: Jakob Koschel +Reviewed-by: Hyunchul Lee +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/smb2pdu.c | 21 ++++++++++----------- + 1 file changed, 10 insertions(+), 11 deletions(-) + +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -6691,8 +6691,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; +- int canceled = 0; ++ struct ksmbd_work *cancel_work = NULL, *iter; + struct list_head *command_list; + + ksmbd_debug(SMB, "smb2 cancel called on mid %llu, async flags 0x%x\n", +@@ -6702,11 +6701,11 @@ int smb2_cancel(struct ksmbd_work *work) + command_list = &conn->async_requests; + + spin_lock(&conn->request_lock); +- list_for_each_entry(cancel_work, command_list, ++ list_for_each_entry(iter, command_list, + async_request_entry) { +- chdr = smb2_get_msg(cancel_work->request_buf); ++ chdr = smb2_get_msg(iter->request_buf); + +- if (cancel_work->async_id != ++ if (iter->async_id != + le64_to_cpu(hdr->Id.AsyncId)) + continue; + +@@ -6714,7 +6713,7 @@ 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)); +- canceled = 1; ++ cancel_work = iter; + break; + } + spin_unlock(&conn->request_lock); +@@ -6722,24 +6721,24 @@ int smb2_cancel(struct ksmbd_work *work) + command_list = &conn->requests; + + spin_lock(&conn->request_lock); +- list_for_each_entry(cancel_work, command_list, request_entry) { +- chdr = smb2_get_msg(cancel_work->request_buf); ++ list_for_each_entry(iter, command_list, request_entry) { ++ chdr = smb2_get_msg(iter->request_buf); + + if (chdr->MessageId != hdr->MessageId || +- cancel_work == work) ++ iter == work) + continue; + + ksmbd_debug(SMB, + "smb2 with mid %llu cancelled command = 0x%x\n", + le64_to_cpu(hdr->MessageId), + le16_to_cpu(chdr->Command)); +- canceled = 1; ++ cancel_work = iter; + break; + } + spin_unlock(&conn->request_lock); + } + +- if (canceled) { ++ if (cancel_work) { + cancel_work->state = KSMBD_WORK_CANCELLED; + if (cancel_work->cancel_fn) + cancel_work->cancel_fn(cancel_work->cancel_argv); diff --git a/queue-5.15/ksmbd-request-update-to-stale-share-config.patch b/queue-5.15/ksmbd-request-update-to-stale-share-config.patch new file mode 100644 index 00000000000..97e95c31764 --- /dev/null +++ b/queue-5.15/ksmbd-request-update-to-stale-share-config.patch @@ -0,0 +1,115 @@ +From linkinjeon@gmail.com Mon Dec 18 16:37:53 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:33:06 +0900 +Subject: ksmbd: request update to stale share config +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, "Atte Heikkilä" , "Namjae Jeon" , "Steve French" +Message-ID: <20231218153454.8090-47-linkinjeon@kernel.org> + +From: Atte Heikkilä + +[ Upstream commit 4963d74f8a6cc0eafd71d9ffc13e3a11ff1dd160 ] + +ksmbd_share_config_get() retrieves the cached share config as long +as there is at least one connection to the share. This is an issue when +the user space utilities are used to update share configs. In that case +there is a need to inform ksmbd that it should not use the cached share +config for a new connection to the share. With these changes the tree +connection flag KSMBD_TREE_CONN_FLAG_UPDATE indicates this. When this +flag is set, ksmbd removes the share config from the shares hash table +meaning that ksmbd_share_config_get() ends up requesting a share config +from user space. + +Signed-off-by: Atte Heikkilä +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/ksmbd_netlink.h | 2 ++ + fs/ksmbd/mgmt/share_config.c | 6 +++++- + fs/ksmbd/mgmt/share_config.h | 1 + + fs/ksmbd/mgmt/tree_connect.c | 14 ++++++++++++++ + fs/ksmbd/smb2pdu.c | 1 + + 5 files changed, 23 insertions(+), 1 deletion(-) + +--- a/fs/ksmbd/ksmbd_netlink.h ++++ b/fs/ksmbd/ksmbd_netlink.h +@@ -350,6 +350,7 @@ enum KSMBD_TREE_CONN_STATUS { + #define KSMBD_SHARE_FLAG_STREAMS BIT(11) + #define KSMBD_SHARE_FLAG_FOLLOW_SYMLINKS BIT(12) + #define KSMBD_SHARE_FLAG_ACL_XATTR BIT(13) ++#define KSMBD_SHARE_FLAG_UPDATE BIT(14) + + /* + * Tree connect request flags. +@@ -365,6 +366,7 @@ enum KSMBD_TREE_CONN_STATUS { + #define KSMBD_TREE_CONN_FLAG_READ_ONLY BIT(1) + #define KSMBD_TREE_CONN_FLAG_WRITABLE BIT(2) + #define KSMBD_TREE_CONN_FLAG_ADMIN_ACCOUNT BIT(3) ++#define KSMBD_TREE_CONN_FLAG_UPDATE BIT(4) + + /* + * RPC over IPC. +--- a/fs/ksmbd/mgmt/share_config.c ++++ b/fs/ksmbd/mgmt/share_config.c +@@ -51,12 +51,16 @@ static void kill_share(struct ksmbd_shar + kfree(share); + } + +-void __ksmbd_share_config_put(struct ksmbd_share_config *share) ++void ksmbd_share_config_del(struct ksmbd_share_config *share) + { + down_write(&shares_table_lock); + hash_del(&share->hlist); + up_write(&shares_table_lock); ++} + ++void __ksmbd_share_config_put(struct ksmbd_share_config *share) ++{ ++ ksmbd_share_config_del(share); + kill_share(share); + } + +--- a/fs/ksmbd/mgmt/share_config.h ++++ b/fs/ksmbd/mgmt/share_config.h +@@ -64,6 +64,7 @@ static inline int test_share_config_flag + return share->flags & flag; + } + ++void ksmbd_share_config_del(struct ksmbd_share_config *share); + void __ksmbd_share_config_put(struct ksmbd_share_config *share); + + static inline void ksmbd_share_config_put(struct ksmbd_share_config *share) +--- a/fs/ksmbd/mgmt/tree_connect.c ++++ b/fs/ksmbd/mgmt/tree_connect.c +@@ -57,6 +57,20 @@ ksmbd_tree_conn_connect(struct ksmbd_con + goto out_error; + + tree_conn->flags = resp->connection_flags; ++ if (test_tree_conn_flag(tree_conn, KSMBD_TREE_CONN_FLAG_UPDATE)) { ++ struct ksmbd_share_config *new_sc; ++ ++ ksmbd_share_config_del(sc); ++ new_sc = ksmbd_share_config_get(share_name); ++ if (!new_sc) { ++ pr_err("Failed to update stale share config\n"); ++ status.ret = -ESTALE; ++ goto out_error; ++ } ++ ksmbd_share_config_put(sc); ++ sc = new_sc; ++ } ++ + tree_conn->user = sess->user; + tree_conn->share_conf = sc; + status.tree_conn = tree_conn; +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -1985,6 +1985,7 @@ out_err1: + rsp->hdr.Status = STATUS_SUCCESS; + rc = 0; + break; ++ case -ESTALE: + case -ENOENT: + case KSMBD_TREE_CONN_STATUS_NO_SHARE: + rsp->hdr.Status = STATUS_BAD_NETWORK_NAME; diff --git a/queue-5.15/ksmbd-return-a-literal-instead-of-err-in-ksmbd_vfs_kern_path_locked.patch b/queue-5.15/ksmbd-return-a-literal-instead-of-err-in-ksmbd_vfs_kern_path_locked.patch new file mode 100644 index 00000000000..2e95603af37 --- /dev/null +++ b/queue-5.15/ksmbd-return-a-literal-instead-of-err-in-ksmbd_vfs_kern_path_locked.patch @@ -0,0 +1,33 @@ +From linkinjeon@gmail.com Mon Dec 18 16:41:02 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:34:06 +0900 +Subject: ksmbd: return a literal instead of 'err' in ksmbd_vfs_kern_path_locked() +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , Dan Carpenter , Steve French +Message-ID: <20231218153454.8090-107-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit cf5e7f734f445588a30350591360bca2f6bf016f ] + +Return a literal instead of 'err' in ksmbd_vfs_kern_path_locked(). + +Reported-by: Dan Carpenter +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/vfs.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/fs/ksmbd/vfs.c ++++ b/fs/ksmbd/vfs.c +@@ -1209,7 +1209,7 @@ int ksmbd_vfs_kern_path_locked(struct ks + + err = ksmbd_vfs_path_lookup_locked(share_conf, name, flags, path); + if (!err) +- return err; ++ return 0; + + if (caseless) { + char *filepath; diff --git a/queue-5.15/ksmbd-return-invalid-parameter-error-response-if-smb2-request-is-invalid.patch b/queue-5.15/ksmbd-return-invalid-parameter-error-response-if-smb2-request-is-invalid.patch new file mode 100644 index 00000000000..fcfa3b2e72a --- /dev/null +++ b/queue-5.15/ksmbd-return-invalid-parameter-error-response-if-smb2-request-is-invalid.patch @@ -0,0 +1,98 @@ +From linkinjeon@gmail.com Mon Dec 18 16:42:17 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:34:29 +0900 +Subject: ksmbd: return invalid parameter error response if smb2 request is invalid +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , Tom Talpey , Steve French +Message-ID: <20231218153454.8090-130-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit f2f11fca5d7112e2f91c4854cddd68a059fdaa4a ] + +If smb2 request from client is invalid, The following kernel oops could +happen. The patch e2b76ab8b5c9: "ksmbd: add support for read compound" +leads this issue. When request is invalid, It doesn't set anything in +the response buffer. This patch add missing set invalid parameter error +response. + +[ 673.085542] ksmbd: cli req too short, len 184 not 142. cmd:5 mid:109 +[ 673.085580] BUG: kernel NULL pointer dereference, address: 0000000000000000 +[ 673.085591] #PF: supervisor read access in kernel mode +[ 673.085600] #PF: error_code(0x0000) - not-present page +[ 673.085608] PGD 0 P4D 0 +[ 673.085620] Oops: 0000 [#1] PREEMPT SMP NOPTI +[ 673.085631] CPU: 3 PID: 1039 Comm: kworker/3:0 Not tainted 6.6.0-rc2-tmt #16 +[ 673.085643] Hardware name: AZW U59/U59, BIOS JTKT001 05/05/2022 +[ 673.085651] Workqueue: ksmbd-io handle_ksmbd_work [ksmbd] +[ 673.085719] RIP: 0010:ksmbd_conn_write+0x68/0xc0 [ksmbd] +[ 673.085808] RAX: 0000000000000000 RBX: ffff88811ade4f00 RCX: 0000000000000000 +[ 673.085817] RDX: 0000000000000000 RSI: ffff88810c2a9780 RDI: ffff88810c2a9ac0 +[ 673.085826] RBP: ffffc900005e3e00 R08: 0000000000000000 R09: 0000000000000000 +[ 673.085834] R10: ffffffffa3168160 R11: 63203a64626d736b R12: ffff8881057c8800 +[ 673.085842] R13: ffff8881057c8820 R14: ffff8882781b2380 R15: ffff8881057c8800 +[ 673.085852] FS: 0000000000000000(0000) GS:ffff888278180000(0000) knlGS:0000000000000000 +[ 673.085864] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +[ 673.085872] CR2: 0000000000000000 CR3: 000000015b63c000 CR4: 0000000000350ee0 +[ 673.085883] Call Trace: +[ 673.085890] +[ 673.085900] ? show_regs+0x6a/0x80 +[ 673.085916] ? __die+0x25/0x70 +[ 673.085926] ? page_fault_oops+0x154/0x4b0 +[ 673.085938] ? tick_nohz_tick_stopped+0x18/0x50 +[ 673.085954] ? __irq_work_queue_local+0xba/0x140 +[ 673.085967] ? do_user_addr_fault+0x30f/0x6c0 +[ 673.085979] ? exc_page_fault+0x79/0x180 +[ 673.085992] ? asm_exc_page_fault+0x27/0x30 +[ 673.086009] ? ksmbd_conn_write+0x68/0xc0 [ksmbd] +[ 673.086067] ? ksmbd_conn_write+0x46/0xc0 [ksmbd] +[ 673.086123] handle_ksmbd_work+0x28d/0x4b0 [ksmbd] +[ 673.086177] process_one_work+0x178/0x350 +[ 673.086193] ? __pfx_worker_thread+0x10/0x10 +[ 673.086202] worker_thread+0x2f3/0x420 +[ 673.086210] ? _raw_spin_unlock_irqrestore+0x27/0x50 +[ 673.086222] ? __pfx_worker_thread+0x10/0x10 +[ 673.086230] kthread+0x103/0x140 +[ 673.086242] ? __pfx_kthread+0x10/0x10 +[ 673.086253] ret_from_fork+0x39/0x60 +[ 673.086263] ? __pfx_kthread+0x10/0x10 +[ 673.086274] ret_from_fork_asm+0x1b/0x30 + +Fixes: e2b76ab8b5c9 ("ksmbd: add support for read compound") +Reported-by: Tom Talpey +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/server.c | 4 +++- + fs/ksmbd/smb2misc.c | 4 +--- + 2 files changed, 4 insertions(+), 4 deletions(-) + +--- a/fs/ksmbd/server.c ++++ b/fs/ksmbd/server.c +@@ -115,8 +115,10 @@ static int __process_request(struct ksmb + if (check_conn_state(work)) + return SERVER_HANDLER_CONTINUE; + +- if (ksmbd_verify_smb_message(work)) ++ if (ksmbd_verify_smb_message(work)) { ++ conn->ops->set_rsp_status(work, STATUS_INVALID_PARAMETER); + return SERVER_HANDLER_ABORT; ++ } + + command = conn->ops->get_cmd_val(work); + *cmd = command; +--- a/fs/ksmbd/smb2misc.c ++++ b/fs/ksmbd/smb2misc.c +@@ -441,10 +441,8 @@ int ksmbd_smb2_check_message(struct ksmb + + validate_credit: + if ((work->conn->vals->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU) && +- smb2_validate_credit_charge(work->conn, hdr)) { +- work->conn->ops->set_rsp_status(work, STATUS_INVALID_PARAMETER); ++ smb2_validate_credit_charge(work->conn, hdr)) + return 1; +- } + + return 0; + } diff --git a/queue-5.15/ksmbd-send-proper-error-response-in-smb2_tree_connect.patch b/queue-5.15/ksmbd-send-proper-error-response-in-smb2_tree_connect.patch new file mode 100644 index 00000000000..a88186f892d --- /dev/null +++ b/queue-5.15/ksmbd-send-proper-error-response-in-smb2_tree_connect.patch @@ -0,0 +1,56 @@ +From linkinjeon@gmail.com Mon Dec 18 16:39:05 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:33:29 +0900 +Subject: ksmbd: send proper error response in smb2_tree_connect() +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Marios Makassikis , Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-70-linkinjeon@kernel.org> + +From: Marios Makassikis + +[ Upstream commit cdfb2fef522d0c3f9cf293db51de88e9b3d46846 ] + +Currently, smb2_tree_connect doesn't send an error response packet on +error. + +This causes libsmb2 to skip the specific error code and fail with the +following: + smb2_service failed with : Failed to parse fixed part of command + payload. Unexpected size of Error reply. Expected 9, got 8 + +Signed-off-by: Marios Makassikis +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/smb2pdu.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -1969,13 +1969,13 @@ int smb2_tree_connect(struct ksmbd_work + if (conn->posix_ext_supported) + status.tree_conn->posix_extensions = true; + +-out_err1: + rsp->StructureSize = cpu_to_le16(16); ++ inc_rfc1001_len(work->response_buf, 16); ++out_err1: + rsp->Capabilities = 0; + rsp->Reserved = 0; + /* default manual caching */ + rsp->ShareFlags = SMB2_SHAREFLAG_MANUAL_CACHING; +- inc_rfc1001_len(work->response_buf, 16); + + if (!IS_ERR(treename)) + kfree(treename); +@@ -2008,6 +2008,9 @@ out_err1: + rsp->hdr.Status = STATUS_ACCESS_DENIED; + } + ++ if (status.ret != KSMBD_TREE_CONN_STATUS_OK) ++ smb2_set_err_rsp(work); ++ + return rc; + } + diff --git a/queue-5.15/ksmbd-separately-allocate-ci-per-dentry.patch b/queue-5.15/ksmbd-separately-allocate-ci-per-dentry.patch new file mode 100644 index 00000000000..236b74247f4 --- /dev/null +++ b/queue-5.15/ksmbd-separately-allocate-ci-per-dentry.patch @@ -0,0 +1,173 @@ +From linkinjeon@gmail.com Mon Dec 18 16:43:28 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:34:50 +0900 +Subject: ksmbd: separately allocate ci per dentry +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-151-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit 4274a9dc6aeb9fea66bffba15697a35ae8983b6a ] + +xfstests generic/002 test fail when enabling smb2 leases feature. +This test create hard link file, but removeal failed. +ci has a file open count to count file open through the smb client, +but in the case of hard link files, The allocation of ci per inode +cause incorrectly open count for file deletion. This patch allocate +ci per dentry to counts open counts for hard link. + +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/smb2pdu.c | 2 +- + fs/ksmbd/vfs.c | 2 +- + fs/ksmbd/vfs_cache.c | 33 +++++++++++++-------------------- + fs/ksmbd/vfs_cache.h | 6 +++--- + 4 files changed, 18 insertions(+), 25 deletions(-) + +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -3036,7 +3036,7 @@ int smb2_open(struct ksmbd_work *work) + } + } + +- rc = ksmbd_query_inode_status(d_inode(path.dentry->d_parent)); ++ rc = ksmbd_query_inode_status(path.dentry->d_parent); + if (rc == KSMBD_INODE_STATUS_PENDING_DELETE) { + rc = -EBUSY; + goto err_out; +--- a/fs/ksmbd/vfs.c ++++ b/fs/ksmbd/vfs.c +@@ -719,7 +719,7 @@ retry: + goto out3; + } + +- parent_fp = ksmbd_lookup_fd_inode(d_inode(old_child->d_parent)); ++ parent_fp = ksmbd_lookup_fd_inode(old_child->d_parent); + if (parent_fp) { + if (parent_fp->daccess & FILE_DELETE_LE) { + pr_err("parent dir is opened with delete access\n"); +--- a/fs/ksmbd/vfs_cache.c ++++ b/fs/ksmbd/vfs_cache.c +@@ -65,14 +65,14 @@ static unsigned long inode_hash(struct s + return tmp & inode_hash_mask; + } + +-static struct ksmbd_inode *__ksmbd_inode_lookup(struct inode *inode) ++static struct ksmbd_inode *__ksmbd_inode_lookup(struct dentry *de) + { + struct hlist_head *head = inode_hashtable + +- inode_hash(inode->i_sb, inode->i_ino); ++ inode_hash(d_inode(de)->i_sb, (unsigned long)de); + struct ksmbd_inode *ci = NULL, *ret_ci = NULL; + + hlist_for_each_entry(ci, head, m_hash) { +- if (ci->m_inode == inode) { ++ if (ci->m_de == de) { + if (atomic_inc_not_zero(&ci->m_count)) + ret_ci = ci; + break; +@@ -83,26 +83,16 @@ static struct ksmbd_inode *__ksmbd_inode + + static struct ksmbd_inode *ksmbd_inode_lookup(struct ksmbd_file *fp) + { +- return __ksmbd_inode_lookup(file_inode(fp->filp)); ++ return __ksmbd_inode_lookup(fp->filp->f_path.dentry); + } + +-static struct ksmbd_inode *ksmbd_inode_lookup_by_vfsinode(struct inode *inode) +-{ +- struct ksmbd_inode *ci; +- +- read_lock(&inode_hash_lock); +- ci = __ksmbd_inode_lookup(inode); +- read_unlock(&inode_hash_lock); +- return ci; +-} +- +-int ksmbd_query_inode_status(struct inode *inode) ++int ksmbd_query_inode_status(struct dentry *dentry) + { + struct ksmbd_inode *ci; + int ret = KSMBD_INODE_STATUS_UNKNOWN; + + read_lock(&inode_hash_lock); +- ci = __ksmbd_inode_lookup(inode); ++ ci = __ksmbd_inode_lookup(dentry); + if (ci) { + ret = KSMBD_INODE_STATUS_OK; + if (ci->m_flags & (S_DEL_PENDING | S_DEL_ON_CLS)) +@@ -142,7 +132,7 @@ void ksmbd_fd_set_delete_on_close(struct + static void ksmbd_inode_hash(struct ksmbd_inode *ci) + { + struct hlist_head *b = inode_hashtable + +- inode_hash(ci->m_inode->i_sb, ci->m_inode->i_ino); ++ inode_hash(d_inode(ci->m_de)->i_sb, (unsigned long)ci->m_de); + + hlist_add_head(&ci->m_hash, b); + } +@@ -156,7 +146,6 @@ static void ksmbd_inode_unhash(struct ks + + static int ksmbd_inode_init(struct ksmbd_inode *ci, struct ksmbd_file *fp) + { +- ci->m_inode = file_inode(fp->filp); + atomic_set(&ci->m_count, 1); + atomic_set(&ci->op_count, 0); + atomic_set(&ci->sop_count, 0); +@@ -165,6 +154,7 @@ static int ksmbd_inode_init(struct ksmbd + INIT_LIST_HEAD(&ci->m_fp_list); + INIT_LIST_HEAD(&ci->m_op_list); + rwlock_init(&ci->m_lock); ++ ci->m_de = fp->filp->f_path.dentry; + return 0; + } + +@@ -487,12 +477,15 @@ struct ksmbd_file *ksmbd_lookup_fd_cguid + return fp; + } + +-struct ksmbd_file *ksmbd_lookup_fd_inode(struct inode *inode) ++struct ksmbd_file *ksmbd_lookup_fd_inode(struct dentry *dentry) + { + struct ksmbd_file *lfp; + struct ksmbd_inode *ci; ++ struct inode *inode = d_inode(dentry); + +- ci = ksmbd_inode_lookup_by_vfsinode(inode); ++ read_lock(&inode_hash_lock); ++ ci = __ksmbd_inode_lookup(dentry); ++ read_unlock(&inode_hash_lock); + if (!ci) + return NULL; + +--- a/fs/ksmbd/vfs_cache.h ++++ b/fs/ksmbd/vfs_cache.h +@@ -51,7 +51,7 @@ struct ksmbd_inode { + atomic_t op_count; + /* opinfo count for streams */ + atomic_t sop_count; +- struct inode *m_inode; ++ struct dentry *m_de; + unsigned int m_flags; + struct hlist_node m_hash; + struct list_head m_fp_list; +@@ -140,7 +140,7 @@ struct ksmbd_file *ksmbd_lookup_fd_slow( + void ksmbd_fd_put(struct ksmbd_work *work, struct ksmbd_file *fp); + struct ksmbd_file *ksmbd_lookup_durable_fd(unsigned long long id); + struct ksmbd_file *ksmbd_lookup_fd_cguid(char *cguid); +-struct ksmbd_file *ksmbd_lookup_fd_inode(struct inode *inode); ++struct ksmbd_file *ksmbd_lookup_fd_inode(struct dentry *dentry); + unsigned int ksmbd_open_durable_fd(struct ksmbd_file *fp); + struct ksmbd_file *ksmbd_open_fd(struct ksmbd_work *work, struct file *filp); + void ksmbd_close_tree_conn_fds(struct ksmbd_work *work); +@@ -164,7 +164,7 @@ enum KSMBD_INODE_STATUS { + KSMBD_INODE_STATUS_PENDING_DELETE, + }; + +-int ksmbd_query_inode_status(struct inode *inode); ++int ksmbd_query_inode_status(struct dentry *dentry); + bool ksmbd_inode_pending_delete(struct ksmbd_file *fp); + void ksmbd_set_inode_pending_delete(struct ksmbd_file *fp); + void ksmbd_clear_inode_pending_delete(struct ksmbd_file *fp); diff --git a/queue-5.15/ksmbd-set-445-port-to-smbdirect-port-by-default.patch b/queue-5.15/ksmbd-set-445-port-to-smbdirect-port-by-default.patch new file mode 100644 index 00000000000..45bffb6a6f8 --- /dev/null +++ b/queue-5.15/ksmbd-set-445-port-to-smbdirect-port-by-default.patch @@ -0,0 +1,87 @@ +From stable+bounces-7646-greg=kroah.com@vger.kernel.org Mon Dec 18 16:38:15 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:32:37 +0900 +Subject: ksmbd: set 445 port to smbdirect port by default +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-18-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit cb097b3dd5ece9596a0a0b7e33893c02a9bde8c6 ] + +When SMB Direct is used with iWARP, Windows use 5445 port for smb direct +port, 445 port for SMB. This patch check ib_device using ib_client to +know if NICs type is iWARP or Infiniband. + +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/transport_rdma.c | 15 ++++++++++++--- + fs/ksmbd/transport_rdma.h | 2 -- + 2 files changed, 12 insertions(+), 5 deletions(-) + +--- a/fs/ksmbd/transport_rdma.c ++++ b/fs/ksmbd/transport_rdma.c +@@ -34,7 +34,8 @@ + #include "smbstatus.h" + #include "transport_rdma.h" + +-#define SMB_DIRECT_PORT 5445 ++#define SMB_DIRECT_PORT_IWARP 5445 ++#define SMB_DIRECT_PORT_INFINIBAND 445 + + #define SMB_DIRECT_VERSION_LE cpu_to_le16(0x0100) + +@@ -60,6 +61,10 @@ + * as defined in [MS-SMBD] 3.1.1.1 + * Those may change after a SMB_DIRECT negotiation + */ ++ ++/* Set 445 port to SMB Direct port by default */ ++static int smb_direct_port = SMB_DIRECT_PORT_INFINIBAND; ++ + /* The local peer's maximum number of credits to grant to the peer */ + static int smb_direct_receive_credit_max = 255; + +@@ -1948,7 +1953,7 @@ static int smb_direct_handle_connect_req + + KSMBD_TRANS(t)->handler = kthread_run(ksmbd_conn_handler_loop, + KSMBD_TRANS(t)->conn, "ksmbd:r%u", +- SMB_DIRECT_PORT); ++ smb_direct_port); + if (IS_ERR(KSMBD_TRANS(t)->handler)) { + int ret = PTR_ERR(KSMBD_TRANS(t)->handler); + +@@ -2025,6 +2030,10 @@ static int smb_direct_ib_client_add(stru + { + struct smb_direct_device *smb_dev; + ++ /* Set 5445 port if device type is iWARP(No IB) */ ++ if (ib_dev->node_type != RDMA_NODE_IB_CA) ++ smb_direct_port = SMB_DIRECT_PORT_IWARP; ++ + if (!ib_dev->ops.get_netdev || + !rdma_frwr_is_supported(&ib_dev->attrs)) + return 0; +@@ -2086,7 +2095,7 @@ int ksmbd_rdma_init(void) + if (!smb_direct_wq) + return -ENOMEM; + +- ret = smb_direct_listen(SMB_DIRECT_PORT); ++ ret = smb_direct_listen(smb_direct_port); + if (ret) { + destroy_workqueue(smb_direct_wq); + smb_direct_wq = NULL; +--- a/fs/ksmbd/transport_rdma.h ++++ b/fs/ksmbd/transport_rdma.h +@@ -7,8 +7,6 @@ + #ifndef __KSMBD_TRANSPORT_RDMA_H__ + #define __KSMBD_TRANSPORT_RDMA_H__ + +-#define SMB_DIRECT_PORT 5445 +- + #define SMBD_DEFAULT_IOSIZE (8 * 1024 * 1024) + #define SMBD_MIN_IOSIZE (512 * 1024) + #define SMBD_MAX_IOSIZE (16 * 1024 * 1024) diff --git a/queue-5.15/ksmbd-set-both-ipv4-and-ipv6-in-fsctl_query_network_interface_info.patch b/queue-5.15/ksmbd-set-both-ipv4-and-ipv6-in-fsctl_query_network_interface_info.patch new file mode 100644 index 00000000000..66a8683ee1e --- /dev/null +++ b/queue-5.15/ksmbd-set-both-ipv4-and-ipv6-in-fsctl_query_network_interface_info.patch @@ -0,0 +1,84 @@ +From stable+bounces-7640-greg=kroah.com@vger.kernel.org Mon Dec 18 16:36:25 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:32:31 +0900 +Subject: ksmbd: set both ipv4 and ipv6 in FSCTL_QUERY_NETWORK_INTERFACE_INFO +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-12-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit a58b45a4dbfd0bf2ebb157789da4d8e6368afb1b ] + +Set ipv4 and ipv6 address in FSCTL_QUERY_NETWORK_INTERFACE_INFO. + +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/smb2pdu.c | 22 ++++++++++++---------- + 1 file changed, 12 insertions(+), 10 deletions(-) + +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -7328,15 +7328,10 @@ static int fsctl_query_iface_info_ioctl( + struct sockaddr_storage_rsp *sockaddr_storage; + unsigned int flags; + unsigned long long speed; +- struct sockaddr_in6 *csin6 = (struct sockaddr_in6 *)&conn->peer_addr; + + rtnl_lock(); + for_each_netdev(&init_net, netdev) { +- if (out_buf_len < +- nbytes + sizeof(struct network_interface_info_ioctl_rsp)) { +- rtnl_unlock(); +- return -ENOSPC; +- } ++ bool ipv4_set = false; + + if (netdev->type == ARPHRD_LOOPBACK) + continue; +@@ -7344,6 +7339,12 @@ static int fsctl_query_iface_info_ioctl( + flags = dev_get_flags(netdev); + if (!(flags & IFF_RUNNING)) + continue; ++ipv6_retry: ++ if (out_buf_len < ++ nbytes + sizeof(struct network_interface_info_ioctl_rsp)) { ++ rtnl_unlock(); ++ return -ENOSPC; ++ } + + nii_rsp = (struct network_interface_info_ioctl_rsp *) + &rsp->Buffer[nbytes]; +@@ -7376,8 +7377,7 @@ static int fsctl_query_iface_info_ioctl( + nii_rsp->SockAddr_Storage; + memset(sockaddr_storage, 0, 128); + +- if (conn->peer_addr.ss_family == PF_INET || +- ipv6_addr_v4mapped(&csin6->sin6_addr)) { ++ if (!ipv4_set) { + struct in_device *idev; + + sockaddr_storage->Family = cpu_to_le16(INTERNETWORK); +@@ -7388,6 +7388,9 @@ static int fsctl_query_iface_info_ioctl( + continue; + sockaddr_storage->addr4.IPv4address = + idev_ipv4_address(idev); ++ nbytes += sizeof(struct network_interface_info_ioctl_rsp); ++ ipv4_set = true; ++ goto ipv6_retry; + } else { + struct inet6_dev *idev6; + struct inet6_ifaddr *ifa; +@@ -7409,9 +7412,8 @@ static int fsctl_query_iface_info_ioctl( + break; + } + sockaddr_storage->addr6.ScopeId = 0; ++ nbytes += sizeof(struct network_interface_info_ioctl_rsp); + } +- +- nbytes += sizeof(struct network_interface_info_ioctl_rsp); + } + rtnl_unlock(); + diff --git a/queue-5.15/ksmbd-set-file-permission-mode-to-match-samba-server-posix-extension-behavior.patch b/queue-5.15/ksmbd-set-file-permission-mode-to-match-samba-server-posix-extension-behavior.patch new file mode 100644 index 00000000000..6b601a15099 --- /dev/null +++ b/queue-5.15/ksmbd-set-file-permission-mode-to-match-samba-server-posix-extension-behavior.patch @@ -0,0 +1,53 @@ +From linkinjeon@gmail.com Mon Dec 18 16:38:19 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:33:14 +0900 +Subject: ksmbd: set file permission mode to match Samba server posix extension behavior +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-55-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit f6c2b201da7588f7f7688ddc99b7bb000609129c ] + +Set file permission mode to match Samba server posix extension behavior. + +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/oplock.c | 2 +- + fs/ksmbd/smb2pdu.c | 4 ++-- + 2 files changed, 3 insertions(+), 3 deletions(-) + +--- a/fs/ksmbd/oplock.c ++++ b/fs/ksmbd/oplock.c +@@ -1643,7 +1643,7 @@ void create_posix_rsp_buf(char *cc, stru + + buf->nlink = cpu_to_le32(inode->i_nlink); + buf->reparse_tag = cpu_to_le32(fp->volatile_id); +- buf->mode = cpu_to_le32(inode->i_mode); ++ buf->mode = cpu_to_le32(inode->i_mode & 0777); + /* + * SidBuffer(44) contain two sids(Domain sid(28), UNIX group sid(16)). + * Domain sid(28) = revision(1) + num_subauth(1) + authority(6) + +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -3613,7 +3613,7 @@ static int smb2_populate_readdir_entry(s + posix_info->AllocationSize = cpu_to_le64(ksmbd_kstat->kstat->blocks << 9); + posix_info->DeviceId = cpu_to_le32(ksmbd_kstat->kstat->rdev); + posix_info->HardLinks = cpu_to_le32(ksmbd_kstat->kstat->nlink); +- posix_info->Mode = cpu_to_le32(ksmbd_kstat->kstat->mode); ++ posix_info->Mode = cpu_to_le32(ksmbd_kstat->kstat->mode & 0777); + posix_info->Inode = cpu_to_le64(ksmbd_kstat->kstat->ino); + posix_info->DosAttributes = + S_ISDIR(ksmbd_kstat->kstat->mode) ? ATTR_DIRECTORY_LE : ATTR_ARCHIVE_LE; +@@ -4769,7 +4769,7 @@ static int find_file_posix_info(struct s + file_info->EndOfFile = cpu_to_le64(inode->i_size); + file_info->AllocationSize = cpu_to_le64(inode->i_blocks << 9); + file_info->HardLinks = cpu_to_le32(inode->i_nlink); +- file_info->Mode = cpu_to_le32(inode->i_mode); ++ file_info->Mode = cpu_to_le32(inode->i_mode & 0777); + file_info->DeviceId = cpu_to_le32(inode->i_rdev); + rsp->OutputBufferLength = + cpu_to_le32(sizeof(struct smb311_posix_qinfo)); diff --git a/queue-5.15/ksmbd-set-negotiatecontextcount-once-instead-of-every-inc.patch b/queue-5.15/ksmbd-set-negotiatecontextcount-once-instead-of-every-inc.patch new file mode 100644 index 00000000000..7d1f0d95b6c --- /dev/null +++ b/queue-5.15/ksmbd-set-negotiatecontextcount-once-instead-of-every-inc.patch @@ -0,0 +1,73 @@ +From linkinjeon@gmail.com Mon Dec 18 16:39:48 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:33:43 +0900 +Subject: ksmbd: set NegotiateContextCount once instead of every inc +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, David Disseldorp , Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-84-linkinjeon@kernel.org> + +From: David Disseldorp + +[ Upstream commit 34e8ccf9ce24b6b2e275bbe35cd392e18fbbd369 ] + +There are no early returns, so marshalling the incremented +NegotiateContextCount with every context is unnecessary. + +Signed-off-by: David Disseldorp +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/smb2pdu.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -848,7 +848,6 @@ static void assemble_neg_contexts(struct + "assemble SMB2_PREAUTH_INTEGRITY_CAPABILITIES context\n"); + build_preauth_ctxt((struct smb2_preauth_neg_context *)pneg_ctxt, + conn->preauth_info->Preauth_HashId); +- rsp->NegotiateContextCount = cpu_to_le16(neg_ctxt_cnt); + inc_rfc1001_len(smb2_buf_len, AUTH_GSS_PADDING); + ctxt_size = sizeof(struct smb2_preauth_neg_context); + /* Round to 8 byte boundary */ +@@ -860,7 +859,7 @@ static void assemble_neg_contexts(struct + "assemble SMB2_ENCRYPTION_CAPABILITIES context\n"); + build_encrypt_ctxt((struct smb2_encryption_neg_context *)pneg_ctxt, + conn->cipher_type); +- rsp->NegotiateContextCount = cpu_to_le16(++neg_ctxt_cnt); ++ neg_ctxt_cnt++; + ctxt_size += sizeof(struct smb2_encryption_neg_context) + 2; + /* Round to 8 byte boundary */ + pneg_ctxt += +@@ -875,7 +874,7 @@ static void assemble_neg_contexts(struct + /* Temporarily set to SMB3_COMPRESS_NONE */ + build_compression_ctxt((struct smb2_compression_ctx *)pneg_ctxt, + conn->compress_algorithm); +- rsp->NegotiateContextCount = cpu_to_le16(++neg_ctxt_cnt); ++ neg_ctxt_cnt++; + ctxt_size += sizeof(struct smb2_compression_ctx) + 2; + /* Round to 8 byte boundary */ + pneg_ctxt += round_up(sizeof(struct smb2_compression_ctx) + 2, +@@ -887,7 +886,7 @@ static void assemble_neg_contexts(struct + ksmbd_debug(SMB, + "assemble SMB2_POSIX_EXTENSIONS_AVAILABLE context\n"); + build_posix_ctxt((struct smb2_posix_neg_context *)pneg_ctxt); +- rsp->NegotiateContextCount = cpu_to_le16(++neg_ctxt_cnt); ++ neg_ctxt_cnt++; + ctxt_size += sizeof(struct smb2_posix_neg_context); + /* Round to 8 byte boundary */ + pneg_ctxt += round_up(sizeof(struct smb2_posix_neg_context), 8); +@@ -899,10 +898,11 @@ static void assemble_neg_contexts(struct + "assemble SMB2_SIGNING_CAPABILITIES context\n"); + build_sign_cap_ctxt((struct smb2_signing_capabilities *)pneg_ctxt, + conn->signing_algorithm); +- rsp->NegotiateContextCount = cpu_to_le16(++neg_ctxt_cnt); ++ neg_ctxt_cnt++; + ctxt_size += sizeof(struct smb2_signing_capabilities) + 2; + } + ++ rsp->NegotiateContextCount = cpu_to_le16(neg_ctxt_cnt); + inc_rfc1001_len(smb2_buf_len, ctxt_size); + } + diff --git a/queue-5.15/ksmbd-set-ntlmssp_negotiate_seal-flag-to-challenge-blob.patch b/queue-5.15/ksmbd-set-ntlmssp_negotiate_seal-flag-to-challenge-blob.patch new file mode 100644 index 00000000000..35714ac061f --- /dev/null +++ b/queue-5.15/ksmbd-set-ntlmssp_negotiate_seal-flag-to-challenge-blob.patch @@ -0,0 +1,57 @@ +From linkinjeon@gmail.com Mon Dec 18 16:38:28 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:33:17 +0900 +Subject: ksmbd: set NTLMSSP_NEGOTIATE_SEAL flag to challenge blob +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-58-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit 5bedae90b369ca1a7660b9af39591ed19009b495 ] + +If NTLMSSP_NEGOTIATE_SEAL flags is set in negotiate blob from client, +Set NTLMSSP_NEGOTIATE_SEAL flag to challenge blob. + +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/auth.c | 3 +++ + fs/ksmbd/smb2pdu.c | 2 +- + fs/ksmbd/smb2pdu.h | 1 + + 3 files changed, 5 insertions(+), 1 deletion(-) + +--- a/fs/ksmbd/auth.c ++++ b/fs/ksmbd/auth.c +@@ -428,6 +428,9 @@ ksmbd_build_ntlmssp_challenge_blob(struc + NTLMSSP_NEGOTIATE_56); + } + ++ if (cflags & NTLMSSP_NEGOTIATE_SEAL && smb3_encryption_negotiated(conn)) ++ flags |= NTLMSSP_NEGOTIATE_SEAL; ++ + if (cflags & NTLMSSP_NEGOTIATE_ALWAYS_SIGN) + flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN; + +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -956,7 +956,7 @@ static void decode_encrypt_ctxt(struct k + * + * Return: true if connection should be encrypted, else false + */ +-static bool smb3_encryption_negotiated(struct ksmbd_conn *conn) ++bool smb3_encryption_negotiated(struct ksmbd_conn *conn) + { + if (!conn->ops->generate_encryptionkey) + return false; +--- a/fs/ksmbd/smb2pdu.h ++++ b/fs/ksmbd/smb2pdu.h +@@ -1672,6 +1672,7 @@ int smb3_decrypt_req(struct ksmbd_work * + int smb3_encrypt_resp(struct ksmbd_work *work); + bool smb3_11_final_sess_setup_resp(struct ksmbd_work *work); + int smb2_set_rsp_credits(struct ksmbd_work *work); ++bool smb3_encryption_negotiated(struct ksmbd_conn *conn); + + /* smb2 misc functions */ + int ksmbd_smb2_check_message(struct ksmbd_work *work); diff --git a/queue-5.15/ksmbd-set-smb2_session_flag_encrypt_data-when-enforcing-data-encryption-for-this-share.patch b/queue-5.15/ksmbd-set-smb2_session_flag_encrypt_data-when-enforcing-data-encryption-for-this-share.patch new file mode 100644 index 00000000000..48a3dcd0109 --- /dev/null +++ b/queue-5.15/ksmbd-set-smb2_session_flag_encrypt_data-when-enforcing-data-encryption-for-this-share.patch @@ -0,0 +1,96 @@ +From linkinjeon@gmail.com Mon Dec 18 16:38:52 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:33:25 +0900 +Subject: ksmbd: set SMB2_SESSION_FLAG_ENCRYPT_DATA when enforcing data encryption for this share +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-66-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit 37ba7b005a7a4454046bd8659c7a9c5330552396 ] + +Currently, SMB2_SESSION_FLAG_ENCRYPT_DATA is always set session setup +response. Since this forces data encryption from the client, there is a +problem that data is always encrypted regardless of the use of the cifs +seal mount option. SMB2_SESSION_FLAG_ENCRYPT_DATA should be set according +to KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION flags, and in case of +KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION_OFF, encryption mode is turned off for +all connections. + +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/ksmbd_netlink.h | 1 + + fs/ksmbd/smb2ops.c | 10 ++++++++-- + fs/ksmbd/smb2pdu.c | 8 +++++--- + 3 files changed, 14 insertions(+), 5 deletions(-) + +--- a/fs/ksmbd/ksmbd_netlink.h ++++ b/fs/ksmbd/ksmbd_netlink.h +@@ -74,6 +74,7 @@ struct ksmbd_heartbeat { + #define KSMBD_GLOBAL_FLAG_SMB2_LEASES BIT(0) + #define KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION BIT(1) + #define KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL BIT(2) ++#define KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION_OFF BIT(3) + + /* + * IPC request for ksmbd server startup +--- a/fs/ksmbd/smb2ops.c ++++ b/fs/ksmbd/smb2ops.c +@@ -248,8 +248,9 @@ void init_smb3_02_server(struct ksmbd_co + if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_LEASES) + conn->vals->capabilities |= SMB2_GLOBAL_CAP_LEASING; + +- if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION && +- conn->cli_cap & SMB2_GLOBAL_CAP_ENCRYPTION) ++ if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION || ++ (!(server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION_OFF) && ++ conn->cli_cap & SMB2_GLOBAL_CAP_ENCRYPTION)) + conn->vals->capabilities |= SMB2_GLOBAL_CAP_ENCRYPTION; + + if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL) +@@ -272,6 +273,11 @@ int init_smb3_11_server(struct ksmbd_con + if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_LEASES) + conn->vals->capabilities |= SMB2_GLOBAL_CAP_LEASING; + ++ if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION || ++ (!(server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION_OFF) && ++ conn->cli_cap & SMB2_GLOBAL_CAP_ENCRYPTION)) ++ conn->vals->capabilities |= SMB2_GLOBAL_CAP_ENCRYPTION; ++ + if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL) + conn->vals->capabilities |= SMB2_GLOBAL_CAP_MULTI_CHANNEL; + +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -934,7 +934,7 @@ static void decode_encrypt_ctxt(struct k + return; + } + +- if (!(server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION)) ++ if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION_OFF) + return; + + for (i = 0; i < cph_cnt; i++) { +@@ -1538,7 +1538,8 @@ static int ntlm_authenticate(struct ksmb + return -EINVAL; + } + sess->enc = true; +- rsp->SessionFlags = SMB2_SESSION_FLAG_ENCRYPT_DATA_LE; ++ if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION) ++ rsp->SessionFlags = SMB2_SESSION_FLAG_ENCRYPT_DATA_LE; + /* + * signing is disable if encryption is enable + * on this session +@@ -1629,7 +1630,8 @@ static int krb5_authenticate(struct ksmb + return -EINVAL; + } + sess->enc = true; +- rsp->SessionFlags = SMB2_SESSION_FLAG_ENCRYPT_DATA_LE; ++ if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION) ++ rsp->SessionFlags = SMB2_SESSION_FLAG_ENCRYPT_DATA_LE; + sess->sign = false; + } + diff --git a/queue-5.15/ksmbd-shorten-experimental-warning-on-loading-the-module.patch b/queue-5.15/ksmbd-shorten-experimental-warning-on-loading-the-module.patch new file mode 100644 index 00000000000..33ccce4ebd4 --- /dev/null +++ b/queue-5.15/ksmbd-shorten-experimental-warning-on-loading-the-module.patch @@ -0,0 +1,34 @@ +From linkinjeon@gmail.com Mon Dec 18 16:36:49 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:32:47 +0900 +Subject: ksmbd: shorten experimental warning on loading the module +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Steve French , Namjae Jeon +Message-ID: <20231218153454.8090-28-linkinjeon@kernel.org> + +From: Steve French + +[ Upstream commit adc32821409aef8d7f6d868c20a96f4901f48705 ] + +ksmbd is continuing to improve. Shorten the warning message +logged the first time it is loaded to: + "The ksmbd server is experimental" + +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/server.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/fs/ksmbd/server.c ++++ b/fs/ksmbd/server.c +@@ -590,7 +590,7 @@ static int __init ksmbd_server_init(void + if (ret) + goto err_crypto_destroy; + +- pr_warn_once("The ksmbd server is experimental, use at your own risk.\n"); ++ pr_warn_once("The ksmbd server is experimental\n"); + + return 0; + diff --git a/queue-5.15/ksmbd-smbd-call-rdma_accept-under-cm-handler.patch b/queue-5.15/ksmbd-smbd-call-rdma_accept-under-cm-handler.patch new file mode 100644 index 00000000000..f57999c3395 --- /dev/null +++ b/queue-5.15/ksmbd-smbd-call-rdma_accept-under-cm-handler.patch @@ -0,0 +1,225 @@ +From stable+bounces-7647-greg=kroah.com@vger.kernel.org Mon Dec 18 16:38:58 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:32:38 +0900 +Subject: ksmbd: smbd: call rdma_accept() under CM handler +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Hyunchul Lee , Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-19-linkinjeon@kernel.org> + +From: Hyunchul Lee + +[ Upstream commit 99b7650ac51847e81b4d5139824e321e6cb76130 ] + +if CONFIG_LOCKDEP is enabled, the following +kernel warning message is generated because +rdma_accept() checks whehter the handler_mutex +is held by lockdep_assert_held. CM(Connection +Manager) holds the mutex before CM handler +callback is called. + +[ 63.211405 ] WARNING: CPU: 1 PID: 345 at drivers/infiniband/core/cma.c:4405 rdma_accept+0x17a/0x350 +[ 63.212080 ] RIP: 0010:rdma_accept+0x17a/0x350 +... +[ 63.214036 ] Call Trace: +[ 63.214098 ] +[ 63.214185 ] smb_direct_accept_client+0xb4/0x170 [ksmbd] +[ 63.214412 ] smb_direct_prepare+0x322/0x8c0 [ksmbd] +[ 63.214555 ] ? rcu_read_lock_sched_held+0x3a/0x70 +[ 63.214700 ] ksmbd_conn_handler_loop+0x63/0x270 [ksmbd] +[ 63.214826 ] ? ksmbd_conn_alive+0x80/0x80 [ksmbd] +[ 63.214952 ] kthread+0x171/0x1a0 +[ 63.215039 ] ? set_kthread_struct+0x40/0x40 +[ 63.215128 ] ret_from_fork+0x22/0x30 + +To avoid this, move creating a queue pair and accepting +a client from transport_ops->prepare() to +smb_direct_handle_connect_request(). + +Acked-by: Namjae Jeon +Signed-off-by: Hyunchul Lee +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/transport_rdma.c | 102 ++++++++++++++++++++++++++-------------------- + 1 file changed, 59 insertions(+), 43 deletions(-) + +--- a/fs/ksmbd/transport_rdma.c ++++ b/fs/ksmbd/transport_rdma.c +@@ -574,6 +574,7 @@ static void recv_done(struct ib_cq *cq, + } + t->negotiation_requested = true; + t->full_packet_received = true; ++ enqueue_reassembly(t, recvmsg, 0); + wake_up_interruptible(&t->wait_status); + break; + case SMB_DIRECT_MSG_DATA_TRANSFER: { +@@ -1600,19 +1601,13 @@ static int smb_direct_accept_client(stru + pr_err("error at rdma_accept: %d\n", ret); + return ret; + } +- +- wait_event_interruptible(t->wait_status, +- t->status != SMB_DIRECT_CS_NEW); +- if (t->status != SMB_DIRECT_CS_CONNECTED) +- return -ENOTCONN; + return 0; + } + +-static int smb_direct_negotiate(struct smb_direct_transport *t) ++static int smb_direct_prepare_negotiation(struct smb_direct_transport *t) + { + int ret; + struct smb_direct_recvmsg *recvmsg; +- struct smb_direct_negotiate_req *req; + + recvmsg = get_free_recvmsg(t); + if (!recvmsg) +@@ -1622,44 +1617,20 @@ static int smb_direct_negotiate(struct s + ret = smb_direct_post_recv(t, recvmsg); + if (ret) { + pr_err("Can't post recv: %d\n", ret); +- goto out; ++ goto out_err; + } + + t->negotiation_requested = false; + ret = smb_direct_accept_client(t); + if (ret) { + pr_err("Can't accept client\n"); +- goto out; ++ goto out_err; + } + + smb_direct_post_recv_credits(&t->post_recv_credits_work.work); +- +- ksmbd_debug(RDMA, "Waiting for SMB_DIRECT negotiate request\n"); +- ret = wait_event_interruptible_timeout(t->wait_status, +- t->negotiation_requested || +- t->status == SMB_DIRECT_CS_DISCONNECTED, +- SMB_DIRECT_NEGOTIATE_TIMEOUT * HZ); +- if (ret <= 0 || t->status == SMB_DIRECT_CS_DISCONNECTED) { +- ret = ret < 0 ? ret : -ETIMEDOUT; +- goto out; +- } +- +- ret = smb_direct_check_recvmsg(recvmsg); +- if (ret == -ECONNABORTED) +- goto out; +- +- req = (struct smb_direct_negotiate_req *)recvmsg->packet; +- t->max_recv_size = min_t(int, t->max_recv_size, +- le32_to_cpu(req->preferred_send_size)); +- t->max_send_size = min_t(int, t->max_send_size, +- le32_to_cpu(req->max_receive_size)); +- t->max_fragmented_send_size = +- le32_to_cpu(req->max_fragmented_size); +- +- ret = smb_direct_send_negotiate_response(t, ret); +-out: +- if (recvmsg) +- put_recvmsg(t, recvmsg); ++ return 0; ++out_err: ++ put_recvmsg(t, recvmsg); + return ret; + } + +@@ -1896,6 +1867,47 @@ err: + static int smb_direct_prepare(struct ksmbd_transport *t) + { + struct smb_direct_transport *st = smb_trans_direct_transfort(t); ++ struct smb_direct_recvmsg *recvmsg; ++ struct smb_direct_negotiate_req *req; ++ int ret; ++ ++ ksmbd_debug(RDMA, "Waiting for SMB_DIRECT negotiate request\n"); ++ ret = wait_event_interruptible_timeout(st->wait_status, ++ st->negotiation_requested || ++ st->status == SMB_DIRECT_CS_DISCONNECTED, ++ SMB_DIRECT_NEGOTIATE_TIMEOUT * HZ); ++ if (ret <= 0 || st->status == SMB_DIRECT_CS_DISCONNECTED) ++ return ret < 0 ? ret : -ETIMEDOUT; ++ ++ recvmsg = get_first_reassembly(st); ++ if (!recvmsg) ++ return -ECONNABORTED; ++ ++ ret = smb_direct_check_recvmsg(recvmsg); ++ if (ret == -ECONNABORTED) ++ goto out; ++ ++ req = (struct smb_direct_negotiate_req *)recvmsg->packet; ++ st->max_recv_size = min_t(int, st->max_recv_size, ++ le32_to_cpu(req->preferred_send_size)); ++ st->max_send_size = min_t(int, st->max_send_size, ++ le32_to_cpu(req->max_receive_size)); ++ st->max_fragmented_send_size = ++ le32_to_cpu(req->max_fragmented_size); ++ ++ ret = smb_direct_send_negotiate_response(st, ret); ++out: ++ spin_lock_irq(&st->reassembly_queue_lock); ++ st->reassembly_queue_length--; ++ list_del(&recvmsg->list); ++ spin_unlock_irq(&st->reassembly_queue_lock); ++ put_recvmsg(st, recvmsg); ++ ++ return ret; ++} ++ ++static int smb_direct_connect(struct smb_direct_transport *st) ++{ + int ret; + struct ib_qp_cap qp_cap; + +@@ -1917,13 +1929,11 @@ static int smb_direct_prepare(struct ksm + return ret; + } + +- ret = smb_direct_negotiate(st); ++ ret = smb_direct_prepare_negotiation(st); + if (ret) { + pr_err("Can't negotiate: %d\n", ret); + return ret; + } +- +- st->status = SMB_DIRECT_CS_CONNECTED; + return 0; + } + +@@ -1939,6 +1949,7 @@ static bool rdma_frwr_is_supported(struc + static int smb_direct_handle_connect_request(struct rdma_cm_id *new_cm_id) + { + struct smb_direct_transport *t; ++ int ret; + + if (!rdma_frwr_is_supported(&new_cm_id->device->attrs)) { + ksmbd_debug(RDMA, +@@ -1951,18 +1962,23 @@ static int smb_direct_handle_connect_req + if (!t) + return -ENOMEM; + ++ ret = smb_direct_connect(t); ++ if (ret) ++ goto out_err; ++ + KSMBD_TRANS(t)->handler = kthread_run(ksmbd_conn_handler_loop, + KSMBD_TRANS(t)->conn, "ksmbd:r%u", + smb_direct_port); + if (IS_ERR(KSMBD_TRANS(t)->handler)) { +- int ret = PTR_ERR(KSMBD_TRANS(t)->handler); +- ++ ret = PTR_ERR(KSMBD_TRANS(t)->handler); + pr_err("Can't start thread\n"); +- free_transport(t); +- return ret; ++ goto out_err; + } + + return 0; ++out_err: ++ free_transport(t); ++ return ret; + } + + static int smb_direct_listen_handler(struct rdma_cm_id *cm_id, diff --git a/queue-5.15/ksmbd-smbd-change-prototypes-of-rdma-read-write-related-functions.patch b/queue-5.15/ksmbd-smbd-change-prototypes-of-rdma-read-write-related-functions.patch new file mode 100644 index 00000000000..dd484aff995 --- /dev/null +++ b/queue-5.15/ksmbd-smbd-change-prototypes-of-rdma-read-write-related-functions.patch @@ -0,0 +1,250 @@ +From linkinjeon@gmail.com Mon Dec 18 16:37:09 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:32:53 +0900 +Subject: ksmbd: smbd: change prototypes of RDMA read/write related functions +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Hyunchul Lee , Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-34-linkinjeon@kernel.org> + +From: Hyunchul Lee + +[ Upstream commit 1807abcf8778bcbbf584fe54da9ccbe9029c49bb ] + +Change the prototypes of RDMA read/write +operations to accept a pointer and length +of buffer descriptors. + +Signed-off-by: Hyunchul Lee +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/connection.c | 20 ++++++++++---------- + fs/ksmbd/connection.h | 27 ++++++++++++++++----------- + fs/ksmbd/smb2pdu.c | 23 ++++++++--------------- + fs/ksmbd/transport_rdma.c | 30 +++++++++++++++++------------- + 4 files changed, 51 insertions(+), 49 deletions(-) + +--- a/fs/ksmbd/connection.c ++++ b/fs/ksmbd/connection.c +@@ -206,31 +206,31 @@ int ksmbd_conn_write(struct ksmbd_work * + return 0; + } + +-int ksmbd_conn_rdma_read(struct ksmbd_conn *conn, void *buf, +- unsigned int buflen, u32 remote_key, u64 remote_offset, +- u32 remote_len) ++int ksmbd_conn_rdma_read(struct ksmbd_conn *conn, ++ void *buf, unsigned int buflen, ++ struct smb2_buffer_desc_v1 *desc, ++ unsigned int desc_len) + { + int ret = -EINVAL; + + if (conn->transport->ops->rdma_read) + ret = conn->transport->ops->rdma_read(conn->transport, + buf, buflen, +- remote_key, remote_offset, +- remote_len); ++ desc, desc_len); + return ret; + } + +-int ksmbd_conn_rdma_write(struct ksmbd_conn *conn, void *buf, +- unsigned int buflen, u32 remote_key, +- u64 remote_offset, u32 remote_len) ++int ksmbd_conn_rdma_write(struct ksmbd_conn *conn, ++ void *buf, unsigned int buflen, ++ struct smb2_buffer_desc_v1 *desc, ++ unsigned int desc_len) + { + int ret = -EINVAL; + + if (conn->transport->ops->rdma_write) + ret = conn->transport->ops->rdma_write(conn->transport, + buf, buflen, +- remote_key, remote_offset, +- remote_len); ++ desc, desc_len); + return ret; + } + +--- a/fs/ksmbd/connection.h ++++ b/fs/ksmbd/connection.h +@@ -116,11 +116,14 @@ struct ksmbd_transport_ops { + int (*writev)(struct ksmbd_transport *t, struct kvec *iovs, int niov, + int size, bool need_invalidate_rkey, + unsigned int remote_key); +- int (*rdma_read)(struct ksmbd_transport *t, void *buf, unsigned int len, +- u32 remote_key, u64 remote_offset, u32 remote_len); +- int (*rdma_write)(struct ksmbd_transport *t, void *buf, +- unsigned int len, u32 remote_key, u64 remote_offset, +- u32 remote_len); ++ int (*rdma_read)(struct ksmbd_transport *t, ++ void *buf, unsigned int len, ++ struct smb2_buffer_desc_v1 *desc, ++ unsigned int desc_len); ++ int (*rdma_write)(struct ksmbd_transport *t, ++ void *buf, unsigned int len, ++ struct smb2_buffer_desc_v1 *desc, ++ unsigned int desc_len); + }; + + struct ksmbd_transport { +@@ -142,12 +145,14 @@ struct ksmbd_conn *ksmbd_conn_alloc(void + void ksmbd_conn_free(struct ksmbd_conn *conn); + bool ksmbd_conn_lookup_dialect(struct ksmbd_conn *c); + int ksmbd_conn_write(struct ksmbd_work *work); +-int ksmbd_conn_rdma_read(struct ksmbd_conn *conn, void *buf, +- unsigned int buflen, u32 remote_key, u64 remote_offset, +- u32 remote_len); +-int ksmbd_conn_rdma_write(struct ksmbd_conn *conn, void *buf, +- unsigned int buflen, u32 remote_key, u64 remote_offset, +- u32 remote_len); ++int ksmbd_conn_rdma_read(struct ksmbd_conn *conn, ++ void *buf, unsigned int buflen, ++ struct smb2_buffer_desc_v1 *desc, ++ unsigned int desc_len); ++int ksmbd_conn_rdma_write(struct ksmbd_conn *conn, ++ void *buf, unsigned int buflen, ++ struct smb2_buffer_desc_v1 *desc, ++ unsigned int desc_len); + void ksmbd_conn_enqueue_request(struct ksmbd_work *work); + int ksmbd_conn_try_dequeue_request(struct ksmbd_work *work); + void ksmbd_conn_init_server_callbacks(struct ksmbd_conn_ops *ops); +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -6193,7 +6193,6 @@ out: + static int smb2_set_remote_key_for_rdma(struct ksmbd_work *work, + struct smb2_buffer_desc_v1 *desc, + __le32 Channel, +- __le16 ChannelInfoOffset, + __le16 ChannelInfoLength) + { + unsigned int i, ch_count; +@@ -6219,7 +6218,8 @@ static int smb2_set_remote_key_for_rdma( + + work->need_invalidate_rkey = + (Channel == SMB2_CHANNEL_RDMA_V1_INVALIDATE); +- work->remote_key = le32_to_cpu(desc->token); ++ if (Channel == SMB2_CHANNEL_RDMA_V1_INVALIDATE) ++ work->remote_key = le32_to_cpu(desc->token); + return 0; + } + +@@ -6227,14 +6227,12 @@ static ssize_t smb2_read_rdma_channel(st + struct smb2_read_req *req, void *data_buf, + size_t length) + { +- struct smb2_buffer_desc_v1 *desc = +- (struct smb2_buffer_desc_v1 *)&req->Buffer[0]; + int err; + + err = ksmbd_conn_rdma_write(work->conn, data_buf, length, +- le32_to_cpu(desc->token), +- le64_to_cpu(desc->offset), +- le32_to_cpu(desc->length)); ++ (struct smb2_buffer_desc_v1 *) ++ ((char *)req + le16_to_cpu(req->ReadChannelInfoOffset)), ++ le16_to_cpu(req->ReadChannelInfoLength)); + if (err) + return err; + +@@ -6283,7 +6281,6 @@ int smb2_read(struct ksmbd_work *work) + (struct smb2_buffer_desc_v1 *) + ((char *)req + ch_offset), + req->Channel, +- req->ReadChannelInfoOffset, + req->ReadChannelInfoLength); + if (err) + goto out; +@@ -6461,21 +6458,18 @@ static ssize_t smb2_write_rdma_channel(s + struct ksmbd_file *fp, + loff_t offset, size_t length, bool sync) + { +- struct smb2_buffer_desc_v1 *desc; + char *data_buf; + int ret; + ssize_t nbytes; + +- desc = (struct smb2_buffer_desc_v1 *)&req->Buffer[0]; +- + data_buf = kvmalloc(length, GFP_KERNEL | __GFP_ZERO); + if (!data_buf) + return -ENOMEM; + + ret = ksmbd_conn_rdma_read(work->conn, data_buf, length, +- le32_to_cpu(desc->token), +- le64_to_cpu(desc->offset), +- le32_to_cpu(desc->length)); ++ (struct smb2_buffer_desc_v1 *) ++ ((char *)req + le16_to_cpu(req->WriteChannelInfoOffset)), ++ le16_to_cpu(req->WriteChannelInfoLength)); + if (ret < 0) { + kvfree(data_buf); + return ret; +@@ -6527,7 +6521,6 @@ int smb2_write(struct ksmbd_work *work) + (struct smb2_buffer_desc_v1 *) + ((char *)req + ch_offset), + req->Channel, +- req->WriteChannelInfoOffset, + req->WriteChannelInfoLength); + if (err) + goto out; +--- a/fs/ksmbd/transport_rdma.c ++++ b/fs/ksmbd/transport_rdma.c +@@ -1357,14 +1357,18 @@ static void write_done(struct ib_cq *cq, + read_write_done(cq, wc, DMA_TO_DEVICE); + } + +-static int smb_direct_rdma_xmit(struct smb_direct_transport *t, void *buf, +- int buf_len, u32 remote_key, u64 remote_offset, +- u32 remote_len, bool is_read) ++static int smb_direct_rdma_xmit(struct smb_direct_transport *t, ++ void *buf, int buf_len, ++ struct smb2_buffer_desc_v1 *desc, ++ unsigned int desc_len, ++ bool is_read) + { + struct smb_direct_rdma_rw_msg *msg; + int ret; + DECLARE_COMPLETION_ONSTACK(completion); + struct ib_send_wr *first_wr = NULL; ++ u32 remote_key = le32_to_cpu(desc[0].token); ++ u64 remote_offset = le64_to_cpu(desc[0].offset); + + ret = wait_for_credits(t, &t->wait_rw_avail_ops, &t->rw_avail_ops); + if (ret < 0) +@@ -1429,22 +1433,22 @@ err: + return ret; + } + +-static int smb_direct_rdma_write(struct ksmbd_transport *t, void *buf, +- unsigned int buflen, u32 remote_key, +- u64 remote_offset, u32 remote_len) ++static int smb_direct_rdma_write(struct ksmbd_transport *t, ++ void *buf, unsigned int buflen, ++ struct smb2_buffer_desc_v1 *desc, ++ unsigned int desc_len) + { + return smb_direct_rdma_xmit(smb_trans_direct_transfort(t), buf, buflen, +- remote_key, remote_offset, +- remote_len, false); ++ desc, desc_len, false); + } + +-static int smb_direct_rdma_read(struct ksmbd_transport *t, void *buf, +- unsigned int buflen, u32 remote_key, +- u64 remote_offset, u32 remote_len) ++static int smb_direct_rdma_read(struct ksmbd_transport *t, ++ void *buf, unsigned int buflen, ++ struct smb2_buffer_desc_v1 *desc, ++ unsigned int desc_len) + { + return smb_direct_rdma_xmit(smb_trans_direct_transfort(t), buf, buflen, +- remote_key, remote_offset, +- remote_len, true); ++ desc, desc_len, true); + } + + static void smb_direct_disconnect(struct ksmbd_transport *t) diff --git a/queue-5.15/ksmbd-smbd-change-the-default-maximum-read-write-receive-size.patch b/queue-5.15/ksmbd-smbd-change-the-default-maximum-read-write-receive-size.patch new file mode 100644 index 00000000000..21217775118 --- /dev/null +++ b/queue-5.15/ksmbd-smbd-change-the-default-maximum-read-write-receive-size.patch @@ -0,0 +1,40 @@ +From stable+bounces-7649-greg=kroah.com@vger.kernel.org Mon Dec 18 16:39:23 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:32:40 +0900 +Subject: ksmbd: smbd: change the default maximum read/write, receive size +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Hyunchul Lee , Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-21-linkinjeon@kernel.org> + +From: Hyunchul Lee + +[ Upstream commit 4d02c4fdc0e256b493f9a3b604c7ff18f0019f17 ] + +Due to restriction that cannot handle multiple +buffer descriptor structures, decrease the maximum +read/write size for Windows clients. + +And set the maximum fragmented receive size +in consideration of the receive queue size. + +Acked-by: Namjae Jeon +Signed-off-by: Hyunchul Lee +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/transport_rdma.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/fs/ksmbd/transport_rdma.c ++++ b/fs/ksmbd/transport_rdma.c +@@ -1914,7 +1914,9 @@ static int smb_direct_prepare(struct ksm + st->max_send_size = min_t(int, st->max_send_size, + le32_to_cpu(req->max_receive_size)); + st->max_fragmented_send_size = +- le32_to_cpu(req->max_fragmented_size); ++ le32_to_cpu(req->max_fragmented_size); ++ st->max_fragmented_recv_size = ++ (st->recv_credit_max * st->max_recv_size) / 2; + + ret = smb_direct_send_negotiate_response(st, ret); + out: diff --git a/queue-5.15/ksmbd-smbd-change-the-return-value-of-get_sg_list.patch b/queue-5.15/ksmbd-smbd-change-the-return-value-of-get_sg_list.patch new file mode 100644 index 00000000000..9f49d5d58bf --- /dev/null +++ b/queue-5.15/ksmbd-smbd-change-the-return-value-of-get_sg_list.patch @@ -0,0 +1,43 @@ +From linkinjeon@gmail.com Mon Dec 18 16:37:19 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:32:56 +0900 +Subject: ksmbd: smbd: change the return value of get_sg_list +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Hyunchul Lee , Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-37-linkinjeon@kernel.org> + +From: Hyunchul Lee + +[ Upstream commit 4e3edd0092704b25626a0fe60a974f6f382ff93d ] + +Make get_sg_list return EINVAL if there aren't +mapped scatterlists. + +Signed-off-by: Hyunchul Lee +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/transport_rdma.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/fs/ksmbd/transport_rdma.c ++++ b/fs/ksmbd/transport_rdma.c +@@ -1085,7 +1085,7 @@ static int get_sg_list(void *buf, int si + int offset, len; + int i = 0; + +- if (nentries < get_buf_page_count(buf, size)) ++ if (size <= 0 || nentries < get_buf_page_count(buf, size)) + return -EINVAL; + + offset = offset_in_page(buf); +@@ -1117,7 +1117,7 @@ static int get_mapped_sg_list(struct ib_ + int npages; + + npages = get_sg_list(buf, size, sg_list, nentries); +- if (npages <= 0) ++ if (npages < 0) + return -EINVAL; + return ib_dma_map_sg(device, sg_list, npages, dir); + } diff --git a/queue-5.15/ksmbd-smbd-create-mr-pool.patch b/queue-5.15/ksmbd-smbd-create-mr-pool.patch new file mode 100644 index 00000000000..49b3402feed --- /dev/null +++ b/queue-5.15/ksmbd-smbd-create-mr-pool.patch @@ -0,0 +1,77 @@ +From stable+bounces-7648-greg=kroah.com@vger.kernel.org Mon Dec 18 16:39:20 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:32:39 +0900 +Subject: ksmbd: smbd: create MR pool +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Hyunchul Lee , Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-20-linkinjeon@kernel.org> + +From: Hyunchul Lee + +[ Upstream commit c9f189271cff85d5d735e25dfa4bc95952ec12d8 ] + +Create a memory region pool because rdma_rw_ctx_init() +uses memory registration if memory registration yields +better performance than using multiple SGE entries. + +Acked-by: Namjae Jeon +Signed-off-by: Hyunchul Lee +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/transport_rdma.c | 23 ++++++++++++++++++++++- + 1 file changed, 22 insertions(+), 1 deletion(-) + +--- a/fs/ksmbd/transport_rdma.c ++++ b/fs/ksmbd/transport_rdma.c +@@ -434,6 +434,7 @@ static void free_transport(struct smb_di + + if (t->qp) { + ib_drain_qp(t->qp); ++ ib_mr_pool_destroy(t->qp, &t->qp->rdma_mrs); + ib_destroy_qp(t->qp); + } + +@@ -1714,7 +1715,9 @@ static int smb_direct_init_params(struct + cap->max_send_sge = SMB_DIRECT_MAX_SEND_SGES; + cap->max_recv_sge = SMB_DIRECT_MAX_RECV_SGES; + cap->max_inline_data = 0; +- cap->max_rdma_ctxs = 0; ++ cap->max_rdma_ctxs = ++ rdma_rw_mr_factor(device, t->cm_id->port_num, max_pages) * ++ smb_direct_max_outstanding_rw_ops; + return 0; + } + +@@ -1796,6 +1799,7 @@ static int smb_direct_create_qpair(struc + { + int ret; + struct ib_qp_init_attr qp_attr; ++ int pages_per_rw; + + t->pd = ib_alloc_pd(t->cm_id->device, 0); + if (IS_ERR(t->pd)) { +@@ -1843,6 +1847,23 @@ static int smb_direct_create_qpair(struc + t->qp = t->cm_id->qp; + t->cm_id->event_handler = smb_direct_cm_handler; + ++ pages_per_rw = DIV_ROUND_UP(t->max_rdma_rw_size, PAGE_SIZE) + 1; ++ if (pages_per_rw > t->cm_id->device->attrs.max_sgl_rd) { ++ int pages_per_mr, mr_count; ++ ++ pages_per_mr = min_t(int, pages_per_rw, ++ t->cm_id->device->attrs.max_fast_reg_page_list_len); ++ mr_count = DIV_ROUND_UP(pages_per_rw, pages_per_mr) * ++ atomic_read(&t->rw_avail_ops); ++ ret = ib_mr_pool_init(t->qp, &t->qp->rdma_mrs, mr_count, ++ IB_MR_TYPE_MEM_REG, pages_per_mr, 0); ++ if (ret) { ++ pr_err("failed to init mr pool count %d pages %d\n", ++ mr_count, pages_per_mr); ++ goto err; ++ } ++ } ++ + return 0; + err: + if (t->qp) { diff --git a/queue-5.15/ksmbd-smbd-fix-connection-dropped-issue.patch b/queue-5.15/ksmbd-smbd-fix-connection-dropped-issue.patch new file mode 100644 index 00000000000..9c2f5f49e88 --- /dev/null +++ b/queue-5.15/ksmbd-smbd-fix-connection-dropped-issue.patch @@ -0,0 +1,40 @@ +From linkinjeon@gmail.com Mon Dec 18 16:37:31 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:33:00 +0900 +Subject: ksmbd: smbd: fix connection dropped issue +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Hyunchul Lee , Yufan Chen , Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-41-linkinjeon@kernel.org> + +From: Hyunchul Lee + +[ Upstream commit 5366afc4065075a4456941fbd51c33604d631ee5 ] + +When there are bursty connection requests, +RDMA connection event handler is deferred and +Negotiation requests are received even if +connection status is NEW. + +To handle it, set the status to CONNECTED +if Negotiation requests are received. + +Reported-by: Yufan Chen +Signed-off-by: Hyunchul Lee +Tested-by: Yufan Chen +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/transport_rdma.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/fs/ksmbd/transport_rdma.c ++++ b/fs/ksmbd/transport_rdma.c +@@ -576,6 +576,7 @@ static void recv_done(struct ib_cq *cq, + } + t->negotiation_requested = true; + t->full_packet_received = true; ++ t->status = SMB_DIRECT_CS_CONNECTED; + enqueue_reassembly(t, recvmsg, 0); + wake_up_interruptible(&t->wait_status); + break; diff --git a/queue-5.15/ksmbd-smbd-fix-missing-client-s-memory-region-invalidation.patch b/queue-5.15/ksmbd-smbd-fix-missing-client-s-memory-region-invalidation.patch new file mode 100644 index 00000000000..5f85cead171 --- /dev/null +++ b/queue-5.15/ksmbd-smbd-fix-missing-client-s-memory-region-invalidation.patch @@ -0,0 +1,140 @@ +From stable+bounces-7651-greg=kroah.com@vger.kernel.org Mon Dec 18 16:40:20 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:32:42 +0900 +Subject: ksmbd: smbd: fix missing client's memory region invalidation +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Hyunchul Lee , Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-23-linkinjeon@kernel.org> + +From: Hyunchul Lee + +[ Upstream commit 2fd5dcb1c8ef96c9f0fa8bda53ca480524b80ae7 ] + +if the Channel of a SMB2 WRITE request is +SMB2_CHANNEL_RDMA_V1_INVALIDTE, a client +does not invalidate its memory regions but +ksmbd must do it by sending a SMB2 WRITE response +with IB_WR_SEND_WITH_INV. + +But if errors occur while processing a SMB2 +READ/WRITE request, ksmbd sends a response +with IB_WR_SEND. So a client could use memory +regions already in use. + +Acked-by: Namjae Jeon +Signed-off-by: Hyunchul Lee +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/smb2pdu.c | 71 +++++++++++++++++++++++++++++++++-------------------- + 1 file changed, 45 insertions(+), 26 deletions(-) + +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -6203,25 +6203,33 @@ out: + return err; + } + +-static ssize_t smb2_read_rdma_channel(struct ksmbd_work *work, +- struct smb2_read_req *req, void *data_buf, +- size_t length) ++static int smb2_set_remote_key_for_rdma(struct ksmbd_work *work, ++ struct smb2_buffer_desc_v1 *desc, ++ __le32 Channel, ++ __le16 ChannelInfoOffset, ++ __le16 ChannelInfoLength) + { +- struct smb2_buffer_desc_v1 *desc = +- (struct smb2_buffer_desc_v1 *)&req->Buffer[0]; +- int err; +- + if (work->conn->dialect == SMB30_PROT_ID && +- req->Channel != SMB2_CHANNEL_RDMA_V1) ++ Channel != SMB2_CHANNEL_RDMA_V1) + return -EINVAL; + +- if (req->ReadChannelInfoOffset == 0 || +- le16_to_cpu(req->ReadChannelInfoLength) < sizeof(*desc)) ++ if (ChannelInfoOffset == 0 || ++ le16_to_cpu(ChannelInfoLength) < sizeof(*desc)) + return -EINVAL; + + work->need_invalidate_rkey = +- (req->Channel == SMB2_CHANNEL_RDMA_V1_INVALIDATE); ++ (Channel == SMB2_CHANNEL_RDMA_V1_INVALIDATE); + work->remote_key = le32_to_cpu(desc->token); ++ return 0; ++} ++ ++static ssize_t smb2_read_rdma_channel(struct ksmbd_work *work, ++ struct smb2_read_req *req, void *data_buf, ++ size_t length) ++{ ++ struct smb2_buffer_desc_v1 *desc = ++ (struct smb2_buffer_desc_v1 *)&req->Buffer[0]; ++ int err; + + err = ksmbd_conn_rdma_write(work->conn, data_buf, length, + le32_to_cpu(desc->token), +@@ -6263,6 +6271,18 @@ int smb2_read(struct ksmbd_work *work) + return smb2_read_pipe(work); + } + ++ if (req->Channel == SMB2_CHANNEL_RDMA_V1_INVALIDATE || ++ req->Channel == SMB2_CHANNEL_RDMA_V1) { ++ err = smb2_set_remote_key_for_rdma(work, ++ (struct smb2_buffer_desc_v1 *) ++ &req->Buffer[0], ++ req->Channel, ++ req->ReadChannelInfoOffset, ++ req->ReadChannelInfoLength); ++ if (err) ++ goto out; ++ } ++ + fp = ksmbd_lookup_fd_slow(work, le64_to_cpu(req->VolatileFileId), + le64_to_cpu(req->PersistentFileId)); + if (!fp) { +@@ -6448,21 +6468,6 @@ static ssize_t smb2_write_rdma_channel(s + + desc = (struct smb2_buffer_desc_v1 *)&req->Buffer[0]; + +- if (work->conn->dialect == SMB30_PROT_ID && +- req->Channel != SMB2_CHANNEL_RDMA_V1) +- return -EINVAL; +- +- if (req->Length != 0 || req->DataOffset != 0) +- return -EINVAL; +- +- if (req->WriteChannelInfoOffset == 0 || +- le16_to_cpu(req->WriteChannelInfoLength) < sizeof(*desc)) +- return -EINVAL; +- +- work->need_invalidate_rkey = +- (req->Channel == SMB2_CHANNEL_RDMA_V1_INVALIDATE); +- work->remote_key = le32_to_cpu(desc->token); +- + data_buf = kvmalloc(length, GFP_KERNEL | __GFP_ZERO); + if (!data_buf) + return -ENOMEM; +@@ -6509,6 +6514,20 @@ int smb2_write(struct ksmbd_work *work) + return smb2_write_pipe(work); + } + ++ if (req->Channel == SMB2_CHANNEL_RDMA_V1 || ++ req->Channel == SMB2_CHANNEL_RDMA_V1_INVALIDATE) { ++ if (req->Length != 0 || req->DataOffset != 0) ++ return -EINVAL; ++ err = smb2_set_remote_key_for_rdma(work, ++ (struct smb2_buffer_desc_v1 *) ++ &req->Buffer[0], ++ req->Channel, ++ req->WriteChannelInfoOffset, ++ req->WriteChannelInfoLength); ++ if (err) ++ goto out; ++ } ++ + if (!test_tree_conn_flag(work->tcon, KSMBD_TREE_CONN_FLAG_WRITABLE)) { + ksmbd_debug(SMB, "User does not have write permission\n"); + err = -EACCES; diff --git a/queue-5.15/ksmbd-smbd-handle-multiple-buffer-descriptors.patch b/queue-5.15/ksmbd-smbd-handle-multiple-buffer-descriptors.patch new file mode 100644 index 00000000000..c7f03f7ab72 --- /dev/null +++ b/queue-5.15/ksmbd-smbd-handle-multiple-buffer-descriptors.patch @@ -0,0 +1,262 @@ +From stable+bounces-7666-greg=kroah.com@vger.kernel.org Mon Dec 18 16:42:47 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:32:57 +0900 +Subject: ksmbd: smbd: handle multiple Buffer descriptors +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Hyunchul Lee , Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-38-linkinjeon@kernel.org> + +From: Hyunchul Lee + +[ Upstream commit ee1b0558965909872775183dc237cdf9f8eddaba ] + +Make ksmbd handle multiple buffer descriptors +when reading and writing files using SMB direct: +Post the work requests of rdma_rw_ctx for +RDMA read/write in smb_direct_rdma_xmit(), and +the work request for the READ/WRITE response +with a remote invalidation in smb_direct_writev(). + +Signed-off-by: Hyunchul Lee +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/smb2pdu.c | 5 - + fs/ksmbd/transport_rdma.c | 164 +++++++++++++++++++++++++++++----------------- + 2 files changed, 107 insertions(+), 62 deletions(-) + +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -6210,11 +6210,8 @@ static int smb2_set_remote_key_for_rdma( + le32_to_cpu(desc[i].length)); + } + } +- if (ch_count != 1) { +- ksmbd_debug(RDMA, "RDMA multiple buffer descriptors %d are not supported yet\n", +- ch_count); ++ if (!ch_count) + return -EINVAL; +- } + + work->need_invalidate_rkey = + (Channel == SMB2_CHANNEL_RDMA_V1_INVALIDATE); +--- a/fs/ksmbd/transport_rdma.c ++++ b/fs/ksmbd/transport_rdma.c +@@ -206,7 +206,9 @@ struct smb_direct_recvmsg { + struct smb_direct_rdma_rw_msg { + struct smb_direct_transport *t; + struct ib_cqe cqe; ++ int status; + struct completion *completion; ++ struct list_head list; + struct rdma_rw_ctx rw_ctx; + struct sg_table sgt; + struct scatterlist sg_list[0]; +@@ -1317,6 +1319,16 @@ done: + return ret; + } + ++static void smb_direct_free_rdma_rw_msg(struct smb_direct_transport *t, ++ struct smb_direct_rdma_rw_msg *msg, ++ enum dma_data_direction dir) ++{ ++ rdma_rw_ctx_destroy(&msg->rw_ctx, t->qp, t->qp->port, ++ msg->sgt.sgl, msg->sgt.nents, dir); ++ sg_free_table_chained(&msg->sgt, SG_CHUNK_SIZE); ++ kfree(msg); ++} ++ + static void read_write_done(struct ib_cq *cq, struct ib_wc *wc, + enum dma_data_direction dir) + { +@@ -1325,19 +1337,14 @@ static void read_write_done(struct ib_cq + struct smb_direct_transport *t = msg->t; + + if (wc->status != IB_WC_SUCCESS) { ++ msg->status = -EIO; + pr_err("read/write error. opcode = %d, status = %s(%d)\n", + wc->opcode, ib_wc_status_msg(wc->status), wc->status); +- smb_direct_disconnect_rdma_connection(t); ++ if (wc->status != IB_WC_WR_FLUSH_ERR) ++ smb_direct_disconnect_rdma_connection(t); + } + +- if (atomic_inc_return(&t->rw_credits) > 0) +- wake_up(&t->wait_rw_credits); +- +- rdma_rw_ctx_destroy(&msg->rw_ctx, t->qp, t->qp->port, +- msg->sg_list, msg->sgt.nents, dir); +- sg_free_table_chained(&msg->sgt, SG_CHUNK_SIZE); + complete(msg->completion); +- kfree(msg); + } + + static void read_done(struct ib_cq *cq, struct ib_wc *wc) +@@ -1356,75 +1363,116 @@ static int smb_direct_rdma_xmit(struct s + unsigned int desc_len, + bool is_read) + { +- struct smb_direct_rdma_rw_msg *msg; +- int ret; ++ struct smb_direct_rdma_rw_msg *msg, *next_msg; ++ int i, ret; + DECLARE_COMPLETION_ONSTACK(completion); +- struct ib_send_wr *first_wr = NULL; +- u32 remote_key = le32_to_cpu(desc[0].token); +- u64 remote_offset = le64_to_cpu(desc[0].offset); ++ struct ib_send_wr *first_wr; ++ LIST_HEAD(msg_list); ++ char *desc_buf; + int credits_needed; ++ unsigned int desc_buf_len; ++ size_t total_length = 0; ++ ++ if (t->status != SMB_DIRECT_CS_CONNECTED) ++ return -ENOTCONN; ++ ++ /* calculate needed credits */ ++ credits_needed = 0; ++ desc_buf = buf; ++ for (i = 0; i < desc_len / sizeof(*desc); i++) { ++ desc_buf_len = le32_to_cpu(desc[i].length); ++ ++ credits_needed += calc_rw_credits(t, desc_buf, desc_buf_len); ++ desc_buf += desc_buf_len; ++ total_length += desc_buf_len; ++ if (desc_buf_len == 0 || total_length > buf_len || ++ total_length > t->max_rdma_rw_size) ++ return -EINVAL; ++ } ++ ++ ksmbd_debug(RDMA, "RDMA %s, len %#x, needed credits %#x\n", ++ is_read ? "read" : "write", buf_len, credits_needed); + +- credits_needed = calc_rw_credits(t, buf, buf_len); + ret = wait_for_rw_credits(t, credits_needed); + if (ret < 0) + return ret; + +- /* TODO: mempool */ +- msg = kmalloc(offsetof(struct smb_direct_rdma_rw_msg, sg_list) + +- sizeof(struct scatterlist) * SG_CHUNK_SIZE, GFP_KERNEL); +- if (!msg) { +- atomic_add(credits_needed, &t->rw_credits); +- return -ENOMEM; +- } ++ /* build rdma_rw_ctx for each descriptor */ ++ desc_buf = buf; ++ for (i = 0; i < desc_len / sizeof(*desc); i++) { ++ msg = kzalloc(offsetof(struct smb_direct_rdma_rw_msg, sg_list) + ++ sizeof(struct scatterlist) * SG_CHUNK_SIZE, GFP_KERNEL); ++ if (!msg) { ++ ret = -ENOMEM; ++ goto out; ++ } + +- msg->sgt.sgl = &msg->sg_list[0]; +- ret = sg_alloc_table_chained(&msg->sgt, +- get_buf_page_count(buf, buf_len), +- msg->sg_list, SG_CHUNK_SIZE); +- if (ret) { +- atomic_add(credits_needed, &t->rw_credits); +- kfree(msg); +- return -ENOMEM; +- } ++ desc_buf_len = le32_to_cpu(desc[i].length); + +- ret = get_sg_list(buf, buf_len, msg->sgt.sgl, msg->sgt.orig_nents); +- if (ret <= 0) { +- pr_err("failed to get pages\n"); +- goto err; +- } ++ msg->t = t; ++ msg->cqe.done = is_read ? read_done : write_done; ++ msg->completion = &completion; ++ ++ msg->sgt.sgl = &msg->sg_list[0]; ++ ret = sg_alloc_table_chained(&msg->sgt, ++ get_buf_page_count(desc_buf, desc_buf_len), ++ msg->sg_list, SG_CHUNK_SIZE); ++ if (ret) { ++ kfree(msg); ++ ret = -ENOMEM; ++ goto out; ++ } + +- ret = rdma_rw_ctx_init(&msg->rw_ctx, t->qp, t->qp->port, +- msg->sg_list, get_buf_page_count(buf, buf_len), +- 0, remote_offset, remote_key, +- is_read ? DMA_FROM_DEVICE : DMA_TO_DEVICE); +- if (ret < 0) { +- pr_err("failed to init rdma_rw_ctx: %d\n", ret); +- goto err; ++ ret = get_sg_list(desc_buf, desc_buf_len, ++ msg->sgt.sgl, msg->sgt.orig_nents); ++ if (ret < 0) { ++ sg_free_table_chained(&msg->sgt, SG_CHUNK_SIZE); ++ kfree(msg); ++ goto out; ++ } ++ ++ ret = rdma_rw_ctx_init(&msg->rw_ctx, t->qp, t->qp->port, ++ msg->sgt.sgl, ++ get_buf_page_count(desc_buf, desc_buf_len), ++ 0, ++ le64_to_cpu(desc[i].offset), ++ le32_to_cpu(desc[i].token), ++ is_read ? DMA_FROM_DEVICE : DMA_TO_DEVICE); ++ if (ret < 0) { ++ pr_err("failed to init rdma_rw_ctx: %d\n", ret); ++ sg_free_table_chained(&msg->sgt, SG_CHUNK_SIZE); ++ kfree(msg); ++ goto out; ++ } ++ ++ list_add_tail(&msg->list, &msg_list); ++ desc_buf += desc_buf_len; + } + +- msg->t = t; +- msg->cqe.done = is_read ? read_done : write_done; +- msg->completion = &completion; +- first_wr = rdma_rw_ctx_wrs(&msg->rw_ctx, t->qp, t->qp->port, +- &msg->cqe, NULL); ++ /* concatenate work requests of rdma_rw_ctxs */ ++ first_wr = NULL; ++ list_for_each_entry_reverse(msg, &msg_list, list) { ++ first_wr = rdma_rw_ctx_wrs(&msg->rw_ctx, t->qp, t->qp->port, ++ &msg->cqe, first_wr); ++ } + + ret = ib_post_send(t->qp, first_wr, NULL); + if (ret) { +- pr_err("failed to post send wr: %d\n", ret); +- goto err; ++ pr_err("failed to post send wr for RDMA R/W: %d\n", ret); ++ goto out; + } + ++ msg = list_last_entry(&msg_list, struct smb_direct_rdma_rw_msg, list); + wait_for_completion(&completion); +- return 0; +- +-err: ++ ret = msg->status; ++out: ++ list_for_each_entry_safe(msg, next_msg, &msg_list, list) { ++ list_del(&msg->list); ++ smb_direct_free_rdma_rw_msg(t, msg, ++ is_read ? DMA_FROM_DEVICE : DMA_TO_DEVICE); ++ } + atomic_add(credits_needed, &t->rw_credits); +- if (first_wr) +- rdma_rw_ctx_destroy(&msg->rw_ctx, t->qp, t->qp->port, +- msg->sg_list, msg->sgt.nents, +- is_read ? DMA_FROM_DEVICE : DMA_TO_DEVICE); +- sg_free_table_chained(&msg->sgt, SG_CHUNK_SIZE); +- kfree(msg); ++ wake_up(&t->wait_rw_credits); + return ret; + } + diff --git a/queue-5.15/ksmbd-smbd-introduce-read-write-credits-for-rdma-read-write.patch b/queue-5.15/ksmbd-smbd-introduce-read-write-credits-for-rdma-read-write.patch new file mode 100644 index 00000000000..b44a256d172 --- /dev/null +++ b/queue-5.15/ksmbd-smbd-introduce-read-write-credits-for-rdma-read-write.patch @@ -0,0 +1,290 @@ +From linkinjeon@gmail.com Mon Dec 18 16:37:13 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:32:54 +0900 +Subject: ksmbd: smbd: introduce read/write credits for RDMA read/write +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Hyunchul Lee , Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-35-linkinjeon@kernel.org> + +From: Hyunchul Lee + +[ Upstream commit ddbdc861e37c168cf2fb8a7b7477f5d18b4daf76 ] + +SMB2_READ/SMB2_WRITE request has to be granted the number +of rw credits, the pages the request wants to transfer +/ the maximum pages which can be registered with one +MR to read and write a file. +And allocate enough RDMA resources for the maximum +number of rw credits allowed by ksmbd. + +Signed-off-by: Hyunchul Lee +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/transport_rdma.c | 118 +++++++++++++++++++++++++++------------------- + 1 file changed, 70 insertions(+), 48 deletions(-) + +--- a/fs/ksmbd/transport_rdma.c ++++ b/fs/ksmbd/transport_rdma.c +@@ -82,8 +82,6 @@ static int smb_direct_max_receive_size = + + static int smb_direct_max_read_write_size = SMBD_DEFAULT_IOSIZE; + +-static int smb_direct_max_outstanding_rw_ops = 8; +- + static LIST_HEAD(smb_direct_device_list); + static DEFINE_RWLOCK(smb_direct_device_lock); + +@@ -147,10 +145,12 @@ struct smb_direct_transport { + atomic_t send_credits; + spinlock_t lock_new_recv_credits; + int new_recv_credits; +- atomic_t rw_avail_ops; ++ int max_rw_credits; ++ int pages_per_rw_credit; ++ atomic_t rw_credits; + + wait_queue_head_t wait_send_credits; +- wait_queue_head_t wait_rw_avail_ops; ++ wait_queue_head_t wait_rw_credits; + + mempool_t *sendmsg_mempool; + struct kmem_cache *sendmsg_cache; +@@ -383,7 +383,7 @@ static struct smb_direct_transport *allo + t->reassembly_queue_length = 0; + init_waitqueue_head(&t->wait_reassembly_queue); + init_waitqueue_head(&t->wait_send_credits); +- init_waitqueue_head(&t->wait_rw_avail_ops); ++ init_waitqueue_head(&t->wait_rw_credits); + + spin_lock_init(&t->receive_credit_lock); + spin_lock_init(&t->recvmsg_queue_lock); +@@ -989,18 +989,19 @@ static int smb_direct_flush_send_list(st + } + + static int wait_for_credits(struct smb_direct_transport *t, +- wait_queue_head_t *waitq, atomic_t *credits) ++ wait_queue_head_t *waitq, atomic_t *total_credits, ++ int needed) + { + int ret; + + do { +- if (atomic_dec_return(credits) >= 0) ++ if (atomic_sub_return(needed, total_credits) >= 0) + return 0; + +- atomic_inc(credits); ++ atomic_add(needed, total_credits); + ret = wait_event_interruptible(*waitq, +- atomic_read(credits) > 0 || +- t->status != SMB_DIRECT_CS_CONNECTED); ++ atomic_read(total_credits) >= needed || ++ t->status != SMB_DIRECT_CS_CONNECTED); + + if (t->status != SMB_DIRECT_CS_CONNECTED) + return -ENOTCONN; +@@ -1021,7 +1022,19 @@ static int wait_for_send_credits(struct + return ret; + } + +- return wait_for_credits(t, &t->wait_send_credits, &t->send_credits); ++ return wait_for_credits(t, &t->wait_send_credits, &t->send_credits, 1); ++} ++ ++static int wait_for_rw_credits(struct smb_direct_transport *t, int credits) ++{ ++ return wait_for_credits(t, &t->wait_rw_credits, &t->rw_credits, credits); ++} ++ ++static int calc_rw_credits(struct smb_direct_transport *t, ++ char *buf, unsigned int len) ++{ ++ return DIV_ROUND_UP(get_buf_page_count(buf, len), ++ t->pages_per_rw_credit); + } + + static int smb_direct_create_header(struct smb_direct_transport *t, +@@ -1337,8 +1350,8 @@ static void read_write_done(struct ib_cq + smb_direct_disconnect_rdma_connection(t); + } + +- if (atomic_inc_return(&t->rw_avail_ops) > 0) +- wake_up(&t->wait_rw_avail_ops); ++ if (atomic_inc_return(&t->rw_credits) > 0) ++ wake_up(&t->wait_rw_credits); + + rdma_rw_ctx_destroy(&msg->rw_ctx, t->qp, t->qp->port, + msg->sg_list, msg->sgt.nents, dir); +@@ -1369,8 +1382,10 @@ static int smb_direct_rdma_xmit(struct s + struct ib_send_wr *first_wr = NULL; + u32 remote_key = le32_to_cpu(desc[0].token); + u64 remote_offset = le64_to_cpu(desc[0].offset); ++ int credits_needed; + +- ret = wait_for_credits(t, &t->wait_rw_avail_ops, &t->rw_avail_ops); ++ credits_needed = calc_rw_credits(t, buf, buf_len); ++ ret = wait_for_rw_credits(t, credits_needed); + if (ret < 0) + return ret; + +@@ -1378,7 +1393,7 @@ static int smb_direct_rdma_xmit(struct s + msg = kmalloc(offsetof(struct smb_direct_rdma_rw_msg, sg_list) + + sizeof(struct scatterlist) * SG_CHUNK_SIZE, GFP_KERNEL); + if (!msg) { +- atomic_inc(&t->rw_avail_ops); ++ atomic_add(credits_needed, &t->rw_credits); + return -ENOMEM; + } + +@@ -1387,7 +1402,7 @@ static int smb_direct_rdma_xmit(struct s + get_buf_page_count(buf, buf_len), + msg->sg_list, SG_CHUNK_SIZE); + if (ret) { +- atomic_inc(&t->rw_avail_ops); ++ atomic_add(credits_needed, &t->rw_credits); + kfree(msg); + return -ENOMEM; + } +@@ -1423,7 +1438,7 @@ static int smb_direct_rdma_xmit(struct s + return 0; + + err: +- atomic_inc(&t->rw_avail_ops); ++ atomic_add(credits_needed, &t->rw_credits); + if (first_wr) + rdma_rw_ctx_destroy(&msg->rw_ctx, t->qp, t->qp->port, + msg->sg_list, msg->sgt.nents, +@@ -1648,11 +1663,19 @@ out_err: + return ret; + } + ++static unsigned int smb_direct_get_max_fr_pages(struct smb_direct_transport *t) ++{ ++ return min_t(unsigned int, ++ t->cm_id->device->attrs.max_fast_reg_page_list_len, ++ 256); ++} ++ + static int smb_direct_init_params(struct smb_direct_transport *t, + struct ib_qp_cap *cap) + { + struct ib_device *device = t->cm_id->device; +- int max_send_sges, max_pages, max_rw_wrs, max_send_wrs; ++ int max_send_sges, max_rw_wrs, max_send_wrs; ++ unsigned int max_sge_per_wr, wrs_per_credit; + + /* need 2 more sge. because a SMB_DIRECT header will be mapped, + * and maybe a send buffer could be not page aligned. +@@ -1664,25 +1687,31 @@ static int smb_direct_init_params(struct + return -EINVAL; + } + +- /* +- * allow smb_direct_max_outstanding_rw_ops of in-flight RDMA +- * read/writes. HCA guarantees at least max_send_sge of sges for +- * a RDMA read/write work request, and if memory registration is used, +- * we need reg_mr, local_inv wrs for each read/write. ++ /* Calculate the number of work requests for RDMA R/W. ++ * The maximum number of pages which can be registered ++ * with one Memory region can be transferred with one ++ * R/W credit. And at least 4 work requests for each credit ++ * are needed for MR registration, RDMA R/W, local & remote ++ * MR invalidation. + */ + t->max_rdma_rw_size = smb_direct_max_read_write_size; +- max_pages = DIV_ROUND_UP(t->max_rdma_rw_size, PAGE_SIZE) + 1; +- max_rw_wrs = DIV_ROUND_UP(max_pages, SMB_DIRECT_MAX_SEND_SGES); +- max_rw_wrs += rdma_rw_mr_factor(device, t->cm_id->port_num, +- max_pages) * 2; +- max_rw_wrs *= smb_direct_max_outstanding_rw_ops; ++ t->pages_per_rw_credit = smb_direct_get_max_fr_pages(t); ++ t->max_rw_credits = DIV_ROUND_UP(t->max_rdma_rw_size, ++ (t->pages_per_rw_credit - 1) * ++ PAGE_SIZE); ++ ++ max_sge_per_wr = min_t(unsigned int, device->attrs.max_send_sge, ++ device->attrs.max_sge_rd); ++ wrs_per_credit = max_t(unsigned int, 4, ++ DIV_ROUND_UP(t->pages_per_rw_credit, ++ max_sge_per_wr) + 1); ++ max_rw_wrs = t->max_rw_credits * wrs_per_credit; + + max_send_wrs = smb_direct_send_credit_target + max_rw_wrs; + if (max_send_wrs > device->attrs.max_cqe || + max_send_wrs > device->attrs.max_qp_wr) { +- pr_err("consider lowering send_credit_target = %d, or max_outstanding_rw_ops = %d\n", +- smb_direct_send_credit_target, +- smb_direct_max_outstanding_rw_ops); ++ pr_err("consider lowering send_credit_target = %d\n", ++ smb_direct_send_credit_target); + pr_err("Possible CQE overrun, device reporting max_cqe %d max_qp_wr %d\n", + device->attrs.max_cqe, device->attrs.max_qp_wr); + return -EINVAL; +@@ -1717,7 +1746,7 @@ static int smb_direct_init_params(struct + + t->send_credit_target = smb_direct_send_credit_target; + atomic_set(&t->send_credits, 0); +- atomic_set(&t->rw_avail_ops, smb_direct_max_outstanding_rw_ops); ++ atomic_set(&t->rw_credits, t->max_rw_credits); + + t->max_send_size = smb_direct_max_send_size; + t->max_recv_size = smb_direct_max_receive_size; +@@ -1725,12 +1754,10 @@ static int smb_direct_init_params(struct + + cap->max_send_wr = max_send_wrs; + cap->max_recv_wr = t->recv_credit_max; +- cap->max_send_sge = SMB_DIRECT_MAX_SEND_SGES; ++ cap->max_send_sge = max_sge_per_wr; + cap->max_recv_sge = SMB_DIRECT_MAX_RECV_SGES; + cap->max_inline_data = 0; +- cap->max_rdma_ctxs = +- rdma_rw_mr_factor(device, t->cm_id->port_num, max_pages) * +- smb_direct_max_outstanding_rw_ops; ++ cap->max_rdma_ctxs = t->max_rw_credits; + return 0; + } + +@@ -1823,7 +1850,8 @@ static int smb_direct_create_qpair(struc + } + + t->send_cq = ib_alloc_cq(t->cm_id->device, t, +- t->send_credit_target, 0, IB_POLL_WORKQUEUE); ++ smb_direct_send_credit_target + cap->max_rdma_ctxs, ++ 0, IB_POLL_WORKQUEUE); + if (IS_ERR(t->send_cq)) { + pr_err("Can't create RDMA send CQ\n"); + ret = PTR_ERR(t->send_cq); +@@ -1832,8 +1860,7 @@ static int smb_direct_create_qpair(struc + } + + t->recv_cq = ib_alloc_cq(t->cm_id->device, t, +- cap->max_send_wr + cap->max_rdma_ctxs, +- 0, IB_POLL_WORKQUEUE); ++ t->recv_credit_max, 0, IB_POLL_WORKQUEUE); + if (IS_ERR(t->recv_cq)) { + pr_err("Can't create RDMA recv CQ\n"); + ret = PTR_ERR(t->recv_cq); +@@ -1862,17 +1889,12 @@ static int smb_direct_create_qpair(struc + + pages_per_rw = DIV_ROUND_UP(t->max_rdma_rw_size, PAGE_SIZE) + 1; + if (pages_per_rw > t->cm_id->device->attrs.max_sgl_rd) { +- int pages_per_mr, mr_count; +- +- pages_per_mr = min_t(int, pages_per_rw, +- t->cm_id->device->attrs.max_fast_reg_page_list_len); +- mr_count = DIV_ROUND_UP(pages_per_rw, pages_per_mr) * +- atomic_read(&t->rw_avail_ops); +- ret = ib_mr_pool_init(t->qp, &t->qp->rdma_mrs, mr_count, +- IB_MR_TYPE_MEM_REG, pages_per_mr, 0); ++ ret = ib_mr_pool_init(t->qp, &t->qp->rdma_mrs, ++ t->max_rw_credits, IB_MR_TYPE_MEM_REG, ++ t->pages_per_rw_credit, 0); + if (ret) { + pr_err("failed to init mr pool count %d pages %d\n", +- mr_count, pages_per_mr); ++ t->max_rw_credits, t->pages_per_rw_credit); + goto err; + } + } diff --git a/queue-5.15/ksmbd-smbd-relax-the-count-of-sges-required.patch b/queue-5.15/ksmbd-smbd-relax-the-count-of-sges-required.patch new file mode 100644 index 00000000000..0ffa5d2b91a --- /dev/null +++ b/queue-5.15/ksmbd-smbd-relax-the-count-of-sges-required.patch @@ -0,0 +1,66 @@ +From linkinjeon@gmail.com Mon Dec 18 16:37:35 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:33:01 +0900 +Subject: ksmbd: smbd: relax the count of sges required +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Hyunchul Lee , Namjae Jeon , Tom Talpey , Steve French +Message-ID: <20231218153454.8090-42-linkinjeon@kernel.org> + +From: Hyunchul Lee + +[ Upstream commit 621433b7e25d6d42e5f75bd8c4a62d6c7251511b ] + +Remove the condition that the count of sges +must be greater than or equal to +SMB_DIRECT_MAX_SEND_SGES(8). +Because ksmbd needs sges only for SMB direct +header, SMB2 transform header, SMB2 response, +and optional payload. + +Signed-off-by: Hyunchul Lee +Acked-by: Namjae Jeon +Reviewed-by: Tom Talpey +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/transport_rdma.c | 13 +++++-------- + 1 file changed, 5 insertions(+), 8 deletions(-) + +--- a/fs/ksmbd/transport_rdma.c ++++ b/fs/ksmbd/transport_rdma.c +@@ -1711,11 +1711,11 @@ static int smb_direct_init_params(struct + int max_send_sges, max_rw_wrs, max_send_wrs; + unsigned int max_sge_per_wr, wrs_per_credit; + +- /* need 2 more sge. because a SMB_DIRECT header will be mapped, +- * and maybe a send buffer could be not page aligned. ++ /* need 3 more sge. because a SMB_DIRECT header, SMB2 header, ++ * SMB2 response could be mapped. + */ + t->max_send_size = smb_direct_max_send_size; +- max_send_sges = DIV_ROUND_UP(t->max_send_size, PAGE_SIZE) + 2; ++ max_send_sges = DIV_ROUND_UP(t->max_send_size, PAGE_SIZE) + 3; + if (max_send_sges > SMB_DIRECT_MAX_SEND_SGES) { + pr_err("max_send_size %d is too large\n", t->max_send_size); + return -EINVAL; +@@ -1736,6 +1736,8 @@ static int smb_direct_init_params(struct + + max_sge_per_wr = min_t(unsigned int, device->attrs.max_send_sge, + device->attrs.max_sge_rd); ++ max_sge_per_wr = max_t(unsigned int, max_sge_per_wr, ++ max_send_sges); + wrs_per_credit = max_t(unsigned int, 4, + DIV_ROUND_UP(t->pages_per_rw_credit, + max_sge_per_wr) + 1); +@@ -1760,11 +1762,6 @@ static int smb_direct_init_params(struct + return -EINVAL; + } + +- if (device->attrs.max_send_sge < SMB_DIRECT_MAX_SEND_SGES) { +- pr_err("warning: device max_send_sge = %d too small\n", +- device->attrs.max_send_sge); +- return -EINVAL; +- } + if (device->attrs.max_recv_sge < SMB_DIRECT_MAX_RECV_SGES) { + pr_err("warning: device max_recv_sge = %d too small\n", + device->attrs.max_recv_sge); diff --git a/queue-5.15/ksmbd-smbd-remove-useless-license-text-when-spdx-license-identifier-is-already-used.patch b/queue-5.15/ksmbd-smbd-remove-useless-license-text-when-spdx-license-identifier-is-already-used.patch new file mode 100644 index 00000000000..f9d1906f755 --- /dev/null +++ b/queue-5.15/ksmbd-smbd-remove-useless-license-text-when-spdx-license-identifier-is-already-used.patch @@ -0,0 +1,42 @@ +From stable+bounces-7671-greg=kroah.com@vger.kernel.org Mon Dec 18 16:42:52 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:33:02 +0900 +Subject: ksmbd: smbd: Remove useless license text when SPDX-License-Identifier is already used +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Christophe JAILLET , Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-43-linkinjeon@kernel.org> + +From: Christophe JAILLET + +[ Upstream commit 06ee1c0aebd5dfdf6bf237165b22415f64f38b7c ] + +An SPDX-License-Identifier is already in place. There is no need to +duplicate part of the corresponding license. + +Signed-off-by: Christophe JAILLET +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/transport_rdma.c | 10 ---------- + 1 file changed, 10 deletions(-) + +--- a/fs/ksmbd/transport_rdma.c ++++ b/fs/ksmbd/transport_rdma.c +@@ -5,16 +5,6 @@ + * + * Author(s): Long Li , + * Hyunchul Lee +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See +- * the GNU General Public License for more details. + */ + + #define SUBMOD_NAME "smb_direct" diff --git a/queue-5.15/ksmbd-smbd-simplify-tracking-pending-packets.patch b/queue-5.15/ksmbd-smbd-simplify-tracking-pending-packets.patch new file mode 100644 index 00000000000..0cebe391d0c --- /dev/null +++ b/queue-5.15/ksmbd-smbd-simplify-tracking-pending-packets.patch @@ -0,0 +1,105 @@ +From linkinjeon@gmail.com Mon Dec 18 16:37:15 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:32:55 +0900 +Subject: ksmbd: smbd: simplify tracking pending packets +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Hyunchul Lee , Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-36-linkinjeon@kernel.org> + +From: Hyunchul Lee + +[ Upstream commit 11659a8ddbd9c4c1ab6f3b8f52837178ef121b20 ] + +Because we don't have to tracking pending packets +by dividing these into packets with payload and +packets without payload, merge the tracking code. + +Signed-off-by: Hyunchul Lee +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/transport_rdma.c | 34 +++++++--------------------------- + 1 file changed, 7 insertions(+), 27 deletions(-) + +--- a/fs/ksmbd/transport_rdma.c ++++ b/fs/ksmbd/transport_rdma.c +@@ -157,8 +157,6 @@ struct smb_direct_transport { + mempool_t *recvmsg_mempool; + struct kmem_cache *recvmsg_cache; + +- wait_queue_head_t wait_send_payload_pending; +- atomic_t send_payload_pending; + wait_queue_head_t wait_send_pending; + atomic_t send_pending; + +@@ -392,8 +390,6 @@ static struct smb_direct_transport *allo + spin_lock_init(&t->empty_recvmsg_queue_lock); + INIT_LIST_HEAD(&t->empty_recvmsg_queue); + +- init_waitqueue_head(&t->wait_send_payload_pending); +- atomic_set(&t->send_payload_pending, 0); + init_waitqueue_head(&t->wait_send_pending); + atomic_set(&t->send_pending, 0); + +@@ -423,8 +419,6 @@ static void free_transport(struct smb_di + wake_up_interruptible(&t->wait_send_credits); + + ksmbd_debug(RDMA, "wait for all send posted to IB to finish\n"); +- wait_event(t->wait_send_payload_pending, +- atomic_read(&t->send_payload_pending) == 0); + wait_event(t->wait_send_pending, + atomic_read(&t->send_pending) == 0); + +@@ -879,13 +873,8 @@ static void send_done(struct ib_cq *cq, + smb_direct_disconnect_rdma_connection(t); + } + +- if (sendmsg->num_sge > 1) { +- if (atomic_dec_and_test(&t->send_payload_pending)) +- wake_up(&t->wait_send_payload_pending); +- } else { +- if (atomic_dec_and_test(&t->send_pending)) +- wake_up(&t->wait_send_pending); +- } ++ if (atomic_dec_and_test(&t->send_pending)) ++ wake_up(&t->wait_send_pending); + + /* iterate and free the list of messages in reverse. the list's head + * is invalid. +@@ -917,21 +906,12 @@ static int smb_direct_post_send(struct s + { + int ret; + +- if (wr->num_sge > 1) +- atomic_inc(&t->send_payload_pending); +- else +- atomic_inc(&t->send_pending); +- ++ atomic_inc(&t->send_pending); + ret = ib_post_send(t->qp, wr, NULL); + if (ret) { + pr_err("failed to post send: %d\n", ret); +- if (wr->num_sge > 1) { +- if (atomic_dec_and_test(&t->send_payload_pending)) +- wake_up(&t->wait_send_payload_pending); +- } else { +- if (atomic_dec_and_test(&t->send_pending)) +- wake_up(&t->wait_send_pending); +- } ++ if (atomic_dec_and_test(&t->send_pending)) ++ wake_up(&t->wait_send_pending); + smb_direct_disconnect_rdma_connection(t); + } + return ret; +@@ -1332,8 +1312,8 @@ done: + * that means all the I/Os have been out and we are good to return + */ + +- wait_event(st->wait_send_payload_pending, +- atomic_read(&st->send_payload_pending) == 0); ++ wait_event(st->wait_send_pending, ++ atomic_read(&st->send_pending) == 0); + return ret; + } + diff --git a/queue-5.15/ksmbd-smbd-validate-buffer-descriptor-structures.patch b/queue-5.15/ksmbd-smbd-validate-buffer-descriptor-structures.patch new file mode 100644 index 00000000000..8a7f0a016a8 --- /dev/null +++ b/queue-5.15/ksmbd-smbd-validate-buffer-descriptor-structures.patch @@ -0,0 +1,93 @@ +From linkinjeon@gmail.com Mon Dec 18 16:36:36 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:32:43 +0900 +Subject: ksmbd: smbd: validate buffer descriptor structures +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Hyunchul Lee , Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-24-linkinjeon@kernel.org> + +From: Hyunchul Lee + +[ Upstream commit 6d896d3b44cf64ab9b2483697e222098e7b72f70 ] + +Check ChannelInfoOffset and ChannelInfoLength +to validate buffer descriptor structures. +And add a debug log to print the structures' +content. + +Acked-by: Namjae Jeon +Signed-off-by: Hyunchul Lee +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/smb2pdu.c | 36 ++++++++++++++++++++++++++++++------ + 1 file changed, 30 insertions(+), 6 deletions(-) + +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -6209,13 +6209,26 @@ static int smb2_set_remote_key_for_rdma( + __le16 ChannelInfoOffset, + __le16 ChannelInfoLength) + { ++ unsigned int i, ch_count; ++ + if (work->conn->dialect == SMB30_PROT_ID && + Channel != SMB2_CHANNEL_RDMA_V1) + return -EINVAL; + +- if (ChannelInfoOffset == 0 || +- le16_to_cpu(ChannelInfoLength) < sizeof(*desc)) ++ ch_count = le16_to_cpu(ChannelInfoLength) / sizeof(*desc); ++ if (ksmbd_debug_types & KSMBD_DEBUG_RDMA) { ++ for (i = 0; i < ch_count; i++) { ++ pr_info("RDMA r/w request %#x: token %#x, length %#x\n", ++ i, ++ le32_to_cpu(desc[i].token), ++ le32_to_cpu(desc[i].length)); ++ } ++ } ++ if (ch_count != 1) { ++ ksmbd_debug(RDMA, "RDMA multiple buffer descriptors %d are not supported yet\n", ++ ch_count); + return -EINVAL; ++ } + + work->need_invalidate_rkey = + (Channel == SMB2_CHANNEL_RDMA_V1_INVALIDATE); +@@ -6273,9 +6286,15 @@ int smb2_read(struct ksmbd_work *work) + + if (req->Channel == SMB2_CHANNEL_RDMA_V1_INVALIDATE || + req->Channel == SMB2_CHANNEL_RDMA_V1) { ++ unsigned int ch_offset = le16_to_cpu(req->ReadChannelInfoOffset); ++ ++ if (ch_offset < offsetof(struct smb2_read_req, Buffer)) { ++ err = -EINVAL; ++ goto out; ++ } + err = smb2_set_remote_key_for_rdma(work, + (struct smb2_buffer_desc_v1 *) +- &req->Buffer[0], ++ ((char *)req + ch_offset), + req->Channel, + req->ReadChannelInfoOffset, + req->ReadChannelInfoLength); +@@ -6516,11 +6535,16 @@ int smb2_write(struct ksmbd_work *work) + + if (req->Channel == SMB2_CHANNEL_RDMA_V1 || + req->Channel == SMB2_CHANNEL_RDMA_V1_INVALIDATE) { +- if (req->Length != 0 || req->DataOffset != 0) +- return -EINVAL; ++ unsigned int ch_offset = le16_to_cpu(req->WriteChannelInfoOffset); ++ ++ if (req->Length != 0 || req->DataOffset != 0 || ++ ch_offset < offsetof(struct smb2_write_req, Buffer)) { ++ err = -EINVAL; ++ goto out; ++ } + err = smb2_set_remote_key_for_rdma(work, + (struct smb2_buffer_desc_v1 *) +- &req->Buffer[0], ++ ((char *)req + ch_offset), + req->Channel, + req->WriteChannelInfoOffset, + req->WriteChannelInfoLength); diff --git a/queue-5.15/ksmbd-store-fids-as-opaque-u64-integers.patch b/queue-5.15/ksmbd-store-fids-as-opaque-u64-integers.patch new file mode 100644 index 00000000000..a666c34b08b --- /dev/null +++ b/queue-5.15/ksmbd-store-fids-as-opaque-u64-integers.patch @@ -0,0 +1,415 @@ +From linkinjeon@gmail.com Mon Dec 18 16:36:46 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:32:46 +0900 +Subject: ksmbd: store fids as opaque u64 integers +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, "Paulo Alcantara (SUSE)" , Tom Talpey , Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-27-linkinjeon@kernel.org> + +From: "Paulo Alcantara (SUSE)" + +[ Upstream commit 2d004c6cae567e33ab2e197757181c72a322451f ] + +There is no need to store the fids as le64 integers as they are opaque +to the client and only used for equality. + +Signed-off-by: Paulo Alcantara (SUSE) +Reviewed-by: Tom Talpey +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/smb2pdu.c | 94 +++++++++++++++++++++-------------------------------- + fs/ksmbd/smb2pdu.h | 34 +++++++++---------- + 2 files changed, 56 insertions(+), 72 deletions(-) + +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -392,12 +392,8 @@ static void init_chained_smb2_rsp(struct + * command in the compound request + */ + if (req->Command == SMB2_CREATE && rsp->Status == STATUS_SUCCESS) { +- work->compound_fid = +- le64_to_cpu(((struct smb2_create_rsp *)rsp)-> +- VolatileFileId); +- work->compound_pfid = +- le64_to_cpu(((struct smb2_create_rsp *)rsp)-> +- PersistentFileId); ++ work->compound_fid = ((struct smb2_create_rsp *)rsp)->VolatileFileId; ++ work->compound_pfid = ((struct smb2_create_rsp *)rsp)->PersistentFileId; + work->compound_sid = le64_to_cpu(rsp->SessionId); + } + +@@ -2192,7 +2188,7 @@ static noinline int create_smb2_pipe(str + rsp->EndofFile = cpu_to_le64(0); + rsp->FileAttributes = ATTR_NORMAL_LE; + rsp->Reserved2 = 0; +- rsp->VolatileFileId = cpu_to_le64(id); ++ rsp->VolatileFileId = id; + rsp->PersistentFileId = 0; + rsp->CreateContextsOffset = 0; + rsp->CreateContextsLength = 0; +@@ -3230,8 +3226,8 @@ int smb2_open(struct ksmbd_work *work) + + rsp->Reserved2 = 0; + +- rsp->PersistentFileId = cpu_to_le64(fp->persistent_id); +- rsp->VolatileFileId = cpu_to_le64(fp->volatile_id); ++ rsp->PersistentFileId = fp->persistent_id; ++ rsp->VolatileFileId = fp->volatile_id; + + rsp->CreateContextsOffset = 0; + rsp->CreateContextsLength = 0; +@@ -3939,9 +3935,7 @@ int smb2_query_dir(struct ksmbd_work *wo + goto err_out2; + } + +- dir_fp = ksmbd_lookup_fd_slow(work, +- le64_to_cpu(req->VolatileFileId), +- le64_to_cpu(req->PersistentFileId)); ++ dir_fp = ksmbd_lookup_fd_slow(work, req->VolatileFileId, req->PersistentFileId); + if (!dir_fp) { + rc = -EBADF; + goto err_out2; +@@ -4169,12 +4163,12 @@ static int smb2_get_info_file_pipe(struc + * Windows can sometime send query file info request on + * pipe without opening it, checking error condition here + */ +- id = le64_to_cpu(req->VolatileFileId); ++ id = req->VolatileFileId; + if (!ksmbd_session_rpc_method(sess, id)) + return -ENOENT; + + ksmbd_debug(SMB, "FileInfoClass %u, FileId 0x%llx\n", +- req->FileInfoClass, le64_to_cpu(req->VolatileFileId)); ++ req->FileInfoClass, req->VolatileFileId); + + switch (req->FileInfoClass) { + case FILE_STANDARD_INFORMATION: +@@ -4804,7 +4798,7 @@ static int smb2_get_info_file(struct ksm + } + + if (work->next_smb2_rcv_hdr_off) { +- if (!has_file_id(le64_to_cpu(req->VolatileFileId))) { ++ if (!has_file_id(req->VolatileFileId)) { + ksmbd_debug(SMB, "Compound request set FID = %llu\n", + work->compound_fid); + id = work->compound_fid; +@@ -4813,8 +4807,8 @@ static int smb2_get_info_file(struct ksm + } + + if (!has_file_id(id)) { +- id = le64_to_cpu(req->VolatileFileId); +- pid = le64_to_cpu(req->PersistentFileId); ++ id = req->VolatileFileId; ++ pid = req->PersistentFileId; + } + + fp = ksmbd_lookup_fd_slow(work, id, pid); +@@ -5188,7 +5182,7 @@ static int smb2_get_info_sec(struct ksmb + } + + if (work->next_smb2_rcv_hdr_off) { +- if (!has_file_id(le64_to_cpu(req->VolatileFileId))) { ++ if (!has_file_id(req->VolatileFileId)) { + ksmbd_debug(SMB, "Compound request set FID = %llu\n", + work->compound_fid); + id = work->compound_fid; +@@ -5197,8 +5191,8 @@ static int smb2_get_info_sec(struct ksmb + } + + if (!has_file_id(id)) { +- id = le64_to_cpu(req->VolatileFileId); +- pid = le64_to_cpu(req->PersistentFileId); ++ id = req->VolatileFileId; ++ pid = req->PersistentFileId; + } + + fp = ksmbd_lookup_fd_slow(work, id, pid); +@@ -5299,7 +5293,7 @@ static noinline int smb2_close_pipe(stru + struct smb2_close_req *req = smb2_get_msg(work->request_buf); + struct smb2_close_rsp *rsp = smb2_get_msg(work->response_buf); + +- id = le64_to_cpu(req->VolatileFileId); ++ id = req->VolatileFileId; + ksmbd_session_rpc_close(work->sess, id); + + rsp->StructureSize = cpu_to_le16(60); +@@ -5358,7 +5352,7 @@ int smb2_close(struct ksmbd_work *work) + } + + if (work->next_smb2_rcv_hdr_off && +- !has_file_id(le64_to_cpu(req->VolatileFileId))) { ++ !has_file_id(req->VolatileFileId)) { + if (!has_file_id(work->compound_fid)) { + /* file already closed, return FILE_CLOSED */ + ksmbd_debug(SMB, "file already closed\n"); +@@ -5377,7 +5371,7 @@ int smb2_close(struct ksmbd_work *work) + work->compound_pfid = KSMBD_NO_FID; + } + } else { +- volatile_id = le64_to_cpu(req->VolatileFileId); ++ volatile_id = req->VolatileFileId; + } + ksmbd_debug(SMB, "volatile_id = %llu\n", volatile_id); + +@@ -6070,7 +6064,7 @@ int smb2_set_info(struct ksmbd_work *wor + if (work->next_smb2_rcv_hdr_off) { + req = ksmbd_req_buf_next(work); + rsp = ksmbd_resp_buf_next(work); +- if (!has_file_id(le64_to_cpu(req->VolatileFileId))) { ++ if (!has_file_id(req->VolatileFileId)) { + ksmbd_debug(SMB, "Compound request set FID = %llu\n", + work->compound_fid); + id = work->compound_fid; +@@ -6082,8 +6076,8 @@ int smb2_set_info(struct ksmbd_work *wor + } + + if (!has_file_id(id)) { +- id = le64_to_cpu(req->VolatileFileId); +- pid = le64_to_cpu(req->PersistentFileId); ++ id = req->VolatileFileId; ++ pid = req->PersistentFileId; + } + + fp = ksmbd_lookup_fd_slow(work, id, pid); +@@ -6161,7 +6155,7 @@ static noinline int smb2_read_pipe(struc + struct smb2_read_req *req = smb2_get_msg(work->request_buf); + struct smb2_read_rsp *rsp = smb2_get_msg(work->response_buf); + +- id = le64_to_cpu(req->VolatileFileId); ++ id = req->VolatileFileId; + + inc_rfc1001_len(work->response_buf, 16); + rpc_resp = ksmbd_rpc_read(work->sess, id); +@@ -6302,8 +6296,7 @@ int smb2_read(struct ksmbd_work *work) + goto out; + } + +- fp = ksmbd_lookup_fd_slow(work, le64_to_cpu(req->VolatileFileId), +- le64_to_cpu(req->PersistentFileId)); ++ fp = ksmbd_lookup_fd_slow(work, req->VolatileFileId, req->PersistentFileId); + if (!fp) { + err = -ENOENT; + goto out; +@@ -6422,7 +6415,7 @@ static noinline int smb2_write_pipe(stru + size_t length; + + length = le32_to_cpu(req->Length); +- id = le64_to_cpu(req->VolatileFileId); ++ id = req->VolatileFileId; + + if (le16_to_cpu(req->DataOffset) == + offsetof(struct smb2_write_req, Buffer)) { +@@ -6558,8 +6551,7 @@ int smb2_write(struct ksmbd_work *work) + goto out; + } + +- fp = ksmbd_lookup_fd_slow(work, le64_to_cpu(req->VolatileFileId), +- le64_to_cpu(req->PersistentFileId)); ++ fp = ksmbd_lookup_fd_slow(work, req->VolatileFileId, req->PersistentFileId); + if (!fp) { + err = -ENOENT; + goto out; +@@ -6668,12 +6660,9 @@ int smb2_flush(struct ksmbd_work *work) + + WORK_BUFFERS(work, req, rsp); + +- ksmbd_debug(SMB, "SMB2_FLUSH called for fid %llu\n", +- le64_to_cpu(req->VolatileFileId)); ++ ksmbd_debug(SMB, "SMB2_FLUSH called for fid %llu\n", req->VolatileFileId); + +- err = ksmbd_vfs_fsync(work, +- le64_to_cpu(req->VolatileFileId), +- le64_to_cpu(req->PersistentFileId)); ++ err = ksmbd_vfs_fsync(work, req->VolatileFileId, req->PersistentFileId); + if (err) + goto out; + +@@ -6888,12 +6877,9 @@ int smb2_lock(struct ksmbd_work *work) + int prior_lock = 0; + + ksmbd_debug(SMB, "Received lock request\n"); +- fp = ksmbd_lookup_fd_slow(work, +- le64_to_cpu(req->VolatileFileId), +- le64_to_cpu(req->PersistentFileId)); ++ fp = ksmbd_lookup_fd_slow(work, req->VolatileFileId, req->PersistentFileId); + if (!fp) { +- ksmbd_debug(SMB, "Invalid file id for lock : %llu\n", +- le64_to_cpu(req->VolatileFileId)); ++ ksmbd_debug(SMB, "Invalid file id for lock : %llu\n", req->VolatileFileId); + err = -ENOENT; + goto out2; + } +@@ -7249,8 +7235,8 @@ static int fsctl_copychunk(struct ksmbd_ + + ci_rsp = (struct copychunk_ioctl_rsp *)&rsp->Buffer[0]; + +- rsp->VolatileFileId = cpu_to_le64(volatile_id); +- rsp->PersistentFileId = cpu_to_le64(persistent_id); ++ rsp->VolatileFileId = volatile_id; ++ rsp->PersistentFileId = persistent_id; + ci_rsp->ChunksWritten = + cpu_to_le32(ksmbd_server_side_copy_max_chunk_count()); + ci_rsp->ChunkBytesWritten = +@@ -7464,8 +7450,8 @@ ipv6_retry: + if (nii_rsp) + nii_rsp->Next = 0; + +- rsp->PersistentFileId = cpu_to_le64(SMB2_NO_FID); +- rsp->VolatileFileId = cpu_to_le64(SMB2_NO_FID); ++ rsp->PersistentFileId = SMB2_NO_FID; ++ rsp->VolatileFileId = SMB2_NO_FID; + return nbytes; + } + +@@ -7635,9 +7621,7 @@ static int fsctl_request_resume_key(stru + { + struct ksmbd_file *fp; + +- fp = ksmbd_lookup_fd_slow(work, +- le64_to_cpu(req->VolatileFileId), +- le64_to_cpu(req->PersistentFileId)); ++ fp = ksmbd_lookup_fd_slow(work, req->VolatileFileId, req->PersistentFileId); + if (!fp) + return -ENOENT; + +@@ -7667,7 +7651,7 @@ int smb2_ioctl(struct ksmbd_work *work) + if (work->next_smb2_rcv_hdr_off) { + req = ksmbd_req_buf_next(work); + rsp = ksmbd_resp_buf_next(work); +- if (!has_file_id(le64_to_cpu(req->VolatileFileId))) { ++ if (!has_file_id(req->VolatileFileId)) { + ksmbd_debug(SMB, "Compound request set FID = %llu\n", + work->compound_fid); + id = work->compound_fid; +@@ -7678,7 +7662,7 @@ int smb2_ioctl(struct ksmbd_work *work) + } + + if (!has_file_id(id)) +- id = le64_to_cpu(req->VolatileFileId); ++ id = req->VolatileFileId; + + if (req->Flags != cpu_to_le32(SMB2_0_IOCTL_IS_FSCTL)) { + rsp->hdr.Status = STATUS_NOT_SUPPORTED; +@@ -7749,8 +7733,8 @@ int smb2_ioctl(struct ksmbd_work *work) + goto out; + + nbytes = sizeof(struct validate_negotiate_info_rsp); +- rsp->PersistentFileId = cpu_to_le64(SMB2_NO_FID); +- rsp->VolatileFileId = cpu_to_le64(SMB2_NO_FID); ++ rsp->PersistentFileId = SMB2_NO_FID; ++ rsp->VolatileFileId = SMB2_NO_FID; + break; + case FSCTL_QUERY_NETWORK_INTERFACE_INFO: + ret = fsctl_query_iface_info_ioctl(conn, rsp, out_buf_len); +@@ -7798,8 +7782,8 @@ int smb2_ioctl(struct ksmbd_work *work) + (struct copychunk_ioctl_req *)&req->Buffer[0], + le32_to_cpu(req->CntCode), + le32_to_cpu(req->InputCount), +- le64_to_cpu(req->VolatileFileId), +- le64_to_cpu(req->PersistentFileId), ++ req->VolatileFileId, ++ req->PersistentFileId, + rsp); + break; + case FSCTL_SET_SPARSE: +--- a/fs/ksmbd/smb2pdu.h ++++ b/fs/ksmbd/smb2pdu.h +@@ -634,8 +634,8 @@ struct create_durable_reconn_req { + union { + __u8 Reserved[16]; + struct { +- __le64 PersistentFileId; +- __le64 VolatileFileId; ++ __u64 PersistentFileId; ++ __u64 VolatileFileId; + } Fid; + } Data; + } __packed; +@@ -644,8 +644,8 @@ struct create_durable_reconn_v2_req { + struct create_context ccontext; + __u8 Name[8]; + struct { +- __le64 PersistentFileId; +- __le64 VolatileFileId; ++ __u64 PersistentFileId; ++ __u64 VolatileFileId; + } Fid; + __u8 CreateGuid[16]; + __le32 Flags; +@@ -889,8 +889,8 @@ struct smb2_ioctl_req { + __le16 StructureSize; /* Must be 57 */ + __le16 Reserved; /* offset from start of SMB2 header to write data */ + __le32 CntCode; +- __le64 PersistentFileId; +- __le64 VolatileFileId; ++ __u64 PersistentFileId; ++ __u64 VolatileFileId; + __le32 InputOffset; /* Reserved MBZ */ + __le32 InputCount; + __le32 MaxInputResponse; +@@ -907,8 +907,8 @@ struct smb2_ioctl_rsp { + __le16 StructureSize; /* Must be 49 */ + __le16 Reserved; /* offset from start of SMB2 header to write data */ + __le32 CntCode; +- __le64 PersistentFileId; +- __le64 VolatileFileId; ++ __u64 PersistentFileId; ++ __u64 VolatileFileId; + __le32 InputOffset; /* Reserved MBZ */ + __le32 InputCount; + __le32 OutputOffset; +@@ -977,7 +977,7 @@ struct file_object_buf_type1_ioctl_rsp { + } __packed; + + struct resume_key_ioctl_rsp { +- __le64 ResumeKey[3]; ++ __u64 ResumeKey[3]; + __le32 ContextLength; + __u8 Context[4]; /* ignored, Windows sets to 4 bytes of zero */ + } __packed; +@@ -1089,8 +1089,8 @@ struct smb2_lock_req { + __le16 StructureSize; /* Must be 48 */ + __le16 LockCount; + __le32 Reserved; +- __le64 PersistentFileId; +- __le64 VolatileFileId; ++ __u64 PersistentFileId; ++ __u64 VolatileFileId; + /* Followed by at least one */ + struct smb2_lock_element locks[1]; + } __packed; +@@ -1125,8 +1125,8 @@ struct smb2_query_directory_req { + __u8 FileInformationClass; + __u8 Flags; + __le32 FileIndex; +- __le64 PersistentFileId; +- __le64 VolatileFileId; ++ __u64 PersistentFileId; ++ __u64 VolatileFileId; + __le16 FileNameOffset; + __le16 FileNameLength; + __le32 OutputBufferLength; +@@ -1172,8 +1172,8 @@ struct smb2_query_info_req { + __le32 InputBufferLength; + __le32 AdditionalInformation; + __le32 Flags; +- __le64 PersistentFileId; +- __le64 VolatileFileId; ++ __u64 PersistentFileId; ++ __u64 VolatileFileId; + __u8 Buffer[1]; + } __packed; + +@@ -1194,8 +1194,8 @@ struct smb2_set_info_req { + __le16 BufferOffset; + __u16 Reserved; + __le32 AdditionalInformation; +- __le64 PersistentFileId; +- __le64 VolatileFileId; ++ __u64 PersistentFileId; ++ __u64 VolatileFileId; + __u8 Buffer[1]; + } __packed; + diff --git a/queue-5.15/ksmbd-switch-to-use-kmemdup_nul-helper.patch b/queue-5.15/ksmbd-switch-to-use-kmemdup_nul-helper.patch new file mode 100644 index 00000000000..921a645fe6d --- /dev/null +++ b/queue-5.15/ksmbd-switch-to-use-kmemdup_nul-helper.patch @@ -0,0 +1,39 @@ +From linkinjeon@gmail.com Mon Dec 18 16:41:41 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:34:18 +0900 +Subject: ksmbd: switch to use kmemdup_nul() helper +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Yang Yingliang , Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-119-linkinjeon@kernel.org> + +From: Yang Yingliang + +[ Upstream commit 084ba46fc41c21ba827fd92e61f78def7a6e52ea ] + +Use kmemdup_nul() helper instead of open-coding to +simplify the code. + +Acked-by: Namjae Jeon +Signed-off-by: Yang Yingliang +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/asn1.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +--- a/fs/ksmbd/asn1.c ++++ b/fs/ksmbd/asn1.c +@@ -214,12 +214,10 @@ static int ksmbd_neg_token_alloc(void *c + { + struct ksmbd_conn *conn = context; + +- conn->mechToken = kmalloc(vlen + 1, GFP_KERNEL); ++ conn->mechToken = kmemdup_nul(value, vlen, GFP_KERNEL); + if (!conn->mechToken) + return -ENOMEM; + +- memcpy(conn->mechToken, value, vlen); +- conn->mechToken[vlen] = '\0'; + return 0; + } + diff --git a/queue-5.15/ksmbd-update-kconfig-to-note-kerberos-support-and-fix-indentation.patch b/queue-5.15/ksmbd-update-kconfig-to-note-kerberos-support-and-fix-indentation.patch new file mode 100644 index 00000000000..9c20039a5cf --- /dev/null +++ b/queue-5.15/ksmbd-update-kconfig-to-note-kerberos-support-and-fix-indentation.patch @@ -0,0 +1,56 @@ +From linkinjeon@gmail.com Mon Dec 18 16:39:20 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:33:34 +0900 +Subject: ksmbd: update Kconfig to note Kerberos support and fix indentation +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Steve French , Namjae Jeon , David Howells +Message-ID: <20231218153454.8090-75-linkinjeon@kernel.org> + +From: Steve French + +[ Upstream commit d280a958f8b2b62610c280ecdf35d780e7922620 ] + +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 +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/Kconfig | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +--- 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 diff --git a/queue-5.15/ksmbd-use-f_setlk-when-unlocking-a-file.patch b/queue-5.15/ksmbd-use-f_setlk-when-unlocking-a-file.patch new file mode 100644 index 00000000000..76b62eec650 --- /dev/null +++ b/queue-5.15/ksmbd-use-f_setlk-when-unlocking-a-file.patch @@ -0,0 +1,48 @@ +From linkinjeon@gmail.com Mon Dec 18 16:38:55 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:33:26 +0900 +Subject: ksmbd: use F_SETLK when unlocking a file +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Jeff Layton , David Howells , Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-67-linkinjeon@kernel.org> + +From: Jeff Layton + +[ Upstream commit 7ecbe92696bb7fe32c80b6cf64736a0d157717a9 ] + +ksmbd seems to be trying to use a cmd value of 0 when unlocking a file. +That activity requires a type of F_UNLCK with a cmd of F_SETLK. For +local POSIX locking, it doesn't matter much since vfs_lock_file ignores +@cmd, but filesystems that define their own ->lock operation expect to +see it set sanely. + +Cc: David Howells +Signed-off-by: Jeff Layton +Reviewed-by: David Howells +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/smb2pdu.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -6803,7 +6803,7 @@ static int smb2_set_flock_flags(struct f + case SMB2_LOCKFLAG_UNLOCK: + ksmbd_debug(SMB, "received unlock request\n"); + flock->fl_type = F_UNLCK; +- cmd = 0; ++ cmd = F_SETLK; + break; + } + +@@ -7182,7 +7182,7 @@ out: + rlock->fl_start = smb_lock->start; + rlock->fl_end = smb_lock->end; + +- rc = vfs_lock_file(filp, 0, rlock, NULL); ++ rc = vfs_lock_file(filp, F_SETLK, rlock, NULL); + if (rc) + pr_err("rollback unlock fail : %d\n", rc); + diff --git a/queue-5.15/ksmbd-use-ksmbd_req_buf_next-in-ksmbd_verify_smb_message.patch b/queue-5.15/ksmbd-use-ksmbd_req_buf_next-in-ksmbd_verify_smb_message.patch new file mode 100644 index 00000000000..343293633a4 --- /dev/null +++ b/queue-5.15/ksmbd-use-ksmbd_req_buf_next-in-ksmbd_verify_smb_message.patch @@ -0,0 +1,33 @@ +From stable+bounces-7630-greg=kroah.com@vger.kernel.org Mon Dec 18 16:35:31 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:32:21 +0900 +Subject: ksmbd: use ksmbd_req_buf_next() in ksmbd_verify_smb_message() +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Ralph Boehme , Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-2-linkinjeon@kernel.org> + +From: Ralph Boehme + +[ Upstream commit a088ac859f8124d491f02a19d080fc5ee4dbd202 ] + +Use ksmbd_req_buf_next() in ksmbd_verify_smb_message(). + +Acked-by: Namjae Jeon +Signed-off-by: Ralph Boehme +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/smb_common.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/fs/ksmbd/smb_common.c ++++ b/fs/ksmbd/smb_common.c +@@ -134,7 +134,7 @@ int ksmbd_lookup_protocol_idx(char *str) + */ + int ksmbd_verify_smb_message(struct ksmbd_work *work) + { +- struct smb2_hdr *smb2_hdr = work->request_buf + work->next_smb2_rcv_hdr_off; ++ struct smb2_hdr *smb2_hdr = ksmbd_req_buf_next(work); + struct smb_hdr *hdr; + + if (smb2_hdr->ProtocolId == SMB2_PROTO_NUMBER) diff --git a/queue-5.15/ksmbd-use-kvzalloc-instead-of-kvmalloc.patch b/queue-5.15/ksmbd-use-kvzalloc-instead-of-kvmalloc.patch new file mode 100644 index 00000000000..3efdbefd9c4 --- /dev/null +++ b/queue-5.15/ksmbd-use-kvzalloc-instead-of-kvmalloc.patch @@ -0,0 +1,102 @@ +From linkinjeon@gmail.com Mon Dec 18 16:41:08 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:34:08 +0900 +Subject: ksmbd: use kvzalloc instead of kvmalloc +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , kernel test robot , Steve French +Message-ID: <20231218153454.8090-109-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit 81a94b27847f7d2e499415db14dd9dc7c22b19b0 ] + +Use kvzalloc instead of kvmalloc. + +Reported-by: kernel test robot +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/smb2pdu.c | 8 ++++---- + fs/ksmbd/transport_ipc.c | 4 ++-- + fs/ksmbd/vfs.c | 4 ++-- + 3 files changed, 8 insertions(+), 8 deletions(-) + +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -544,7 +544,7 @@ int smb2_allocate_rsp_buf(struct ksmbd_w + if (le32_to_cpu(hdr->NextCommand) > 0) + sz = large_sz; + +- work->response_buf = kvmalloc(sz, GFP_KERNEL | __GFP_ZERO); ++ work->response_buf = kvzalloc(sz, GFP_KERNEL); + if (!work->response_buf) + return -ENOMEM; + +@@ -6104,7 +6104,7 @@ static noinline int smb2_read_pipe(struc + } + + work->aux_payload_buf = +- kvmalloc(rpc_resp->payload_sz, GFP_KERNEL | __GFP_ZERO); ++ kvmalloc(rpc_resp->payload_sz, GFP_KERNEL); + if (!work->aux_payload_buf) { + err = -ENOMEM; + goto out; +@@ -6261,7 +6261,7 @@ int smb2_read(struct ksmbd_work *work) + ksmbd_debug(SMB, "filename %pD, offset %lld, len %zu\n", + fp->filp, offset, length); + +- work->aux_payload_buf = kvmalloc(length, GFP_KERNEL | __GFP_ZERO); ++ work->aux_payload_buf = kvzalloc(length, GFP_KERNEL); + if (!work->aux_payload_buf) { + err = -ENOMEM; + goto out; +@@ -6410,7 +6410,7 @@ static ssize_t smb2_write_rdma_channel(s + int ret; + ssize_t nbytes; + +- data_buf = kvmalloc(length, GFP_KERNEL | __GFP_ZERO); ++ data_buf = kvzalloc(length, GFP_KERNEL); + if (!data_buf) + return -ENOMEM; + +--- a/fs/ksmbd/transport_ipc.c ++++ b/fs/ksmbd/transport_ipc.c +@@ -228,7 +228,7 @@ static struct ksmbd_ipc_msg *ipc_msg_all + struct ksmbd_ipc_msg *msg; + size_t msg_sz = sz + sizeof(struct ksmbd_ipc_msg); + +- msg = kvmalloc(msg_sz, GFP_KERNEL | __GFP_ZERO); ++ msg = kvzalloc(msg_sz, GFP_KERNEL); + if (msg) + msg->sz = sz; + return msg; +@@ -267,7 +267,7 @@ static int handle_response(int type, voi + entry->type + 1, type); + } + +- entry->response = kvmalloc(sz, GFP_KERNEL | __GFP_ZERO); ++ entry->response = kvzalloc(sz, GFP_KERNEL); + if (!entry->response) { + ret = -ENOMEM; + break; +--- a/fs/ksmbd/vfs.c ++++ b/fs/ksmbd/vfs.c +@@ -436,7 +436,7 @@ static int ksmbd_vfs_stream_write(struct + } + + if (v_len < size) { +- wbuf = kvmalloc(size, GFP_KERNEL | __GFP_ZERO); ++ wbuf = kvzalloc(size, GFP_KERNEL); + if (!wbuf) { + err = -ENOMEM; + goto out; +@@ -853,7 +853,7 @@ ssize_t ksmbd_vfs_listxattr(struct dentr + if (size <= 0) + return size; + +- vlist = kvmalloc(size, GFP_KERNEL | __GFP_ZERO); ++ vlist = kvzalloc(size, GFP_KERNEL); + if (!vlist) + return -ENOMEM; + diff --git a/queue-5.15/ksmbd-use-kzalloc-instead-of-__gfp_zero.patch b/queue-5.15/ksmbd-use-kzalloc-instead-of-__gfp_zero.patch new file mode 100644 index 00000000000..7f0a62c9249 --- /dev/null +++ b/queue-5.15/ksmbd-use-kzalloc-instead-of-__gfp_zero.patch @@ -0,0 +1,36 @@ +From linkinjeon@gmail.com Mon Dec 18 16:40:59 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:34:05 +0900 +Subject: ksmbd: use kzalloc() instead of __GFP_ZERO +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , Dan Carpenter , Sergey Senozhatsky , Steve French +Message-ID: <20231218153454.8090-106-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit f87d4f85f43f0d4b12ef64b015478d8053e1a33e ] + +Use kzalloc() instead of __GFP_ZERO. + +Reported-by: Dan Carpenter +Signed-off-by: Namjae Jeon +Reviewed-by: Sergey Senozhatsky +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/smb_common.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/fs/ksmbd/smb_common.c ++++ b/fs/ksmbd/smb_common.c +@@ -359,8 +359,8 @@ static int smb1_check_user_session(struc + */ + static int smb1_allocate_rsp_buf(struct ksmbd_work *work) + { +- work->response_buf = kmalloc(MAX_CIFS_SMALL_BUFFER_SIZE, +- GFP_KERNEL | __GFP_ZERO); ++ work->response_buf = kzalloc(MAX_CIFS_SMALL_BUFFER_SIZE, ++ GFP_KERNEL); + work->response_sz = MAX_CIFS_SMALL_BUFFER_SIZE; + + if (!work->response_buf) { diff --git a/queue-5.15/ksmbd-use-netif_is_bridge_port.patch b/queue-5.15/ksmbd-use-netif_is_bridge_port.patch new file mode 100644 index 00000000000..c883705f740 --- /dev/null +++ b/queue-5.15/ksmbd-use-netif_is_bridge_port.patch @@ -0,0 +1,43 @@ +From linkinjeon@gmail.com Mon Dec 18 16:36:42 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:32:45 +0900 +Subject: ksmbd: use netif_is_bridge_port +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Tobias Klauser , Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-26-linkinjeon@kernel.org> + +From: Tobias Klauser + +[ Upstream commit 1b699bf3a8786f7d41eebd9f6ba673185fa5b6bd ] + +Use netif_is_bridge_port defined in instead of +open-coding it. + +Acked-by: Namjae Jeon +Signed-off-by: Tobias Klauser +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/transport_tcp.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/fs/ksmbd/transport_tcp.c ++++ b/fs/ksmbd/transport_tcp.c +@@ -505,7 +505,7 @@ static int ksmbd_netdev_event(struct not + + switch (event) { + case NETDEV_UP: +- if (netdev->priv_flags & IFF_BRIDGE_PORT) ++ if (netif_is_bridge_port(netdev)) + return NOTIFY_OK; + + list_for_each_entry(iface, &iface_list, entry) { +@@ -614,7 +614,7 @@ int ksmbd_tcp_set_interfaces(char *ifc_l + + rtnl_lock(); + for_each_netdev(&init_net, netdev) { +- if (netdev->priv_flags & IFF_BRIDGE_PORT) ++ if (netif_is_bridge_port(netdev)) + continue; + if (!alloc_iface(kstrdup(netdev->name, GFP_KERNEL))) + return -ENOMEM; diff --git a/queue-5.15/ksmbd-use-oid-registry-functions-to-decode-oids.patch b/queue-5.15/ksmbd-use-oid-registry-functions-to-decode-oids.patch new file mode 100644 index 00000000000..6af930dfa39 --- /dev/null +++ b/queue-5.15/ksmbd-use-oid-registry-functions-to-decode-oids.patch @@ -0,0 +1,211 @@ +From linkinjeon@gmail.com Mon Dec 18 16:35:44 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:32:28 +0900 +Subject: ksmbd: use oid registry functions to decode OIDs +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Hyunchul Lee , Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-9-linkinjeon@kernel.org> + +From: Hyunchul Lee + +[ Upstream commit 294277410cf3b46bee2b8282ab754e52975c0a70 ] + +Use look_up_OID to decode OIDs rather than +implementing functions. + +Acked-by: Namjae Jeon +Signed-off-by: Hyunchul Lee +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/asn1.c | 142 +++++++------------------------------------------------- + 1 file changed, 19 insertions(+), 123 deletions(-) + +--- a/fs/ksmbd/asn1.c ++++ b/fs/ksmbd/asn1.c +@@ -21,101 +21,11 @@ + #include "ksmbd_spnego_negtokeninit.asn1.h" + #include "ksmbd_spnego_negtokentarg.asn1.h" + +-#define SPNEGO_OID_LEN 7 + #define NTLMSSP_OID_LEN 10 +-#define KRB5_OID_LEN 7 +-#define KRB5U2U_OID_LEN 8 +-#define MSKRB5_OID_LEN 7 +-static unsigned long SPNEGO_OID[7] = { 1, 3, 6, 1, 5, 5, 2 }; +-static unsigned long NTLMSSP_OID[10] = { 1, 3, 6, 1, 4, 1, 311, 2, 2, 10 }; +-static unsigned long KRB5_OID[7] = { 1, 2, 840, 113554, 1, 2, 2 }; +-static unsigned long KRB5U2U_OID[8] = { 1, 2, 840, 113554, 1, 2, 2, 3 }; +-static unsigned long MSKRB5_OID[7] = { 1, 2, 840, 48018, 1, 2, 2 }; + + static char NTLMSSP_OID_STR[NTLMSSP_OID_LEN] = { 0x2b, 0x06, 0x01, 0x04, 0x01, + 0x82, 0x37, 0x02, 0x02, 0x0a }; + +-static bool +-asn1_subid_decode(const unsigned char **begin, const unsigned char *end, +- unsigned long *subid) +-{ +- const unsigned char *ptr = *begin; +- unsigned char ch; +- +- *subid = 0; +- +- do { +- if (ptr >= end) +- return false; +- +- ch = *ptr++; +- *subid <<= 7; +- *subid |= ch & 0x7F; +- } while ((ch & 0x80) == 0x80); +- +- *begin = ptr; +- return true; +-} +- +-static bool asn1_oid_decode(const unsigned char *value, size_t vlen, +- unsigned long **oid, size_t *oidlen) +-{ +- const unsigned char *iptr = value, *end = value + vlen; +- unsigned long *optr; +- unsigned long subid; +- +- vlen += 1; +- if (vlen < 2 || vlen > UINT_MAX / sizeof(unsigned long)) +- goto fail_nullify; +- +- *oid = kmalloc(vlen * sizeof(unsigned long), GFP_KERNEL); +- if (!*oid) +- return false; +- +- optr = *oid; +- +- if (!asn1_subid_decode(&iptr, end, &subid)) +- goto fail; +- +- if (subid < 40) { +- optr[0] = 0; +- optr[1] = subid; +- } else if (subid < 80) { +- optr[0] = 1; +- optr[1] = subid - 40; +- } else { +- optr[0] = 2; +- optr[1] = subid - 80; +- } +- +- *oidlen = 2; +- optr += 2; +- +- while (iptr < end) { +- if (++(*oidlen) > vlen) +- goto fail; +- +- if (!asn1_subid_decode(&iptr, end, optr++)) +- goto fail; +- } +- return true; +- +-fail: +- kfree(*oid); +-fail_nullify: +- *oid = NULL; +- return false; +-} +- +-static bool oid_eq(unsigned long *oid1, unsigned int oid1len, +- unsigned long *oid2, unsigned int oid2len) +-{ +- if (oid1len != oid2len) +- return false; +- +- return memcmp(oid1, oid2, oid1len) == 0; +-} +- + int + ksmbd_decode_negTokenInit(unsigned char *security_blob, int length, + struct ksmbd_conn *conn) +@@ -252,26 +162,18 @@ int build_spnego_ntlmssp_auth_blob(unsig + int ksmbd_gssapi_this_mech(void *context, size_t hdrlen, unsigned char tag, + const void *value, size_t vlen) + { +- unsigned long *oid; +- size_t oidlen; +- int err = 0; +- +- if (!asn1_oid_decode(value, vlen, &oid, &oidlen)) { +- err = -EBADMSG; +- goto out; +- } ++ enum OID oid; + +- if (!oid_eq(oid, oidlen, SPNEGO_OID, SPNEGO_OID_LEN)) +- err = -EBADMSG; +- kfree(oid); +-out: +- if (err) { ++ oid = look_up_OID(value, vlen); ++ if (oid != OID_spnego) { + char buf[50]; + + sprint_oid(value, vlen, buf, sizeof(buf)); + ksmbd_debug(AUTH, "Unexpected OID: %s\n", buf); ++ return -EBADMSG; + } +- return err; ++ ++ return 0; + } + + int ksmbd_neg_token_init_mech_type(void *context, size_t hdrlen, +@@ -279,37 +181,31 @@ int ksmbd_neg_token_init_mech_type(void + size_t vlen) + { + struct ksmbd_conn *conn = context; +- unsigned long *oid; +- size_t oidlen; ++ enum OID oid; + int mech_type; +- char buf[50]; +- +- if (!asn1_oid_decode(value, vlen, &oid, &oidlen)) +- goto fail; + +- if (oid_eq(oid, oidlen, NTLMSSP_OID, NTLMSSP_OID_LEN)) ++ oid = look_up_OID(value, vlen); ++ if (oid == OID_ntlmssp) { + mech_type = KSMBD_AUTH_NTLMSSP; +- else if (oid_eq(oid, oidlen, MSKRB5_OID, MSKRB5_OID_LEN)) ++ } else if (oid == OID_mskrb5) { + mech_type = KSMBD_AUTH_MSKRB5; +- else if (oid_eq(oid, oidlen, KRB5_OID, KRB5_OID_LEN)) ++ } else if (oid == OID_krb5) { + mech_type = KSMBD_AUTH_KRB5; +- else if (oid_eq(oid, oidlen, KRB5U2U_OID, KRB5U2U_OID_LEN)) ++ } else if (oid == OID_krb5u2u) { + mech_type = KSMBD_AUTH_KRB5U2U; +- else +- goto fail; ++ } else { ++ char buf[50]; ++ ++ sprint_oid(value, vlen, buf, sizeof(buf)); ++ ksmbd_debug(AUTH, "Unexpected OID: %s\n", buf); ++ return -EBADMSG; ++ } + + conn->auth_mechs |= mech_type; + if (conn->preferred_auth_mech == 0) + conn->preferred_auth_mech = mech_type; + +- kfree(oid); + return 0; +- +-fail: +- kfree(oid); +- sprint_oid(value, vlen, buf, sizeof(buf)); +- ksmbd_debug(AUTH, "Unexpected OID: %s\n", buf); +- return -EBADMSG; + } + + int ksmbd_neg_token_init_mech_token(void *context, size_t hdrlen, diff --git a/queue-5.15/ksmbd-use-struct_size-helper-in-ksmbd_negotiate_smb_dialect.patch b/queue-5.15/ksmbd-use-struct_size-helper-in-ksmbd_negotiate_smb_dialect.patch new file mode 100644 index 00000000000..751854c47d8 --- /dev/null +++ b/queue-5.15/ksmbd-use-struct_size-helper-in-ksmbd_negotiate_smb_dialect.patch @@ -0,0 +1,36 @@ +From linkinjeon@gmail.com Mon Dec 18 16:41:21 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:34:12 +0900 +Subject: ksmbd: Use struct_size() helper in ksmbd_negotiate_smb_dialect() +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, "Gustavo A. R. Silva" , Kees Cook , Namjae Jeon , Sergey Senozhatsky , Steve French +Message-ID: <20231218153454.8090-113-linkinjeon@kernel.org> + +From: "Gustavo A. R. Silva" + +[ Upstream commit 5211cc8727ed9701b04976ab47602955e5641bda ] + +Prefer struct_size() over open-coded versions. + +Link: https://github.com/KSPP/linux/issues/160 +Signed-off-by: Gustavo A. R. Silva +Reviewed-by: Kees Cook +Acked-by: Namjae Jeon +Reviewed-by: Sergey Senozhatsky +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/smb_common.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/fs/ksmbd/smb_common.c ++++ b/fs/ksmbd/smb_common.c +@@ -266,7 +266,7 @@ static int ksmbd_negotiate_smb_dialect(v + if (smb2_neg_size > smb_buf_length) + goto err_out; + +- if (smb2_neg_size + le16_to_cpu(req->DialectCount) * sizeof(__le16) > ++ if (struct_size(req, Dialects, le16_to_cpu(req->DialectCount)) > + smb_buf_length) + goto err_out; + diff --git a/queue-5.15/ksmbd-use-wait_event-instead-of-schedule_timeout.patch b/queue-5.15/ksmbd-use-wait_event-instead-of-schedule_timeout.patch new file mode 100644 index 00000000000..8560f43c08b --- /dev/null +++ b/queue-5.15/ksmbd-use-wait_event-instead-of-schedule_timeout.patch @@ -0,0 +1,156 @@ +From linkinjeon@gmail.com Mon Dec 18 16:37:48 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:33:05 +0900 +Subject: ksmbd: use wait_event instead of schedule_timeout() +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , Hyunchul Lee , Steve French +Message-ID: <20231218153454.8090-46-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit a14c573870a664386adc10526a6c2648ea56dae1 ] + +ksmbd threads eating masses of cputime when connection is disconnected. +If connection is disconnected, ksmbd thread waits for pending requests +to be processed using schedule_timeout. schedule_timeout() incorrectly +is used, and it is more efficient to use wait_event/wake_up than to check +r_count every time with timeout. + +Signed-off-by: Namjae Jeon +Reviewed-by: Hyunchul Lee +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/connection.c | 6 +++--- + fs/ksmbd/connection.h | 1 + + fs/ksmbd/oplock.c | 35 ++++++++++++++++++++++------------- + fs/ksmbd/server.c | 8 +++++++- + 4 files changed, 33 insertions(+), 17 deletions(-) + +--- a/fs/ksmbd/connection.c ++++ b/fs/ksmbd/connection.c +@@ -66,6 +66,7 @@ struct ksmbd_conn *ksmbd_conn_alloc(void + conn->outstanding_credits = 0; + + init_waitqueue_head(&conn->req_running_q); ++ init_waitqueue_head(&conn->r_count_q); + INIT_LIST_HEAD(&conn->conns_list); + INIT_LIST_HEAD(&conn->requests); + INIT_LIST_HEAD(&conn->async_requests); +@@ -165,7 +166,6 @@ int ksmbd_conn_write(struct ksmbd_work * + struct kvec iov[3]; + int iov_idx = 0; + +- ksmbd_conn_try_dequeue_request(work); + if (!work->response_buf) { + pr_err("NULL response header\n"); + return -EINVAL; +@@ -358,8 +358,8 @@ int ksmbd_conn_handler_loop(void *p) + + out: + /* Wait till all reference dropped to the Server object*/ +- while (atomic_read(&conn->r_count) > 0) +- schedule_timeout(HZ); ++ wait_event(conn->r_count_q, atomic_read(&conn->r_count) == 0); ++ + + unload_nls(conn->local_nls); + if (default_conn_ops.terminate_fn) +--- a/fs/ksmbd/connection.h ++++ b/fs/ksmbd/connection.h +@@ -58,6 +58,7 @@ struct ksmbd_conn { + unsigned int outstanding_credits; + spinlock_t credits_lock; + wait_queue_head_t req_running_q; ++ wait_queue_head_t r_count_q; + /* Lock to protect requests list*/ + spinlock_t request_lock; + struct list_head requests; +--- a/fs/ksmbd/oplock.c ++++ b/fs/ksmbd/oplock.c +@@ -616,18 +616,13 @@ static void __smb2_oplock_break_noti(str + struct ksmbd_file *fp; + + fp = ksmbd_lookup_durable_fd(br_info->fid); +- if (!fp) { +- atomic_dec(&conn->r_count); +- ksmbd_free_work_struct(work); +- return; +- } ++ if (!fp) ++ goto out; + + if (allocate_oplock_break_buf(work)) { + pr_err("smb2_allocate_rsp_buf failed! "); +- atomic_dec(&conn->r_count); + ksmbd_fd_put(work, fp); +- ksmbd_free_work_struct(work); +- return; ++ goto out; + } + + rsp_hdr = smb2_get_msg(work->response_buf); +@@ -668,8 +663,16 @@ static void __smb2_oplock_break_noti(str + + ksmbd_fd_put(work, fp); + ksmbd_conn_write(work); ++ ++out: + ksmbd_free_work_struct(work); +- atomic_dec(&conn->r_count); ++ /* ++ * Checking waitqueue to dropping pending requests on ++ * disconnection. waitqueue_active is safe because it ++ * uses atomic operation for condition. ++ */ ++ if (!atomic_dec_return(&conn->r_count) && waitqueue_active(&conn->r_count_q)) ++ wake_up(&conn->r_count_q); + } + + /** +@@ -732,9 +735,7 @@ static void __smb2_lease_break_noti(stru + + if (allocate_oplock_break_buf(work)) { + ksmbd_debug(OPLOCK, "smb2_allocate_rsp_buf failed! "); +- ksmbd_free_work_struct(work); +- atomic_dec(&conn->r_count); +- return; ++ goto out; + } + + rsp_hdr = smb2_get_msg(work->response_buf); +@@ -772,8 +773,16 @@ static void __smb2_lease_break_noti(stru + inc_rfc1001_len(work->response_buf, 44); + + ksmbd_conn_write(work); ++ ++out: + ksmbd_free_work_struct(work); +- atomic_dec(&conn->r_count); ++ /* ++ * Checking waitqueue to dropping pending requests on ++ * disconnection. waitqueue_active is safe because it ++ * uses atomic operation for condition. ++ */ ++ if (!atomic_dec_return(&conn->r_count) && waitqueue_active(&conn->r_count_q)) ++ wake_up(&conn->r_count_q); + } + + /** +--- a/fs/ksmbd/server.c ++++ b/fs/ksmbd/server.c +@@ -266,7 +266,13 @@ static void handle_ksmbd_work(struct wor + + ksmbd_conn_try_dequeue_request(work); + ksmbd_free_work_struct(work); +- atomic_dec(&conn->r_count); ++ /* ++ * Checking waitqueue to dropping pending requests on ++ * disconnection. waitqueue_active is safe because it ++ * uses atomic operation for condition. ++ */ ++ if (!atomic_dec_return(&conn->r_count) && waitqueue_active(&conn->r_count_q)) ++ wake_up(&conn->r_count_q); + } + + /** diff --git a/queue-5.15/ksmbd-validate-length-in-smb2_write.patch b/queue-5.15/ksmbd-validate-length-in-smb2_write.patch new file mode 100644 index 00000000000..29eebb61f00 --- /dev/null +++ b/queue-5.15/ksmbd-validate-length-in-smb2_write.patch @@ -0,0 +1,95 @@ +From linkinjeon@gmail.com Mon Dec 18 16:37:06 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:32:52 +0900 +Subject: ksmbd: validate length in smb2_write() +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , Marios Makassikis , Steve French +Message-ID: <20231218153454.8090-33-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit 158a66b245739e15858de42c0ba60fcf3de9b8e6 ] + +The SMB2 Write packet contains data that is to be written +to a file or to a pipe. Depending on the client, there may +be padding between the header and the data field. +Currently, the length is validated only in the case padding +is present. + +Since the DataOffset field always points to the beginning +of the data, there is no need to have a special case for +padding. By removing this, the length is validated in both +cases. + +Signed-off-by: Marios Makassikis +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Namjae Jeon +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/smb2pdu.c | 42 ++++++++++++++++-------------------------- + 1 file changed, 16 insertions(+), 26 deletions(-) + +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -6410,23 +6410,18 @@ static noinline int smb2_write_pipe(stru + length = le32_to_cpu(req->Length); + id = req->VolatileFileId; + +- if (le16_to_cpu(req->DataOffset) == +- offsetof(struct smb2_write_req, Buffer)) { +- data_buf = (char *)&req->Buffer[0]; +- } else { +- if ((u64)le16_to_cpu(req->DataOffset) + length > +- get_rfc1002_len(work->request_buf)) { +- pr_err("invalid write data offset %u, smb_len %u\n", +- le16_to_cpu(req->DataOffset), +- get_rfc1002_len(work->request_buf)); +- err = -EINVAL; +- goto out; +- } +- +- data_buf = (char *)(((char *)&req->hdr.ProtocolId) + +- le16_to_cpu(req->DataOffset)); ++ if ((u64)le16_to_cpu(req->DataOffset) + length > ++ get_rfc1002_len(work->request_buf)) { ++ pr_err("invalid write data offset %u, smb_len %u\n", ++ le16_to_cpu(req->DataOffset), ++ get_rfc1002_len(work->request_buf)); ++ err = -EINVAL; ++ goto out; + } + ++ data_buf = (char *)(((char *)&req->hdr.ProtocolId) + ++ le16_to_cpu(req->DataOffset)); ++ + rpc_resp = ksmbd_rpc_write(work->sess, id, data_buf, length); + if (rpc_resp) { + if (rpc_resp->flags == KSMBD_RPC_ENOTIMPLEMENTED) { +@@ -6571,20 +6566,15 @@ int smb2_write(struct ksmbd_work *work) + + if (req->Channel != SMB2_CHANNEL_RDMA_V1 && + req->Channel != SMB2_CHANNEL_RDMA_V1_INVALIDATE) { +- if (le16_to_cpu(req->DataOffset) == ++ if (le16_to_cpu(req->DataOffset) < + offsetof(struct smb2_write_req, Buffer)) { +- data_buf = (char *)&req->Buffer[0]; +- } else { +- if (le16_to_cpu(req->DataOffset) < +- offsetof(struct smb2_write_req, Buffer)) { +- err = -EINVAL; +- goto out; +- } +- +- data_buf = (char *)(((char *)&req->hdr.ProtocolId) + +- le16_to_cpu(req->DataOffset)); ++ err = -EINVAL; ++ goto out; + } + ++ data_buf = (char *)(((char *)&req->hdr.ProtocolId) + ++ le16_to_cpu(req->DataOffset)); ++ + ksmbd_debug(SMB, "flags %u\n", le32_to_cpu(req->Flags)); + if (le32_to_cpu(req->Flags) & SMB2_WRITEFLAG_WRITE_THROUGH) + writethrough = true; diff --git a/queue-5.15/ksmbd-validate-session-id-and-tree-id-in-compound-request.patch b/queue-5.15/ksmbd-validate-session-id-and-tree-id-in-compound-request.patch new file mode 100644 index 00000000000..6abf894d3ac --- /dev/null +++ b/queue-5.15/ksmbd-validate-session-id-and-tree-id-in-compound-request.patch @@ -0,0 +1,70 @@ +From linkinjeon@gmail.com Mon Dec 18 16:41:36 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:34:16 +0900 +Subject: ksmbd: validate session id and tree id in compound request +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , zdi-disclosures@trendmicro.com, Steve French +Message-ID: <20231218153454.8090-117-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit 3df0411e132ee74a87aa13142dfd2b190275332e ] + +`smb2_get_msg()` in smb2_get_ksmbd_tcon() and smb2_check_user_session() +will always return the first request smb2 header in a compound request. +if `SMB2_TREE_CONNECT_HE` is the first command in compound request, will +return 0, i.e. The tree id check is skipped. +This patch use ksmbd_req_buf_next() to get current command in compound. + +Reported-by: zdi-disclosures@trendmicro.com # ZDI-CAN-21506 +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/smb2pdu.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -87,9 +87,9 @@ struct channel *lookup_chann_list(struct + */ + int smb2_get_ksmbd_tcon(struct ksmbd_work *work) + { +- struct smb2_hdr *req_hdr = smb2_get_msg(work->request_buf); ++ struct smb2_hdr *req_hdr = ksmbd_req_buf_next(work); + unsigned int cmd = le16_to_cpu(req_hdr->Command); +- int tree_id; ++ unsigned int tree_id; + + if (cmd == SMB2_TREE_CONNECT_HE || + cmd == SMB2_CANCEL_HE || +@@ -114,7 +114,7 @@ int smb2_get_ksmbd_tcon(struct ksmbd_wor + pr_err("The first operation in the compound does not have tcon\n"); + return -EINVAL; + } +- if (work->tcon->id != tree_id) { ++ if (tree_id != UINT_MAX && work->tcon->id != tree_id) { + pr_err("tree id(%u) is different with id(%u) in first operation\n", + tree_id, work->tcon->id); + return -EINVAL; +@@ -560,9 +560,9 @@ int smb2_allocate_rsp_buf(struct ksmbd_w + */ + int smb2_check_user_session(struct ksmbd_work *work) + { +- struct smb2_hdr *req_hdr = smb2_get_msg(work->request_buf); ++ struct smb2_hdr *req_hdr = ksmbd_req_buf_next(work); + struct ksmbd_conn *conn = work->conn; +- unsigned int cmd = conn->ops->get_cmd_val(work); ++ unsigned int cmd = le16_to_cpu(req_hdr->Command); + unsigned long long sess_id; + + /* +@@ -588,7 +588,7 @@ int smb2_check_user_session(struct ksmbd + pr_err("The first operation in the compound does not have sess\n"); + return -EINVAL; + } +- if (work->sess->id != sess_id) { ++ if (sess_id != ULLONG_MAX && work->sess->id != sess_id) { + pr_err("session id(%llu) is different with the first operation(%lld)\n", + sess_id, work->sess->id); + return -EINVAL; diff --git a/queue-5.15/ksmbd-validate-share-name-from-share-config-response.patch b/queue-5.15/ksmbd-validate-share-name-from-share-config-response.patch new file mode 100644 index 00000000000..0017c95ade3 --- /dev/null +++ b/queue-5.15/ksmbd-validate-share-name-from-share-config-response.patch @@ -0,0 +1,177 @@ +From linkinjeon@gmail.com Mon Dec 18 16:38:46 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:33:23 +0900 +Subject: ksmbd: validate share name from share config response +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, "Atte Heikkilä" , "Tom Talpey" , "Namjae Jeon" , "Steve French" +Message-ID: <20231218153454.8090-64-linkinjeon@kernel.org> + +From: Atte Heikkilä + +[ Upstream commit f5ba1cdaf5eb380e148183bda06d4844b457d095 ] + +Share config response may contain the share name without casefolding as +it is known to the user space daemon. When it is present, casefold and +compare it to the share name the share config request was made with. If +they differ, we have a share config which is incompatible with the way +share config caching is done. This is the case when CONFIG_UNICODE is +not set, the share name contains non-ASCII characters, and those non- +ASCII characters do not match those in the share name known to user +space. In other words, when CONFIG_UNICODE is not set, UTF-8 share +names now work but are only case-insensitive in the ASCII range. + +Signed-off-by: Atte Heikkilä +Acked-by: Tom Talpey +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/ksmbd_netlink.h | 3 ++- + fs/ksmbd/mgmt/share_config.c | 22 +++++++++++++++++++--- + fs/ksmbd/mgmt/share_config.h | 4 +++- + fs/ksmbd/mgmt/tree_connect.c | 4 ++-- + fs/ksmbd/misc.c | 4 ++-- + fs/ksmbd/misc.h | 1 + + 6 files changed, 29 insertions(+), 9 deletions(-) + +--- a/fs/ksmbd/ksmbd_netlink.h ++++ b/fs/ksmbd/ksmbd_netlink.h +@@ -164,7 +164,8 @@ struct ksmbd_share_config_response { + __u16 force_directory_mode; + __u16 force_uid; + __u16 force_gid; +- __u32 reserved[128]; /* Reserved room */ ++ __s8 share_name[KSMBD_REQ_MAX_SHARE_NAME]; ++ __u32 reserved[112]; /* Reserved room */ + __u32 veto_list_sz; + __s8 ____payload[]; + }; +--- a/fs/ksmbd/mgmt/share_config.c ++++ b/fs/ksmbd/mgmt/share_config.c +@@ -16,6 +16,7 @@ + #include "user_config.h" + #include "user_session.h" + #include "../transport_ipc.h" ++#include "../misc.h" + + #define SHARE_HASH_BITS 3 + static DEFINE_HASHTABLE(shares_table, SHARE_HASH_BITS); +@@ -119,7 +120,8 @@ static int parse_veto_list(struct ksmbd_ + return 0; + } + +-static struct ksmbd_share_config *share_config_request(const char *name) ++static struct ksmbd_share_config *share_config_request(struct unicode_map *um, ++ const char *name) + { + struct ksmbd_share_config_response *resp; + struct ksmbd_share_config *share = NULL; +@@ -133,6 +135,19 @@ static struct ksmbd_share_config *share_ + if (resp->flags == KSMBD_SHARE_FLAG_INVALID) + goto out; + ++ if (*resp->share_name) { ++ char *cf_resp_name; ++ bool equal; ++ ++ cf_resp_name = ksmbd_casefold_sharename(um, resp->share_name); ++ if (IS_ERR(cf_resp_name)) ++ goto out; ++ equal = !strcmp(cf_resp_name, name); ++ kfree(cf_resp_name); ++ if (!equal) ++ goto out; ++ } ++ + share = kzalloc(sizeof(struct ksmbd_share_config), GFP_KERNEL); + if (!share) + goto out; +@@ -190,7 +205,8 @@ out: + return share; + } + +-struct ksmbd_share_config *ksmbd_share_config_get(const char *name) ++struct ksmbd_share_config *ksmbd_share_config_get(struct unicode_map *um, ++ const char *name) + { + struct ksmbd_share_config *share; + +@@ -202,7 +218,7 @@ struct ksmbd_share_config *ksmbd_share_c + + if (share) + return share; +- return share_config_request(name); ++ return share_config_request(um, name); + } + + bool ksmbd_share_veto_filename(struct ksmbd_share_config *share, +--- a/fs/ksmbd/mgmt/share_config.h ++++ b/fs/ksmbd/mgmt/share_config.h +@@ -9,6 +9,7 @@ + #include + #include + #include ++#include + + struct ksmbd_share_config { + char *name; +@@ -74,7 +75,8 @@ static inline void ksmbd_share_config_pu + __ksmbd_share_config_put(share); + } + +-struct ksmbd_share_config *ksmbd_share_config_get(const char *name); ++struct ksmbd_share_config *ksmbd_share_config_get(struct unicode_map *um, ++ const char *name); + bool ksmbd_share_veto_filename(struct ksmbd_share_config *share, + const char *filename); + #endif /* __SHARE_CONFIG_MANAGEMENT_H__ */ +--- a/fs/ksmbd/mgmt/tree_connect.c ++++ b/fs/ksmbd/mgmt/tree_connect.c +@@ -26,7 +26,7 @@ ksmbd_tree_conn_connect(struct ksmbd_con + struct sockaddr *peer_addr; + int ret; + +- sc = ksmbd_share_config_get(share_name); ++ sc = ksmbd_share_config_get(conn->um, share_name); + if (!sc) + return status; + +@@ -61,7 +61,7 @@ ksmbd_tree_conn_connect(struct ksmbd_con + struct ksmbd_share_config *new_sc; + + ksmbd_share_config_del(sc); +- new_sc = ksmbd_share_config_get(share_name); ++ new_sc = ksmbd_share_config_get(conn->um, share_name); + if (!new_sc) { + pr_err("Failed to update stale share config\n"); + status.ret = -ESTALE; +--- a/fs/ksmbd/misc.c ++++ b/fs/ksmbd/misc.c +@@ -227,7 +227,7 @@ void ksmbd_conv_path_to_windows(char *pa + strreplace(path, '/', '\\'); + } + +-static char *casefold_sharename(struct unicode_map *um, const char *name) ++char *ksmbd_casefold_sharename(struct unicode_map *um, const char *name) + { + char *cf_name; + int cf_len; +@@ -273,7 +273,7 @@ char *ksmbd_extract_sharename(struct uni + name = (pos + 1); + + /* caller has to free the memory */ +- return casefold_sharename(um, name); ++ return ksmbd_casefold_sharename(um, name); + } + + /** +--- a/fs/ksmbd/misc.h ++++ b/fs/ksmbd/misc.h +@@ -20,6 +20,7 @@ int get_nlink(struct kstat *st); + void ksmbd_conv_path_to_unix(char *path); + void ksmbd_strip_last_slash(char *path); + void ksmbd_conv_path_to_windows(char *path); ++char *ksmbd_casefold_sharename(struct unicode_map *um, const char *name); + char *ksmbd_extract_sharename(struct unicode_map *um, const char *treename); + char *convert_to_unix_name(struct ksmbd_share_config *share, const char *name); + diff --git a/queue-5.15/ksmbd-validate-smb-request-protocol-id.patch b/queue-5.15/ksmbd-validate-smb-request-protocol-id.patch new file mode 100644 index 00000000000..530d3bdf0c0 --- /dev/null +++ b/queue-5.15/ksmbd-validate-smb-request-protocol-id.patch @@ -0,0 +1,95 @@ +From linkinjeon@gmail.com Mon Dec 18 16:40:49 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:34:02 +0900 +Subject: ksmbd: validate smb request protocol id +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Namjae Jeon , Chih-Yen Chang , Steve French +Message-ID: <20231218153454.8090-103-linkinjeon@kernel.org> + +From: Namjae Jeon + +[ Upstream commit 1c1bcf2d3ea061613119b534f57507c377df20f9 ] + +This patch add the validation for smb request protocol id. +If it is not one of the four ids(SMB1_PROTO_NUMBER, SMB2_PROTO_NUMBER, +SMB2_TRANSFORM_PROTO_NUM, SMB2_COMPRESSION_TRANSFORM_ID), don't allow +processing the request. And this will fix the following KASAN warning +also. + +[ 13.905265] BUG: KASAN: slab-out-of-bounds in init_smb2_rsp_hdr+0x1b9/0x1f0 +[ 13.905900] Read of size 16 at addr ffff888005fd2f34 by task kworker/0:2/44 +... +[ 13.908553] Call Trace: +[ 13.908793] +[ 13.908995] dump_stack_lvl+0x33/0x50 +[ 13.909369] print_report+0xcc/0x620 +[ 13.910870] kasan_report+0xae/0xe0 +[ 13.911519] kasan_check_range+0x35/0x1b0 +[ 13.911796] init_smb2_rsp_hdr+0x1b9/0x1f0 +[ 13.912492] handle_ksmbd_work+0xe5/0x820 + +Cc: stable@vger.kernel.org +Reported-by: Chih-Yen Chang +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/connection.c | 5 +++-- + fs/ksmbd/smb2pdu.h | 1 + + fs/ksmbd/smb_common.c | 14 +++++++++++++- + 3 files changed, 17 insertions(+), 3 deletions(-) + +--- a/fs/ksmbd/connection.c ++++ b/fs/ksmbd/connection.c +@@ -364,8 +364,6 @@ int ksmbd_conn_handler_loop(void *p) + break; + + memcpy(conn->request_buf, hdr_buf, sizeof(hdr_buf)); +- if (!ksmbd_smb_request(conn)) +- break; + + /* + * We already read 4 bytes to find out PDU size, now +@@ -383,6 +381,9 @@ int ksmbd_conn_handler_loop(void *p) + continue; + } + ++ if (!ksmbd_smb_request(conn)) ++ break; ++ + if (((struct smb2_hdr *)smb2_get_msg(conn->request_buf))->ProtocolId == + SMB2_PROTO_NUMBER) { + if (pdu_size < SMB2_MIN_SUPPORTED_HEADER_SIZE) +--- a/fs/ksmbd/smb2pdu.h ++++ b/fs/ksmbd/smb2pdu.h +@@ -109,6 +109,7 @@ + + #define SMB2_PROTO_NUMBER cpu_to_le32(0x424d53fe) /* 'B''M''S' */ + #define SMB2_TRANSFORM_PROTO_NUM cpu_to_le32(0x424d53fd) ++#define SMB2_COMPRESSION_TRANSFORM_ID cpu_to_le32(0x424d53fc) + + #define SMB21_DEFAULT_IOSIZE (1024 * 1024) + #define SMB3_DEFAULT_IOSIZE (4 * 1024 * 1024) +--- a/fs/ksmbd/smb_common.c ++++ b/fs/ksmbd/smb_common.c +@@ -158,7 +158,19 @@ int ksmbd_verify_smb_message(struct ksmb + */ + bool ksmbd_smb_request(struct ksmbd_conn *conn) + { +- return conn->request_buf[0] == 0; ++ __le32 *proto = (__le32 *)smb2_get_msg(conn->request_buf); ++ ++ if (*proto == SMB2_COMPRESSION_TRANSFORM_ID) { ++ pr_err_ratelimited("smb2 compression not support yet"); ++ return false; ++ } ++ ++ if (*proto != SMB1_PROTO_NUMBER && ++ *proto != SMB2_PROTO_NUMBER && ++ *proto != SMB2_TRANSFORM_PROTO_NUM) ++ return false; ++ ++ return true; + } + + static bool supported_protocol(int idx) diff --git a/queue-5.15/ksmdb-use-cmd-helper-variable-in-smb2_get_ksmbd_tcon.patch b/queue-5.15/ksmdb-use-cmd-helper-variable-in-smb2_get_ksmbd_tcon.patch new file mode 100644 index 00000000000..bc58be3948e --- /dev/null +++ b/queue-5.15/ksmdb-use-cmd-helper-variable-in-smb2_get_ksmbd_tcon.patch @@ -0,0 +1,45 @@ +From stable+bounces-7631-greg=kroah.com@vger.kernel.org Mon Dec 18 16:35:34 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:32:22 +0900 +Subject: ksmdb: use cmd helper variable in smb2_get_ksmbd_tcon() +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Ralph Boehme , Tom Talpey , Ronnie Sahlberg , Hyunchul Lee , Namjae Jeon , Steve French +Message-ID: <20231218153454.8090-3-linkinjeon@kernel.org> + +From: Ralph Boehme + +[ Upstream commit 341b16014bf871115f0883e831372c4b76389d03 ] + +Use cmd helper variable in smb2_get_ksmbd_tcon(). + +Cc: Tom Talpey +Cc: Ronnie Sahlberg +Cc: Steve French +Cc: Hyunchul Lee +Acked-by: Namjae Jeon +Signed-off-by: Ralph Boehme +Signed-off-by: Steve French +Signed-off-by: Namjae Jeon +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/smb2pdu.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -95,11 +95,12 @@ struct channel *lookup_chann_list(struct + int smb2_get_ksmbd_tcon(struct ksmbd_work *work) + { + struct smb2_hdr *req_hdr = work->request_buf; ++ unsigned int cmd = le16_to_cpu(req_hdr->Command); + int tree_id; + +- if (work->conn->ops->get_cmd_val(work) == SMB2_TREE_CONNECT_HE || +- work->conn->ops->get_cmd_val(work) == SMB2_CANCEL_HE || +- work->conn->ops->get_cmd_val(work) == SMB2_LOGOFF_HE) { ++ if (cmd == SMB2_TREE_CONNECT_HE || ++ cmd == SMB2_CANCEL_HE || ++ cmd == SMB2_LOGOFF_HE) { + ksmbd_debug(SMB, "skip to check tree connect request\n"); + return 0; + } diff --git a/queue-5.15/series b/queue-5.15/series new file mode 100644 index 00000000000..d854eec1a52 --- /dev/null +++ b/queue-5.15/series @@ -0,0 +1,154 @@ +ksmbd-use-ksmbd_req_buf_next-in-ksmbd_verify_smb_message.patch +ksmdb-use-cmd-helper-variable-in-smb2_get_ksmbd_tcon.patch +ksmbd-remove-redundant-flush_workqueue-calls.patch +ksmbd-remove-md4-leftovers.patch +ksmbd-remove-smb2_buf_length-in-smb2_hdr.patch +ksmbd-remove-smb2_buf_length-in-smb2_transform_hdr.patch +ksmbd-change-leasekey-data-type-to-u8-array.patch +ksmbd-use-oid-registry-functions-to-decode-oids.patch +ksmbd-remove-unused-parameter-from-smb2_get_name.patch +ksmbd-remove-unused-fields-from-ksmbd_file-struct-definition.patch +ksmbd-set-both-ipv4-and-ipv6-in-fsctl_query_network_interface_info.patch +ksmbd-fix-buffer_check_err-kernel-doc-comment.patch +ksmbd-fix-smb2_set_info_file-kernel-doc-comment.patch +ksmbd-delete-an-invalid-argument-description-in-smb2_populate_readdir_entry.patch +ksmbd-fix-smb2_get_name-kernel-doc-comment.patch +ksmbd-register-ksmbd-ib-client-with-ib_register_client.patch +ksmbd-set-445-port-to-smbdirect-port-by-default.patch +ksmbd-smbd-call-rdma_accept-under-cm-handler.patch +ksmbd-smbd-create-mr-pool.patch +ksmbd-smbd-change-the-default-maximum-read-write-receive-size.patch +ksmbd-add-smb-direct-shutdown.patch +ksmbd-smbd-fix-missing-client-s-memory-region-invalidation.patch +ksmbd-smbd-validate-buffer-descriptor-structures.patch +ksmbd-add-support-for-key-exchange.patch +ksmbd-use-netif_is_bridge_port.patch +ksmbd-store-fids-as-opaque-u64-integers.patch +ksmbd-shorten-experimental-warning-on-loading-the-module.patch +ksmbd-remove-a-redundant-zeroing-of-memory.patch +ksmbd-replace-usage-of-found-with-dedicated-list-iterator-variable.patch +smb3-fix-ksmbd-bigendian-bug-in-oplock-break-and-move-its-struct-to-smbfs_common.patch +ksmbd-remove-filename-in-ksmbd_file.patch +ksmbd-validate-length-in-smb2_write.patch +ksmbd-smbd-change-prototypes-of-rdma-read-write-related-functions.patch +ksmbd-smbd-introduce-read-write-credits-for-rdma-read-write.patch +ksmbd-smbd-simplify-tracking-pending-packets.patch +ksmbd-smbd-change-the-return-value-of-get_sg_list.patch +ksmbd-smbd-handle-multiple-buffer-descriptors.patch +ksmbd-fix-wrong-smbd-max-read-write-size-check.patch +ksmbd-fix-some-kernel-doc-comments.patch +ksmbd-smbd-fix-connection-dropped-issue.patch +ksmbd-smbd-relax-the-count-of-sges-required.patch +ksmbd-smbd-remove-useless-license-text-when-spdx-license-identifier-is-already-used.patch +ksmbd-remove-duplicate-flag-set-in-smb2_write.patch +ksmbd-remove-unused-ksmbd_share_configs_cleanup-function.patch +ksmbd-use-wait_event-instead-of-schedule_timeout.patch +ksmbd-request-update-to-stale-share-config.patch +ksmbd-remove-unnecessary-generic_fillattr-in-smb2_open.patch +ksmbd-don-t-open-code-file_path.patch +ksmbd-don-t-open-code-pd.patch +ksmbd-constify-struct-path.patch +ksmbd-remove-generic_fillattr-use-in-smb2_open.patch +ksmbd-casefold-utf-8-share-names-and-fix-ascii-lowercase-conversion.patch +ksmbd-change-security-id-to-the-one-samba-used-for-posix-extension.patch +ksmbd-set-file-permission-mode-to-match-samba-server-posix-extension-behavior.patch +ksmbd-fill-sids-in-smb_find_file_posix_info-response.patch +ksmbd-fix-encryption-failure-issue-for-session-logoff-response.patch +ksmbd-set-ntlmssp_negotiate_seal-flag-to-challenge-blob.patch +ksmbd-decrease-the-number-of-smb3-smbdirect-server-sges.patch +ksmbd-reduce-server-smbdirect-max-send-receive-segment-sizes.patch +ksmbd-hide-socket-error-message-when-ipv6-config-is-disable.patch +ksmbd-make-utf-8-file-name-comparison-work-in-__caseless_lookup.patch +ksmbd-call-ib_drain_qp-when-disconnected.patch +ksmbd-validate-share-name-from-share-config-response.patch +ksmbd-replace-one-element-arrays-with-flexible-array-members.patch +ksmbd-set-smb2_session_flag_encrypt_data-when-enforcing-data-encryption-for-this-share.patch +ksmbd-use-f_setlk-when-unlocking-a-file.patch +ksmbd-fix-resource-leak-in-smb2_lock.patch +ksmbd-convert-to-use-sysfs_emit-sysfs_emit_at-apis.patch +ksmbd-send-proper-error-response-in-smb2_tree_connect.patch +ksmbd-implements-sess-ksmbd_chann_list-as-xarray.patch +ksmbd-implements-sess-rpc_handle_list-as-xarray.patch +ksmbd-fix-typo-syncronous-synchronous.patch +ksmbd-remove-duplicated-codes.patch +ksmbd-update-kconfig-to-note-kerberos-support-and-fix-indentation.patch +ksmbd-fix-spelling-mistake-excceed-exceeded.patch +ksmbd-fix-parameter-name-and-comment-mismatch.patch +ksmbd-fix-possible-memory-leak-in-smb2_lock.patch +ksmbd-fix-wrong-signingkey-creation-when-encryption-is-aes256.patch +ksmbd-remove-unused-is_char_allowed-function.patch +ksmbd-delete-asynchronous-work-from-list.patch +ksmbd-fix-slab-out-of-bounds-in-init_smb2_rsp_hdr.patch +ksmbd-avoid-out-of-bounds-access-in-decode_preauth_ctxt.patch +ksmbd-set-negotiatecontextcount-once-instead-of-every-inc.patch +ksmbd-avoid-duplicate-negotiate-ctx-offset-increments.patch +ksmbd-remove-unused-compression-negotiate-ctx-packing.patch +fs-introduce-lock_rename_child-helper.patch +ksmbd-fix-racy-issue-from-using-d_parent-and-d_name.patch +ksmbd-fix-racy-issue-from-session-setup-and-logoff.patch +ksmbd-destroy-expired-sessions.patch +ksmbd-block-asynchronous-requests-when-making-a-delay-on-session-setup.patch +ksmbd-fix-racy-issue-from-smb2-close-and-logoff-with-multichannel.patch +ksmbd-fix-racy-issue-under-cocurrent-smb2-tree-disconnect.patch +ksmbd-fix-uninitialized-pointer-read-in-ksmbd_vfs_rename.patch +ksmbd-fix-uninitialized-pointer-read-in-smb2_create_link.patch +ksmbd-fix-multiple-out-of-bounds-read-during-context-decoding.patch +ksmbd-fix-uaf-issue-from-opinfo-conn.patch +ksmbd-call-putname-after-using-the-last-component.patch +ksmbd-fix-out-of-bound-read-in-deassemble_neg_contexts.patch +ksmbd-fix-out-of-bound-read-in-parse_lease_state.patch +ksmbd-fix-posix_acls-and-acls-dereferencing-possible-err_ptr.patch +ksmbd-check-the-validation-of-pdu_size-in-ksmbd_conn_handler_loop.patch +ksmbd-validate-smb-request-protocol-id.patch +ksmbd-add-mnt_want_write-to-ksmbd-vfs-functions.patch +ksmbd-remove-unused-ksmbd_tree_conn_share-function.patch +ksmbd-use-kzalloc-instead-of-__gfp_zero.patch +ksmbd-return-a-literal-instead-of-err-in-ksmbd_vfs_kern_path_locked.patch +ksmbd-change-the-return-value-of-ksmbd_vfs_query_maximal_access-to-void.patch +ksmbd-use-kvzalloc-instead-of-kvmalloc.patch +ksmbd-replace-the-ternary-conditional-operator-with-min.patch +ksmbd-fix-out-of-bounds-read-in-smb2_sess_setup.patch +ksmbd-add-missing-compound-request-handing-in-some-commands.patch +ksmbd-use-struct_size-helper-in-ksmbd_negotiate_smb_dialect.patch +ksmbd-replace-one-element-array-with-flexible-array-member.patch +ksmbd-fix-unsigned-expression-compared-with-zero.patch +ksmbd-check-if-a-mount-point-is-crossed-during-path-lookup.patch +ksmbd-validate-session-id-and-tree-id-in-compound-request.patch +ksmbd-fix-out-of-bounds-in-init_smb2_rsp_hdr.patch +ksmbd-switch-to-use-kmemdup_nul-helper.patch +ksmbd-add-support-for-read-compound.patch +ksmbd-fix-wrong-interim-response-on-compound.patch +ksmbd-fix-force-create-mode-and-force-directory-mode.patch +ksmbd-reduce-descriptor-size-if-remaining-bytes-is-less-than-request-size.patch +ksmbd-fix-one-kernel-doc-comment.patch +ksmbd-fix-slub-overflow-in-ksmbd_decode_ntlmssp_auth_blob.patch +ksmbd-add-missing-calling-smb2_set_err_rsp-on-error.patch +ksmbd-remove-experimental-warning.patch +ksmbd-remove-unneeded-mark_inode_dirty-in-set_info_sec.patch +ksmbd-fix-passing-freed-memory-aux_payload_buf.patch +ksmbd-return-invalid-parameter-error-response-if-smb2-request-is-invalid.patch +ksmbd-check-iov-vector-index-in-ksmbd_conn_write.patch +ksmbd-fix-race-condition-between-session-lookup-and-expire.patch +ksmbd-fix-race-condition-with-fp.patch +ksmbd-fix-race-condition-from-parallel-smb2-logoff-requests.patch +ksmbd-fix-race-condition-from-parallel-smb2-lock-requests.patch +ksmbd-fix-race-condition-between-tree-conn-lookup-and-disconnect.patch +ksmbd-fix-wrong-error-response-status-by-using-set_smb2_rsp_status.patch +ksmbd-fix-null-pointer-dereferences-in-ksmbd_update_fstate.patch +ksmbd-fix-potential-double-free-on-smb2_read_pipe-error-path.patch +ksmbd-remove-unused-field-in-ksmbd_user-struct.patch +ksmbd-reorganize-ksmbd_iov_pin_rsp.patch +ksmbd-fix-kernel-doc-comment-of-ksmbd_vfs_setxattr.patch +ksmbd-fix-recursive-locking-in-vfs-helpers.patch +ksmbd-fix-missing-rdma-capable-flag-for-ipoib-device-in-ksmbd_rdma_capable_netdev.patch +ksmbd-add-support-for-surrogate-pair-conversion.patch +ksmbd-no-need-to-wait-for-binded-connection-termination-at-logoff.patch +ksmbd-fix-kernel-doc-comment-of-ksmbd_vfs_kern_path_locked.patch +ksmbd-handle-malformed-smb1-message.patch +ksmbd-prevent-memory-leak-on-error-return.patch +ksmbd-fix-possible-deadlock-in-smb2_open.patch +ksmbd-separately-allocate-ci-per-dentry.patch +ksmbd-move-oplock-handling-after-unlock-parent-dir.patch +ksmbd-release-interim-response-after-sending-status-pending-response.patch +ksmbd-move-setting-smb2_flags_async_command-and-asyncid.patch +ksmbd-don-t-update-op_state-as-oplock_state_none-on-error.patch diff --git a/queue-5.15/smb3-fix-ksmbd-bigendian-bug-in-oplock-break-and-move-its-struct-to-smbfs_common.patch b/queue-5.15/smb3-fix-ksmbd-bigendian-bug-in-oplock-break-and-move-its-struct-to-smbfs_common.patch new file mode 100644 index 00000000000..a68389949b1 --- /dev/null +++ b/queue-5.15/smb3-fix-ksmbd-bigendian-bug-in-oplock-break-and-move-its-struct-to-smbfs_common.patch @@ -0,0 +1,73 @@ +From linkinjeon@gmail.com Mon Dec 18 16:37:00 2023 +From: Namjae Jeon +Date: Tue, 19 Dec 2023 00:32:50 +0900 +Subject: smb3: fix ksmbd bigendian bug in oplock break, and move its struct to smbfs_common +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: smfrench@gmail.com, Steve French , Paulo Alcantara , Namjae Jeon +Message-ID: <20231218153454.8090-31-linkinjeon@kernel.org> + +From: Steve French + +[ Upstream commit c7803b05f74bc3941b127f3155671e1944f632ae ] + +Fix an endian bug in ksmbd for one remaining use of +Persistent/VolatileFid that unnecessarily converted it (it is an +opaque endian field that does not need to be and should not +be converted) in oplock_break for ksmbd, and move the definitions +for the oplock and lease break protocol requests and responses +to fs/smbfs_common/smb2pdu.h + +Also move a few more definitions for various protocol requests +that were duplicated (in fs/cifs/smb2pdu.h and fs/ksmbd/smb2pdu.h) +into fs/smbfs_common/smb2pdu.h including: + +- various ioctls and reparse structures +- validate negotiate request and response structs +- duplicate extents structs + +Reviewed-by: Paulo Alcantara (SUSE) +Reviewed-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/oplock.c | 4 ++-- + fs/ksmbd/smb2pdu.c | 8 ++++---- + 2 files changed, 6 insertions(+), 6 deletions(-) + +--- a/fs/ksmbd/oplock.c ++++ b/fs/ksmbd/oplock.c +@@ -657,8 +657,8 @@ static void __smb2_oplock_break_noti(str + rsp->OplockLevel = SMB2_OPLOCK_LEVEL_NONE; + rsp->Reserved = 0; + rsp->Reserved2 = 0; +- rsp->PersistentFid = cpu_to_le64(fp->persistent_id); +- rsp->VolatileFid = cpu_to_le64(fp->volatile_id); ++ rsp->PersistentFid = fp->persistent_id; ++ rsp->VolatileFid = fp->volatile_id; + + inc_rfc1001_len(work->response_buf, 24); + +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -7996,8 +7996,8 @@ static void smb20_oplock_break_ack(struc + char req_oplevel = 0, rsp_oplevel = 0; + unsigned int oplock_change_type; + +- volatile_id = le64_to_cpu(req->VolatileFid); +- persistent_id = le64_to_cpu(req->PersistentFid); ++ volatile_id = req->VolatileFid; ++ persistent_id = req->PersistentFid; + req_oplevel = req->OplockLevel; + ksmbd_debug(OPLOCK, "v_id %llu, p_id %llu request oplock level %d\n", + volatile_id, persistent_id, req_oplevel); +@@ -8092,8 +8092,8 @@ static void smb20_oplock_break_ack(struc + rsp->OplockLevel = rsp_oplevel; + rsp->Reserved = 0; + rsp->Reserved2 = 0; +- rsp->VolatileFid = cpu_to_le64(volatile_id); +- rsp->PersistentFid = cpu_to_le64(persistent_id); ++ rsp->VolatileFid = volatile_id; ++ rsp->PersistentFid = persistent_id; + inc_rfc1001_len(work->response_buf, 24); + return; +