From nobody Mon Jun 8 12:14:07 2026 Received: from out162-62-57-252.mail.qq.com (out162-62-57-252.mail.qq.com [162.62.57.252]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2FF6033B6C6; Fri, 29 May 2026 08:25:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=162.62.57.252 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780043143; cv=none; b=aafCnLrIzAJX2L2azcFSeSu++EAWjTPvJYiwDG/qHySUgVYajYnZ9KOtmK8p8oUuTsNvMxO9dMXAog42p3xGKv0978MM/pL4VGMHnt9YOW4/AfVDVDe6m9ejR/eiHDKOBsngxIJtuJ5H0yG46u/8UZvsByB/aM8V7U5IGJxatX4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780043143; c=relaxed/simple; bh=l3xgtWsnc/8P37Wt4I9y5h9Msr8UEl33UMan+h7su2k=; h=Message-ID:From:To:Cc:Subject:Date:MIME-Version; b=aDVWWAC8uZn9pJc3oTh0Wi38UxJyLySV0iqkFvgMHLIhwF4VAw6wR/8p5ShjWl9i73LfPX6OairxHxSRWP+l7I/x3dCd010BQN58bpW9ZMwxgnTXkkIMX17ACBp2w28+RAJfwZoQ+cSxMkb0EPukOBwkqr3LA33RM0tSoXYeFw8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=foxmail.com; spf=pass smtp.mailfrom=foxmail.com; dkim=pass (1024-bit key) header.d=foxmail.com header.i=@foxmail.com header.b=o54Rz/UP; arc=none smtp.client-ip=162.62.57.252 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=foxmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=foxmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=foxmail.com header.i=@foxmail.com header.b="o54Rz/UP" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=foxmail.com; s=s201512; t=1780043128; bh=nVosto6nhcaBEAjsYH0X0Ne6xvjpeZ+XIIDQ0tzHwxI=; h=From:To:Cc:Subject:Date; b=o54Rz/UPPlYfLkiiccSGFdauKouzvqB45PysloAq3pI7NlNDyr9Lw6K85xHPF/Y5P Zoq0N73BkhC8eT4AMzb+CNObxKCLkmNX9XUW/33/AfcVZ/SaSQwOPt7JL1akDQ5L/K v/yNZw0sN4ByqUfXFBdU8LxDBzu6hNLNdgHR2dbs= Received: from China-team ([47.95.114.252]) by newxmesmtplogicsvrszb43-0.qq.com (NewEsmtp) with SMTP id 56F268DA; Fri, 29 May 2026 16:21:47 +0800 X-QQ-mid: xmsmtpt1780042907tu7llr6rg Message-ID: X-QQ-XMAILINFO: M+6QKz8nsrJQglZM38BhwlChqRkhX9ti1JYkT1pjIcg/J40i5zZ6L9acRMRihu akrSmE9kzr3qOuXsrDxJJQ5O81SVuULzsH1CKaa9b7BiPFWJIZ0hDM8lA5qU+J4p9kS3ySb6hMoQ CRWEbvNKRedIHX7Foz6wMiHzs20IAwRAO4q3gH/qvncTmpjubDGyEkOyvqrnCCodgTUkk4zuaUJA lbDvWOqJ0a6KLBoIbQaAGjrFpnXbFyUCv9pYlnJvU30o/q4k5Tii7tMbIYUMMgXMtiMFkwwlKLrb Fr+pfVP9DSBc3d02vpjkPPFpTHJsBKWcClL65rAqoM1z4cWjvQOaOIkeTvOY6xnbS+bM+GS5lBgh SUm1XSKY10iwIeP+YGBP/MfA9HDbVj152prLimOVVtfkKuI3d7J1d8vDg0bzHAKO5BB7P6gCr7lo c6eT7jzxnF3BLKRTO6+PS88Zin+5IIv0299HLHexZHvPEY5WbACPxXDcDJ+91pekL03bPrGo5qel xafFwkmsxWB9yed22V+NF+Enst/UVe49AzP/sVWOHWbtwFLLwKngzTyuQO2yiV16zGzaKJ55Fbqt lVstvU73w4+79WKiFv2UXC9kwpQqnArvvazeHpx2MreW6QgDgdM7ATgMnDincGDpyWDLMWIV51ST yHDRKOvZXYTu1tJAmtSQrflyDF9Qf53V/UETgDy2QUixZMfe1G38M3AenW86kZ8rqUTMVfaR5K2E 53h3ZE8aZSAotx2gXzXmKRX/z/C2gdKYDHV31zBJl/kS3d50Jzxtqq/EQZCklqnuEw7OHOAzWUEn 3FM1FRtUOhdeTk31wzdQAVYIobzvJNs2nMDvmzkonj58DjgTWTF8DmdS/EC5prS1VvBOH/DVHDKL l9PwtzH66KL4ZWrMd19/EESsgfWm36DMqtqN/Z1LToyhs2+iL+2nXd5QruojGmVRqeoVRuv4v8yz H16c125j/1IP4dZIlLhjZMYPE5oX9rPGpBGw+ij2i7EZFzH0YPXgOKOiBlkQSvdX98xf/RS7Lw68 cX14jErsJ6smOzk2Vgs/nSw/D1OYkhwJLz0Y5sm/uQZ4oEi/ukQSZEczXlNwY= X-QQ-XMRINFO: OD9hHCdaPRBwH5bRRRw8tsiH4UAatJqXfg== From: Alva Lan To: gregkh@linuxfoundation.org, sashal@kernel.org, stable@vger.kernel.org Cc: linux-kernel@vger.kernel.org, Asim Viladi Oglu Manizada , Namjae Jeon , Steve French , Alva Lan Subject: [PATCH 6.6.y] ksmbd: fix OOB write in QUERY_INFO for compound requests Date: Fri, 29 May 2026 16:21:25 +0800 X-OQ-MSGID: <20260529082125.62990-1-alvalan9@foxmail.com> X-Mailer: git-send-email 2.43.0 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Asim Viladi Oglu Manizada [ Upstream commit fda9522ed6afaec45cabc198d8492270c394c7bc ] 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. Cc: stable@vger.kernel.org Fixes: e2b76ab8b5c9 ("ksmbd: add support for read compound") Signed-off-by: Asim Viladi Oglu Manizada Signed-off-by: Namjae Jeon Signed-off-by: Steve French [ In v6.6, replace KSMBD_DEFAULT_GFP with GFP_KERNEL per commit 0066f623bce8 ("ksmbd: use __GFP_RETRY_MAYFAIL"). ] Signed-off-by: Alva Lan --- Testing: - Backport compiles cleanly on 6.6.141 (x86_64) - Regression tests pass: file I/O, directory operations, security descriptor queries (OWNER/GROUP/DACL), filesystem info queries, large reads, and compound requests all work correctly - Verified compound READ + QUERY_INFO(Security) is processed without memory corruption on a file with 100 POSIX ACL entries (~3KB SD) --- fs/smb/server/smb2pdu.c | 121 +++++++++++++++++++++++++++++----------- fs/smb/server/smbacl.c | 43 ++++++++++++++ fs/smb/server/smbacl.h | 2 + 3 files changed, 134 insertions(+), 32 deletions(-) diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index d68fe617369e..ce60c26b2297 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -3384,20 +3384,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 =3D 0; + int pntsd_size; + size_t scratch_len; =20 ksmbd_acls_fattr(&fattr, idmap, inode); - if (fattr.cf_acls) - ace_num =3D fattr.cf_acls->a_count; - if (fattr.cf_dacls) - ace_num +=3D fattr.cf_dacls->a_count; - - pntsd =3D kmalloc(sizeof(struct smb_ntsd) + - sizeof(struct smb_sid) * 3 + - sizeof(struct smb_acl) + - sizeof(struct smb_ace) * ace_num * 2, - GFP_KERNEL); + scratch_len =3D smb_acl_sec_desc_scratch_len(&fattr, + NULL, 0, + OWNER_SECINFO | GROUP_SECINFO | + DACL_SECINFO); + if (!scratch_len || scratch_len =3D=3D SIZE_MAX) { + rc =3D -EFBIG; + posix_acl_release(fattr.cf_acls); + posix_acl_release(fattr.cf_dacls); + goto err_out; + } + + pntsd =3D kvzalloc(scratch_len, GFP_KERNEL); if (!pntsd) { + rc =3D -ENOMEM; posix_acl_release(fattr.cf_acls); posix_acl_release(fattr.cf_dacls); goto err_out; @@ -3412,7 +3416,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; } =20 @@ -3422,7 +3426,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); @@ -5344,8 +5348,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 =3D smb2_get_info_file_pipe(work->sess, req, rsp, work->response_buf); + goto iov_pin_out; } =20 if (work->next_smb2_rcv_hdr_off) { @@ -5445,6 +5450,12 @@ static int smb2_get_info_file(struct ksmbd_work *wor= k, rc =3D buffer_check_err(le32_to_cpu(req->OutputBufferLength), rsp, work->response_buf); ksmbd_fd_put(work, fp); + +iov_pin_out: + if (!rc) + rc =3D ksmbd_iov_pin_rsp(work, (void *)rsp, + offsetof(struct smb2_query_info_rsp, Buffer) + + le32_to_cpu(rsp->OutputBufferLength)); return rc; } =20 @@ -5664,6 +5675,11 @@ static int smb2_get_info_filesystem(struct ksmbd_wor= k *work, rc =3D buffer_check_err(le32_to_cpu(req->OutputBufferLength), rsp, work->response_buf); path_put(&path); + + if (!rc) + rc =3D ksmbd_iov_pin_rsp(work, (void *)rsp, + offsetof(struct smb2_query_info_rsp, Buffer) + + le32_to_cpu(rsp->OutputBufferLength)); return rc; } =20 @@ -5673,13 +5689,14 @@ static int smb2_get_info_sec(struct ksmbd_work *wor= k, { struct ksmbd_file *fp; struct mnt_idmap *idmap; - struct smb_ntsd *pntsd =3D (struct smb_ntsd *)rsp->Buffer, *ppntsd =3D NU= LL; + struct smb_ntsd *pntsd =3D NULL, *ppntsd =3D NULL; struct smb_fattr fattr =3D {{0}}; struct inode *inode; __u32 secdesclen =3D 0; unsigned int id =3D KSMBD_NO_FID, pid =3D KSMBD_NO_FID; int addition_info =3D le32_to_cpu(req->AdditionalInformation); - int rc =3D 0, ppntsd_size =3D 0; + int rc =3D 0, ppntsd_size =3D 0, max_len; + size_t scratch_len =3D 0; =20 if (addition_info & ~(OWNER_SECINFO | GROUP_SECINFO | DACL_SECINFO | PROTECTED_DACL_SECINFO | @@ -5687,6 +5704,11 @@ static int smb2_get_info_sec(struct ksmbd_work *work, ksmbd_debug(SMB, "Unsupported addition info: 0x%x)\n", addition_info); =20 + pntsd =3D kzalloc(ALIGN(sizeof(struct smb_ntsd), 8), + GFP_KERNEL); + if (!pntsd) + return -ENOMEM; + pntsd->revision =3D cpu_to_le16(1); pntsd->type =3D cpu_to_le16(SELF_RELATIVE | DACL_PROTECTED); pntsd->osidoffset =3D 0; @@ -5695,9 +5717,7 @@ static int smb2_get_info_sec(struct ksmbd_work *work, pntsd->dacloffset =3D 0; =20 secdesclen =3D sizeof(struct smb_ntsd); - rsp->OutputBufferLength =3D cpu_to_le32(secdesclen); - - return 0; + goto iov_pin; } =20 if (work->next_smb2_rcv_hdr_off) { @@ -5729,18 +5749,58 @@ static int smb2_get_info_sec(struct ksmbd_work *wor= k, &ppntsd); =20 /* Check if sd buffer size exceeds response buffer size */ - if (smb2_resp_buf_len(work, 8) > ppntsd_size) - rc =3D build_sec_desc(idmap, pntsd, ppntsd, ppntsd_size, - addition_info, &secdesclen, &fattr); + max_len =3D smb2_calc_max_out_buf_len(work, + offsetof(struct smb2_query_info_rsp, Buffer), + le32_to_cpu(req->OutputBufferLength)); + if (max_len < 0) { + rc =3D -EINVAL; + goto release_acl; + } + + scratch_len =3D smb_acl_sec_desc_scratch_len(&fattr, ppntsd, + ppntsd_size, addition_info); + if (!scratch_len || scratch_len =3D=3D SIZE_MAX) { + rc =3D -EFBIG; + goto release_acl; + } + + pntsd =3D kvzalloc(scratch_len, GFP_KERNEL); + if (!pntsd) { + rc =3D -ENOMEM; + goto release_acl; + } + + rc =3D 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 && ALIGN(secdesclen, 8) > scratch_len) + rc =3D -EFBIG; if (rc) - return rc; + goto err_out; =20 +iov_pin: rsp->OutputBufferLength =3D cpu_to_le32(secdesclen); - return 0; + rc =3D buffer_check_err(le32_to_cpu(req->OutputBufferLength), + rsp, work->response_buf); + if (rc) + goto err_out; + + rc =3D ksmbd_iov_pin_rsp_read(work, (void *)rsp, + offsetof(struct smb2_query_info_rsp, Buffer), + pntsd, secdesclen); +err_out: + if (rc) { + rsp->OutputBufferLength =3D 0; + kvfree(pntsd); + } + + return rc; } =20 /** @@ -5764,6 +5824,9 @@ int smb2_query_info(struct ksmbd_work *work) goto err_out; } =20 + rsp->StructureSize =3D cpu_to_le16(9); + rsp->OutputBufferOffset =3D cpu_to_le16(72); + switch (req->InfoType) { case SMB2_O_INFO_FILE: ksmbd_debug(SMB, "GOT SMB2_O_INFO_FILE\n"); @@ -5784,14 +5847,6 @@ int smb2_query_info(struct ksmbd_work *work) } ksmbd_revert_fsids(work); =20 - if (!rc) { - rsp->StructureSize =3D cpu_to_le16(9); - rsp->OutputBufferOffset =3D cpu_to_le16(72); - rc =3D 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 =3D=3D -EACCES) @@ -5802,6 +5857,8 @@ int smb2_query_info(struct ksmbd_work *work) rsp->hdr.Status =3D STATUS_UNEXPECTED_IO_ERROR; else if (rc =3D=3D -ENOMEM) rsp->hdr.Status =3D STATUS_INSUFFICIENT_RESOURCES; + else if (rc =3D=3D -EINVAL && rsp->hdr.Status =3D=3D 0) + rsp->hdr.Status =3D STATUS_INVALID_PARAMETER; else if (rc =3D=3D -EOPNOTSUPP || rsp->hdr.Status =3D=3D 0) rsp->hdr.Status =3D STATUS_INVALID_INFO_CLASS; smb2_set_err_rsp(work); diff --git a/fs/smb/server/smbacl.c b/fs/smb/server/smbacl.c index ff59217b4bea..a295007609d2 100644 --- a/fs/smb/server/smbacl.c +++ b/fs/smb/server/smbacl.c @@ -924,6 +924,49 @@ int parse_sec_desc(struct mnt_idmap *idmap, struct smb= _ntsd *pntsd, return 0; } =20 +size_t smb_acl_sec_desc_scratch_len(struct smb_fattr *fattr, + struct smb_ntsd *ppntsd, int ppntsd_size, int addition_info) +{ + size_t len =3D sizeof(struct smb_ntsd); + size_t tmp; + + if (addition_info & OWNER_SECINFO) + len +=3D sizeof(struct smb_sid); + if (addition_info & GROUP_SECINFO) + len +=3D sizeof(struct smb_sid); + if (!(addition_info & DACL_SECINFO)) + return len; + + len +=3D sizeof(struct smb_acl); + if (ppntsd && ppntsd_size > 0) { + unsigned int dacl_offset =3D le32_to_cpu(ppntsd->dacloffset); + + if (dacl_offset < ppntsd_size && + check_add_overflow(len, ppntsd_size - dacl_offset, &len)) + return 0; + } + + if (fattr->cf_acls) { + if (check_mul_overflow((size_t)fattr->cf_acls->a_count, + 2 * sizeof(struct smb_ace), &tmp) || + check_add_overflow(len, tmp, &len)) + return 0; + } else { + /* default/minimum DACL */ + if (check_add_overflow(len, 5 * sizeof(struct smb_ace), &len)) + return 0; + } + + if (fattr->cf_dacls) { + if (check_mul_overflow((size_t)fattr->cf_dacls->a_count, + sizeof(struct smb_ace), &tmp) || + check_add_overflow(len, tmp, &len)) + return 0; + } + + return len; +} + /* Convert permission bits from mode to equivalent CIFS ACL */ int build_sec_desc(struct mnt_idmap *idmap, struct smb_ntsd *pntsd, struct smb_ntsd *ppntsd, diff --git a/fs/smb/server/smbacl.h b/fs/smb/server/smbacl.h index 355adaee39b8..ab21ba2cd4df 100644 --- a/fs/smb/server/smbacl.h +++ b/fs/smb/server/smbacl.h @@ -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); =20 static inline uid_t posix_acl_uid_translate(struct mnt_idmap *idmap, struct posix_acl_entry *pace) --=20 2.43.0