FAILED: patch "[PATCH] ksmbd: prevent out-of-bounds reads in share config responses" failed to apply to 6.1-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 6.1-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.1.y
git checkout FETCH_HEAD
git cherry-pick -x f25e93768fcc5d8287e50b1ec52a42e4c276df34
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026091412-bottom-cadillac-a0fb@gregkh' --subject-prefix 'PATCH 6.1.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From f25e93768fcc5d8287e50b1ec52a42e4c276df34 Mon Sep 17 00:00:00 2001
From: Namjae Jeon <[email protected]>
Date: Fri, 28 Aug 2026 08:39:57 +0900
Subject: [PATCH] ksmbd: prevent out-of-bounds reads in share config responses
Validate IPC share configuration payload sizes before consuming variable-length fields. Bound veto list parsing and account for the separator byte when deriving the path length.
fs/smb/server/mgmt/share_config.c +27 -13
@@ -146,9 +146,9 @@ static struct ksmbd_share_config *__share_lookup(const char *name)static int parse_veto_list (struct ksmbd_share_config *share,char *veto_list, -int veto_list_sz) +size_t veto_list_sz) { -int sz =0 ; +size_t sz;if (!veto_list_sz)return 0 ;
@@ -156,7 +156,7 @@ static int parse_veto_list(struct ksmbd_share_config *share,while (veto_list_sz >0 ) {struct ksmbd_veto_pattern *p; - sz =strlen (veto_list); + sz =strnlen (veto_list, veto_list_sz);if (!sz)break ;
@@ -164,7 +164,7 @@ static int parse_veto_list(struct ksmbd_share_config *share,if (!p)return -ENOMEM ; - p->pattern =kstrdup (veto_list,KSMBD_DEFAULT_GFP ); + p->pattern =kstrndup (veto_list, sz,KSMBD_DEFAULT_GFP );if (!p->pattern) {kfree (p);return -ENOMEM ;
@@ -172,6 +172,9 @@ static int parse_veto_list(struct ksmbd_share_config *share,list_add (&p->list, &share->veto_list); +if (sz == veto_list_sz) +break ; + veto_list += sz +1 ; veto_list_sz -= (sz +1 ); }
@@ -224,17 +227,28 @@ static struct ksmbd_share_config *share_config_request(struct ksmbd_work *work, }if (!test_share_config_flag (share,KSMBD_SHARE_FLAG_PIPE )) { -int path_len =PATH_MAX ; +size_t path_len; -if (resp->payload_sz) - path_len = resp->payload_sz - resp->veto_list_sz; - - share->path =kstrndup (ksmbd_share_config_path (resp), path_len, -KSMBD_DEFAULT_GFP ); -if (!share->path) { - ret = -ENOMEM ; +if (resp->payload_sz <= resp->veto_list_sz) { + ret = -EINVAL ; }else { - ret =0 ; + path_len = resp->payload_sz - resp->veto_list_sz; +if (resp->veto_list_sz) + path_len--; + +if (!path_len) { + ret = -EINVAL ; + }else { + share->path =kstrndup ( +ksmbd_share_config_path (resp), + path_len,KSMBD_DEFAULT_GFP ); +if (!share->path) + ret = -ENOMEM ; +else + ret =0 ; + } + } +if (share->path) { share->path_sz =strlen (share->path);while (share->path_sz >1 && share->path[share->path_sz -1 ] =='/' )
fs/smb/server/transport_ipc.c +14 -7
@@ -532,14 +532,21 @@ static int ipc_validate_msg(struct ipc_msg_table_entry *entry)if (entry->msg_sz <sizeof (struct ksmbd_share_config_response ))return -EINVAL ; -if (resp->payload_sz) { -if (resp->payload_sz < resp->veto_list_sz) -return -EINVAL ; +if (strnlen (resp->share_name,sizeof (resp->share_name)) == +sizeof (resp->share_name)) +return -EINVAL ; -if (check_add_overflow (sizeof (struct ksmbd_share_config_response ), - resp->payload_sz, &msg_sz)) -return -EINVAL ; - } +if (resp->veto_list_sz > resp->payload_sz) +return -EINVAL ; + +if (resp->flags !=KSMBD_SHARE_FLAG_INVALID && + !(resp->flags &KSMBD_SHARE_FLAG_PIPE ) && + resp->payload_sz <= resp->veto_list_sz) +return -EINVAL ; + +if (check_add_overflow (sizeof (struct ksmbd_share_config_response ), + resp->payload_sz, &msg_sz)) +return -EINVAL ;break ; }case KSMBD_EVENT_LOGIN_REQUEST_EXT :
Sasha Levin
maintainerPATCH 1/5 ksmbd: Use struct_size() to improve smb_direct_rdma_xmit()
From: Thorsten Blum <[email protected]>
[ Upstream commit 9c383396362a4d1db99ed5240f4708d443361ef3 ]
Use struct_size() to calculate the number of bytes to allocate for a new message.
Stable-dep-of: f25e93768fcc ("ksmbd: prevent out-of-bounds reads in share config responses")
--- fs/smb/server/transport_rdma.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
fs/smb/server/transport_rdma.c +2 -2
@@ -1397,8 +1397,8 @@ static int smb_direct_rdma_xmit(struct smb_direct_transport *t,/* build rdma_rw_ctx for each descriptor */ desc_buf = buf;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 ); + msg =kzalloc (struct_size (msg, sg_list,SG_CHUNK_SIZE ), +GFP_KERNEL );if (!msg) { ret = -ENOMEM ; goto out;
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 2/5 ksmbd: use __GFP_RETRY_MAYFAIL
From: Namjae Jeon <[email protected]>
[ Upstream commit 0066f623bce8f98b69b752ee03d46a5047c281b8 ]
Prefer to report ENOMEM rather than incur the oom for allocations in ksmbd. __GFP_NORETRY could not achieve that, It would fail the allocations just too easily. __GFP_RETRY_MAYFAIL will keep retrying the allocation until there is no more progress and fail the allocation instead go OOM and let the caller to deal with it.
[ Stable dependency adaptation for f25e93768fcc5d8287e50b1ec52a42e4c276df34:
Keep the default allocation mask and its uses in share_config.c and transport_ipc.c. Drop unrelated allocation conversions, including the hunks that require IDA, supplementary-group, RPC, interface, or durable handle code not present in this stable tree.
Prepare the existing share-config path for the target by retaining path allocation failures and only parsing the veto list on success, as in a74668eb2c0b. Convert the existing IPC validator to a switch for its three supported request types; add the share-response header-length check and checked size addition needed by the target, from e9b33376bd07 and d6a6aa81eac2. Do not introduce extended-login support or new functions. ]
[ sashal: Reduced backport -- upstream 0066f623bce8f touches 24 file(s), this
backport carries 3. Not backported here:
fs/smb/server/asn1.c
fs/smb/server/auth.c
fs/smb/server/connection.c
fs/smb/server/crypto_ctx.c
fs/smb/server/ksmbd_work.c
fs/smb/server/mgmt/ksmbd_ida.c fs/smb/server/mgmt/tree_connect.c fs/smb/server/mgmt/user_config.c
... and 13 more
This note is generated from the file lists only; see the resolution record for the reasoning. ]
Stable-dep-of: f25e93768fcc ("ksmbd: prevent out-of-bounds reads in share config responses")
--- fs/smb/server/glob.h | 2 ++ fs/smb/server/mgmt/share_config.c | 22 +++++++++++++--------- fs/smb/server/transport_ipc.c | 31 +++++++++++++++++++++++-------- 3 files changed, 38 insertions(+), 17 deletions(-)
fs/smb/server/glob.h +2 -0
@@ -46,4 +46,6 @@ extern int ksmbd_debug_types;#define UNICODE_LEN (x) ((x) * 2) +#define KSMBD_DEFAULT_GFP (GFP_KERNEL | __GFP_RETRY_MAYFAIL) +#endif /* __KSMBD_GLOB_H */
fs/smb/server/mgmt/share_config.c +13 -9
@@ -102,11 +102,11 @@ static int parse_veto_list(struct ksmbd_share_config *share,if (!sz)break ; - p =kzalloc (sizeof (struct ksmbd_veto_pattern ),GFP_KERNEL ); + p =kzalloc (sizeof (struct ksmbd_veto_pattern ),KSMBD_DEFAULT_GFP );if (!p)return -ENOMEM ; - p->pattern =kstrdup (veto_list,GFP_KERNEL ); + p->pattern =kstrdup (veto_list,KSMBD_DEFAULT_GFP );if (!p->pattern) {kfree (p);return -ENOMEM ;
@@ -150,14 +150,14 @@ static struct ksmbd_share_config *share_config_request(struct ksmbd_work *work, goto out; } - share =kzalloc (sizeof (struct ksmbd_share_config ),GFP_KERNEL ); + share =kzalloc (sizeof (struct ksmbd_share_config ),KSMBD_DEFAULT_GFP );if (!share) goto out; share->flags = resp->flags;atomic_set (&share->refcount,1 );INIT_LIST_HEAD (&share->veto_list); - share->name =kstrdup (name,GFP_KERNEL ); + share->name =kstrdup (name,KSMBD_DEFAULT_GFP );if (!test_share_config_flag (share,KSMBD_SHARE_FLAG_PIPE )) {int path_len =PATH_MAX ;
@@ -166,8 +166,11 @@ static struct ksmbd_share_config *share_config_request(struct ksmbd_work *work, path_len = resp->payload_sz - resp->veto_list_sz; share->path =kstrndup (ksmbd_share_config_path (resp), path_len, -GFP_KERNEL ); -if (share->path) { +KSMBD_DEFAULT_GFP ); +if (!share->path) { + ret = -ENOMEM ; + }else { + ret =0 ; share->path_sz =strlen (share->path);while (share->path_sz >1 && share->path[share->path_sz -1 ] =='/' )
@@ -179,9 +182,10 @@ static struct ksmbd_share_config *share_config_request(struct ksmbd_work *work, share->force_directory_mode = resp->force_directory_mode; share->force_uid = resp->force_uid; share->force_gid = resp->force_gid; - ret =parse_veto_list (share, -KSMBD_SHARE_CONFIG_VETO_LIST (resp), - resp->veto_list_sz); +if (!ret) + ret =parse_veto_list (share, +KSMBD_SHARE_CONFIG_VETO_LIST (resp), + resp->veto_list_sz);if (!ret && share->path) {if (__ksmbd_override_fsids (work, share)) {kill_share (share);
fs/smb/server/transport_ipc.c +23 -8
@@ -13,6 +13,7 @@#include <net/genetlink.h> #include <linux/socket.h> #include <linux/workqueue.h> +#include <linux/overflow.h> #include "vfs_cache.h" #include "transport_ipc.h"
@@ -230,7 +231,7 @@ static struct ksmbd_ipc_msg *ipc_msg_alloc(size_t sz)struct ksmbd_ipc_msg *msg;size_t msg_sz = sz +sizeof (struct ksmbd_ipc_msg ); - msg =kvzalloc (msg_sz,GFP_KERNEL ); + msg =kvzalloc (msg_sz,KSMBD_DEFAULT_GFP );if (msg) msg->sz = sz;return msg;
@@ -276,7 +277,7 @@ static int handle_response(int type, void *payload, size_t sz)continue ; } - entry->response =kvzalloc (sz,GFP_KERNEL ); + entry->response =kvzalloc (sz,KSMBD_DEFAULT_GFP );if (!entry->response) { ret = -ENOMEM ;break ;
@@ -446,7 +447,7 @@ static int ipc_msg_send(struct ksmbd_ipc_msg *msg)if (!ksmbd_tools_pid)return ret; - skb =genlmsg_new (msg->sz,GFP_KERNEL ); + skb =genlmsg_new (msg->sz,KSMBD_DEFAULT_GFP );if (!skb)return -ENOMEM ;
@@ -475,25 +476,39 @@ static int ipc_validate_msg(struct ipc_msg_table_entry *entry) {unsigned int msg_sz = entry->msg_sz; -if (entry->type ==KSMBD_EVENT_RPC_REQUEST ) { +switch (entry->type) { +case KSMBD_EVENT_RPC_REQUEST : + {struct ksmbd_rpc_command *resp = entry->response; msg_sz =sizeof (struct ksmbd_rpc_command ) + resp->payload_sz; - }else if (entry->type ==KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST ) { +break ; + } +case KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST : + {struct ksmbd_spnego_authen_response *resp = entry->response; msg_sz =sizeof (struct ksmbd_spnego_authen_response ) + resp->session_key_len + resp->spnego_blob_len; - }else if (entry->type ==KSMBD_EVENT_SHARE_CONFIG_REQUEST ) { +break ; + } +case KSMBD_EVENT_SHARE_CONFIG_REQUEST : + {struct ksmbd_share_config_response *resp = entry->response; +if (entry->msg_sz <sizeof (struct ksmbd_share_config_response )) +return -EINVAL ; +if (resp->payload_sz) {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 ; + } }return entry->msg_sz != msg_sz ? -EINVAL :0 ;
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 3/5 ksmbd: validate response sizes in ipc_validate_msg()
In reply to Sasha LevinFrom: Michael Bommarito <[email protected]>
[ Upstream commit d6a6aa81eac2c9bff66dc6e191179cb69a14426b ]
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.
[ Stable dependency adaptation for f25e93768fcc5d8287e50b1ec52a42e4c276df34:
Retain the RPC response-size overflow check in ipc_validate_msg(). The previous dependency, 2d1f4c041770, already supplied the overflow header and the share-response checked addition required by the target.
Drop both supplementary-group hunks: this stable tree has neither extended-login IPC messages nor supplementary-group fields in ksmbd_user. Keep user_config.c unchanged and do not introduce extended-login support or any new functions. The target applies cleanly by three-way application with the existing share-config preparation and this reduced dependency. ]
[ sashal: Reduced backport -- upstream d6a6aa81eac2c touches 2 file(s), this
backport carries 1. Not backported here:
fs/smb/server/mgmt/user_config.c
This note is generated from the file lists only; see the resolution record for the reasoning. ]
Stable-dep-of: f25e93768fcc ("ksmbd: prevent out-of-bounds reads in share config responses")
--- fs/smb/server/transport_ipc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
fs/smb/server/transport_ipc.c +3 -1
@@ -481,7 +481,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 :
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 4/5 ksmbd: validate ipc response length before dereferencing its fields
In reply to Sasha LevinFrom: Yunseong Kim <[email protected]>
[ Upstream commit e9b33376bd07bca4175f7bcc2d6034ef250f8181 ]
ipc_validate_msg() computes the expected message size by reading length fields out of the response buffer supplied by the userspace ksmbd daemon (payload_sz, session_key_len, ngroups, ...). Those fields are read before the buffer is verified to be large enough to contain the struct they belong to, so a short response makes the read land past the end of the allocation.
handle_response() sizes entry->response purely from the netlink attribute length (nla_len()) and only guards the leading handle read, so the daemon can install a response as small as the kmalloc-8 object seen below. When ipc_msg_send_request() then calls ipc_validate_msg() for a KSMBD_EVENT_RPC_REQUEST, the cast to struct ksmbd_rpc_command reads resp->payload_sz at offset 8 of an 8-byte allocation:
[ 3697.841381] ================================================================== [ 3697.844099] BUG: KASAN: slab-out-of-bounds in ipc_msg_send_request+0x763/0x800 [ 3697.846604] Read of size 4 at addr ffff888105f95910 by task kworker/4:3/20682 [ 3697.849061] [ 3697.849801] CPU: 4 UID: 0 PID: 20682 Comm: kworker/4:3 Not tainted 7.2.0-rc3-next-20260717-virtme #117 PREEMPT(lazy) [ 3697.850077] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.17.0-debian-1.17.0-1 04/01/2014 [ 3697.850303] Workqueue: ksmbd-io handle_ksmbd_work [ 3697.850592] Call Trace: [ 3697.850794] <TASK> [ 3697.850952] __dump_stack+0x21/0x60 [ 3697.851239] dump_stack_lvl+0xc2/0x100 [ 3697.851528] print_address_description+0x77/0x200 [ 3697.851816] ? ipc_msg_send_request+0x763/0x800 [ 3697.852024] print_report+0x58/0x70 [ 3697.852316] kasan_report+0x117/0x150 [ 3697.852585] ? down_write+0x146/0x1f0 [ 3697.852809] ? ipc_msg_send_request+0x763/0x800 [ 3697.853082] ipc_msg_send_request+0x763/0x800 [ 3697.853385] ? __pfx_ipc_msg_send_request+0x10/0x10 [ 3697.853604] ? kasan_unpoison+0x48/0x70 [ 3697.853936] ? __pfx___up_read+0x10/0x10 [ 3697.854221] ksmbd_rpc_ioctl+0x380/0x520 [ 3697.854542] ? __pfx_ksmbd_rpc_ioctl+0x10/0x10 [ 3697.854757] ? kasan_unpoison+0x48/0x70 [ 3697.854962] ? copy_from_kernel_nofault+0x32c/0x4e0 [ 3697.855166] ? kasan_unpoison+0x48/0x70 [ 3697.855416] fsctl_pipe_transceive+0x139/0x7a0 [ 3697.855705] ? __pfx_copy_from_kernel_nofault+0x10/0x10 [ 3697.855937] ? __pfx_fsctl_pipe_transceive+0x10/0x10 [ 3697.856388] ? __sanitizer_cov_trace_switch+0x7b/0x140 [ 3697.856620] smb2_ioctl+0x1141/0x3420 [ 3697.856994] ? __pfx_smb2_ioctl+0x10/0x10 [ 3697.857182] ? get_smb2_cmd_val+0xe3/0x1c0 [ 3697.857655] handle_ksmbd_work+0x9ad/0x15e0 [ 3697.858034] ? __pfx_handle_ksmbd_work+0x10/0x10 [ 3697.858251] ? lock_release+0xf7/0x360 [ 3697.858466] ? process_scheduled_works+0x954/0x1600 [ 3697.858698] ? process_scheduled_works+0x954/0x1600 [ 3697.858905] process_scheduled_works+0xc22/0x1600 [ 3697.859368] ? __pfx_process_scheduled_works+0x10/0x10 [ 3697.859637] ? __pfx_assign_work+0x10/0x10 [ 3697.859896] ? lock_is_held_type+0x7b/0x110 [ 3697.860146] worker_thread+0x975/0xee0 [ 3697.860524] ? __pfx_do_raw_spin_lock+0x10/0x10 [ 3697.860830] ? __kthread_parkme+0x21e/0x260 [ 3697.861105] kthread+0x3a6/0x490 [ 3697.861423] ? __pfx_worker_thread+0x10/0x10 [ 3697.861643] ? __pfx_kthread+0x10/0x10 [ 3697.861878] ret_from_fork+0x55a/0xa20 [ 3697.862194] ? __pfx_ret_from_fork+0x10/0x10 [ 3697.862480] ? __pfx_kthread+0x10/0x10 [ 3697.862714] ret_from_fork_asm+0x1a/0x30 [ 3697.862965] </TASK> [ 3697.863039] [ 3697.938882] Allocated by task 20761: [ 3697.940257] kasan_save_track+0x3e/0x80 [ 3697.941782] __kasan_kmalloc+0x72/0x90 [ 3697.943228] __kvmalloc_node_noprof+0x3e9/0x6a0 [ 3697.944948] handle_generic_event+0x59b/0x750 [ 3697.946592] genl_family_rcv_msg_doit+0x3d6/0x560 [ 3697.946977] genl_rcv_msg+0x67c/0x900 [ 3697.947224] netlink_rcv_skb+0x286/0x580 [ 3697.947488] genl_rcv+0x2d/0x80 [ 3697.947706] netlink_unicast+0x937/0xb70 [ 3697.947993] netlink_sendmsg+0x977/0xc10 [ 3697.948268] __sock_sendmsg+0x264/0x2d0 [ 3697.948536] __sys_sendto+0x4de/0x690 [ 3697.948789] __x64_sys_sendto+0x173/0x380 [ 3697.949069] do_syscall_64+0x13d/0x420 [ 3697.949328] entry_SYSCALL_64_after_hwframe+0x77/0x7f [ 3697.949662] [ 3697.949779] The buggy address belongs to the object at ffff888105f95908 [ 3697.949779] which belongs to the cache kmalloc-8 of size 8 [ 3697.950550] The buggy address is located 0 bytes to the right of [ 3697.950550] allocated 8-byte region [ffff888105f95908, ffff888105f95910) [ 3697.951455] [ 3697.951574] The buggy address belongs to the physical page: [ 3697.951958] page: refcount:0 mapcount:0 mapping:0000000000000000 index:0xffff888105f951b8 pfn:0x105f95 [ 3697.952571] flags: 0x100000000000200(workingset|node=0|zone=2) [ 3697.952973] page_type: f5(slab) [ 3697.953198] raw: 0100000000000200 ffff888100042640 ffffea0004063610 ffff888100040588 [ 3697.953707] raw: ffff888105f951b8 00000000001c000e 00000000f5000000 0000000000000000 [ 3697.954240] page dumped because: kasan: bad access detected [ 3697.954616] [ 3697.954734] Memory state around the buggy address: [ 3697.955063] ffff888105f95800: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fa [ 3697.955534] ffff888105f95880: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 3697.956006] >ffff888105f95900: fc 00 fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 3697.956477] ^ [ 3697.956728] ffff888105f95980: fc fc fc fa fc fc fc fc fc fc fc fc fc fc fc fc [ 3697.957202] ffff888105f95a00: fc fc fc fc fc fa fc fc fc fc fc fc fc fc fc fc [ 3697.957671] ==================================================================
The final "entry->msg_sz != msg_sz" comparison cannot help: the offending read has already happened by the time it runs. Every case in the switch shares this pattern.
Floor entry->msg_sz against the base struct of each event type before dereferencing any of its length fields. On failure ipc_msg_send_request() already frees the response and returns NULL, so callers stay safe.
The malformed message originates from the ksmbd.mountd daemon over genl netlink rather than a remote SMB client, so triggering it requires a buggy or compromised daemon; it is still an out-of-bounds read the validator is meant to prevent.
[ Stable dependency adaptation for f25e93768fcc5d8287e50b1ec52a42e4c276df34:
Retain the minimum response-header checks for RPC and SPNEGO before dereferencing their variable-length fields in ipc_validate_msg(). The share-config header check is already present from dependency 2d1f4c041770, so it needs no additional change here.
Drop the extended-login hunk: this stable tree has neither KSMBD_EVENT_LOGIN_REQUEST_EXT nor struct ksmbd_login_response_ext. Do not introduce extended-login support or any new functions. The target applies cleanly by three-way application to this tree. ]
Stable-dep-of: f25e93768fcc ("ksmbd: prevent out-of-bounds reads in share config responses")
--- fs/smb/server/transport_ipc.c | 6 ++++++ 1 file changed, 6 insertions(+)
fs/smb/server/transport_ipc.c +6 -0
@@ -481,6 +481,9 @@ static int ipc_validate_msg(struct ipc_msg_table_entry *entry) {struct ksmbd_rpc_command *resp = entry->response; +if (entry->msg_sz <sizeof (struct ksmbd_rpc_command )) +return -EINVAL ; +if (check_add_overflow (sizeof (struct ksmbd_rpc_command ), resp->payload_sz, &msg_sz))return -EINVAL ;
@@ -490,6 +493,9 @@ static int ipc_validate_msg(struct ipc_msg_table_entry *entry) {struct ksmbd_spnego_authen_response *resp = entry->response; +if (entry->msg_sz <sizeof (struct ksmbd_spnego_authen_response )) +return -EINVAL ; + msg_sz =sizeof (struct ksmbd_spnego_authen_response ) + resp->session_key_len + resp->spnego_blob_len;break ;
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 5/5 ksmbd: prevent out-of-bounds reads in share config responses
In reply to Sasha LevinFrom: Namjae Jeon <[email protected]>
[ Upstream commit f25e93768fcc5d8287e50b1ec52a42e4c276df34 ]
Validate IPC share configuration payload sizes before consuming variable-length fields. Bound veto list parsing and account for the separator byte when deriving the path length.
--- fs/smb/server/mgmt/share_config.c | 40 +++++++++++++++++++++---------- fs/smb/server/transport_ipc.c | 21 ++++++++++------ 2 files changed, 41 insertions(+), 20 deletions(-)
fs/smb/server/mgmt/share_config.c +27 -13
@@ -88,9 +88,9 @@ static struct ksmbd_share_config *__share_lookup(const char *name)static int parse_veto_list (struct ksmbd_share_config *share,char *veto_list, -int veto_list_sz) +size_t veto_list_sz) { -int sz =0 ; +size_t sz;if (!veto_list_sz)return 0 ;
@@ -98,7 +98,7 @@ static int parse_veto_list(struct ksmbd_share_config *share,while (veto_list_sz >0 ) {struct ksmbd_veto_pattern *p; - sz =strlen (veto_list); + sz =strnlen (veto_list, veto_list_sz);if (!sz)break ;
@@ -106,7 +106,7 @@ static int parse_veto_list(struct ksmbd_share_config *share,if (!p)return -ENOMEM ; - p->pattern =kstrdup (veto_list,KSMBD_DEFAULT_GFP ); + p->pattern =kstrndup (veto_list, sz,KSMBD_DEFAULT_GFP );if (!p->pattern) {kfree (p);return -ENOMEM ;
@@ -114,6 +114,9 @@ static int parse_veto_list(struct ksmbd_share_config *share,list_add (&p->list, &share->veto_list); +if (sz == veto_list_sz) +break ; + veto_list += sz +1 ; veto_list_sz -= (sz +1 ); }
@@ -160,17 +163,28 @@ static struct ksmbd_share_config *share_config_request(struct ksmbd_work *work, share->name =kstrdup (name,KSMBD_DEFAULT_GFP );if (!test_share_config_flag (share,KSMBD_SHARE_FLAG_PIPE )) { -int path_len =PATH_MAX ; - -if (resp->payload_sz) - path_len = resp->payload_sz - resp->veto_list_sz; +size_t path_len; - share->path =kstrndup (ksmbd_share_config_path (resp), path_len, -KSMBD_DEFAULT_GFP ); -if (!share->path) { - ret = -ENOMEM ; +if (resp->payload_sz <= resp->veto_list_sz) { + ret = -EINVAL ; }else { - ret =0 ; + path_len = resp->payload_sz - resp->veto_list_sz; +if (resp->veto_list_sz) + path_len--; + +if (!path_len) { + ret = -EINVAL ; + }else { + share->path =kstrndup ( +ksmbd_share_config_path (resp), + path_len,KSMBD_DEFAULT_GFP ); +if (!share->path) + ret = -ENOMEM ; +else + ret =0 ; + } + } +if (share->path) { share->path_sz =strlen (share->path);while (share->path_sz >1 && share->path[share->path_sz -1 ] =='/' )
fs/smb/server/transport_ipc.c +14 -7
@@ -507,14 +507,21 @@ static int ipc_validate_msg(struct ipc_msg_table_entry *entry)if (entry->msg_sz <sizeof (struct ksmbd_share_config_response ))return -EINVAL ; -if (resp->payload_sz) { -if (resp->payload_sz < resp->veto_list_sz) -return -EINVAL ; +if (strnlen (resp->share_name,sizeof (resp->share_name)) == +sizeof (resp->share_name)) +return -EINVAL ; -if (check_add_overflow (sizeof (struct ksmbd_share_config_response ), - resp->payload_sz, &msg_sz)) -return -EINVAL ; - } +if (resp->veto_list_sz > resp->payload_sz) +return -EINVAL ; + +if (resp->flags !=KSMBD_SHARE_FLAG_INVALID && + !(resp->flags &KSMBD_SHARE_FLAG_PIPE ) && + resp->payload_sz <= resp->veto_list_sz) +return -EINVAL ; + +if (check_add_overflow (sizeof (struct ksmbd_share_config_response ), + resp->payload_sz, &msg_sz)) +return -EINVAL ;break ; } }
Signature · 1 line
2.53.0