From 6551300dc452ac16a855a83dbd1e74899542d3b3 Mon Sep 17 00:00:00 2001 From: Michael Bommarito Date: Tue, 14 Apr 2026 18:54:38 -0400 Subject: [PATCH 01/18] smb: server: fix active_num_conn leak on transport allocation failure Commit 77ffbcac4e56 ("smb: server: fix leak of active_num_conn in ksmbd_tcp_new_connection()") addressed the kthread_run() failure path. The earlier alloc_transport() == NULL path in the same function has the same leak, is reachable pre-authentication via any TCP connect to port 445, and was empirically reproduced on UML (ARCH=um, v7.0-rc7): a small number of forced allocation failures were sufficient to put ksmbd into a state where every subsequent connection attempt was rejected for the remainder of the boot. ksmbd_kthread_fn() increments active_num_conn before calling ksmbd_tcp_new_connection() and discards the return value, so when alloc_transport() returns NULL the socket is released and -ENOMEM returned without decrementing the counter. Each such failure permanently consumes one slot from the max_connections pool; once cumulative failures reach the cap, atomic_inc_return() hits the threshold on every subsequent accept and every new connection is rejected. The counter is only reset by module reload. An unauthenticated remote attacker can drive the server toward the memory pressure that makes alloc_transport() fail by holding open connections with large RFC1002 lengths up to MAX_STREAM_PROT_LEN (0x00FFFFFF); natural transient allocation failures on a loaded host produce the same drift more slowly. Mirror the existing rollback pattern in ksmbd_kthread_fn(): on the alloc_transport() failure path, decrement active_num_conn gated on server_conf.max_connections. Repro details: with the patch reverted, forced alloc_transport() NULL returns leaked counter slots and subsequent connection attempts -- including legitimate connects issued after the forced-fail window had closed -- were all rejected with "Limit the maximum number of connections". With this patch applied, the same connect sequence produces no rejections and the counter cycles cleanly between zero and one on every accept. Fixes: 0d0d4680db22 ("ksmbd: add max connections parameter") Cc: stable@vger.kernel.org Assisted-by: Claude:claude-opus-4-6 Assisted-by: Codex:gpt-5-4 Signed-off-by: Michael Bommarito Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_tcp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/smb/server/transport_tcp.c b/fs/smb/server/transport_tcp.c index 7e29b06820e2..8d7fe71f525c 100644 --- a/fs/smb/server/transport_tcp.c +++ b/fs/smb/server/transport_tcp.c @@ -183,6 +183,8 @@ static int ksmbd_tcp_new_connection(struct socket *client_sk) t = alloc_transport(client_sk); if (!t) { sock_release(client_sk); + if (server_conf.max_connections) + atomic_dec(&active_num_conn); return -ENOMEM; } From d6a6aa81eac2c9bff66dc6e191179cb69a14426b Mon Sep 17 00:00:00 2001 From: Michael Bommarito Date: Wed, 15 Apr 2026 07:25:00 -0400 Subject: [PATCH 02/18] ksmbd: validate response sizes in ipc_validate_msg() ipc_validate_msg() computes the expected message size for each response type by adding (or multiplying) attacker-controlled fields from the daemon response to a fixed struct size in unsigned int arithmetic. Three cases can overflow: KSMBD_EVENT_RPC_REQUEST: msg_sz = sizeof(struct ksmbd_rpc_command) + resp->payload_sz; KSMBD_EVENT_SHARE_CONFIG_REQUEST: msg_sz = sizeof(struct ksmbd_share_config_response) + resp->payload_sz; KSMBD_EVENT_LOGIN_REQUEST_EXT: msg_sz = sizeof(struct ksmbd_login_response_ext) + resp->ngroups * sizeof(gid_t); resp->payload_sz is __u32 and resp->ngroups is __s32. Each addition can wrap in unsigned int; the multiplication by sizeof(gid_t) mixes signed and size_t, so a negative ngroups is converted to SIZE_MAX before the multiply. A wrapped value of msg_sz that happens to equal entry->msg_sz bypasses the size check on the next line, and downstream consumers (smb2pdu.c:6742 memcpy using rpc_resp->payload_sz, kmemdup in ksmbd_alloc_user using resp_ext->ngroups) then trust the unverified length. Use check_add_overflow() on the RPC_REQUEST and SHARE_CONFIG_REQUEST paths to detect integer overflow without constraining functional payload size; userspace ksmbd-tools grows NDR responses in 4096-byte chunks for calls like NetShareEnumAll, so a hard transport cap is unworkable on the response side. For LOGIN_REQUEST_EXT, reject resp->ngroups outside the signed [0, NGROUPS_MAX] range up front and report the error from ipc_validate_msg() so it fires at the IPC boundary; with that bound the subsequent multiplication and addition stay well below UINT_MAX. The now-redundant ngroups check and pr_err in ksmbd_alloc_user() are removed. This is the response-side analogue of aab98e2dbd64 ("ksmbd: fix integer overflows on 32 bit systems"), which hardened the request side. Fixes: 0626e6641f6b ("cifsd: add server handler for central processing and tranport layers") Fixes: a77e0e02af1c ("ksmbd: add support for supplementary groups") Cc: stable@vger.kernel.org Assisted-by: Claude:claude-opus-4-6 Assisted-by: Codex:gpt-5-4 Signed-off-by: Michael Bommarito Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/mgmt/user_config.c | 6 ------ fs/smb/server/transport_ipc.c | 16 +++++++++++++--- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/fs/smb/server/mgmt/user_config.c b/fs/smb/server/mgmt/user_config.c index a3183fe5c536..cf45841d9d1b 100644 --- a/fs/smb/server/mgmt/user_config.c +++ b/fs/smb/server/mgmt/user_config.c @@ -56,12 +56,6 @@ struct ksmbd_user *ksmbd_alloc_user(struct ksmbd_login_response *resp, goto err_free; if (resp_ext) { - if (resp_ext->ngroups > NGROUPS_MAX) { - pr_err("ngroups(%u) from login response exceeds max groups(%d)\n", - resp_ext->ngroups, NGROUPS_MAX); - goto err_free; - } - user->sgid = kmemdup(resp_ext->____payload, resp_ext->ngroups * sizeof(gid_t), KSMBD_DEFAULT_GFP); diff --git a/fs/smb/server/transport_ipc.c b/fs/smb/server/transport_ipc.c index f7aa427a06fe..0c581b9624d3 100644 --- a/fs/smb/server/transport_ipc.c +++ b/fs/smb/server/transport_ipc.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "vfs_cache.h" #include "transport_ipc.h" @@ -496,7 +497,9 @@ static int ipc_validate_msg(struct ipc_msg_table_entry *entry) { struct ksmbd_rpc_command *resp = entry->response; - msg_sz = sizeof(struct ksmbd_rpc_command) + resp->payload_sz; + if (check_add_overflow(sizeof(struct ksmbd_rpc_command), + resp->payload_sz, &msg_sz)) + return -EINVAL; break; } case KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST: @@ -515,8 +518,9 @@ static int ipc_validate_msg(struct ipc_msg_table_entry *entry) if (resp->payload_sz < resp->veto_list_sz) return -EINVAL; - msg_sz = sizeof(struct ksmbd_share_config_response) + - resp->payload_sz; + if (check_add_overflow(sizeof(struct ksmbd_share_config_response), + resp->payload_sz, &msg_sz)) + return -EINVAL; } break; } @@ -525,6 +529,12 @@ static int ipc_validate_msg(struct ipc_msg_table_entry *entry) struct ksmbd_login_response_ext *resp = entry->response; if (resp->ngroups) { + if (resp->ngroups < 0 || + resp->ngroups > NGROUPS_MAX) { + pr_err("ngroups(%d) from login response exceeds max groups(%d)\n", + resp->ngroups, NGROUPS_MAX); + return -EINVAL; + } msg_sz = sizeof(struct ksmbd_login_response_ext) + resp->ngroups * sizeof(gid_t); } From d07b26f39246a82399661936dd0c853983cfade7 Mon Sep 17 00:00:00 2001 From: Michael Bommarito Date: Tue, 14 Apr 2026 15:15:33 -0400 Subject: [PATCH 03/18] ksmbd: require minimum ACE size in smb_check_perm_dacl() Both ACE-walk loops in smb_check_perm_dacl() only guard against an under-sized remaining buffer, not against an ACE whose declared `ace->size` is smaller than the struct it claims to describe: if (offsetof(struct smb_ace, access_req) > aces_size) break; ace_size = le16_to_cpu(ace->size); if (ace_size > aces_size) break; The first check only requires the 4-byte ACE header to be in bounds; it does not require access_req (4 bytes at offset 4) to be readable. An attacker who has set a crafted DACL on a file they own can declare ace->size == 4 with aces_size == 4, pass both checks, and then granted |= le32_to_cpu(ace->access_req); /* upper loop */ compare_sids(&sid, &ace->sid); /* lower loop */ reads access_req at offset 4 (OOB by up to 4 bytes) and ace->sid at offset 8 (OOB by up to CIFS_SID_BASE_SIZE + SID_MAX_SUB_AUTHORITIES * 4 bytes). Tighten both loops to require ace_size >= offsetof(struct smb_ace, sid) + CIFS_SID_BASE_SIZE which is the smallest valid on-wire ACE layout (4-byte header + 4-byte access_req + 8-byte sid base with zero sub-auths). Also reject ACEs whose sid.num_subauth exceeds SID_MAX_SUB_AUTHORITIES before letting compare_sids() dereference sub_auth[] entries. parse_sec_desc() already enforces an equivalent check (lines 441-448); smb_check_perm_dacl() simply grew weaker validation over time. Reachability: authenticated SMB client with permission to set an ACL on a file. On a subsequent CREATE against that file, the kernel walks the stored DACL via smb_check_perm_dacl() and triggers the OOB read. Not pre-auth, and the OOB read is not reflected to the attacker, but KASAN reports and kernel state corruption are possible. Fixes: e2f34481b24d ("cifsd: add server-side procedures for SMB3") Cc: stable@vger.kernel.org Assisted-by: Claude:claude-opus-4-6 Assisted-by: Codex:gpt-5-4 Signed-off-by: Michael Bommarito Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/smbacl.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/fs/smb/server/smbacl.c b/fs/smb/server/smbacl.c index 061a305bf9c8..bba26a0355bb 100644 --- a/fs/smb/server/smbacl.c +++ b/fs/smb/server/smbacl.c @@ -1342,10 +1342,13 @@ int smb_check_perm_dacl(struct ksmbd_conn *conn, const struct path *path, ace = (struct smb_ace *)((char *)pdacl + sizeof(struct smb_acl)); aces_size = acl_size - sizeof(struct smb_acl); for (i = 0; i < le16_to_cpu(pdacl->num_aces); i++) { - if (offsetof(struct smb_ace, access_req) > aces_size) + if (offsetof(struct smb_ace, sid) + + aces_size < CIFS_SID_BASE_SIZE) break; ace_size = le16_to_cpu(ace->size); - if (ace_size > aces_size) + if (ace_size > aces_size || + ace_size < offsetof(struct smb_ace, sid) + + CIFS_SID_BASE_SIZE) break; aces_size -= ace_size; granted |= le32_to_cpu(ace->access_req); @@ -1360,13 +1363,19 @@ int smb_check_perm_dacl(struct ksmbd_conn *conn, const struct path *path, ace = (struct smb_ace *)((char *)pdacl + sizeof(struct smb_acl)); aces_size = acl_size - sizeof(struct smb_acl); for (i = 0; i < le16_to_cpu(pdacl->num_aces); i++) { - if (offsetof(struct smb_ace, access_req) > aces_size) + if (offsetof(struct smb_ace, sid) + + aces_size < CIFS_SID_BASE_SIZE) break; ace_size = le16_to_cpu(ace->size); - if (ace_size > aces_size) + if (ace_size > aces_size || + ace_size < offsetof(struct smb_ace, sid) + + CIFS_SID_BASE_SIZE) break; aces_size -= ace_size; + if (ace->sid.num_subauth > SID_MAX_SUB_AUTHORITIES) + break; + if (!compare_sids(&sid, &ace->sid) || !compare_sids(&sid_unix_NFS_mode, &ace->sid)) { found = 1; From ce23158bfe584bd90d1918f279fdf9de57802012 Mon Sep 17 00:00:00 2001 From: DaeMyung Kang Date: Fri, 17 Apr 2026 06:17:35 +0900 Subject: [PATCH 04/18] smb: server: fix max_connections off-by-one in tcp accept path The global max_connections check in ksmbd's TCP accept path counts the newly accepted connection with atomic_inc_return(), but then rejects the connection when the result is greater than or equal to server_conf.max_connections. That makes the effective limit one smaller than configured. For example: - max_connections=1 rejects the first connection - max_connections=2 allows only one connection The per-IP limit in the same function uses <= correctly because it counts only pre-existing connections. The global limit instead checks the post-increment total, so it should reject only when that total exceeds the configured maximum. Fix this by changing the comparison from >= to >, so exactly max_connections simultaneous connections are allowed and the next one is rejected. This matches the documented meaning of max_connections in fs/smb/server/ksmbd_netlink.h as the "Number of maximum simultaneous connections". Fixes: 0d0d4680db22 ("ksmbd: add max connections parameter") Cc: stable@vger.kernel.org Signed-off-by: DaeMyung Kang Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_tcp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/smb/server/transport_tcp.c b/fs/smb/server/transport_tcp.c index 8d7fe71f525c..13b711ea575d 100644 --- a/fs/smb/server/transport_tcp.c +++ b/fs/smb/server/transport_tcp.c @@ -281,7 +281,7 @@ static int ksmbd_kthread_fn(void *p) skip_max_ip_conns_limit: if (server_conf.max_connections && - atomic_inc_return(&active_num_conn) >= server_conf.max_connections) { + atomic_inc_return(&active_num_conn) > server_conf.max_connections) { pr_info_ratelimited("Limit the maximum number of connections(%u)\n", atomic_read(&active_num_conn)); atomic_dec(&active_num_conn); From 3e4e2ea2a781018ed5d75f969e3e5606beb66e48 Mon Sep 17 00:00:00 2001 From: Michael Bommarito Date: Fri, 17 Apr 2026 14:45:57 -0400 Subject: [PATCH 05/18] ksmbd: validate num_aces and harden ACE walk in smb_inherit_dacl() smb_inherit_dacl() trusts the on-disk num_aces value from the parent directory's DACL xattr and uses it to size a heap allocation: aces_base = kmalloc(sizeof(struct smb_ace) * num_aces * 2, ...); num_aces is a u16 read from le16_to_cpu(parent_pdacl->num_aces) without checking that it is consistent with the declared pdacl_size. An authenticated client whose parent directory's security.NTACL is tampered (e.g. via offline xattr corruption or a concurrent path that bypasses parse_dacl()) can present num_aces = 65535 with minimal actual ACE data. This causes a ~8 MB allocation (not kzalloc, so uninitialized) that the subsequent loop only partially populates, and may also overflow the three-way size_t multiply on 32-bit kernels. Additionally, the ACE walk loop uses the weaker offsetof(struct smb_ace, access_req) minimum size check rather than the minimum valid on-wire ACE size, and does not reject ACEs whose declared size is below the minimum. Reproduced on UML + KASAN + LOCKDEP against the real ksmbd code path. A legitimate mount.cifs client creates a parent directory over SMB (ksmbd writes a valid security.NTACL xattr), then the NTACL blob on the backing filesystem is rewritten to set num_aces = 0xFFFF while keeping the posix_acl_hash bytes intact so ksmbd_vfs_get_sd_xattr()'s hash check still passes. A subsequent SMB2 CREATE of a child under that parent drives smb2_open() into smb_inherit_dacl() (share has "vfs objects = acl_xattr" set), which fails the page allocator: WARNING: mm/page_alloc.c:5226 at __alloc_frozen_pages_noprof+0x46c/0x9c0 Workqueue: ksmbd-io handle_ksmbd_work __alloc_frozen_pages_noprof+0x46c/0x9c0 ___kmalloc_large_node+0x68/0x130 __kmalloc_large_node_noprof+0x24/0x70 __kmalloc_noprof+0x4c9/0x690 smb_inherit_dacl+0x394/0x2430 smb2_open+0x595d/0xabe0 handle_ksmbd_work+0x3d3/0x1140 With the patch applied the added guard rejects the tampered value with -EINVAL before any large allocation runs, smb2_open() falls back to smb2_create_sd_buffer(), and the child is created with a default SD. No warning, no splat. Fix by: 1. Validating num_aces against pdacl_size using the same formula applied in parse_dacl(). 2. Replacing the raw kmalloc(sizeof * num_aces * 2) with kmalloc_array(num_aces * 2, sizeof(...)) for overflow-safe allocation. 3. Tightening the per-ACE loop guard to require the minimum valid ACE size (offsetof(smb_ace, sid) + CIFS_SID_BASE_SIZE) and rejecting under-sized ACEs, matching the hardening in smb_check_perm_dacl() and parse_dacl(). v1 -> v2: - Replace the synthetic test-module splat in the changelog with a real-path UML + KASAN reproduction driven through mount.cifs and SMB2 CREATE; Namjae flagged the kcifs3_test_inherit_dacl_old name in v1 since it does not exist in ksmbd. - Drop the commit-hash citation from the code comment per Namjae's review; keep the parse_dacl() pointer. Fixes: e2f34481b24d ("cifsd: add server-side procedures for SMB3") Cc: stable@vger.kernel.org Assisted-by: Claude:claude-opus-4-6 Signed-off-by: Michael Bommarito Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/smbacl.c | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/fs/smb/server/smbacl.c b/fs/smb/server/smbacl.c index bba26a0355bb..a1de89cc09be 100644 --- a/fs/smb/server/smbacl.c +++ b/fs/smb/server/smbacl.c @@ -1106,8 +1106,24 @@ int smb_inherit_dacl(struct ksmbd_conn *conn, goto free_parent_pntsd; } - aces_base = kmalloc(sizeof(struct smb_ace) * num_aces * 2, - KSMBD_DEFAULT_GFP); + aces_size = pdacl_size - sizeof(struct smb_acl); + + /* + * Validate num_aces against the DACL payload before allocating. + * Each ACE must be at least as large as its fixed-size header + * (up to the SID base), so num_aces cannot exceed the payload + * divided by the minimum ACE size. This mirrors the existing + * check in parse_dacl(). + */ + if (num_aces > aces_size / (offsetof(struct smb_ace, sid) + + offsetof(struct smb_sid, sub_auth) + + sizeof(__le16))) { + rc = -EINVAL; + goto free_parent_pntsd; + } + + aces_base = kmalloc_array(num_aces * 2, sizeof(struct smb_ace), + KSMBD_DEFAULT_GFP); if (!aces_base) { rc = -ENOMEM; goto free_parent_pntsd; @@ -1116,7 +1132,6 @@ int smb_inherit_dacl(struct ksmbd_conn *conn, aces = (struct smb_ace *)aces_base; parent_aces = (struct smb_ace *)((char *)parent_pdacl + sizeof(struct smb_acl)); - aces_size = acl_len - sizeof(struct smb_acl); if (pntsd_type & DACL_AUTO_INHERITED) inherited_flags = INHERITED_ACE; @@ -1124,11 +1139,14 @@ int smb_inherit_dacl(struct ksmbd_conn *conn, for (i = 0; i < num_aces; i++) { int pace_size; - if (offsetof(struct smb_ace, access_req) > aces_size) + if (aces_size < offsetof(struct smb_ace, sid) + + CIFS_SID_BASE_SIZE) break; pace_size = le16_to_cpu(parent_aces->size); - if (pace_size > aces_size) + if (pace_size > aces_size || + pace_size < offsetof(struct smb_ace, sid) + + CIFS_SID_BASE_SIZE) break; aces_size -= pace_size; From 1baff47b81f94f9231c91236aa511420d0e266b9 Mon Sep 17 00:00:00 2001 From: Akif Date: Fri, 17 Apr 2026 23:57:09 +0530 Subject: [PATCH 06/18] ksmbd: fix use-after-free in smb2_open during durable reconnect In smb2_open, the call to ksmbd_put_durable_fd(fp) drops the reference to the durable file descriptor early during the durable reconnect process. If an error occurs subsequently (eg, ksmbd_iov_pin_rsp fails) or a scavenger accesses the file, it leads to a use-after-free when accessing fp properties (eg fp->create_time). Move the single put to the end of the function below err_out2 so fp stays valid until smb2_open returns. Fixes: c8efcc786146 ("ksmbd: add support for durable handles v1/v2") Signed-off-by: Akif Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/smb2pdu.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index ee32e61b6d3c..395007c82831 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -3014,29 +3014,23 @@ int smb2_open(struct ksmbd_work *work) if (dh_info.reconnected == true) { rc = smb2_check_durable_oplock(conn, share, dh_info.fp, lc, sess->user, name); - if (rc) { - ksmbd_put_durable_fd(dh_info.fp); + if (rc) goto err_out2; - } rc = ksmbd_reopen_durable_fd(work, dh_info.fp); - if (rc) { - ksmbd_put_durable_fd(dh_info.fp); + if (rc) goto err_out2; - } fp = dh_info.fp; if (ksmbd_override_fsids(work)) { rc = -ENOMEM; - ksmbd_put_durable_fd(dh_info.fp); goto err_out2; } file_info = FILE_OPENED; rc = ksmbd_vfs_getattr(&fp->filp->f_path, &stat); - ksmbd_put_durable_fd(fp); if (rc) goto err_out2; @@ -3806,6 +3800,9 @@ int smb2_open(struct ksmbd_work *work) ksmbd_debug(SMB, "Error response: %x\n", rsp->hdr.Status); } + if (dh_info.reconnected) + ksmbd_put_durable_fd(dh_info.fp); + kfree(name); kfree(lc); From 299f962c0b02d048fb45d248b4da493d03f3175d Mon Sep 17 00:00:00 2001 From: Tristan Madani Date: Fri, 17 Apr 2026 19:54:57 +0000 Subject: [PATCH 07/18] ksmbd: use check_add_overflow() to prevent u16 DACL size overflow set_posix_acl_entries_dacl() and set_ntacl_dacl() accumulate ACE sizes in u16 variables. When a file has many POSIX ACL entries, the accumulated size can wrap past 65535, causing the pointer arithmetic (char *)pndace + *size to land within already-written ACEs. Subsequent writes then overwrite earlier entries, and pndacl->size gets a truncated value. Use check_add_overflow() at each accumulation point to detect the wrap before it corrupts the buffer, consistent with existing check_mul_overflow() usage elsewhere in smbacl.c. Cc: stable@vger.kernel.org Fixes: e2f34481b24d ("cifsd: add server-side procedures for SMB3") Signed-off-by: Tristan Madani Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/smbacl.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/fs/smb/server/smbacl.c b/fs/smb/server/smbacl.c index a1de89cc09be..4bbc2c27e680 100644 --- a/fs/smb/server/smbacl.c +++ b/fs/smb/server/smbacl.c @@ -596,6 +596,7 @@ static void set_posix_acl_entries_dacl(struct mnt_idmap *idmap, struct smb_sid *sid; struct smb_ace *ntace; int i, j; + u16 ace_sz; if (!fattr->cf_acls) goto posix_default_acl; @@ -640,8 +641,10 @@ static void set_posix_acl_entries_dacl(struct mnt_idmap *idmap, flags = 0x03; ntace = (struct smb_ace *)((char *)pndace + *size); - *size += fill_ace_for_sid(ntace, sid, ACCESS_ALLOWED, flags, + ace_sz = fill_ace_for_sid(ntace, sid, ACCESS_ALLOWED, flags, pace->e_perm, 0777); + if (check_add_overflow(*size, ace_sz, size)) + break; (*num_aces)++; if (pace->e_tag == ACL_USER) ntace->access_req |= @@ -650,8 +653,10 @@ static void set_posix_acl_entries_dacl(struct mnt_idmap *idmap, if (S_ISDIR(fattr->cf_mode) && (pace->e_tag == ACL_USER || pace->e_tag == ACL_GROUP)) { ntace = (struct smb_ace *)((char *)pndace + *size); - *size += fill_ace_for_sid(ntace, sid, ACCESS_ALLOWED, + ace_sz = fill_ace_for_sid(ntace, sid, ACCESS_ALLOWED, 0x03, pace->e_perm, 0777); + if (check_add_overflow(*size, ace_sz, size)) + break; (*num_aces)++; if (pace->e_tag == ACL_USER) ntace->access_req |= @@ -691,8 +696,10 @@ static void set_posix_acl_entries_dacl(struct mnt_idmap *idmap, } ntace = (struct smb_ace *)((char *)pndace + *size); - *size += fill_ace_for_sid(ntace, sid, ACCESS_ALLOWED, 0x0b, + ace_sz = fill_ace_for_sid(ntace, sid, ACCESS_ALLOWED, 0x0b, pace->e_perm, 0777); + if (check_add_overflow(*size, ace_sz, size)) + break; (*num_aces)++; if (pace->e_tag == ACL_USER) ntace->access_req |= @@ -728,7 +735,8 @@ static void set_ntacl_dacl(struct mnt_idmap *idmap, break; memcpy((char *)pndace + size, ntace, nt_ace_size); - size += nt_ace_size; + if (check_add_overflow(size, nt_ace_size, &size)) + break; aces_size -= nt_ace_size; ntace = (struct smb_ace *)((char *)ntace + nt_ace_size); num_aces++; From 30010c952077a1c89ecdd71fc4d574c75a8f5617 Mon Sep 17 00:00:00 2001 From: Tristan Madani Date: Fri, 17 Apr 2026 19:33:17 +0000 Subject: [PATCH 08/18] ksmbd: fix out-of-bounds write in smb2_get_ea() EA alignment smb2_get_ea() applies 4-byte alignment padding via memset() after writing each EA entry. The bounds check on buf_free_len is performed before the value memcpy, but the alignment memset fires unconditionally afterward with no check on remaining space. When the EA value exactly fills the remaining buffer (buf_free_len == 0 after value subtraction), the alignment memset writes 1-3 NUL bytes past the buf_free_len boundary. In compound requests where the response buffer is shared across commands, the first command (e.g., READ) can consume most of the buffer, leaving a tight remainder for the QUERY_INFO EA response. The alignment memset then overwrites past the physical kvmalloc allocation into adjacent kernel heap memory. Add a bounds check before the alignment memset to ensure buf_free_len can accommodate the padding bytes. This is the same bug pattern fixed by commit beef2634f81f ("ksmbd: fix potencial OOB in get_file_all_info() for compound requests") and commit fda9522ed6af ("ksmbd: fix OOB write in QUERY_INFO for compound requests"), both of which added bounds checks before unconditional writes in QUERY_INFO response handlers. Cc: stable@vger.kernel.org Fixes: e2b76ab8b5c9 ("ksmbd: add support for read compound") Signed-off-by: Tristan Madani Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/smb2pdu.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index 395007c82831..652b6771ccaf 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -4818,6 +4818,8 @@ static int smb2_get_ea(struct ksmbd_work *work, struct ksmbd_file *fp, /* align next xattr entry at 4 byte bundary */ alignment_bytes = ((next_offset + 3) & ~3) - next_offset; if (alignment_bytes) { + if (buf_free_len < alignment_bytes) + break; memset(ptr, '\0', alignment_bytes); ptr += alignment_bytes; next_offset += alignment_bytes; From def036ef87f8641c1c525d5ae17438d7a1006491 Mon Sep 17 00:00:00 2001 From: DaeMyung Kang Date: Sun, 19 Apr 2026 02:28:44 +0900 Subject: [PATCH 09/18] ksmbd: reset rcount per connection in ksmbd_conn_wait_idle_sess_id() rcount is intended to be connection-specific: 2 for curr_conn, 1 for every other connection sharing the same session. However, it is initialised only once before the hash iteration and is never reset. After the loop visits curr_conn, later sibling connections are also checked against rcount == 2, so a sibling with req_running == 1 is incorrectly treated as idle. This makes the outcome depend on the hash iteration order: whether a given sibling is checked against the loose (< 2) or the strict (< 1) threshold is decided by whether it happens to be visited before or after curr_conn. The function's contract is "wait until every connection sharing this session is idle" so that destroy_previous_session() can safely tear the session down. The latched rcount violates that contract and reopens the teardown race window the wait logic was meant to close: destroy_previous_session() may proceed before sibling channels have actually quiesced, overlapping session teardown with in-flight work on those connections. Recompute rcount inside the loop so each connection is compared against its own threshold regardless of iteration order. This is a code-inspection fix for an iteration-order-dependent logic error; a targeted reproducer would require SMB3 multichannel with in-flight work on a sibling channel landing after curr_conn in hash order, which is not something that can be triggered reliably. Fixes: 76e98a158b20 ("ksmbd: fix race condition between destroy_previous_session() and smb2 operations()") Cc: stable@vger.kernel.org Signed-off-by: DaeMyung Kang Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/connection.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/fs/smb/server/connection.c b/fs/smb/server/connection.c index a26899d12df1..b5e077f272cf 100644 --- a/fs/smb/server/connection.c +++ b/fs/smb/server/connection.c @@ -237,7 +237,7 @@ int ksmbd_conn_wait_idle_sess_id(struct ksmbd_conn *curr_conn, u64 sess_id) { struct ksmbd_conn *conn; int rc, retry_count = 0, max_timeout = 120; - int rcount = 1, bkt; + int rcount, bkt; retry_idle: if (retry_count >= max_timeout) @@ -246,8 +246,7 @@ int ksmbd_conn_wait_idle_sess_id(struct ksmbd_conn *curr_conn, u64 sess_id) down_read(&conn_list_lock); hash_for_each(conn_list, bkt, conn, hlist) { if (conn->binding || xa_load(&conn->sessions, sess_id)) { - if (conn == curr_conn) - rcount = 2; + rcount = (conn == curr_conn) ? 2 : 1; if (atomic_read(&conn->req_running) >= rcount) { rc = wait_event_timeout(conn->req_running_q, atomic_read(&conn->req_running) < rcount, From cc92b479b6ed1d7d1a6eb13aba472badb836a832 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sat, 18 Apr 2026 15:17:07 -0700 Subject: [PATCH 10/18] ksmbd: Use AES-CMAC library for SMB3 signature calculation Now that AES-CMAC has a library API, convert ksmbd_sign_smb3_pdu() to use it instead of a "cmac(aes)" crypto_shash. The result is simpler and faster code. With the library there's no need to dynamically allocate memory, no need to handle errors, and the AES-CMAC code is accessed directly without inefficient indirect calls and other unnecessary API overhead. Acked-by: Namjae Jeon Reviewed-by: Ard Biesheuvel Signed-off-by: Eric Biggers Signed-off-by: Steve French --- fs/smb/server/Kconfig | 2 +- fs/smb/server/auth.c | 51 +++++++++------------------------ fs/smb/server/auth.h | 4 +-- fs/smb/server/crypto_ctx.c | 58 -------------------------------------- fs/smb/server/crypto_ctx.h | 12 -------- fs/smb/server/server.c | 1 - fs/smb/server/smb2pdu.c | 8 ++---- 7 files changed, 19 insertions(+), 117 deletions(-) diff --git a/fs/smb/server/Kconfig b/fs/smb/server/Kconfig index 37387410e5bb..8827b3653786 100644 --- a/fs/smb/server/Kconfig +++ b/fs/smb/server/Kconfig @@ -7,13 +7,13 @@ config SMB_SERVER select NLS_UTF8 select NLS_UCS2_UTILS select CRYPTO + select CRYPTO_LIB_AES_CBC_MACS select CRYPTO_LIB_ARC4 select CRYPTO_LIB_DES select CRYPTO_LIB_MD5 select CRYPTO_LIB_SHA256 select CRYPTO_LIB_SHA512 select CRYPTO_LIB_UTILS - select CRYPTO_CMAC select CRYPTO_AEAD2 select CRYPTO_CCM select CRYPTO_GCM diff --git a/fs/smb/server/auth.c b/fs/smb/server/auth.c index 7d0691f7263f..e99409fa721c 100644 --- a/fs/smb/server/auth.c +++ b/fs/smb/server/auth.c @@ -11,8 +11,8 @@ #include #include #include -#include #include +#include #include #include #include @@ -490,46 +490,21 @@ void ksmbd_sign_smb2_pdu(struct ksmbd_conn *conn, char *key, struct kvec *iov, * @sig: signature value generated for client request packet * */ -int ksmbd_sign_smb3_pdu(struct ksmbd_conn *conn, char *key, struct kvec *iov, - int n_vec, char *sig) +void ksmbd_sign_smb3_pdu(struct ksmbd_conn *conn, char *key, struct kvec *iov, + int n_vec, char *sig) { - struct ksmbd_crypto_ctx *ctx; - int rc, i; + struct aes_cmac_key cmac_key; + struct aes_cmac_ctx cmac_ctx; + int i; - ctx = ksmbd_crypto_ctx_find_cmacaes(); - if (!ctx) { - ksmbd_debug(AUTH, "could not crypto alloc cmac\n"); - return -ENOMEM; - } + /* This cannot fail, since we always pass a valid key length. */ + static_assert(SMB2_CMACAES_SIZE == AES_KEYSIZE_128); + aes_cmac_preparekey(&cmac_key, key, SMB2_CMACAES_SIZE); - rc = crypto_shash_setkey(CRYPTO_CMACAES_TFM(ctx), - key, - SMB2_CMACAES_SIZE); - if (rc) - goto out; - - rc = crypto_shash_init(CRYPTO_CMACAES(ctx)); - if (rc) { - ksmbd_debug(AUTH, "cmaces init error %d\n", rc); - goto out; - } - - for (i = 0; i < n_vec; i++) { - rc = crypto_shash_update(CRYPTO_CMACAES(ctx), - iov[i].iov_base, - iov[i].iov_len); - if (rc) { - ksmbd_debug(AUTH, "cmaces update error %d\n", rc); - goto out; - } - } - - rc = crypto_shash_final(CRYPTO_CMACAES(ctx), sig); - if (rc) - ksmbd_debug(AUTH, "cmaces generation error %d\n", rc); -out: - ksmbd_release_crypto_ctx(ctx); - return rc; + aes_cmac_init(&cmac_ctx, &cmac_key); + for (i = 0; i < n_vec; i++) + aes_cmac_update(&cmac_ctx, iov[i].iov_base, iov[i].iov_len); + aes_cmac_final(&cmac_ctx, sig); } struct derivation { diff --git a/fs/smb/server/auth.h b/fs/smb/server/auth.h index 6d351d61b0e5..5767aabc63c9 100644 --- a/fs/smb/server/auth.h +++ b/fs/smb/server/auth.h @@ -54,8 +54,8 @@ int ksmbd_krb5_authenticate(struct ksmbd_session *sess, char *in_blob, int in_len, char *out_blob, int *out_len); void ksmbd_sign_smb2_pdu(struct ksmbd_conn *conn, char *key, struct kvec *iov, int n_vec, char *sig); -int ksmbd_sign_smb3_pdu(struct ksmbd_conn *conn, char *key, struct kvec *iov, - int n_vec, char *sig); +void ksmbd_sign_smb3_pdu(struct ksmbd_conn *conn, char *key, struct kvec *iov, + int n_vec, char *sig); int ksmbd_gen_smb30_signingkey(struct ksmbd_session *sess, struct ksmbd_conn *conn); int ksmbd_gen_smb311_signingkey(struct ksmbd_session *sess, diff --git a/fs/smb/server/crypto_ctx.c b/fs/smb/server/crypto_ctx.c index 8fd9713b00b7..2fe7d3300480 100644 --- a/fs/smb/server/crypto_ctx.c +++ b/fs/smb/server/crypto_ctx.c @@ -28,14 +28,6 @@ static inline void free_aead(struct crypto_aead *aead) crypto_free_aead(aead); } -static void free_shash(struct shash_desc *shash) -{ - if (shash) { - crypto_free_shash(shash->tfm); - kfree(shash); - } -} - static struct crypto_aead *alloc_aead(int id) { struct crypto_aead *tfm = NULL; @@ -60,37 +52,10 @@ static struct crypto_aead *alloc_aead(int id) return tfm; } -static struct shash_desc *alloc_shash_desc(int id) -{ - struct crypto_shash *tfm = NULL; - struct shash_desc *shash; - - switch (id) { - case CRYPTO_SHASH_CMACAES: - tfm = crypto_alloc_shash("cmac(aes)", 0, 0); - break; - default: - return NULL; - } - - if (IS_ERR(tfm)) - return NULL; - - shash = kzalloc(sizeof(*shash) + crypto_shash_descsize(tfm), - KSMBD_DEFAULT_GFP); - if (!shash) - crypto_free_shash(tfm); - else - shash->tfm = tfm; - return shash; -} - static void ctx_free(struct ksmbd_crypto_ctx *ctx) { int i; - for (i = 0; i < CRYPTO_SHASH_MAX; i++) - free_shash(ctx->desc[i]); for (i = 0; i < CRYPTO_AEAD_MAX; i++) free_aead(ctx->ccmaes[i]); kfree(ctx); @@ -153,29 +118,6 @@ void ksmbd_release_crypto_ctx(struct ksmbd_crypto_ctx *ctx) ctx_free(ctx); } -static struct ksmbd_crypto_ctx *____crypto_shash_ctx_find(int id) -{ - struct ksmbd_crypto_ctx *ctx; - - if (id >= CRYPTO_SHASH_MAX) - return NULL; - - ctx = ksmbd_find_crypto_ctx(); - if (ctx->desc[id]) - return ctx; - - ctx->desc[id] = alloc_shash_desc(id); - if (ctx->desc[id]) - return ctx; - ksmbd_release_crypto_ctx(ctx); - return NULL; -} - -struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_cmacaes(void) -{ - return ____crypto_shash_ctx_find(CRYPTO_SHASH_CMACAES); -} - static struct ksmbd_crypto_ctx *____crypto_aead_ctx_find(int id) { struct ksmbd_crypto_ctx *ctx; diff --git a/fs/smb/server/crypto_ctx.h b/fs/smb/server/crypto_ctx.h index 27fd553d10aa..b22c6e086f03 100644 --- a/fs/smb/server/crypto_ctx.h +++ b/fs/smb/server/crypto_ctx.h @@ -6,14 +6,8 @@ #ifndef __CRYPTO_CTX_H__ #define __CRYPTO_CTX_H__ -#include #include -enum { - CRYPTO_SHASH_CMACAES = 0, - CRYPTO_SHASH_MAX, -}; - enum { CRYPTO_AEAD_AES_GCM = 16, CRYPTO_AEAD_AES_CCM, @@ -23,19 +17,13 @@ enum { struct ksmbd_crypto_ctx { struct list_head list; - struct shash_desc *desc[CRYPTO_SHASH_MAX]; struct crypto_aead *ccmaes[CRYPTO_AEAD_MAX]; }; -#define CRYPTO_CMACAES(c) ((c)->desc[CRYPTO_SHASH_CMACAES]) - -#define CRYPTO_CMACAES_TFM(c) ((c)->desc[CRYPTO_SHASH_CMACAES]->tfm) - #define CRYPTO_GCM(c) ((c)->ccmaes[CRYPTO_AEAD_AES_GCM]) #define CRYPTO_CCM(c) ((c)->ccmaes[CRYPTO_AEAD_AES_CCM]) void ksmbd_release_crypto_ctx(struct ksmbd_crypto_ctx *ctx); -struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_cmacaes(void); struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_gcm(void); struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_ccm(void); void ksmbd_crypto_destroy(void); diff --git a/fs/smb/server/server.c b/fs/smb/server/server.c index d8893079abdb..58ef02c423fc 100644 --- a/fs/smb/server/server.c +++ b/fs/smb/server/server.c @@ -631,7 +631,6 @@ MODULE_DESCRIPTION("Linux kernel CIFS/SMB SERVER"); MODULE_LICENSE("GPL"); MODULE_SOFTDEP("pre: nls"); MODULE_SOFTDEP("pre: aes"); -MODULE_SOFTDEP("pre: cmac"); MODULE_SOFTDEP("pre: aead2"); MODULE_SOFTDEP("pre: ccm"); MODULE_SOFTDEP("pre: gcm"); diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index 652b6771ccaf..a5d9a56cdee8 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -9066,8 +9066,7 @@ int smb3_check_sign_req(struct ksmbd_work *work) iov[0].iov_base = (char *)&hdr->ProtocolId; iov[0].iov_len = len; - if (ksmbd_sign_smb3_pdu(conn, signing_key, iov, 1, signature)) - return 0; + ksmbd_sign_smb3_pdu(conn, signing_key, iov, 1, signature); if (crypto_memneq(signature, signature_req, SMB2_SIGNATURE_SIZE)) { pr_err("bad smb2 signature\n"); @@ -9118,9 +9117,8 @@ void smb3_set_sign_rsp(struct ksmbd_work *work) iov = &work->iov[work->iov_idx]; } - if (!ksmbd_sign_smb3_pdu(conn, signing_key, iov, n_vec, - signature)) - memcpy(hdr->Signature, signature, SMB2_SIGNATURE_SIZE); + ksmbd_sign_smb3_pdu(conn, signing_key, iov, n_vec, signature); + memcpy(hdr->Signature, signature, SMB2_SIGNATURE_SIZE); } /** From c049ee14eb4343b69b6f7755563f961f5e153423 Mon Sep 17 00:00:00 2001 From: DaeMyung Kang Date: Sun, 19 Apr 2026 20:02:54 +0900 Subject: [PATCH 11/18] ksmbd: destroy tree_conn_ida in ksmbd_session_destroy() When per-session tree_conn_ida was converted from a dynamically allocated ksmbd_ida to an embedded struct ida, ksmbd_ida_free() was removed from ksmbd_session_destroy() but no matching ida_destroy() was added. The session is therefore freed with the IDA's backing xarray still intact. The kernel IDA API expects ida_init() and ida_destroy() to be paired over an object's lifetime, so add the missing cleanup before the enclosing session is freed. Also move ida_init() to right after the session is allocated so that it is always paired with the destroy call even on the early error paths of __session_create() (ksmbd_init_file_table() or __init_smb2_session() failures), both of which jump to the error label and invoke ksmbd_session_destroy() on a partially initialised session. No leak has been observed in testing; this is a pairing fix to match the IDA lifetime rules, not a response to a reproduced regression. Fixes: d40012a83f87 ("cifsd: declare ida statically") Signed-off-by: DaeMyung Kang Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/mgmt/user_session.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/fs/smb/server/mgmt/user_session.c b/fs/smb/server/mgmt/user_session.c index a86589408835..0dd9e6c976ac 100644 --- a/fs/smb/server/mgmt/user_session.c +++ b/fs/smb/server/mgmt/user_session.c @@ -391,6 +391,7 @@ void ksmbd_session_destroy(struct ksmbd_session *sess) free_channel_list(sess); kfree(sess->Preauth_HashValue); ksmbd_release_id(&session_ida, sess->id); + ida_destroy(&sess->tree_conn_ida); kfree(sess); } @@ -665,6 +666,8 @@ static struct ksmbd_session *__session_create(int protocol) if (!sess) return NULL; + ida_init(&sess->tree_conn_ida); + if (ksmbd_init_file_table(&sess->file_table)) goto error; @@ -684,8 +687,6 @@ static struct ksmbd_session *__session_create(int protocol) if (ret) goto error; - ida_init(&sess->tree_conn_ida); - down_write(&sessions_table_lock); hash_add(sessions_table, &sess->hlist, sess->id); up_write(&sessions_table_lock); From b32c8db48212a34998c36d0bbc05b29d5c407ef5 Mon Sep 17 00:00:00 2001 From: DaeMyung Kang Date: Sun, 19 Apr 2026 20:02:55 +0900 Subject: [PATCH 12/18] ksmbd: destroy async_ida in ksmbd_conn_free() When per-connection async_ida was converted from a dynamically allocated ksmbd_ida to an embedded struct ida, ksmbd_ida_free() was removed from the connection teardown path but no matching ida_destroy() was added. The connection is therefore freed with the IDA's backing xarray still intact. The kernel IDA API expects ida_init() and ida_destroy() to be paired over an object's lifetime, so add the missing cleanup before the connection is freed. No leak has been observed in testing; this is a pairing fix to match the IDA lifetime rules, not a response to a reproduced regression. Fixes: d40012a83f87 ("cifsd: declare ida statically") Signed-off-by: DaeMyung Kang Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/connection.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/fs/smb/server/connection.c b/fs/smb/server/connection.c index b5e077f272cf..fbbc0529743f 100644 --- a/fs/smb/server/connection.c +++ b/fs/smb/server/connection.c @@ -98,6 +98,15 @@ void ksmbd_conn_free(struct ksmbd_conn *conn) kfree(conn->preauth_info); kfree(conn->mechToken); if (atomic_dec_and_test(&conn->refcnt)) { + /* + * async_ida is embedded in struct ksmbd_conn, so pair + * ida_destroy() with the final kfree() rather than with + * the unconditional field teardown above. This keeps + * the IDA valid for the entire lifetime of the struct, + * even while other refcount holders (oplock / vfs + * durable handles) still reference the connection. + */ + ida_destroy(&conn->async_ida); conn->transport->ops->free_transport(conn->transport); kfree(conn); } From bd0a1ca52b6da64b1a163f103b28b488b20497fe Mon Sep 17 00:00:00 2001 From: Akif Sait Date: Mon, 20 Apr 2026 10:58:26 +0900 Subject: [PATCH 13/18] ksmbd: fix O(N^2) DoS in smb2_lock via unbounded LockCount smb2_lock() performs O(N^2) conflict detection with no cap on LockCount. Cap lock_count at 64 to prevent CPU exhaustion from a single request. Signed-off-by: Akif Sait Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/smb2pdu.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index a5d9a56cdee8..1ed44ed1aaeb 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -7491,7 +7491,12 @@ int smb2_lock(struct ksmbd_work *work) lock_ele = req->locks; ksmbd_debug(SMB, "lock count is %d\n", lock_count); - if (!lock_count) { + /* + * Cap lock_count at 64. The MS-SMB2 spec defines Open.LockSequenceArray + * as exactly 64 entries so 64 is the intended ceiling. No real workload + * comes close to this in a single request. + */ + if (!lock_count || lock_count > 64) { err = -EINVAL; goto out2; } From 804054d19886ac6628883d82410f6ee42a818664 Mon Sep 17 00:00:00 2001 From: DaeMyung Kang Date: Tue, 21 Apr 2026 03:45:11 +0900 Subject: [PATCH 14/18] ksmbd: fix durable fd leak on ClientGUID mismatch in durable v2 open ksmbd_lookup_fd_cguid() returns a ksmbd_file with its refcount incremented via ksmbd_fp_get(). parse_durable_handle_context() in the DURABLE_REQ_V2 case properly releases this reference on every path inside the ClientGUID-match branch, either by calling ksmbd_put_durable_fd() or by transferring ownership to dh_info->fp for a successful reconnect. However, when an entry exists in the global file table with the same CreateGuid but a different ClientGUID, the code simply falls through to the new-open path without dropping the reference obtained from ksmbd_lookup_fd_cguid(). Per MS-SMB2 section 3.3.5.9.10 ("Handling the SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2 Create Context"), the server MUST locate an Open whose Open.CreateGuid matches the request's CreateGuid AND whose Open.ClientGuid matches the ClientGuid of the connection that received the request. If no such Open is found, the server MUST continue with the normal open execution phase. A CreateGuid hit with a ClientGUID mismatch is therefore the "Open not found" case: proceeding with a new open is correct, but the reference obtained purely as a side effect of the lookup must not be leaked. Repeated requests that hit this mismatch pin global_ft entries, prevent __ksmbd_close_fd() from ever running for the corresponding files, and defeat the durable scavenger, leading to long-lived resource leaks. Release the reference in the mismatch path and clear dh_info->fp so subsequent logic does not mistake a non-matching lookup result for a reconnect target. Fixes: c8efcc786146 ("ksmbd: add support for durable handles v1/v2") Signed-off-by: DaeMyung Kang Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/smb2pdu.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index 1ed44ed1aaeb..a7abef1b208a 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -2844,6 +2844,8 @@ static int parse_durable_handle_context(struct ksmbd_work *work, dh_info->reconnected = true; goto out; } + ksmbd_put_durable_fd(dh_info->fp); + dh_info->fp = NULL; } if ((lc && (lc->req_state & SMB2_LEASE_HANDLE_CACHING_LE)) || From 5d115fa84027e4b999c3d3c7b1294849cf35cdb2 Mon Sep 17 00:00:00 2001 From: DaeMyung Kang Date: Tue, 21 Apr 2026 02:51:25 +0900 Subject: [PATCH 15/18] ksmbd: fix CreateOptions sanitization clobbering the whole field smb2_open() attempts to clear conflicting CreateOptions bits (FILE_SEQUENTIAL_ONLY_LE together with FILE_RANDOM_ACCESS_LE, and FILE_NO_COMPRESSION_LE on a directory open), but uses a plain assignment of the bitwise negation of the target flag: req->CreateOptions = ~(FILE_SEQUENTIAL_ONLY_LE); req->CreateOptions = ~(FILE_NO_COMPRESSION_LE); This replaces the entire field with 0xFFFFFFFB / 0xFFFFFFEF rather than clearing a single bit. With the SEQUENTIAL/RANDOM case, the next check for FILE_OPEN_BY_FILE_ID_LE | CREATE_TREE_CONNECTION | FILE_RESERVE_OPFILTER_LE then trivially matches and a legitimate request is rejected with -EOPNOTSUPP. With the NO_COMPRESSION case, every downstream test (FILE_DELETE_ON_CLOSE, etc.) operates on a corrupted CreateOptions value. Use &= ~FLAG to clear only the intended bit in both places. Signed-off-by: DaeMyung Kang Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/smb2pdu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index a7abef1b208a..939089304052 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -3057,7 +3057,7 @@ int smb2_open(struct ksmbd_work *work) } else { if (req->CreateOptions & FILE_SEQUENTIAL_ONLY_LE && req->CreateOptions & FILE_RANDOM_ACCESS_LE) - req->CreateOptions = ~(FILE_SEQUENTIAL_ONLY_LE); + req->CreateOptions &= ~FILE_SEQUENTIAL_ONLY_LE; if (req->CreateOptions & (FILE_OPEN_BY_FILE_ID_LE | CREATE_TREE_CONNECTION | @@ -3071,7 +3071,7 @@ int smb2_open(struct ksmbd_work *work) rc = -EINVAL; goto err_out2; } else if (req->CreateOptions & FILE_NO_COMPRESSION_LE) { - req->CreateOptions = ~(FILE_NO_COMPRESSION_LE); + req->CreateOptions &= ~FILE_NO_COMPRESSION_LE; } } } From b0da97c034b6107d14e537e212d4ce8b22109a58 Mon Sep 17 00:00:00 2001 From: Hyunwoo Kim Date: Tue, 21 Apr 2026 00:31:47 +0900 Subject: [PATCH 16/18] ksmbd: scope conn->binding slowpath to bound sessions only When the binding SESSION_SETUP sets conn->binding = true, the flag stays set after the call so that the global session lookup in ksmbd_session_lookup_all() can find the session, which was not added to conn->sessions. Because the flag is connection-wide, the global lookup path will also resolve any other session by id if asked. Tighten the global lookup so that the returned session must have this connection registered in its channel xarray (sess->ksmbd_chann_list). The channel entry is installed by the existing binding_session path in ntlm_authenticate()/krb5_authenticate() when a SESSION_SETUP completes successfully, so this condition is a strict equivalent of "this connection has been accepted as a channel of this session". Connections that have not bound to a given session cannot reach it via the global table. The existing conn->binding gate for entering the slowpath is preserved so that non-binding connections keep the fast-path-only behavior, and the session->state check is unchanged. Fixes: f5a544e3bab7 ("ksmbd: add support for SMB3 multichannel") Signed-off-by: Hyunwoo Kim Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/mgmt/user_session.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/fs/smb/server/mgmt/user_session.c b/fs/smb/server/mgmt/user_session.c index 0dd9e6c976ac..de58aed76cb4 100644 --- a/fs/smb/server/mgmt/user_session.c +++ b/fs/smb/server/mgmt/user_session.c @@ -548,8 +548,13 @@ struct ksmbd_session *ksmbd_session_lookup_all(struct ksmbd_conn *conn, struct ksmbd_session *sess; sess = ksmbd_session_lookup(conn, id); - if (!sess && conn->binding) + if (!sess && conn->binding) { sess = ksmbd_session_lookup_slowpath(id); + if (sess && !xa_load(&sess->ksmbd_chann_list, (long)conn)) { + ksmbd_user_session_put(sess); + sess = NULL; + } + } if (sess && sess->state != SMB2_SESSION_VALID) { ksmbd_user_session_put(sess); sess = NULL; From 5efb579e0d1ee02b85e3ce2da691c88c93111060 Mon Sep 17 00:00:00 2001 From: Marios Makassikis Date: Wed, 22 Apr 2026 10:14:50 +0900 Subject: [PATCH 17/18] smb: server: stop sending fake security descriptors in smb2_get_info_sec, a dummy security descriptor (SD) is returned if the requested information is not supported. the code is currently wrong, as DACL_PROTECTED is set in the type field, but there is no DACL is present. instead of faking a security, report a STATUS_NOT_SUPPORTED error. this seems to fix a "Error 0x80090006: Invalid Signature" on file transfers with Windows 11 clients (25H2, build 26200.8246). capturing traffic shows that the client is sending a GET_INFO/SEC_INFO request, with the additional_info field set to 0x20 (ATTRIBUTE_SECURITY_INFORMATION). Returning an empty SD (with only SELF_RELATIVE set) does not fix the error. Signed-off-by: Marios Makassikis Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/smb2pdu.c | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index 939089304052..21825a69c29a 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -5746,20 +5746,8 @@ static int smb2_get_info_sec(struct ksmbd_work *work, ksmbd_debug(SMB, "Unsupported addition info: 0x%x)\n", addition_info); - pntsd = kzalloc(ALIGN(sizeof(struct smb_ntsd), 8), - KSMBD_DEFAULT_GFP); - if (!pntsd) - return -ENOMEM; - - pntsd->revision = cpu_to_le16(1); - pntsd->type = cpu_to_le16(SELF_RELATIVE | DACL_PROTECTED); - pntsd->osidoffset = 0; - pntsd->gsidoffset = 0; - pntsd->sacloffset = 0; - pntsd->dacloffset = 0; - - secdesclen = sizeof(struct smb_ntsd); - goto iov_pin; + rsp->hdr.Status = STATUS_NOT_SUPPORTED; + return -EINVAL; } if (work->next_smb2_rcv_hdr_off) { @@ -5826,7 +5814,6 @@ static int smb2_get_info_sec(struct ksmbd_work *work, if (rc) goto err_out; -iov_pin: rsp->OutputBufferLength = cpu_to_le32(secdesclen); rc = buffer_check_err(le32_to_cpu(req->OutputBufferLength), rsp, work->response_buf); From 1249c01aa42160e40bc765ba5a3cde751491ff0a Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Sun, 19 Apr 2026 21:20:18 +0200 Subject: [PATCH 18/18] smb: smbdirect: move fs/smb/common/smbdirect/ to fs/smb/smbdirect/ This also removes the smbdirect_ prefix from the files. Suggested-by: Linus Torvalds Link: https://lore.kernel.org/linux-cifs/CAHk-=whmue3PVi88K0UZLZO0at22QhQZ-yu+qO2TOKyZpGqecw@mail.gmail.com/ Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: Linus Torvalds Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Acked-by: Namjae Jeon Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- MAINTAINERS | 2 +- fs/smb/Kconfig | 2 +- fs/smb/Makefile | 1 + fs/smb/client/Kconfig | 2 +- fs/smb/client/smbdirect.c | 2 +- fs/smb/client/smbdirect.h | 2 +- fs/smb/common/Makefile | 1 - fs/smb/common/smbdirect/Makefile | 18 ------------------ fs/smb/server/Kconfig | 2 +- fs/smb/server/transport_rdma.c | 2 +- fs/smb/server/transport_rdma.h | 2 +- fs/smb/{common => }/smbdirect/Kconfig | 2 +- fs/smb/smbdirect/Makefile | 18 ++++++++++++++++++ .../smbdirect_accept.c => smbdirect/accept.c} | 4 ++-- .../connect.c} | 4 ++-- .../connection.c} | 2 +- .../smbdirect_debug.c => smbdirect/debug.c} | 2 +- .../devices.c} | 2 +- .../internal.h} | 6 +++--- .../smbdirect_listen.c => smbdirect/listen.c} | 2 +- .../smbdirect_main.c => smbdirect/main.c} | 2 +- .../smbdirect_mr.c => smbdirect/mr.c} | 2 +- .../smbdirect_pdu.h => smbdirect/pdu.h} | 0 .../smbdirect_public.h => smbdirect/public.h} | 0 .../smbdirect_rw.c => smbdirect/rw.c} | 2 +- fs/smb/{common => }/smbdirect/smbdirect.h | 0 .../smbdirect_socket.c => smbdirect/socket.c} | 2 +- .../smbdirect_socket.h => smbdirect/socket.h} | 0 28 files changed, 43 insertions(+), 43 deletions(-) delete mode 100644 fs/smb/common/smbdirect/Makefile rename fs/smb/{common => }/smbdirect/Kconfig (86%) create mode 100644 fs/smb/smbdirect/Makefile rename fs/smb/{common/smbdirect/smbdirect_accept.c => smbdirect/accept.c} (99%) rename fs/smb/{common/smbdirect/smbdirect_connect.c => smbdirect/connect.c} (99%) rename fs/smb/{common/smbdirect/smbdirect_connection.c => smbdirect/connection.c} (99%) rename fs/smb/{common/smbdirect/smbdirect_debug.c => smbdirect/debug.c} (98%) rename fs/smb/{common/smbdirect/smbdirect_devices.c => smbdirect/devices.c} (99%) rename fs/smb/{common/smbdirect/smbdirect_internal.h => smbdirect/internal.h} (98%) rename fs/smb/{common/smbdirect/smbdirect_listen.c => smbdirect/listen.c} (99%) rename fs/smb/{common/smbdirect/smbdirect_main.c => smbdirect/main.c} (99%) rename fs/smb/{common/smbdirect/smbdirect_mr.c => smbdirect/mr.c} (99%) rename fs/smb/{common/smbdirect/smbdirect_pdu.h => smbdirect/pdu.h} (100%) rename fs/smb/{common/smbdirect/smbdirect_public.h => smbdirect/public.h} (100%) rename fs/smb/{common/smbdirect/smbdirect_rw.c => smbdirect/rw.c} (99%) rename fs/smb/{common => }/smbdirect/smbdirect.h (100%) rename fs/smb/{common/smbdirect/smbdirect_socket.c => smbdirect/socket.c} (99%) rename fs/smb/{common/smbdirect/smbdirect_socket.h => smbdirect/socket.h} (100%) diff --git a/MAINTAINERS b/MAINTAINERS index 54b33d43e9fd..839218627f5f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -24590,7 +24590,7 @@ L: linux-cifs@vger.kernel.org L: samba-technical@lists.samba.org (moderated for non-subscribers) S: Maintained F: fs/smb/client/smbdirect.* -F: fs/smb/common/smbdirect/ +F: fs/smb/smbdirect/ F: fs/smb/server/transport_rdma.* SMC91x ETHERNET DRIVER diff --git a/fs/smb/Kconfig b/fs/smb/Kconfig index b4b2cfdc2a6b..e549e189ee6a 100644 --- a/fs/smb/Kconfig +++ b/fs/smb/Kconfig @@ -4,7 +4,7 @@ source "fs/smb/client/Kconfig" source "fs/smb/server/Kconfig" -source "fs/smb/common/smbdirect/Kconfig" +source "fs/smb/smbdirect/Kconfig" config SMBFS tristate diff --git a/fs/smb/Makefile b/fs/smb/Makefile index 9a1bf59a1a65..353b1c2eefc4 100644 --- a/fs/smb/Makefile +++ b/fs/smb/Makefile @@ -1,5 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_SMBFS) += common/ +obj-$(CONFIG_SMBDIRECT) += smbdirect/ obj-$(CONFIG_CIFS) += client/ obj-$(CONFIG_SMB_SERVER) += server/ diff --git a/fs/smb/client/Kconfig b/fs/smb/client/Kconfig index 63831242fddf..fed621910876 100644 --- a/fs/smb/client/Kconfig +++ b/fs/smb/client/Kconfig @@ -182,7 +182,7 @@ config CIFS_SMB_DIRECT bool "SMB Direct support" depends on CIFS && INFINIBAND && INFINIBAND_ADDR_TRANS depends on CIFS=m || INFINIBAND=y - select SMB_COMMON_SMBDIRECT + select SMBDIRECT help Enables SMB Direct support for SMB 3.0, 3.02 and 3.1.1. SMB Direct allows transferring SMB packets over RDMA. If unsure, diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index 9e67adcdc7d3..75f9f91a7ec9 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -9,7 +9,7 @@ #include "cifs_debug.h" #include "cifsproto.h" #include "smb2proto.h" -#include "../common/smbdirect/smbdirect_public.h" +#include "../smbdirect/public.h" /* Port numbers for SMBD transport */ #define SMB_PORT 445 diff --git a/fs/smb/client/smbdirect.h b/fs/smb/client/smbdirect.h index 0017d5b2de44..287ac849213d 100644 --- a/fs/smb/client/smbdirect.h +++ b/fs/smb/client/smbdirect.h @@ -12,7 +12,7 @@ #include "cifsglob.h" -#include "../common/smbdirect/smbdirect.h" +#include "../smbdirect/smbdirect.h" extern int rdma_readwrite_threshold; extern int smbd_max_frmr_depth; diff --git a/fs/smb/common/Makefile b/fs/smb/common/Makefile index e6ee65c31b5d..9e0730a385fb 100644 --- a/fs/smb/common/Makefile +++ b/fs/smb/common/Makefile @@ -4,4 +4,3 @@ # obj-$(CONFIG_SMBFS) += cifs_md4.o -obj-$(CONFIG_SMB_COMMON_SMBDIRECT) += smbdirect/ diff --git a/fs/smb/common/smbdirect/Makefile b/fs/smb/common/smbdirect/Makefile deleted file mode 100644 index 423f533e1002..000000000000 --- a/fs/smb/common/smbdirect/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-or-later -# -# Makefile for smbdirect support -# - -obj-$(CONFIG_SMB_COMMON_SMBDIRECT) += smbdirect.o - -smbdirect-y := \ - smbdirect_socket.o \ - smbdirect_connection.o \ - smbdirect_mr.o \ - smbdirect_rw.o \ - smbdirect_debug.o \ - smbdirect_connect.o \ - smbdirect_listen.o \ - smbdirect_accept.o \ - smbdirect_devices.o \ - smbdirect_main.o diff --git a/fs/smb/server/Kconfig b/fs/smb/server/Kconfig index 8827b3653786..08d8b7a965a6 100644 --- a/fs/smb/server/Kconfig +++ b/fs/smb/server/Kconfig @@ -49,7 +49,7 @@ config SMB_SERVER_SMBDIRECT bool "Support for SMB Direct protocol" depends on SMB_SERVER && INFINIBAND && INFINIBAND_ADDR_TRANS depends on SMB_SERVER=m || INFINIBAND=y - select SMB_COMMON_SMBDIRECT + select SMBDIRECT default n help diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index 706a2c897948..a8242c00096f 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -18,7 +18,7 @@ #include "smb_common.h" #include "../common/smb2status.h" #include "transport_rdma.h" -#include "../common/smbdirect/smbdirect_public.h" +#include "../smbdirect/public.h" #define SMB_DIRECT_PORT_IWARP 5445 diff --git a/fs/smb/server/transport_rdma.h b/fs/smb/server/transport_rdma.h index 05352dc47f95..bde3d88aecc7 100644 --- a/fs/smb/server/transport_rdma.h +++ b/fs/smb/server/transport_rdma.h @@ -25,6 +25,6 @@ static inline void init_smbd_max_io_size(unsigned int sz) { } static inline unsigned int get_smbd_max_read_write_size(struct ksmbd_transport *kt) { return 0; } #endif -#include "../common/smbdirect/smbdirect.h" +#include "../smbdirect/smbdirect.h" #endif /* __KSMBD_TRANSPORT_RDMA_H__ */ diff --git a/fs/smb/common/smbdirect/Kconfig b/fs/smb/smbdirect/Kconfig similarity index 86% rename from fs/smb/common/smbdirect/Kconfig rename to fs/smb/smbdirect/Kconfig index a46a2e6ec87a..2bf1b3350f7d 100644 --- a/fs/smb/common/smbdirect/Kconfig +++ b/fs/smb/smbdirect/Kconfig @@ -2,7 +2,7 @@ # # smbdirect configuration -config SMB_COMMON_SMBDIRECT +config SMBDIRECT def_tristate n depends on INFINIBAND && INFINIBAND_ADDR_TRANS depends on m || INFINIBAND=y diff --git a/fs/smb/smbdirect/Makefile b/fs/smb/smbdirect/Makefile new file mode 100644 index 000000000000..80d6025984d1 --- /dev/null +++ b/fs/smb/smbdirect/Makefile @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Makefile for smbdirect support +# + +obj-$(CONFIG_SMBDIRECT) += smbdirect.o + +smbdirect-y := \ + socket.o \ + connection.o \ + mr.o \ + rw.o \ + debug.o \ + connect.o \ + listen.o \ + accept.o \ + devices.o \ + main.o diff --git a/fs/smb/common/smbdirect/smbdirect_accept.c b/fs/smb/smbdirect/accept.c similarity index 99% rename from fs/smb/common/smbdirect/smbdirect_accept.c rename to fs/smb/smbdirect/accept.c index d6d5e6a3f5de..704b271af3a8 100644 --- a/fs/smb/common/smbdirect/smbdirect_accept.c +++ b/fs/smb/smbdirect/accept.c @@ -5,9 +5,9 @@ * Copyright (c) 2025, Stefan Metzmacher */ -#include "smbdirect_internal.h" +#include "internal.h" #include -#include "../../common/smb2status.h" +#include "../common/smb2status.h" static int smbdirect_accept_rdma_event_handler(struct rdma_cm_id *id, struct rdma_cm_event *event); diff --git a/fs/smb/common/smbdirect/smbdirect_connect.c b/fs/smb/smbdirect/connect.c similarity index 99% rename from fs/smb/common/smbdirect/smbdirect_connect.c rename to fs/smb/smbdirect/connect.c index 2b54f79dba43..8addee43a381 100644 --- a/fs/smb/common/smbdirect/smbdirect_connect.c +++ b/fs/smb/smbdirect/connect.c @@ -3,8 +3,8 @@ * Copyright (c) 2012,2016,2017,2025 Stefan Metzmacher */ -#include "smbdirect_internal.h" -#include "../../common/smb2status.h" +#include "internal.h" +#include "../common/smb2status.h" static int smbdirect_connect_setup_connection(struct smbdirect_socket *sc); static int smbdirect_connect_resolve_addr(struct smbdirect_socket *sc, diff --git a/fs/smb/common/smbdirect/smbdirect_connection.c b/fs/smb/smbdirect/connection.c similarity index 99% rename from fs/smb/common/smbdirect/smbdirect_connection.c rename to fs/smb/smbdirect/connection.c index 7e4921b9538c..822366718d45 100644 --- a/fs/smb/common/smbdirect/smbdirect_connection.c +++ b/fs/smb/smbdirect/connection.c @@ -4,7 +4,7 @@ * Copyright (c) 2025, Stefan Metzmacher */ -#include "smbdirect_internal.h" +#include "internal.h" #include struct smbdirect_map_sges { diff --git a/fs/smb/common/smbdirect/smbdirect_debug.c b/fs/smb/smbdirect/debug.c similarity index 98% rename from fs/smb/common/smbdirect/smbdirect_debug.c rename to fs/smb/smbdirect/debug.c index d8664fd7f71a..a66a19d4a463 100644 --- a/fs/smb/common/smbdirect/smbdirect_debug.c +++ b/fs/smb/smbdirect/debug.c @@ -4,7 +4,7 @@ * Copyright (c) 2025, Stefan Metzmacher */ -#include "smbdirect_internal.h" +#include "internal.h" #include void smbdirect_connection_legacy_debug_proc_show(struct smbdirect_socket *sc, diff --git a/fs/smb/common/smbdirect/smbdirect_devices.c b/fs/smb/smbdirect/devices.c similarity index 99% rename from fs/smb/common/smbdirect/smbdirect_devices.c rename to fs/smb/smbdirect/devices.c index aaab99e9c045..44962f221c35 100644 --- a/fs/smb/common/smbdirect/smbdirect_devices.c +++ b/fs/smb/smbdirect/devices.c @@ -5,7 +5,7 @@ * Copyright (c) 2025 Stefan Metzmacher */ -#include "smbdirect_internal.h" +#include "internal.h" static u8 smbdirect_ib_device_rdma_capable_node_type(struct ib_device *ib_dev) { diff --git a/fs/smb/common/smbdirect/smbdirect_internal.h b/fs/smb/smbdirect/internal.h similarity index 98% rename from fs/smb/common/smbdirect/smbdirect_internal.h rename to fs/smb/smbdirect/internal.h index 30a1b8643657..2d5acf2c21bc 100644 --- a/fs/smb/common/smbdirect/smbdirect_internal.h +++ b/fs/smb/smbdirect/internal.h @@ -9,8 +9,8 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include "smbdirect.h" -#include "smbdirect_pdu.h" -#include "smbdirect_public.h" +#include "pdu.h" +#include "public.h" #include @@ -34,7 +34,7 @@ struct smbdirect_module_state { extern struct smbdirect_module_state smbdirect_globals; -#include "smbdirect_socket.h" +#include "socket.h" struct smbdirect_device { struct list_head list; diff --git a/fs/smb/common/smbdirect/smbdirect_listen.c b/fs/smb/smbdirect/listen.c similarity index 99% rename from fs/smb/common/smbdirect/smbdirect_listen.c rename to fs/smb/smbdirect/listen.c index 05c7902e7020..143a7618d95f 100644 --- a/fs/smb/common/smbdirect/smbdirect_listen.c +++ b/fs/smb/smbdirect/listen.c @@ -5,7 +5,7 @@ * Copyright (c) 2025, Stefan Metzmacher */ -#include "smbdirect_internal.h" +#include "internal.h" static int smbdirect_listen_rdma_event_handler(struct rdma_cm_id *id, struct rdma_cm_event *event); diff --git a/fs/smb/common/smbdirect/smbdirect_main.c b/fs/smb/smbdirect/main.c similarity index 99% rename from fs/smb/common/smbdirect/smbdirect_main.c rename to fs/smb/smbdirect/main.c index fe6e8d93c34c..606732fefb69 100644 --- a/fs/smb/common/smbdirect/smbdirect_main.c +++ b/fs/smb/smbdirect/main.c @@ -3,7 +3,7 @@ * Copyright (c) 2025, Stefan Metzmacher */ -#include "smbdirect_internal.h" +#include "internal.h" #include struct smbdirect_module_state smbdirect_globals = { diff --git a/fs/smb/common/smbdirect/smbdirect_mr.c b/fs/smb/smbdirect/mr.c similarity index 99% rename from fs/smb/common/smbdirect/smbdirect_mr.c rename to fs/smb/smbdirect/mr.c index fa9be8089925..5228e699cd5d 100644 --- a/fs/smb/common/smbdirect/smbdirect_mr.c +++ b/fs/smb/smbdirect/mr.c @@ -4,7 +4,7 @@ * Copyright (c) 2025, Stefan Metzmacher */ -#include "smbdirect_internal.h" +#include "internal.h" /* * Allocate MRs used for RDMA read/write diff --git a/fs/smb/common/smbdirect/smbdirect_pdu.h b/fs/smb/smbdirect/pdu.h similarity index 100% rename from fs/smb/common/smbdirect/smbdirect_pdu.h rename to fs/smb/smbdirect/pdu.h diff --git a/fs/smb/common/smbdirect/smbdirect_public.h b/fs/smb/smbdirect/public.h similarity index 100% rename from fs/smb/common/smbdirect/smbdirect_public.h rename to fs/smb/smbdirect/public.h diff --git a/fs/smb/common/smbdirect/smbdirect_rw.c b/fs/smb/smbdirect/rw.c similarity index 99% rename from fs/smb/common/smbdirect/smbdirect_rw.c rename to fs/smb/smbdirect/rw.c index 3b2eb8c48efc..c2f46b17731e 100644 --- a/fs/smb/common/smbdirect/smbdirect_rw.c +++ b/fs/smb/smbdirect/rw.c @@ -5,7 +5,7 @@ * Copyright (c) 2025, Stefan Metzmacher */ -#include "smbdirect_internal.h" +#include "internal.h" static int smbdirect_connection_wait_for_rw_credits(struct smbdirect_socket *sc, int credits) diff --git a/fs/smb/common/smbdirect/smbdirect.h b/fs/smb/smbdirect/smbdirect.h similarity index 100% rename from fs/smb/common/smbdirect/smbdirect.h rename to fs/smb/smbdirect/smbdirect.h diff --git a/fs/smb/common/smbdirect/smbdirect_socket.c b/fs/smb/smbdirect/socket.c similarity index 99% rename from fs/smb/common/smbdirect/smbdirect_socket.c rename to fs/smb/smbdirect/socket.c index 9153e1dbf53d..1b4ab01b745e 100644 --- a/fs/smb/common/smbdirect/smbdirect_socket.c +++ b/fs/smb/smbdirect/socket.c @@ -4,7 +4,7 @@ * Copyright (c) 2025, Stefan Metzmacher */ -#include "smbdirect_internal.h" +#include "internal.h" bool smbdirect_frwr_is_supported(const struct ib_device_attr *attrs) { diff --git a/fs/smb/common/smbdirect/smbdirect_socket.h b/fs/smb/smbdirect/socket.h similarity index 100% rename from fs/smb/common/smbdirect/smbdirect_socket.h rename to fs/smb/smbdirect/socket.h