FAILED: patch "[PATCH] ksmbd: fix OOB write in QUERY_INFO for compound requests" failed to apply to 5.15-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 5.15-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-5.15.y
git checkout FETCH_HEAD
git cherry-pick -x fda9522ed6afaec45cabc198d8492270c394c7bc
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026040727-spindle-thigh-9ebd@gregkh' --subject-prefix 'PATCH 5.15.y' HEAD^..
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From fda9522ed6afaec45cabc198d8492270c394c7bc Mon Sep 17 00:00:00 2001
From: Asim Viladi Oglu Manizada <[email protected]>
Date: Wed, 25 Mar 2026 09:14:22 +0900
Subject: [PATCH] ksmbd: fix OOB write in QUERY_INFO for compound requests
When a compound request such as READ + QUERY_INFO(Security) is received, and the first command (READ) consumes most of the response buffer, ksmbd could write beyond the allocated buffer while building a security descriptor.
The root cause was that smb2_get_info_sec() checked buffer space using ppntsd_size from xattr, while build_sec_desc() often synthesized a significantly larger descriptor from POSIX ACLs.
This patch introduces smb_acl_sec_desc_scratch_len() to accurately compute the final descriptor size beforehand, performs proper buffer checking with smb2_calc_max_out_buf_len(), and uses exact-sized allocation + iov pinning.
fs/smb/server/smb2pdu.c +89 -32
@@ -3402,20 +3402,24 @@ int smb2_open(struct ksmbd_work *work) KSMBD_SHARE_FLAG_ACL_XATTR)) {struct smb_fattr fattr;struct smb_ntsd *pntsd; -int pntsd_size, ace_num =0 ; +int pntsd_size; +size_t scratch_len;ksmbd_acls_fattr (&fattr, idmap, inode); -if (fattr.cf_acls) - ace_num = fattr.cf_acls->a_count; -if (fattr.cf_dacls) - ace_num += fattr.cf_dacls->a_count; + scratch_len =smb_acl_sec_desc_scratch_len (&fattr, +NULL ,0 , +OWNER_SECINFO |GROUP_SECINFO | +DACL_SECINFO ); +if (!scratch_len || scratch_len ==SIZE_MAX ) { + rc = -EFBIG ; +posix_acl_release (fattr.cf_acls); +posix_acl_release (fattr.cf_dacls); + goto err_out; + } - pntsd =kmalloc (sizeof (struct smb_ntsd ) + -sizeof (struct smb_sid ) *3 + -sizeof (struct smb_acl ) + -sizeof (struct smb_ace ) * ace_num *2 , -KSMBD_DEFAULT_GFP ); + pntsd =kvzalloc (scratch_len,KSMBD_DEFAULT_GFP );if (!pntsd) { + rc = -ENOMEM ;posix_acl_release (fattr.cf_acls);posix_acl_release (fattr.cf_dacls); goto err_out;
@@ -3430,7 +3434,7 @@ int smb2_open(struct ksmbd_work *work)posix_acl_release (fattr.cf_acls);posix_acl_release (fattr.cf_dacls);if (rc) { -kfree (pntsd); +kvfree (pntsd); goto err_out; }
@@ -3440,7 +3444,7 @@ int smb2_open(struct ksmbd_work *work) pntsd, pntsd_size, false); -kfree (pntsd); +kvfree (pntsd);if (rc)pr_err ("failed to store ntacl in xattr : %d\n" , rc);
@@ -5372,8 +5376,9 @@ static int smb2_get_info_file(struct ksmbd_work *work,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, + rc =smb2_get_info_file_pipe (work->sess, req, rsp, work->response_buf); + goto iov_pin_out; }if (work->next_smb2_rcv_hdr_off) {
@@ -5473,6 +5478,12 @@ static int smb2_get_info_file(struct ksmbd_work *work, rc =buffer_check_err (le32_to_cpu (req->OutputBufferLength), rsp, work->response_buf);ksmbd_fd_put (work, fp); + +iov_pin_out: +if (!rc) + rc =ksmbd_iov_pin_rsp (work, (void *)rsp, + offsetof(struct smb2_query_info_rsp , Buffer) + +le32_to_cpu (rsp->OutputBufferLength));return rc; }
@@ -5699,6 +5710,11 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work, rc =buffer_check_err (le32_to_cpu (req->OutputBufferLength), rsp, work->response_buf);path_put (&path); + +if (!rc) + rc =ksmbd_iov_pin_rsp (work, (void *)rsp, + offsetof(struct smb2_query_info_rsp , Buffer) + +le32_to_cpu (rsp->OutputBufferLength));return rc; }
@@ -5708,13 +5724,14 @@ static int smb2_get_info_sec(struct ksmbd_work *work, {struct ksmbd_file *fp;struct mnt_idmap *idmap; -struct smb_ntsd *pntsd = (struct smb_ntsd *)rsp->Buffer, *ppntsd =NULL ; +struct smb_ntsd *pntsd =NULL , *ppntsd =NULL ;struct smb_fattr fattr = {{0 }};struct inode *inode;__u32 secdesclen =0 ;unsigned int id =KSMBD_NO_FID , pid =KSMBD_NO_FID ;int addition_info =le32_to_cpu (req->AdditionalInformation); -int rc =0 , ppntsd_size =0 ; +int rc =0 , ppntsd_size =0 , max_len; +size_t scratch_len =0 ; if (addition_info & ~(OWNER_SECINFO | GROUP_SECINFO | DACL_SECINFO | PROTECTED_DACL_SECINFO |
@@ -5722,6 +5739,11 @@ 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 ;
@@ -5730,9 +5752,7 @@ static int smb2_get_info_sec(struct ksmbd_work *work, pntsd->dacloffset =0 ; secdesclen =sizeof (struct smb_ntsd ); - rsp->OutputBufferLength =cpu_to_le32 (secdesclen); - -return 0 ; + goto iov_pin; }if (work->next_smb2_rcv_hdr_off) {
@@ -5764,18 +5784,58 @@ static int smb2_get_info_sec(struct ksmbd_work *work, &ppntsd);/* Check if sd buffer size exceeds response buffer size */ -if (smb2_resp_buf_len (work,8 ) > ppntsd_size) - rc =build_sec_desc (idmap, pntsd, ppntsd, ppntsd_size, - addition_info, &secdesclen, &fattr); + max_len =smb2_calc_max_out_buf_len (work, + offsetof(struct smb2_query_info_rsp , Buffer), +le32_to_cpu (req->OutputBufferLength)); +if (max_len <0 ) { + rc = -EINVAL ; + goto release_acl; + } + + scratch_len =smb_acl_sec_desc_scratch_len (&fattr, ppntsd, + ppntsd_size, addition_info); +if (!scratch_len || scratch_len ==SIZE_MAX ) { + rc = -EFBIG ; + goto release_acl; + } + + pntsd =kvzalloc (scratch_len,KSMBD_DEFAULT_GFP ); +if (!pntsd) { + rc = -ENOMEM ; + goto release_acl; + } + + rc =build_sec_desc (idmap, pntsd, ppntsd, ppntsd_size, + addition_info, &secdesclen, &fattr); + +release_acl:posix_acl_release (fattr.cf_acls);posix_acl_release (fattr.cf_dacls);kfree (ppntsd);ksmbd_fd_put (work, fp); -if (rc) -return rc; +if (!rc &&ALIGN (secdesclen,8 ) > scratch_len) + rc = -EFBIG ; +if (rc) + goto err_out; + +iov_pin: rsp->OutputBufferLength =cpu_to_le32 (secdesclen); -return 0 ; + rc =buffer_check_err (le32_to_cpu (req->OutputBufferLength), + rsp, work->response_buf); +if (rc) + goto err_out; + + rc =ksmbd_iov_pin_rsp_read (work, (void *)rsp, + offsetof(struct smb2_query_info_rsp , Buffer), + pntsd, secdesclen); +err_out: +if (rc) { + rsp->OutputBufferLength =0 ; +kvfree (pntsd); + } + +return rc; }/**
@@ -5799,6 +5859,9 @@ int smb2_query_info(struct ksmbd_work *work) goto err_out; } + rsp->StructureSize =cpu_to_le16 (9 ); + rsp->OutputBufferOffset =cpu_to_le16 (72 ); +switch (req->InfoType) {case SMB2_O_INFO_FILE :ksmbd_debug (SMB ,"GOT SMB2_O_INFO_FILE\n" );
@@ -5819,14 +5882,6 @@ int smb2_query_info(struct ksmbd_work *work) }ksmbd_revert_fsids (work); -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)); - } - err_out:if (rc <0 ) {if (rc == -EACCES )
@@ -5837,6 +5892,8 @@ int smb2_query_info(struct ksmbd_work *work) rsp->hdr.Status =STATUS_UNEXPECTED_IO_ERROR ; else if (rc == -ENOMEM) rsp->hdr.Status = STATUS_INSUFFICIENT_RESOURCES; + else if (rc == -EINVAL && rsp->hdr.Status == 0) + rsp->hdr.Status =STATUS_INVALID_PARAMETER ; else if (rc == -EOPNOTSUPP || rsp->hdr.Status == 0) rsp->hdr.Status =STATUS_INVALID_INFO_CLASS ;smb2_set_err_rsp (work);
fs/smb/server/smbacl.c +43 -0
49 lines not on this page · raw message
fs/smb/server/smbacl.h +2 -0
@@ -101,6 +101,8 @@ int set_info_sec(struct ksmbd_conn *conn, struct ksmbd_tree_connect *tcon, 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); +size_t smb_acl_sec_desc_scratch_len (struct smb_fattr *fattr, +struct smb_ntsd *ppntsd,int ppntsd_size,int addition_info);static inline uid_t posix_acl_uid_translate (struct mnt_idmap *idmap,struct posix_acl_entry *pace)