]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
5.15-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 20 Dec 2023 14:31:11 +0000 (15:31 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 20 Dec 2023 14:31:11 +0000 (15:31 +0100)
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

155 files changed:
queue-5.15/fs-introduce-lock_rename_child-helper.patch [new file with mode: 0644]
queue-5.15/ksmbd-add-missing-calling-smb2_set_err_rsp-on-error.patch [new file with mode: 0644]
queue-5.15/ksmbd-add-missing-compound-request-handing-in-some-commands.patch [new file with mode: 0644]
queue-5.15/ksmbd-add-mnt_want_write-to-ksmbd-vfs-functions.patch [new file with mode: 0644]
queue-5.15/ksmbd-add-smb-direct-shutdown.patch [new file with mode: 0644]
queue-5.15/ksmbd-add-support-for-key-exchange.patch [new file with mode: 0644]
queue-5.15/ksmbd-add-support-for-read-compound.patch [new file with mode: 0644]
queue-5.15/ksmbd-add-support-for-surrogate-pair-conversion.patch [new file with mode: 0644]
queue-5.15/ksmbd-avoid-duplicate-negotiate-ctx-offset-increments.patch [new file with mode: 0644]
queue-5.15/ksmbd-avoid-out-of-bounds-access-in-decode_preauth_ctxt.patch [new file with mode: 0644]
queue-5.15/ksmbd-block-asynchronous-requests-when-making-a-delay-on-session-setup.patch [new file with mode: 0644]
queue-5.15/ksmbd-call-ib_drain_qp-when-disconnected.patch [new file with mode: 0644]
queue-5.15/ksmbd-call-putname-after-using-the-last-component.patch [new file with mode: 0644]
queue-5.15/ksmbd-casefold-utf-8-share-names-and-fix-ascii-lowercase-conversion.patch [new file with mode: 0644]
queue-5.15/ksmbd-change-leasekey-data-type-to-u8-array.patch [new file with mode: 0644]
queue-5.15/ksmbd-change-security-id-to-the-one-samba-used-for-posix-extension.patch [new file with mode: 0644]
queue-5.15/ksmbd-change-the-return-value-of-ksmbd_vfs_query_maximal_access-to-void.patch [new file with mode: 0644]
queue-5.15/ksmbd-check-if-a-mount-point-is-crossed-during-path-lookup.patch [new file with mode: 0644]
queue-5.15/ksmbd-check-iov-vector-index-in-ksmbd_conn_write.patch [new file with mode: 0644]
queue-5.15/ksmbd-check-the-validation-of-pdu_size-in-ksmbd_conn_handler_loop.patch [new file with mode: 0644]
queue-5.15/ksmbd-constify-struct-path.patch [new file with mode: 0644]
queue-5.15/ksmbd-convert-to-use-sysfs_emit-sysfs_emit_at-apis.patch [new file with mode: 0644]
queue-5.15/ksmbd-decrease-the-number-of-smb3-smbdirect-server-sges.patch [new file with mode: 0644]
queue-5.15/ksmbd-delete-an-invalid-argument-description-in-smb2_populate_readdir_entry.patch [new file with mode: 0644]
queue-5.15/ksmbd-delete-asynchronous-work-from-list.patch [new file with mode: 0644]
queue-5.15/ksmbd-destroy-expired-sessions.patch [new file with mode: 0644]
queue-5.15/ksmbd-don-t-open-code-file_path.patch [new file with mode: 0644]
queue-5.15/ksmbd-don-t-open-code-pd.patch [new file with mode: 0644]
queue-5.15/ksmbd-don-t-update-op_state-as-oplock_state_none-on-error.patch [new file with mode: 0644]
queue-5.15/ksmbd-fill-sids-in-smb_find_file_posix_info-response.patch [new file with mode: 0644]
queue-5.15/ksmbd-fix-buffer_check_err-kernel-doc-comment.patch [new file with mode: 0644]
queue-5.15/ksmbd-fix-encryption-failure-issue-for-session-logoff-response.patch [new file with mode: 0644]
queue-5.15/ksmbd-fix-force-create-mode-and-force-directory-mode.patch [new file with mode: 0644]
queue-5.15/ksmbd-fix-kernel-doc-comment-of-ksmbd_vfs_kern_path_locked.patch [new file with mode: 0644]
queue-5.15/ksmbd-fix-kernel-doc-comment-of-ksmbd_vfs_setxattr.patch [new file with mode: 0644]
queue-5.15/ksmbd-fix-missing-rdma-capable-flag-for-ipoib-device-in-ksmbd_rdma_capable_netdev.patch [new file with mode: 0644]
queue-5.15/ksmbd-fix-multiple-out-of-bounds-read-during-context-decoding.patch [new file with mode: 0644]
queue-5.15/ksmbd-fix-null-pointer-dereferences-in-ksmbd_update_fstate.patch [new file with mode: 0644]
queue-5.15/ksmbd-fix-one-kernel-doc-comment.patch [new file with mode: 0644]
queue-5.15/ksmbd-fix-out-of-bound-read-in-deassemble_neg_contexts.patch [new file with mode: 0644]
queue-5.15/ksmbd-fix-out-of-bound-read-in-parse_lease_state.patch [new file with mode: 0644]
queue-5.15/ksmbd-fix-out-of-bounds-in-init_smb2_rsp_hdr.patch [new file with mode: 0644]
queue-5.15/ksmbd-fix-out-of-bounds-read-in-smb2_sess_setup.patch [new file with mode: 0644]
queue-5.15/ksmbd-fix-parameter-name-and-comment-mismatch.patch [new file with mode: 0644]
queue-5.15/ksmbd-fix-passing-freed-memory-aux_payload_buf.patch [new file with mode: 0644]
queue-5.15/ksmbd-fix-posix_acls-and-acls-dereferencing-possible-err_ptr.patch [new file with mode: 0644]
queue-5.15/ksmbd-fix-possible-deadlock-in-smb2_open.patch [new file with mode: 0644]
queue-5.15/ksmbd-fix-possible-memory-leak-in-smb2_lock.patch [new file with mode: 0644]
queue-5.15/ksmbd-fix-potential-double-free-on-smb2_read_pipe-error-path.patch [new file with mode: 0644]
queue-5.15/ksmbd-fix-race-condition-between-session-lookup-and-expire.patch [new file with mode: 0644]
queue-5.15/ksmbd-fix-race-condition-between-tree-conn-lookup-and-disconnect.patch [new file with mode: 0644]
queue-5.15/ksmbd-fix-race-condition-from-parallel-smb2-lock-requests.patch [new file with mode: 0644]
queue-5.15/ksmbd-fix-race-condition-from-parallel-smb2-logoff-requests.patch [new file with mode: 0644]
queue-5.15/ksmbd-fix-race-condition-with-fp.patch [new file with mode: 0644]
queue-5.15/ksmbd-fix-racy-issue-from-session-setup-and-logoff.patch [new file with mode: 0644]
queue-5.15/ksmbd-fix-racy-issue-from-smb2-close-and-logoff-with-multichannel.patch [new file with mode: 0644]
queue-5.15/ksmbd-fix-racy-issue-from-using-d_parent-and-d_name.patch [new file with mode: 0644]
queue-5.15/ksmbd-fix-racy-issue-under-cocurrent-smb2-tree-disconnect.patch [new file with mode: 0644]
queue-5.15/ksmbd-fix-recursive-locking-in-vfs-helpers.patch [new file with mode: 0644]
queue-5.15/ksmbd-fix-resource-leak-in-smb2_lock.patch [new file with mode: 0644]
queue-5.15/ksmbd-fix-slab-out-of-bounds-in-init_smb2_rsp_hdr.patch [new file with mode: 0644]
queue-5.15/ksmbd-fix-slub-overflow-in-ksmbd_decode_ntlmssp_auth_blob.patch [new file with mode: 0644]
queue-5.15/ksmbd-fix-smb2_get_name-kernel-doc-comment.patch [new file with mode: 0644]
queue-5.15/ksmbd-fix-smb2_set_info_file-kernel-doc-comment.patch [new file with mode: 0644]
queue-5.15/ksmbd-fix-some-kernel-doc-comments.patch [new file with mode: 0644]
queue-5.15/ksmbd-fix-spelling-mistake-excceed-exceeded.patch [new file with mode: 0644]
queue-5.15/ksmbd-fix-typo-syncronous-synchronous.patch [new file with mode: 0644]
queue-5.15/ksmbd-fix-uaf-issue-from-opinfo-conn.patch [new file with mode: 0644]
queue-5.15/ksmbd-fix-uninitialized-pointer-read-in-ksmbd_vfs_rename.patch [new file with mode: 0644]
queue-5.15/ksmbd-fix-uninitialized-pointer-read-in-smb2_create_link.patch [new file with mode: 0644]
queue-5.15/ksmbd-fix-unsigned-expression-compared-with-zero.patch [new file with mode: 0644]
queue-5.15/ksmbd-fix-wrong-error-response-status-by-using-set_smb2_rsp_status.patch [new file with mode: 0644]
queue-5.15/ksmbd-fix-wrong-interim-response-on-compound.patch [new file with mode: 0644]
queue-5.15/ksmbd-fix-wrong-signingkey-creation-when-encryption-is-aes256.patch [new file with mode: 0644]
queue-5.15/ksmbd-fix-wrong-smbd-max-read-write-size-check.patch [new file with mode: 0644]
queue-5.15/ksmbd-handle-malformed-smb1-message.patch [new file with mode: 0644]
queue-5.15/ksmbd-hide-socket-error-message-when-ipv6-config-is-disable.patch [new file with mode: 0644]
queue-5.15/ksmbd-implements-sess-ksmbd_chann_list-as-xarray.patch [new file with mode: 0644]
queue-5.15/ksmbd-implements-sess-rpc_handle_list-as-xarray.patch [new file with mode: 0644]
queue-5.15/ksmbd-make-utf-8-file-name-comparison-work-in-__caseless_lookup.patch [new file with mode: 0644]
queue-5.15/ksmbd-move-oplock-handling-after-unlock-parent-dir.patch [new file with mode: 0644]
queue-5.15/ksmbd-move-setting-smb2_flags_async_command-and-asyncid.patch [new file with mode: 0644]
queue-5.15/ksmbd-no-need-to-wait-for-binded-connection-termination-at-logoff.patch [new file with mode: 0644]
queue-5.15/ksmbd-prevent-memory-leak-on-error-return.patch [new file with mode: 0644]
queue-5.15/ksmbd-reduce-descriptor-size-if-remaining-bytes-is-less-than-request-size.patch [new file with mode: 0644]
queue-5.15/ksmbd-reduce-server-smbdirect-max-send-receive-segment-sizes.patch [new file with mode: 0644]
queue-5.15/ksmbd-register-ksmbd-ib-client-with-ib_register_client.patch [new file with mode: 0644]
queue-5.15/ksmbd-release-interim-response-after-sending-status-pending-response.patch [new file with mode: 0644]
queue-5.15/ksmbd-remove-a-redundant-zeroing-of-memory.patch [new file with mode: 0644]
queue-5.15/ksmbd-remove-duplicate-flag-set-in-smb2_write.patch [new file with mode: 0644]
queue-5.15/ksmbd-remove-duplicated-codes.patch [new file with mode: 0644]
queue-5.15/ksmbd-remove-experimental-warning.patch [new file with mode: 0644]
queue-5.15/ksmbd-remove-filename-in-ksmbd_file.patch [new file with mode: 0644]
queue-5.15/ksmbd-remove-generic_fillattr-use-in-smb2_open.patch [new file with mode: 0644]
queue-5.15/ksmbd-remove-md4-leftovers.patch [new file with mode: 0644]
queue-5.15/ksmbd-remove-redundant-flush_workqueue-calls.patch [new file with mode: 0644]
queue-5.15/ksmbd-remove-smb2_buf_length-in-smb2_hdr.patch [new file with mode: 0644]
queue-5.15/ksmbd-remove-smb2_buf_length-in-smb2_transform_hdr.patch [new file with mode: 0644]
queue-5.15/ksmbd-remove-unnecessary-generic_fillattr-in-smb2_open.patch [new file with mode: 0644]
queue-5.15/ksmbd-remove-unneeded-mark_inode_dirty-in-set_info_sec.patch [new file with mode: 0644]
queue-5.15/ksmbd-remove-unused-compression-negotiate-ctx-packing.patch [new file with mode: 0644]
queue-5.15/ksmbd-remove-unused-field-in-ksmbd_user-struct.patch [new file with mode: 0644]
queue-5.15/ksmbd-remove-unused-fields-from-ksmbd_file-struct-definition.patch [new file with mode: 0644]
queue-5.15/ksmbd-remove-unused-is_char_allowed-function.patch [new file with mode: 0644]
queue-5.15/ksmbd-remove-unused-ksmbd_share_configs_cleanup-function.patch [new file with mode: 0644]
queue-5.15/ksmbd-remove-unused-ksmbd_tree_conn_share-function.patch [new file with mode: 0644]
queue-5.15/ksmbd-remove-unused-parameter-from-smb2_get_name.patch [new file with mode: 0644]
queue-5.15/ksmbd-reorganize-ksmbd_iov_pin_rsp.patch [new file with mode: 0644]
queue-5.15/ksmbd-replace-one-element-array-with-flexible-array-member.patch [new file with mode: 0644]
queue-5.15/ksmbd-replace-one-element-arrays-with-flexible-array-members.patch [new file with mode: 0644]
queue-5.15/ksmbd-replace-the-ternary-conditional-operator-with-min.patch [new file with mode: 0644]
queue-5.15/ksmbd-replace-usage-of-found-with-dedicated-list-iterator-variable.patch [new file with mode: 0644]
queue-5.15/ksmbd-request-update-to-stale-share-config.patch [new file with mode: 0644]
queue-5.15/ksmbd-return-a-literal-instead-of-err-in-ksmbd_vfs_kern_path_locked.patch [new file with mode: 0644]
queue-5.15/ksmbd-return-invalid-parameter-error-response-if-smb2-request-is-invalid.patch [new file with mode: 0644]
queue-5.15/ksmbd-send-proper-error-response-in-smb2_tree_connect.patch [new file with mode: 0644]
queue-5.15/ksmbd-separately-allocate-ci-per-dentry.patch [new file with mode: 0644]
queue-5.15/ksmbd-set-445-port-to-smbdirect-port-by-default.patch [new file with mode: 0644]
queue-5.15/ksmbd-set-both-ipv4-and-ipv6-in-fsctl_query_network_interface_info.patch [new file with mode: 0644]
queue-5.15/ksmbd-set-file-permission-mode-to-match-samba-server-posix-extension-behavior.patch [new file with mode: 0644]
queue-5.15/ksmbd-set-negotiatecontextcount-once-instead-of-every-inc.patch [new file with mode: 0644]
queue-5.15/ksmbd-set-ntlmssp_negotiate_seal-flag-to-challenge-blob.patch [new file with mode: 0644]
queue-5.15/ksmbd-set-smb2_session_flag_encrypt_data-when-enforcing-data-encryption-for-this-share.patch [new file with mode: 0644]
queue-5.15/ksmbd-shorten-experimental-warning-on-loading-the-module.patch [new file with mode: 0644]
queue-5.15/ksmbd-smbd-call-rdma_accept-under-cm-handler.patch [new file with mode: 0644]
queue-5.15/ksmbd-smbd-change-prototypes-of-rdma-read-write-related-functions.patch [new file with mode: 0644]
queue-5.15/ksmbd-smbd-change-the-default-maximum-read-write-receive-size.patch [new file with mode: 0644]
queue-5.15/ksmbd-smbd-change-the-return-value-of-get_sg_list.patch [new file with mode: 0644]
queue-5.15/ksmbd-smbd-create-mr-pool.patch [new file with mode: 0644]
queue-5.15/ksmbd-smbd-fix-connection-dropped-issue.patch [new file with mode: 0644]
queue-5.15/ksmbd-smbd-fix-missing-client-s-memory-region-invalidation.patch [new file with mode: 0644]
queue-5.15/ksmbd-smbd-handle-multiple-buffer-descriptors.patch [new file with mode: 0644]
queue-5.15/ksmbd-smbd-introduce-read-write-credits-for-rdma-read-write.patch [new file with mode: 0644]
queue-5.15/ksmbd-smbd-relax-the-count-of-sges-required.patch [new file with mode: 0644]
queue-5.15/ksmbd-smbd-remove-useless-license-text-when-spdx-license-identifier-is-already-used.patch [new file with mode: 0644]
queue-5.15/ksmbd-smbd-simplify-tracking-pending-packets.patch [new file with mode: 0644]
queue-5.15/ksmbd-smbd-validate-buffer-descriptor-structures.patch [new file with mode: 0644]
queue-5.15/ksmbd-store-fids-as-opaque-u64-integers.patch [new file with mode: 0644]
queue-5.15/ksmbd-switch-to-use-kmemdup_nul-helper.patch [new file with mode: 0644]
queue-5.15/ksmbd-update-kconfig-to-note-kerberos-support-and-fix-indentation.patch [new file with mode: 0644]
queue-5.15/ksmbd-use-f_setlk-when-unlocking-a-file.patch [new file with mode: 0644]
queue-5.15/ksmbd-use-ksmbd_req_buf_next-in-ksmbd_verify_smb_message.patch [new file with mode: 0644]
queue-5.15/ksmbd-use-kvzalloc-instead-of-kvmalloc.patch [new file with mode: 0644]
queue-5.15/ksmbd-use-kzalloc-instead-of-__gfp_zero.patch [new file with mode: 0644]
queue-5.15/ksmbd-use-netif_is_bridge_port.patch [new file with mode: 0644]
queue-5.15/ksmbd-use-oid-registry-functions-to-decode-oids.patch [new file with mode: 0644]
queue-5.15/ksmbd-use-struct_size-helper-in-ksmbd_negotiate_smb_dialect.patch [new file with mode: 0644]
queue-5.15/ksmbd-use-wait_event-instead-of-schedule_timeout.patch [new file with mode: 0644]
queue-5.15/ksmbd-validate-length-in-smb2_write.patch [new file with mode: 0644]
queue-5.15/ksmbd-validate-session-id-and-tree-id-in-compound-request.patch [new file with mode: 0644]
queue-5.15/ksmbd-validate-share-name-from-share-config-response.patch [new file with mode: 0644]
queue-5.15/ksmbd-validate-smb-request-protocol-id.patch [new file with mode: 0644]
queue-5.15/ksmdb-use-cmd-helper-variable-in-smb2_get_ksmbd_tcon.patch [new file with mode: 0644]
queue-5.15/series [new file with mode: 0644]
queue-5.15/smb3-fix-ksmbd-bigendian-bug-in-oplock-break-and-move-its-struct-to-smbfs_common.patch [new file with mode: 0644]

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 (file)
index 0000000..f1e0d08
--- /dev/null
@@ -0,0 +1,127 @@
+From linkinjeon@gmail.com Mon Dec 18 16:39:57 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <viro@zeniv.linux.org.uk>, Namjae Jeon <linkinjeon@kernel.org>
+Message-ID: <20231218153454.8090-87-linkinjeon@kernel.org>
+
+From: Al Viro <viro@zeniv.linux.org.uk>
+
+[ 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 <viro@zeniv.linux.org.uk>
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..59a2c40
--- /dev/null
@@ -0,0 +1,33 @@
+From linkinjeon@gmail.com Mon Dec 18 16:42:04 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-126-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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 <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..b913ce2
--- /dev/null
@@ -0,0 +1,242 @@
+From linkinjeon@gmail.com Mon Dec 18 16:41:18 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-112-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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 <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..15a8e8c
--- /dev/null
@@ -0,0 +1,590 @@
+From stable+bounces-7732-greg=kroah.com@vger.kernel.org Mon Dec 18 16:45:42 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, Amir Goldstein <amir73il@gmail.com>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-104-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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 <amir73il@gmail.com>
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..bc64a5e
--- /dev/null
@@ -0,0 +1,91 @@
+From stable+bounces-7650-greg=kroah.com@vger.kernel.org Mon Dec 18 16:39:41 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, Yufan Chen <wiz.chen@gmail.com>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-22-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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 <wiz.chen@gmail.com>
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..d6ed007
--- /dev/null
@@ -0,0 +1,79 @@
+From linkinjeon@gmail.com Mon Dec 18 16:36:39 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-25-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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 <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..7d0e7b9
--- /dev/null
@@ -0,0 +1,1921 @@
+From linkinjeon@gmail.com Mon Dec 18 16:41:45 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-120-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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 <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..ae83ec8
--- /dev/null
@@ -0,0 +1,294 @@
+From linkinjeon@gmail.com Mon Dec 18 16:43:07 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, Marios Makassikis <mmakassikis@freebox.fr>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-145-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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 <mmakassikis@freebox.fr>
+Tested-by: Marios Makassikis <mmakassikis@freebox.fr>
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..48062fa
--- /dev/null
@@ -0,0 +1,108 @@
+From linkinjeon@gmail.com Mon Dec 18 16:39:51 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <ddiss@suse.de>, Namjae Jeon <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-85-linkinjeon@kernel.org>
+
+From: David Disseldorp <ddiss@suse.de>
+
+[ 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 <ddiss@suse.de>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..b1a9bc9
--- /dev/null
@@ -0,0 +1,71 @@
+From linkinjeon@gmail.com Mon Dec 18 16:39:45 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <ddiss@suse.de>, Namjae Jeon <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-83-linkinjeon@kernel.org>
+
+From: David Disseldorp <ddiss@suse.de>
+
+[ 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 <ddiss@suse.de>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..f1a3fae
--- /dev/null
@@ -0,0 +1,41 @@
+From linkinjeon@gmail.com Mon Dec 18 16:40:11 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, zdi-disclosures@trendmicro.com, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-91-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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 <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..d188902
--- /dev/null
@@ -0,0 +1,36 @@
+From linkinjeon@gmail.com Mon Dec 18 16:38:43 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, Hyunchul Lee <hyc.lee@gmail.com>, Tom Talpey <tom@talpey.com>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-63-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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 <hyc.lee@gmail.com>
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Reviewed-by: Tom Talpey <tom@talpey.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..5d61f13
--- /dev/null
@@ -0,0 +1,60 @@
+From linkinjeon@gmail.com Mon Dec 18 16:40:33 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-98-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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 <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..0cdc640
--- /dev/null
@@ -0,0 +1,270 @@
+From linkinjeon@gmail.com Mon Dec 18 16:38:13 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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ä" <atteh.mailbox@gmail.com>, "Namjae Jeon" <linkinjeon@kernel.org>, "Steve French" <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-53-linkinjeon@kernel.org>
+
+From: Atte Heikkilä <atteh.mailbox@gmail.com>
+
+[ 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ä <atteh.mailbox@gmail.com>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 <linux/kernel.h>
+ #include <linux/xattr.h>
+ #include <linux/fs.h>
++#include <linux/unicode.h>
+ #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 <asm/byteorder.h>
+ #include <linux/types.h>
+ #include <linux/nls.h>
++#include <linux/unicode.h>
+ #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 (file)
index 0000000..207ed3c
--- /dev/null
@@ -0,0 +1,125 @@
+From linkinjeon@gmail.com Mon Dec 18 16:35:41 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-8-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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 <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..0ea9b4e
--- /dev/null
@@ -0,0 +1,104 @@
+From linkinjeon@gmail.com Mon Dec 18 16:38:16 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-54-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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 <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..4cf5727
--- /dev/null
@@ -0,0 +1,75 @@
+From linkinjeon@gmail.com Mon Dec 18 16:41:05 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <luhongfei@vivo.com>, Namjae Jeon <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-108-linkinjeon@kernel.org>
+
+From: Lu Hongfei <luhongfei@vivo.com>
+
+[ 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 <luhongfei@vivo.com>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..6d352aa
--- /dev/null
@@ -0,0 +1,295 @@
+From linkinjeon@gmail.com Mon Dec 18 16:41:33 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-116-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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 <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..026ca90
--- /dev/null
@@ -0,0 +1,36 @@
+From linkinjeon@gmail.com Mon Dec 18 16:42:20 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-131-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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 <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..5809857
--- /dev/null
@@ -0,0 +1,76 @@
+From stable+bounces-7729-greg=kroah.com@vger.kernel.org Mon Dec 18 16:45:21 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, Chih-Yen Chang <cc85nod@gmail.com>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-102-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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]  <TASK>
+[    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]  </TASK>
+
+Cc: stable@vger.kernel.org
+Reported-by: Chih-Yen Chang <cc85nod@gmail.com>
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..05e9585
--- /dev/null
@@ -0,0 +1,212 @@
+From linkinjeon@gmail.com Mon Dec 18 16:38:07 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <viro@zeniv.linux.org.uk>, Namjae Jeon <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-51-linkinjeon@kernel.org>
+
+From: Al Viro <viro@zeniv.linux.org.uk>
+
+[ Upstream commit c22180a5e2a9e1426fab01d9e54011ec531b1b52 ]
+
+... in particular, there should never be a non-const pointers to
+any file->f_path.
+
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..aaf0e46
--- /dev/null
@@ -0,0 +1,65 @@
+From linkinjeon@gmail.com Mon Dec 18 16:39:02 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <ye.xingchen@zte.com.cn>, Sergey Senozhatsky <senozhatsky@chromium.org>, Namjae Jeon <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-69-linkinjeon@kernel.org>
+
+From: ye xingchen <ye.xingchen@zte.com.cn>
+
+[ 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 <ye.xingchen@zte.com.cn>
+Reviewed-by: Sergey Senozhatsky <senozhatsky@chromium.org>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..763ab70
--- /dev/null
@@ -0,0 +1,36 @@
+From linkinjeon@gmail.com Mon Dec 18 16:38:31 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <tom@talpey.com>, Namjae Jeon <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-59-linkinjeon@kernel.org>
+
+From: Tom Talpey <tom@talpey.com>
+
+[ 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 <tom@talpey.com>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..48b54f7
--- /dev/null
@@ -0,0 +1,37 @@
+From stable+bounces-7643-greg=kroah.com@vger.kernel.org Mon Dec 18 16:36:55 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <yang.lee@linux.alibaba.com>, Abaci Robot <abaci@linux.alibaba.com>, Namjae Jeon <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-15-linkinjeon@kernel.org>
+
+From: Yang Li <yang.lee@linux.alibaba.com>
+
+[ 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 <abaci@linux.alibaba.com>
+Fixes: 475d6f98804c ("ksmbd: fix translation in smb2_populate_readdir_entry()")
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Yang Li <yang.lee@linux.alibaba.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..28c168e
--- /dev/null
@@ -0,0 +1,164 @@
+From linkinjeon@gmail.com Mon Dec 18 16:39:39 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-81-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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 <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..0e86580
--- /dev/null
@@ -0,0 +1,184 @@
+From linkinjeon@gmail.com Mon Dec 18 16:40:08 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, zdi-disclosures@trendmicro.com, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-90-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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 <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..a58d7b9
--- /dev/null
@@ -0,0 +1,40 @@
+From linkinjeon@gmail.com Mon Dec 18 16:38:00 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <viro@zeniv.linux.org.uk>, Namjae Jeon <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-49-linkinjeon@kernel.org>
+
+From: Al Viro <viro@zeniv.linux.org.uk>
+
+[ Upstream commit 2f5930c1d7936b74eb820c5b157011994c707a74 ]
+
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..2457548
--- /dev/null
@@ -0,0 +1,105 @@
+From linkinjeon@gmail.com Mon Dec 18 16:38:03 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <viro@zeniv.linux.org.uk>, Namjae Jeon <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-50-linkinjeon@kernel.org>
+
+From: Al Viro <viro@zeniv.linux.org.uk>
+
+[ 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 <linkinjeon@kernel.org>
+Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..f4064c9
--- /dev/null
@@ -0,0 +1,33 @@
+From linkinjeon@gmail.com Mon Dec 18 16:43:41 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-155-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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 <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..d952b14
--- /dev/null
@@ -0,0 +1,73 @@
+From linkinjeon@gmail.com Mon Dec 18 16:38:22 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-56-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ Upstream commit d5919f2a1459083bd0aaede7fc44e945290e44df ]
+
+This patch fill missing sids in SMB_FIND_FILE_POSIX_INFO response.
+
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..4920373
--- /dev/null
@@ -0,0 +1,38 @@
+From stable+bounces-7641-greg=kroah.com@vger.kernel.org Mon Dec 18 16:36:28 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <yang.lee@linux.alibaba.com>, Abaci Robot <abaci@linux.alibaba.com>, Namjae Jeon <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-13-linkinjeon@kernel.org>
+
+From: Yang Li <yang.lee@linux.alibaba.com>
+
+[ 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 <abaci@linux.alibaba.com>
+Fixes: cb4517201b8a ("ksmbd: remove smb2_buf_length in smb2_hdr")
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Yang Li <yang.lee@linux.alibaba.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..3ea3000
--- /dev/null
@@ -0,0 +1,125 @@
+From linkinjeon@gmail.com Mon Dec 18 16:38:25 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-57-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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 <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..98b57b5
--- /dev/null
@@ -0,0 +1,67 @@
+From linkinjeon@gmail.com Mon Dec 18 16:41:51 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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ä" <atteh.mailbox@gmail.com>, "Namjae Jeon" <linkinjeon@kernel.org>, "Steve French" <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-122-linkinjeon@kernel.org>
+
+From: Atte Heikkilä <atteh.mailbox@gmail.com>
+
+[ 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ä <atteh.mailbox@gmail.com>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..7df71fc
--- /dev/null
@@ -0,0 +1,42 @@
+From linkinjeon@gmail.com Mon Dec 18 16:43:13 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, kernel test robot <lkp@intel.com>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-147-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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 <lkp@intel.com>
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..2fbe145
--- /dev/null
@@ -0,0 +1,37 @@
+From linkinjeon@gmail.com Mon Dec 18 16:42:57 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, kernel test robot <lkp@intel.com>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-142-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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 <lkp@intel.com>
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..3dedf81
--- /dev/null
@@ -0,0 +1,87 @@
+From linkinjeon@gmail.com Mon Dec 18 16:43:05 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <huangkangjing@gmail.com>, Namjae Jeon <linkinjeon@kernel.org>, Tom Talpey <tom@talpey.com>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-144-linkinjeon@kernel.org>
+
+From: Kangjing Huang <huangkangjing@gmail.com>
+
+[ 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 <huangkangjing@gmail.com>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Reviewed-by: Tom Talpey <tom@talpey.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..94aad5e
--- /dev/null
@@ -0,0 +1,154 @@
+From linkinjeon@gmail.com Mon Dec 18 16:40:27 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <h3xrabbit@gmail.com>, Namjae Jeon <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-96-linkinjeon@kernel.org>
+
+From: Kuan-Ting Chen <h3xrabbit@gmail.com>
+
+[ 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 <h3xrabbit@gmail.com>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..8eeac1e
--- /dev/null
@@ -0,0 +1,54 @@
+From linkinjeon@gmail.com Mon Dec 18 16:42:43 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, Coverity Scan <scan-admin@coverity.com>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-138-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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 <scan-admin@coverity.com>
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..ad6739a
--- /dev/null
@@ -0,0 +1,33 @@
+From linkinjeon@gmail.com Mon Dec 18 16:41:58 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <yang.lee@linux.alibaba.com>, Namjae Jeon <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-124-linkinjeon@kernel.org>
+
+From: Yang Li <yang.lee@linux.alibaba.com>
+
+[ 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 <yang.lee@linux.alibaba.com>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..2ff676f
--- /dev/null
@@ -0,0 +1,86 @@
+From linkinjeon@gmail.com Mon Dec 18 16:40:36 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, Chih-Yen Chang <cc85nod@gmail.com>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-99-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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]  <TASK>
+[   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 <cc85nod@gmail.com>
+Tested-by: Chih-Yen Chang <cc85nod@gmail.com>
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..d04e9f8
--- /dev/null
@@ -0,0 +1,128 @@
+From linkinjeon@gmail.com Mon Dec 18 16:40:39 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, Chih-Yen Chang <cc85nod@gmail.com>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-100-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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]  <TASK>
+[    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 <cc85nod@gmail.com>
+Tested-by: Chih-Yen Chang <cc85nod@gmail.com>
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..cc69f47
--- /dev/null
@@ -0,0 +1,101 @@
+From linkinjeon@gmail.com Mon Dec 18 16:41:39 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, zdi-disclosures@trendmicro.com, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-118-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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 <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..ecef0e9
--- /dev/null
@@ -0,0 +1,125 @@
+From linkinjeon@gmail.com Mon Dec 18 16:41:15 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, zdi-disclosures@trendmicro.com, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-111-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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 <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..9e7517b
--- /dev/null
@@ -0,0 +1,40 @@
+From stable+bounces-7705-greg=kroah.com@vger.kernel.org Mon Dec 18 16:44:36 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <jiapeng.chong@linux.alibaba.com>, Abaci Robot <abaci@linux.alibaba.com>, Namjae Jeon <linkinjeon@kernel.org>, Sergey Senozhatsky <senozhatsky@chromium.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-77-linkinjeon@kernel.org>
+
+From: Jiapeng Chong <jiapeng.chong@linux.alibaba.com>
+
+[ 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 <abaci@linux.alibaba.com>
+Link: https://bugzilla.openanolis.cn/show_bug.cgi?id=3946
+Signed-off-by: Jiapeng Chong <jiapeng.chong@linux.alibaba.com>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Reviewed-by: Sergey Senozhatsky <senozhatsky@chromium.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..1f5c9a1
--- /dev/null
@@ -0,0 +1,41 @@
+From linkinjeon@gmail.com Mon Dec 18 16:42:13 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, Dan Carpenter <dan.carpenter@linaro.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-129-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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 <dan.carpenter@linaro.org>
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..02eadea
--- /dev/null
@@ -0,0 +1,75 @@
+From linkinjeon@gmail.com Mon Dec 18 16:40:42 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, Dan Carpenter <dan.carpenter@linaro.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-101-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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 <dan.carpenter@linaro.org>
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..4ed6a2e
--- /dev/null
@@ -0,0 +1,478 @@
+From linkinjeon@gmail.com Mon Dec 18 16:43:25 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, Marios Makassikis <mmakassikis@freebox.fr>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-150-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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 <mmakassikis@freebox.fr>
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..4304ec5
--- /dev/null
@@ -0,0 +1,120 @@
+From linkinjeon@gmail.com Mon Dec 18 16:39:30 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <hbh25y@gmail.com>, Namjae Jeon <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-78-linkinjeon@kernel.org>
+
+From: Hangyu Hua <hbh25y@gmail.com>
+
+[ 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 <hbh25y@gmail.com>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..eebc8f1
--- /dev/null
@@ -0,0 +1,41 @@
+From linkinjeon@gmail.com Mon Dec 18 16:42:46 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, kernel test robot <lkp@intel.com>, Dan Carpenter <dan.carpenter@linaro.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-139-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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 <lkp@intel.com>
+Reported-by: Dan Carpenter <dan.carpenter@linaro.org>
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..3894170
--- /dev/null
@@ -0,0 +1,109 @@
+From linkinjeon@gmail.com Mon Dec 18 16:42:24 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, luosili <rootlab@huawei.com>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-132-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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 <rootlab@huawei.com>
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..2f7f6fc
--- /dev/null
@@ -0,0 +1,268 @@
+From linkinjeon@gmail.com Mon Dec 18 16:42:36 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, luosili <rootlab@huawei.com>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-136-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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 <rootlab@huawei.com>
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..b2092f2
--- /dev/null
@@ -0,0 +1,83 @@
+From linkinjeon@gmail.com Mon Dec 18 16:42:33 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, luosili <rootlab@huawei.com>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-135-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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 <rootlab@huawei.com>
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..8355168
--- /dev/null
@@ -0,0 +1,69 @@
+From linkinjeon@gmail.com Mon Dec 18 16:42:30 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, luosili <rootlab@huawei.com>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-134-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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 <rootlab@huawei.com>
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..7974919
--- /dev/null
@@ -0,0 +1,146 @@
+From linkinjeon@gmail.com Mon Dec 18 16:42:27 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, luosili <rootlab@huawei.com>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-133-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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 <rootlab@huawei.com>
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..e88e69e
--- /dev/null
@@ -0,0 +1,387 @@
+From linkinjeon@gmail.com Mon Dec 18 16:40:04 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, zdi-disclosures@trendmicro.com, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-89-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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 <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..6342d1a
--- /dev/null
@@ -0,0 +1,401 @@
+From linkinjeon@gmail.com Mon Dec 18 16:40:14 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, zdi-disclosures@trendmicro.com, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-92-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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 <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..a9e095f
--- /dev/null
@@ -0,0 +1,1183 @@
+From linkinjeon@gmail.com Mon Dec 18 16:40:02 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-88-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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 <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 <linux/vmalloc.h>
+ #include <linux/sched/xacct.h>
+ #include <linux/crc32c.h>
++#include <linux/namei.h>
+ #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 (file)
index 0000000..de90540
--- /dev/null
@@ -0,0 +1,81 @@
+From linkinjeon@gmail.com Mon Dec 18 16:40:17 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, zdi-disclosures@trendmicro.com, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-93-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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 <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..f1d2cc6
--- /dev/null
@@ -0,0 +1,143 @@
+From linkinjeon@gmail.com Mon Dec 18 16:43:00 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <mmakassikis@freebox.fr>, Namjae Jeon <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-143-linkinjeon@kernel.org>
+
+From: Marios Makassikis <mmakassikis@freebox.fr>
+
+[ 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 <mmakassikis@freebox.fr>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..df09ba6
--- /dev/null
@@ -0,0 +1,57 @@
+From linkinjeon@gmail.com Mon Dec 18 16:38:59 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <mmakassikis@freebox.fr>, Namjae Jeon <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-68-linkinjeon@kernel.org>
+
+From: Marios Makassikis <mmakassikis@freebox.fr>
+
+[ 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 <mmakassikis@freebox.fr>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..3742a13
--- /dev/null
@@ -0,0 +1,282 @@
+From linkinjeon@gmail.com Mon Dec 18 16:39:42 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-82-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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]  <TASK>
+[  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]  </TASK>
+
+Fixes: 39b291b86b59 ("ksmbd: return unsupported error on smb1 mount")
+Cc: stable@vger.kernel.org
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..db115df
--- /dev/null
@@ -0,0 +1,37 @@
+From linkinjeon@gmail.com Mon Dec 18 16:42:01 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, zdi-disclosures@trendmicro.com, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-125-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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 <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..787e107
--- /dev/null
@@ -0,0 +1,39 @@
+From stable+bounces-7644-greg=kroah.com@vger.kernel.org Mon Dec 18 16:37:20 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <yang.lee@linux.alibaba.com>, Abaci Robot <abaci@linux.alibaba.com>, Namjae Jeon <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-16-linkinjeon@kernel.org>
+
+From: Yang Li <yang.lee@linux.alibaba.com>
+
+[ 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 <abaci@linux.alibaba.com>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Yang Li <yang.lee@linux.alibaba.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..9177e0c
--- /dev/null
@@ -0,0 +1,43 @@
+From stable+bounces-7642-greg=kroah.com@vger.kernel.org Mon Dec 18 16:36:29 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <yang.lee@linux.alibaba.com>, Abaci Robot <abaci@linux.alibaba.com>, Namjae Jeon <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-14-linkinjeon@kernel.org>
+
+From: Yang Li <yang.lee@linux.alibaba.com>
+
+[ 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 <abaci@linux.alibaba.com>
+Fixes: 9496e268e3af ("ksmbd: add request buffer validation in smb2_set_info")
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Yang Li <yang.lee@linux.alibaba.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..640937a
--- /dev/null
@@ -0,0 +1,78 @@
+From linkinjeon@gmail.com Mon Dec 18 16:37:27 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <yang.lee@linux.alibaba.com>, Abaci Robot <abaci@linux.alibaba.com>, Namjae Jeon <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-40-linkinjeon@kernel.org>
+
+From: Yang Li <yang.lee@linux.alibaba.com>
+
+[ 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 <abaci@linux.alibaba.com>
+Signed-off-by: Yang Li <yang.lee@linux.alibaba.com>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..e09e32d
--- /dev/null
@@ -0,0 +1,33 @@
+From linkinjeon@gmail.com Mon Dec 18 16:39:25 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <colin.i.king@gmail.com>, Namjae Jeon <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-76-linkinjeon@kernel.org>
+
+From: Colin Ian King <colin.i.king@gmail.com>
+
+[ Upstream commit 7a17c61ee3b2683c40090179c273f4701fca9677 ]
+
+There is a spelling mistake in an error message. Fix it.
+
+Signed-off-by: Colin Ian King <colin.i.king@gmail.com>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..f32197f
--- /dev/null
@@ -0,0 +1,76 @@
+From linkinjeon@gmail.com Mon Dec 18 16:39:14 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <set_pte_at@outlook.com>, Namjae Jeon <linkinjeon@kernel.org>, Sergey Senozhatsky <senozhatsky@chromium.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-73-linkinjeon@kernel.org>
+
+From: Dawei Li <set_pte_at@outlook.com>
+
+[ Upstream commit f8d6e7442aa716a233c7eba99dec628f8885e00b ]
+
+syncronous->synchronous
+
+Signed-off-by: Dawei Li <set_pte_at@outlook.com>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Reviewed-by: Sergey Senozhatsky <senozhatsky@chromium.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..f84e5bb
--- /dev/null
@@ -0,0 +1,196 @@
+From linkinjeon@gmail.com Mon Dec 18 16:40:30 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, Per Forlin <per.forlin@axis.com>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-97-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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 <per.forlin@axis.com>
+Tested-by: Per Forlin <per.forlin@axis.com>
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..ab8a7b5
--- /dev/null
@@ -0,0 +1,35 @@
+From linkinjeon@gmail.com Mon Dec 18 16:40:20 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, Coverity Scan <scan-admin@coverity.com>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-94-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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 <scan-admin@coverity.com>
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..b2c4246
--- /dev/null
@@ -0,0 +1,47 @@
+From linkinjeon@gmail.com Mon Dec 18 16:40:24 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, Coverity Scan <scan-admin@coverity.com>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-95-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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 <scan-admin@coverity.com>
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..cbddab9
--- /dev/null
@@ -0,0 +1,50 @@
+From linkinjeon@gmail.com Mon Dec 18 16:41:29 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <machel@vivo.com>, Tom Talpey <tom@talpey.com>, Namjae Jeon <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-115-linkinjeon@kernel.org>
+
+From: Wang Ming <machel@vivo.com>
+
+[ 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 <machel@vivo.com>
+Acked-by: Tom Talpey <tom@talpey.com>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..5b55e91
--- /dev/null
@@ -0,0 +1,43 @@
+From linkinjeon@gmail.com Mon Dec 18 16:42:40 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-137-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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 <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..fc8121d
--- /dev/null
@@ -0,0 +1,156 @@
+From linkinjeon@gmail.com Mon Dec 18 16:41:49 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-121-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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 <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..2428128
--- /dev/null
@@ -0,0 +1,45 @@
+From linkinjeon@gmail.com Mon Dec 18 16:39:33 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, Miao Lihua <441884205@qq.com>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-79-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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 <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..43c7f33
--- /dev/null
@@ -0,0 +1,166 @@
+From linkinjeon@gmail.com Mon Dec 18 16:37:24 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, Hyunchul Lee <hyc.lee@gmail.com>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-39-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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 <linkinjeon@kernel.org>
+Reviewed-by: Hyunchul Lee <hyc.lee@gmail.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..8766853
--- /dev/null
@@ -0,0 +1,50 @@
+From linkinjeon@gmail.com Mon Dec 18 16:43:17 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, Robert Morris <rtm@csail.mit.edu>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-148-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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 <rtm@csail.mit.edu>
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..fd0370f
--- /dev/null
@@ -0,0 +1,37 @@
+From linkinjeon@gmail.com Mon Dec 18 16:38:37 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, Tom Talpey <tom@talpey.com>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-61-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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 <linkinjeon@kernel.org>
+Acked-by: Tom Talpey <tom@talpey.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..9340214
--- /dev/null
@@ -0,0 +1,270 @@
+From linkinjeon@gmail.com Mon Dec 18 16:39:08 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <set_pte_at@outlook.com>, Namjae Jeon <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-71-linkinjeon@kernel.org>
+
+From: Dawei Li <set_pte_at@outlook.com>
+
+[ 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 <set_pte_at@outlook.com>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..6b722ae
--- /dev/null
@@ -0,0 +1,138 @@
+From linkinjeon@gmail.com Mon Dec 18 16:39:11 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <set_pte_at@outlook.com>, Namjae Jeon <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-72-linkinjeon@kernel.org>
+
+From: Dawei Li <set_pte_at@outlook.com>
+
+[ 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 <set_pte_at@outlook.com>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..b1f8edd
--- /dev/null
@@ -0,0 +1,115 @@
+From linkinjeon@gmail.com Mon Dec 18 16:38:40 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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ä" <atteh.mailbox@gmail.com>, "Namjae Jeon" <linkinjeon@kernel.org>, "Steve French" <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-62-linkinjeon@kernel.org>
+
+From: Atte Heikkilä <atteh.mailbox@gmail.com>
+
+[ 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ä <atteh.mailbox@gmail.com>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 <net/request_sock.h>
+ #include <linux/kthread.h>
+ #include <linux/nls.h>
++#include <linux/unicode.h>
+ #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 <linux/namei.h>
+ #include <uapi/linux/xattr.h>
+ #include <linux/posix_acl.h>
++#include <linux/unicode.h>
+ #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 (file)
index 0000000..3a58822
--- /dev/null
@@ -0,0 +1,361 @@
+From linkinjeon@gmail.com Mon Dec 18 16:43:32 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-152-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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 <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..f499b51
--- /dev/null
@@ -0,0 +1,55 @@
+From linkinjeon@gmail.com Mon Dec 18 16:43:38 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-154-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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 <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..a73177c
--- /dev/null
@@ -0,0 +1,49 @@
+From linkinjeon@gmail.com Mon Dec 18 16:43:10 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-146-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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 <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..f715fcc
--- /dev/null
@@ -0,0 +1,51 @@
+From linkinjeon@gmail.com Mon Dec 18 16:43:20 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <zhouzongmin@kylinos.cn>, kernel test robot <lkp@intel.com>, Dan Carpenter <error27@gmail.com>, Namjae Jeon <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-149-linkinjeon@kernel.org>
+
+From: Zongmin Zhou <zhouzongmin@kylinos.cn>
+
+[ 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 <lkp@intel.com>
+Reported-by: Dan Carpenter <error27@gmail.com>
+Closes: https://lore.kernel.org/r/202311031837.H3yo7JVl-lkp@intel.com/
+Signed-off-by: Zongmin Zhou<zhouzongmin@kylinos.cn>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..76f46af
--- /dev/null
@@ -0,0 +1,107 @@
+From stable+bounces-7751-greg=kroah.com@vger.kernel.org Mon Dec 18 16:47:02 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-123-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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 <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..fc741a4
--- /dev/null
@@ -0,0 +1,42 @@
+From linkinjeon@gmail.com Mon Dec 18 16:38:34 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <tom@talpey.com>, Namjae Jeon <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-60-linkinjeon@kernel.org>
+
+From: Tom Talpey <tom@talpey.com>
+
+[ 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 <tom@talpey.com>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..db6ff59
--- /dev/null
@@ -0,0 +1,186 @@
+From stable+bounces-7645-greg=kroah.com@vger.kernel.org Mon Dec 18 16:37:48 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <hyc.lee@gmail.com>, Namjae Jeon <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-17-linkinjeon@kernel.org>
+
+From: Hyunchul Lee <hyc.lee@gmail.com>
+
+[ 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 <hyc.lee@gmail.com>
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..84422fd
--- /dev/null
@@ -0,0 +1,47 @@
+From linkinjeon@gmail.com Mon Dec 18 16:43:35 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-153-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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 <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..9984e9f
--- /dev/null
@@ -0,0 +1,40 @@
+From linkinjeon@gmail.com Mon Dec 18 16:36:54 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <christophe.jaillet@wanadoo.fr>, Hyunchul Lee <hyc.lee@gmail.com>, Namjae Jeon <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-29-linkinjeon@kernel.org>
+
+From: Christophe JAILLET <christophe.jaillet@wanadoo.fr>
+
+[ 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 <christophe.jaillet@wanadoo.fr>
+Acked-by: Hyunchul Lee <hyc.lee@gmail.com>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..4ec312b
--- /dev/null
@@ -0,0 +1,43 @@
+From linkinjeon@gmail.com Mon Dec 18 16:37:42 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <hyc.lee@gmail.com>, Namjae Jeon <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-44-linkinjeon@kernel.org>
+
+From: Hyunchul Lee <hyc.lee@gmail.com>
+
+[ Upstream commit 745bbc0995c25917dfafb645b8efb29813ef9e0b ]
+
+The writethrough flag is set again if is_rdma_channel is false.
+
+Signed-off-by: Hyunchul Lee <hyc.lee@gmail.com>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..aeecdf9
--- /dev/null
@@ -0,0 +1,64 @@
+From linkinjeon@gmail.com Mon Dec 18 16:39:17 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <set_pte_at@outlook.com>, Namjae Jeon <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-74-linkinjeon@kernel.org>
+
+From: Dawei Li <set_pte_at@outlook.com>
+
+[ 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 <set_pte_at@outlook.com>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..75229de
--- /dev/null
@@ -0,0 +1,44 @@
+From linkinjeon@gmail.com Mon Dec 18 16:42:07 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <stfrench@microsoft.com>, Namjae Jeon <linkinjeon@kernel.org>
+Message-ID: <20231218153454.8090-127-linkinjeon@kernel.org>
+
+From: Steve French <stfrench@microsoft.com>
+
+[ 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 <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..41baf20
--- /dev/null
@@ -0,0 +1,256 @@
+From linkinjeon@gmail.com Mon Dec 18 16:37:03 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, Hyunchul Lee <hyc.lee@gmail.com>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-32-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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 <linkinjeon@kernel.org>
+Reviewed-by: Hyunchul Lee <hyc.lee@gmail.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..d339e74
--- /dev/null
@@ -0,0 +1,61 @@
+From linkinjeon@gmail.com Mon Dec 18 16:38:10 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, Hyunchul Lee <hyc.lee@gmail.com>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-52-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ Upstream commit 823d0d3e2b05791ba8cbab22574b947c21f89c18 ]
+
+Removed the use of unneeded generic_fillattr() in smb2_open().
+
+Reviewed-by: Hyunchul Lee <hyc.lee@gmail.com>
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..358072b
--- /dev/null
@@ -0,0 +1,44 @@
+From stable+bounces-7633-greg=kroah.com@vger.kernel.org Mon Dec 18 16:35:38 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, Hyunchul Lee <hyc.lee@gmail.com>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-5-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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 <hyc.lee@gmail.com>
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..e77c83b
--- /dev/null
@@ -0,0 +1,54 @@
+From stable+bounces-7632-greg=kroah.com@vger.kernel.org Mon Dec 18 16:35:37 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <christophe.jaillet@wanadoo.fr>, Namjae Jeon <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-4-linkinjeon@kernel.org>
+
+From: Christophe JAILLET <christophe.jaillet@wanadoo.fr>
+
+[ 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 <linkinjeon@kernel.org>
+Signed-off-by: Christophe JAILLET <christophe.jaillet@wanadoo.fr>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..3342780
--- /dev/null
@@ -0,0 +1,1833 @@
+From stable+bounces-7634-greg=kroah.com@vger.kernel.org Mon Dec 18 16:35:40 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, Ronnie Sahlberg <ronniesahlberg@gmail.com>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-6-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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 <ronniesahlberg@gmail.com>
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..760665a
--- /dev/null
@@ -0,0 +1,173 @@
+From stable+bounces-7635-greg=kroah.com@vger.kernel.org Mon Dec 18 16:35:41 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, Ronnie Sahlberg <ronniesahlberg@gmail.com>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-7-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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 <ronniesahlberg@gmail.com>
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..448e5f4
--- /dev/null
@@ -0,0 +1,76 @@
+From linkinjeon@gmail.com Mon Dec 18 16:37:57 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <hyc.lee@gmail.com>, Namjae Jeon <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-48-linkinjeon@kernel.org>
+
+From: Hyunchul Lee <hyc.lee@gmail.com>
+
+[ 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 <hyc.lee@gmail.com>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..ba75e57
--- /dev/null
@@ -0,0 +1,32 @@
+From linkinjeon@gmail.com Mon Dec 18 16:42:10 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-128-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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 <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..55821b7
--- /dev/null
@@ -0,0 +1,79 @@
+From linkinjeon@gmail.com Mon Dec 18 16:39:55 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <ddiss@suse.de>, Namjae Jeon <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-86-linkinjeon@kernel.org>
+
+From: David Disseldorp <ddiss@suse.de>
+
+[ 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 <ddiss@suse.de>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..76f7b69
--- /dev/null
@@ -0,0 +1,32 @@
+From linkinjeon@gmail.com Mon Dec 18 16:42:49 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <hank20010209@gmail.com>, Namjae Jeon <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-140-linkinjeon@kernel.org>
+
+From: Cheng-Han Wu <hank20010209@gmail.com>
+
+[ 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 <hank20010209@gmail.com>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..ffde24d
--- /dev/null
@@ -0,0 +1,41 @@
+From stable+bounces-7639-greg=kroah.com@vger.kernel.org Mon Dec 18 16:36:10 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <mmakassikis@freebox.fr>, Namjae Jeon <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-11-linkinjeon@kernel.org>
+
+From: Marios Makassikis <mmakassikis@freebox.fr>
+
+[ Upstream commit 305f8bda15ebbe4004681286a5c67d0dc296c771 ]
+
+These fields are remnants of the not upstreamed SMB1 code.
+
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Marios Makassikis <mmakassikis@freebox.fr>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..b5975de
--- /dev/null
@@ -0,0 +1,55 @@
+From linkinjeon@gmail.com Mon Dec 18 16:39:36 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <trix@redhat.com>, Sergey Senozhatsky <senozhatsky@chromium.org>, Namjae Jeon <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-80-linkinjeon@kernel.org>
+
+From: Tom Rix <trix@redhat.com>
+
+[ 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 <trix@redhat.com>
+Reviewed-by: Sergey Senozhatsky <senozhatsky@chromium.org>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..28b15d9
--- /dev/null
@@ -0,0 +1,51 @@
+From linkinjeon@gmail.com Mon Dec 18 16:37:45 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-45-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ Upstream commit 1c90b54718fdea4f89e7e0c2415803f33f6d0b00 ]
+
+remove unused ksmbd_share_configs_cleanup function.
+
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..d772f74
--- /dev/null
@@ -0,0 +1,55 @@
+From linkinjeon@gmail.com Mon Dec 18 16:40:55 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, Sergey Senozhatsky <senozhatsky@chromium.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-105-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ Upstream commit 7bd9f0876fdef00f4e155be35e6b304981a53f80 ]
+
+Remove unused ksmbd_tree_conn_share function.
+
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Reviewed-by: Sergey Senozhatsky <senozhatsky@chromium.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..3e83c04
--- /dev/null
@@ -0,0 +1,74 @@
+From stable+bounces-7638-greg=kroah.com@vger.kernel.org Mon Dec 18 16:36:08 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <mmakassikis@freebox.fr>, Namjae Jeon <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-10-linkinjeon@kernel.org>
+
+From: Marios Makassikis <mmakassikis@freebox.fr>
+
+[ 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 <linkinjeon@kernel.org>
+Signed-off-by: Marios Makassikis <mmakassikis@freebox.fr>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..efcf37b
--- /dev/null
@@ -0,0 +1,97 @@
+From linkinjeon@gmail.com Mon Dec 18 16:42:52 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-141-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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 <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..2904839
--- /dev/null
@@ -0,0 +1,41 @@
+From linkinjeon@gmail.com Mon Dec 18 16:41:26 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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" <gustavoars@kernel.org>, Kees Cook <keescook@chromium.org>, Namjae Jeon <linkinjeon@kernel.org>, Sergey Senozhatsky <senozhatsky@chromium.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-114-linkinjeon@kernel.org>
+
+From: "Gustavo A. R. Silva" <gustavoars@kernel.org>
+
+[ 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 <gustavoars@kernel.org>
+Reviewed-by: Kees Cook <keescook@chromium.org>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Reviewed-by: Sergey Senozhatsky <senozhatsky@chromium.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..d693f0c
--- /dev/null
@@ -0,0 +1,126 @@
+From linkinjeon@gmail.com Mon Dec 18 16:38:49 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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" <gustavoars@kernel.org>, Sergey Senozhatsky <senozhatsky@chromium.org>, Namjae Jeon <linkinjeon@kernel.org>, Kees Cook <keescook@chromium.org>
+Message-ID: <20231218153454.8090-65-linkinjeon@kernel.org>
+
+From: "Gustavo A. R. Silva" <gustavoars@kernel.org>
+
+[ 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 <gustavoars@kernel.org>
+Reviewed-by: Sergey Senozhatsky <senozhatsky@chromium.org>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Reviewed-by: Kees Cook <keescook@chromium.org>
+Signed-off-by: Kees Cook <keescook@chromium.org>
+Link: https://lore.kernel.org/r/Y3OxronfaPYv9qGP@work
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..6f2f3ba
--- /dev/null
@@ -0,0 +1,34 @@
+From linkinjeon@gmail.com Mon Dec 18 16:41:11 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <luhongfei@vivo.com>, Namjae Jeon <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-110-linkinjeon@kernel.org>
+
+From: Lu Hongfei <luhongfei@vivo.com>
+
+[ Upstream commit f65fadb0422537d73f9a6472861852dc2f7a6a5b ]
+
+It would be better to replace the traditional ternary conditional
+operator with min() in compare_sids.
+
+Signed-off-by: Lu Hongfei <luhongfei@vivo.com>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..a6f8fdb
--- /dev/null
@@ -0,0 +1,99 @@
+From linkinjeon@gmail.com Mon Dec 18 16:36:57 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <jakobkoschel@gmail.com>, Hyunchul Lee <hyc.lee@gmail.com>, Namjae Jeon <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-30-linkinjeon@kernel.org>
+
+From: Jakob Koschel <jakobkoschel@gmail.com>
+
+[ 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 <jakobkoschel@gmail.com>
+Reviewed-by: Hyunchul Lee <hyc.lee@gmail.com>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..97e95c3
--- /dev/null
@@ -0,0 +1,115 @@
+From linkinjeon@gmail.com Mon Dec 18 16:37:53 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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ä" <atteh.mailbox@gmail.com>, "Namjae Jeon" <linkinjeon@kernel.org>, "Steve French" <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-47-linkinjeon@kernel.org>
+
+From: Atte Heikkilä <atteh.mailbox@gmail.com>
+
+[ 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ä <atteh.mailbox@gmail.com>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..2e95603
--- /dev/null
@@ -0,0 +1,33 @@
+From linkinjeon@gmail.com Mon Dec 18 16:41:02 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, Dan Carpenter <dan.carpenter@linaro.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-107-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ Upstream commit cf5e7f734f445588a30350591360bca2f6bf016f ]
+
+Return a literal instead of 'err' in ksmbd_vfs_kern_path_locked().
+
+Reported-by: Dan Carpenter <dan.carpenter@linaro.org>
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..fcfa3b2
--- /dev/null
@@ -0,0 +1,98 @@
+From linkinjeon@gmail.com Mon Dec 18 16:42:17 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, Tom Talpey <tom@talpey.com>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-130-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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]  <TASK>
+[  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 <tom@talpey.com>
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..a88186f
--- /dev/null
@@ -0,0 +1,56 @@
+From linkinjeon@gmail.com Mon Dec 18 16:39:05 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <mmakassikis@freebox.fr>, Namjae Jeon <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-70-linkinjeon@kernel.org>
+
+From: Marios Makassikis <mmakassikis@freebox.fr>
+
+[ 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 <mmakassikis@freebox.fr>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..236b742
--- /dev/null
@@ -0,0 +1,173 @@
+From linkinjeon@gmail.com Mon Dec 18 16:43:28 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-151-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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 <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..45bffb6
--- /dev/null
@@ -0,0 +1,87 @@
+From stable+bounces-7646-greg=kroah.com@vger.kernel.org Mon Dec 18 16:38:15 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-18-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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 <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..66a8683
--- /dev/null
@@ -0,0 +1,84 @@
+From stable+bounces-7640-greg=kroah.com@vger.kernel.org Mon Dec 18 16:36:25 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-12-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ Upstream commit a58b45a4dbfd0bf2ebb157789da4d8e6368afb1b ]
+
+Set ipv4 and ipv6 address in FSCTL_QUERY_NETWORK_INTERFACE_INFO.
+
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..6b601a1
--- /dev/null
@@ -0,0 +1,53 @@
+From linkinjeon@gmail.com Mon Dec 18 16:38:19 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-55-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ Upstream commit f6c2b201da7588f7f7688ddc99b7bb000609129c ]
+
+Set file permission mode to match Samba server posix extension behavior.
+
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..7d1f0d9
--- /dev/null
@@ -0,0 +1,73 @@
+From linkinjeon@gmail.com Mon Dec 18 16:39:48 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <ddiss@suse.de>, Namjae Jeon <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-84-linkinjeon@kernel.org>
+
+From: David Disseldorp <ddiss@suse.de>
+
+[ Upstream commit 34e8ccf9ce24b6b2e275bbe35cd392e18fbbd369 ]
+
+There are no early returns, so marshalling the incremented
+NegotiateContextCount with every context is unnecessary.
+
+Signed-off-by: David Disseldorp <ddiss@suse.de>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..35714ac
--- /dev/null
@@ -0,0 +1,57 @@
+From linkinjeon@gmail.com Mon Dec 18 16:38:28 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-58-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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 <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..48a3dcd
--- /dev/null
@@ -0,0 +1,96 @@
+From linkinjeon@gmail.com Mon Dec 18 16:38:52 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-66-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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 <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..33ccce4
--- /dev/null
@@ -0,0 +1,34 @@
+From linkinjeon@gmail.com Mon Dec 18 16:36:49 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <stfrench@microsoft.com>, Namjae Jeon <linkinjeon@kernel.org>
+Message-ID: <20231218153454.8090-28-linkinjeon@kernel.org>
+
+From: Steve French <stfrench@microsoft.com>
+
+[ 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 <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..f57999c
--- /dev/null
@@ -0,0 +1,225 @@
+From stable+bounces-7647-greg=kroah.com@vger.kernel.org Mon Dec 18 16:38:58 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <hyc.lee@gmail.com>, Namjae Jeon <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-19-linkinjeon@kernel.org>
+
+From: Hyunchul Lee <hyc.lee@gmail.com>
+
+[ 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 ]  <TASK>
+[   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 <linkinjeon@kernel.org>
+Signed-off-by: Hyunchul Lee <hyc.lee@gmail.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..dd484af
--- /dev/null
@@ -0,0 +1,250 @@
+From linkinjeon@gmail.com Mon Dec 18 16:37:09 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <hyc.lee@gmail.com>, Namjae Jeon <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-34-linkinjeon@kernel.org>
+
+From: Hyunchul Lee <hyc.lee@gmail.com>
+
+[ 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 <hyc.lee@gmail.com>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..2121777
--- /dev/null
@@ -0,0 +1,40 @@
+From stable+bounces-7649-greg=kroah.com@vger.kernel.org Mon Dec 18 16:39:23 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <hyc.lee@gmail.com>, Namjae Jeon <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-21-linkinjeon@kernel.org>
+
+From: Hyunchul Lee <hyc.lee@gmail.com>
+
+[ 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 <linkinjeon@kernel.org>
+Signed-off-by: Hyunchul Lee <hyc.lee@gmail.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..9f49d5d
--- /dev/null
@@ -0,0 +1,43 @@
+From linkinjeon@gmail.com Mon Dec 18 16:37:19 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <hyc.lee@gmail.com>, Namjae Jeon <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-37-linkinjeon@kernel.org>
+
+From: Hyunchul Lee <hyc.lee@gmail.com>
+
+[ Upstream commit 4e3edd0092704b25626a0fe60a974f6f382ff93d ]
+
+Make get_sg_list return EINVAL if there aren't
+mapped scatterlists.
+
+Signed-off-by: Hyunchul Lee <hyc.lee@gmail.com>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..49b3402
--- /dev/null
@@ -0,0 +1,77 @@
+From stable+bounces-7648-greg=kroah.com@vger.kernel.org Mon Dec 18 16:39:20 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <hyc.lee@gmail.com>, Namjae Jeon <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-20-linkinjeon@kernel.org>
+
+From: Hyunchul Lee <hyc.lee@gmail.com>
+
+[ 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 <linkinjeon@kernel.org>
+Signed-off-by: Hyunchul Lee <hyc.lee@gmail.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..9c2f5f4
--- /dev/null
@@ -0,0 +1,40 @@
+From linkinjeon@gmail.com Mon Dec 18 16:37:31 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <hyc.lee@gmail.com>, Yufan Chen <wiz.chen@gmail.com>, Namjae Jeon <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-41-linkinjeon@kernel.org>
+
+From: Hyunchul Lee <hyc.lee@gmail.com>
+
+[ 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 <wiz.chen@gmail.com>
+Signed-off-by: Hyunchul Lee <hyc.lee@gmail.com>
+Tested-by: Yufan Chen <wiz.chen@gmail.com>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..5f85cea
--- /dev/null
@@ -0,0 +1,140 @@
+From stable+bounces-7651-greg=kroah.com@vger.kernel.org Mon Dec 18 16:40:20 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <hyc.lee@gmail.com>, Namjae Jeon <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-23-linkinjeon@kernel.org>
+
+From: Hyunchul Lee <hyc.lee@gmail.com>
+
+[ 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 <linkinjeon@kernel.org>
+Signed-off-by: Hyunchul Lee <hyc.lee@gmail.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..c7f03f7
--- /dev/null
@@ -0,0 +1,262 @@
+From stable+bounces-7666-greg=kroah.com@vger.kernel.org Mon Dec 18 16:42:47 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <hyc.lee@gmail.com>, Namjae Jeon <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-38-linkinjeon@kernel.org>
+
+From: Hyunchul Lee <hyc.lee@gmail.com>
+
+[ 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 <hyc.lee@gmail.com>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..b44a256
--- /dev/null
@@ -0,0 +1,290 @@
+From linkinjeon@gmail.com Mon Dec 18 16:37:13 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <hyc.lee@gmail.com>, Namjae Jeon <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-35-linkinjeon@kernel.org>
+
+From: Hyunchul Lee <hyc.lee@gmail.com>
+
+[ 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 <hyc.lee@gmail.com>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..0ffa5d2
--- /dev/null
@@ -0,0 +1,66 @@
+From linkinjeon@gmail.com Mon Dec 18 16:37:35 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <hyc.lee@gmail.com>, Namjae Jeon <linkinjeon@kernel.org>, Tom Talpey <tom@talpey.com>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-42-linkinjeon@kernel.org>
+
+From: Hyunchul Lee <hyc.lee@gmail.com>
+
+[ 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 <hyc.lee@gmail.com>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Reviewed-by: Tom Talpey <tom@talpey.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..f9d1906
--- /dev/null
@@ -0,0 +1,42 @@
+From stable+bounces-7671-greg=kroah.com@vger.kernel.org Mon Dec 18 16:42:52 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <christophe.jaillet@wanadoo.fr>, Namjae Jeon <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-43-linkinjeon@kernel.org>
+
+From: Christophe JAILLET <christophe.jaillet@wanadoo.fr>
+
+[ 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 <christophe.jaillet@wanadoo.fr>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 <longli@microsoft.com>,
+  *            Hyunchul Lee <hyc.lee@gmail.com>
+- *
+- *   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 (file)
index 0000000..0cebe39
--- /dev/null
@@ -0,0 +1,105 @@
+From linkinjeon@gmail.com Mon Dec 18 16:37:15 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <hyc.lee@gmail.com>, Namjae Jeon <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-36-linkinjeon@kernel.org>
+
+From: Hyunchul Lee <hyc.lee@gmail.com>
+
+[ 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 <hyc.lee@gmail.com>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..8a7f0a0
--- /dev/null
@@ -0,0 +1,93 @@
+From linkinjeon@gmail.com Mon Dec 18 16:36:36 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <hyc.lee@gmail.com>, Namjae Jeon <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-24-linkinjeon@kernel.org>
+
+From: Hyunchul Lee <hyc.lee@gmail.com>
+
+[ 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 <linkinjeon@kernel.org>
+Signed-off-by: Hyunchul Lee <hyc.lee@gmail.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..a666c34
--- /dev/null
@@ -0,0 +1,415 @@
+From linkinjeon@gmail.com Mon Dec 18 16:36:46 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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)" <pc@cjr.nz>, Tom Talpey <tom@talpey.com>, Namjae Jeon <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-27-linkinjeon@kernel.org>
+
+From: "Paulo Alcantara (SUSE)" <pc@cjr.nz>
+
+[ 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) <pc@cjr.nz>
+Reviewed-by: Tom Talpey <tom@talpey.com>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..921a645
--- /dev/null
@@ -0,0 +1,39 @@
+From linkinjeon@gmail.com Mon Dec 18 16:41:41 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <yangyingliang@huawei.com>, Namjae Jeon <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-119-linkinjeon@kernel.org>
+
+From: Yang Yingliang <yangyingliang@huawei.com>
+
+[ Upstream commit 084ba46fc41c21ba827fd92e61f78def7a6e52ea ]
+
+Use kmemdup_nul() helper instead of open-coding to
+simplify the code.
+
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Yang Yingliang <yangyingliang@huawei.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..9c20039
--- /dev/null
@@ -0,0 +1,56 @@
+From linkinjeon@gmail.com Mon Dec 18 16:39:20 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <stfrench@microsoft.com>, Namjae Jeon <linkinjeon@kernel.org>, David Howells <dhowells@redhat.com>
+Message-ID: <20231218153454.8090-75-linkinjeon@kernel.org>
+
+From: Steve French <stfrench@microsoft.com>
+
+[ 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 <linkinjeon@kernel.org>
+Acked-by: David Howells <dhowells@redhat.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..76b62ee
--- /dev/null
@@ -0,0 +1,48 @@
+From linkinjeon@gmail.com Mon Dec 18 16:38:55 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <jlayton@kernel.org>, David Howells <dhowells@redhat.com>, Namjae Jeon <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-67-linkinjeon@kernel.org>
+
+From: Jeff Layton <jlayton@kernel.org>
+
+[ 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 <dhowells@redhat.com>
+Signed-off-by: Jeff Layton <jlayton@kernel.org>
+Reviewed-by: David Howells <dhowells@redhat.com>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..3432936
--- /dev/null
@@ -0,0 +1,33 @@
+From stable+bounces-7630-greg=kroah.com@vger.kernel.org Mon Dec 18 16:35:31 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <slow@samba.org>, Namjae Jeon <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-2-linkinjeon@kernel.org>
+
+From: Ralph Boehme <slow@samba.org>
+
+[ Upstream commit a088ac859f8124d491f02a19d080fc5ee4dbd202 ]
+
+Use ksmbd_req_buf_next() in ksmbd_verify_smb_message().
+
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Ralph Boehme <slow@samba.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..3efdbef
--- /dev/null
@@ -0,0 +1,102 @@
+From linkinjeon@gmail.com Mon Dec 18 16:41:08 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, kernel test robot <lkp@intel.com>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-109-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ Upstream commit 81a94b27847f7d2e499415db14dd9dc7c22b19b0 ]
+
+Use kvzalloc instead of kvmalloc.
+
+Reported-by: kernel test robot <lkp@intel.com>
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..7f0a62c
--- /dev/null
@@ -0,0 +1,36 @@
+From linkinjeon@gmail.com Mon Dec 18 16:40:59 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, Dan Carpenter <error27@gmail.com>, Sergey Senozhatsky <senozhatsky@chromium.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-106-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ Upstream commit f87d4f85f43f0d4b12ef64b015478d8053e1a33e ]
+
+Use kzalloc() instead of __GFP_ZERO.
+
+Reported-by: Dan Carpenter <error27@gmail.com>
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Reviewed-by: Sergey Senozhatsky <senozhatsky@chromium.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..c883705
--- /dev/null
@@ -0,0 +1,43 @@
+From linkinjeon@gmail.com Mon Dec 18 16:36:42 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <tklauser@distanz.ch>, Namjae Jeon <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-26-linkinjeon@kernel.org>
+
+From: Tobias Klauser <tklauser@distanz.ch>
+
+[ Upstream commit 1b699bf3a8786f7d41eebd9f6ba673185fa5b6bd ]
+
+Use netif_is_bridge_port defined in <linux/netdevice.h> instead of
+open-coding it.
+
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Tobias Klauser <tklauser@distanz.ch>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..6af930d
--- /dev/null
@@ -0,0 +1,211 @@
+From linkinjeon@gmail.com Mon Dec 18 16:35:44 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <hyc.lee@gmail.com>, Namjae Jeon <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-9-linkinjeon@kernel.org>
+
+From: Hyunchul Lee <hyc.lee@gmail.com>
+
+[ Upstream commit 294277410cf3b46bee2b8282ab754e52975c0a70 ]
+
+Use look_up_OID to decode OIDs rather than
+implementing functions.
+
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Hyunchul Lee <hyc.lee@gmail.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..751854c
--- /dev/null
@@ -0,0 +1,36 @@
+From linkinjeon@gmail.com Mon Dec 18 16:41:21 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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" <gustavoars@kernel.org>, Kees Cook <keescook@chromium.org>, Namjae Jeon <linkinjeon@kernel.org>, Sergey Senozhatsky <senozhatsky@chromium.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-113-linkinjeon@kernel.org>
+
+From: "Gustavo A. R. Silva" <gustavoars@kernel.org>
+
+[ 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 <gustavoars@kernel.org>
+Reviewed-by: Kees Cook <keescook@chromium.org>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Reviewed-by: Sergey Senozhatsky <senozhatsky@chromium.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..8560f43
--- /dev/null
@@ -0,0 +1,156 @@
+From linkinjeon@gmail.com Mon Dec 18 16:37:48 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, Hyunchul Lee <hyc.lee@gmail.com>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-46-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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 <linkinjeon@kernel.org>
+Reviewed-by: Hyunchul Lee <hyc.lee@gmail.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..29eebb6
--- /dev/null
@@ -0,0 +1,95 @@
+From linkinjeon@gmail.com Mon Dec 18 16:37:06 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, Marios Makassikis <mmakassikis@freebox.fr>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-33-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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 <mmakassikis@freebox.fr>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..6abf894
--- /dev/null
@@ -0,0 +1,70 @@
+From linkinjeon@gmail.com Mon Dec 18 16:41:36 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, zdi-disclosures@trendmicro.com, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-117-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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 <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..0017c95
--- /dev/null
@@ -0,0 +1,177 @@
+From linkinjeon@gmail.com Mon Dec 18 16:38:46 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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ä" <atteh.mailbox@gmail.com>, "Tom Talpey" <tom@talpey.com>, "Namjae Jeon" <linkinjeon@kernel.org>, "Steve French" <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-64-linkinjeon@kernel.org>
+
+From: Atte Heikkilä <atteh.mailbox@gmail.com>
+
+[ 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ä <atteh.mailbox@gmail.com>
+Acked-by: Tom Talpey <tom@talpey.com>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 <linux/workqueue.h>
+ #include <linux/hashtable.h>
+ #include <linux/path.h>
++#include <linux/unicode.h>
+ 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 (file)
index 0000000..530d3bd
--- /dev/null
@@ -0,0 +1,95 @@
+From linkinjeon@gmail.com Mon Dec 18 16:40:49 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <linkinjeon@kernel.org>, Chih-Yen Chang <cc85nod@gmail.com>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-103-linkinjeon@kernel.org>
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ 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]  <TASK>
+[   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 <cc85nod@gmail.com>
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..bc58be3
--- /dev/null
@@ -0,0 +1,45 @@
+From stable+bounces-7631-greg=kroah.com@vger.kernel.org Mon Dec 18 16:35:34 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <slow@samba.org>, Tom Talpey <tom@talpey.com>, Ronnie Sahlberg <ronniesahlberg@gmail.com>, Hyunchul Lee <hyc.lee@gmail.com>, Namjae Jeon <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>
+Message-ID: <20231218153454.8090-3-linkinjeon@kernel.org>
+
+From: Ralph Boehme <slow@samba.org>
+
+[ Upstream commit 341b16014bf871115f0883e831372c4b76389d03 ]
+
+Use cmd helper variable in smb2_get_ksmbd_tcon().
+
+Cc: Tom Talpey <tom@talpey.com>
+Cc: Ronnie Sahlberg <ronniesahlberg@gmail.com>
+Cc: Steve French <smfrench@gmail.com>
+Cc: Hyunchul Lee <hyc.lee@gmail.com>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Ralph Boehme <slow@samba.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..d854eec
--- /dev/null
@@ -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 (file)
index 0000000..a683899
--- /dev/null
@@ -0,0 +1,73 @@
+From linkinjeon@gmail.com Mon Dec 18 16:37:00 2023
+From: Namjae Jeon <linkinjeon@kernel.org>
+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 <stfrench@microsoft.com>, Paulo Alcantara <pc@cjr.nz>, Namjae Jeon <linkinjeon@kernel.org>
+Message-ID: <20231218153454.8090-31-linkinjeon@kernel.org>
+
+From: Steve French <stfrench@microsoft.com>
+
+[ 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) <pc@cjr.nz>
+Reviewed-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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;