All of lore.kernel.org
 help / color / mirror / Atom feed
From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
To: stable@vger.kernel.org
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	patches@lists.linux.dev,
	Michael Bommarito <michael.bommarito@gmail.com>,
	Steve French <stfrench@microsoft.com>
Subject: [PATCH 7.0 25/42] smb: client: validate the whole DACL before rewriting it in cifsacl
Date: Fri, 24 Apr 2026 15:30:50 +0200	[thread overview]
Message-ID: <20260424132425.661095423@linuxfoundation.org> (raw)
In-Reply-To: <20260424132420.410310336@linuxfoundation.org>

7.0-stable review patch.  If anyone has any objections, please let me know.

------------------

From: Michael Bommarito <michael.bommarito@gmail.com>

commit 0a8cf165566ba55a39fd0f4de172119dd646d39a upstream.

build_sec_desc() and id_mode_to_cifs_acl() derive a DACL pointer from a
server-supplied dacloffset and then use the incoming ACL to rebuild the
chmod/chown security descriptor.

The original fix only checked that the struct smb_acl header fits before
reading dacl_ptr->size or dacl_ptr->num_aces.  That avoids the immediate
header-field OOB read, but the rewrite helpers still walk ACEs based on
pdacl->num_aces with no structural validation of the incoming DACL body.

A malicious server can return a truncated DACL that still contains a
header, claims one or more ACEs, and then drive
replace_sids_and_copy_aces() or set_chmod_dacl() past the validated
extent while they compare or copy attacker-controlled ACEs.

Factor the DACL structural checks into validate_dacl(), extend them to
validate each ACE against the DACL bounds, and use the shared validator
before the chmod/chown rebuild paths.  parse_dacl() reuses the same
validator so the read-side parser and write-side rewrite paths agree on
what constitutes a well-formed incoming DACL.

Fixes: bc3e9dd9d104 ("cifs: Change SIDs in ACEs while transferring file ownership.")
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-opus-4-6
Assisted-by: Codex:gpt-5-4
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
 fs/smb/client/cifsacl.c |  116 +++++++++++++++++++++++++++++++++++-------------
 1 file changed, 85 insertions(+), 31 deletions(-)

--- a/fs/smb/client/cifsacl.c
+++ b/fs/smb/client/cifsacl.c
@@ -758,6 +758,77 @@ static void dump_ace(struct smb_ace *pac
 }
 #endif
 
+static int validate_dacl(struct smb_acl *pdacl, char *end_of_acl)
+{
+	int i, ace_hdr_size, ace_size, min_ace_size;
+	u16 dacl_size, num_aces;
+	char *acl_base, *end_of_dacl;
+	struct smb_ace *pace;
+
+	if (!pdacl)
+		return 0;
+
+	if (end_of_acl < (char *)pdacl + sizeof(struct smb_acl)) {
+		cifs_dbg(VFS, "ACL too small to parse DACL\n");
+		return -EINVAL;
+	}
+
+	dacl_size = le16_to_cpu(pdacl->size);
+	if (dacl_size < sizeof(struct smb_acl) ||
+	    end_of_acl < (char *)pdacl + dacl_size) {
+		cifs_dbg(VFS, "ACL too small to parse DACL\n");
+		return -EINVAL;
+	}
+
+	num_aces = le16_to_cpu(pdacl->num_aces);
+	if (!num_aces)
+		return 0;
+
+	ace_hdr_size = offsetof(struct smb_ace, sid) +
+		offsetof(struct smb_sid, sub_auth);
+	min_ace_size = ace_hdr_size + sizeof(__le32);
+	if (num_aces > (dacl_size - sizeof(struct smb_acl)) / min_ace_size) {
+		cifs_dbg(VFS, "ACL too small to parse DACL\n");
+		return -EINVAL;
+	}
+
+	end_of_dacl = (char *)pdacl + dacl_size;
+	acl_base = (char *)pdacl;
+	ace_size = sizeof(struct smb_acl);
+
+	for (i = 0; i < num_aces; ++i) {
+		if (end_of_dacl - acl_base < ace_size) {
+			cifs_dbg(VFS, "ACL too small to parse ACE\n");
+			return -EINVAL;
+		}
+
+		pace = (struct smb_ace *)(acl_base + ace_size);
+		acl_base = (char *)pace;
+
+		if (end_of_dacl - acl_base < ace_hdr_size ||
+		    pace->sid.num_subauth == 0 ||
+		    pace->sid.num_subauth > SID_MAX_SUB_AUTHORITIES) {
+			cifs_dbg(VFS, "ACL too small to parse ACE\n");
+			return -EINVAL;
+		}
+
+		ace_size = ace_hdr_size + sizeof(__le32) * pace->sid.num_subauth;
+		if (end_of_dacl - acl_base < ace_size ||
+		    le16_to_cpu(pace->size) < ace_size) {
+			cifs_dbg(VFS, "ACL too small to parse ACE\n");
+			return -EINVAL;
+		}
+
+		ace_size = le16_to_cpu(pace->size);
+		if (end_of_dacl - acl_base < ace_size) {
+			cifs_dbg(VFS, "ACL too small to parse ACE\n");
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
 static void parse_dacl(struct smb_acl *pdacl, char *end_of_acl,
 		       struct smb_sid *pownersid, struct smb_sid *pgrpsid,
 		       struct cifs_fattr *fattr, bool mode_from_special_sid)
@@ -765,7 +836,7 @@ static void parse_dacl(struct smb_acl *p
 	int i;
 	u16 num_aces = 0;
 	int acl_size;
-	char *acl_base;
+	char *acl_base, *end_of_dacl;
 	struct smb_ace **ppace;
 
 	/* BB need to add parm so we can store the SID BB */
@@ -777,12 +848,8 @@ static void parse_dacl(struct smb_acl *p
 		return;
 	}
 
-	/* validate that we do not go past end of acl */
-	if (end_of_acl < (char *)pdacl + sizeof(struct smb_acl) ||
-	    end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) {
-		cifs_dbg(VFS, "ACL too small to parse DACL\n");
+	if (validate_dacl(pdacl, end_of_acl))
 		return;
-	}
 
 	cifs_dbg(NOISY, "DACL revision %d size %d num aces %d\n",
 		 le16_to_cpu(pdacl->revision), le16_to_cpu(pdacl->size),
@@ -793,6 +860,7 @@ static void parse_dacl(struct smb_acl *p
 	   user/group/other have no permissions */
 	fattr->cf_mode &= ~(0777);
 
+	end_of_dacl = (char *)pdacl + le16_to_cpu(pdacl->size);
 	acl_base = (char *)pdacl;
 	acl_size = sizeof(struct smb_acl);
 
@@ -800,35 +868,15 @@ static void parse_dacl(struct smb_acl *p
 	if (num_aces > 0) {
 		umode_t denied_mode = 0;
 
-		if (num_aces > (le16_to_cpu(pdacl->size) - sizeof(struct smb_acl)) /
-				(offsetof(struct smb_ace, sid) +
-				 offsetof(struct smb_sid, sub_auth) + sizeof(__le16)))
-			return;
-
 		ppace = kmalloc_objs(struct smb_ace *, num_aces);
 		if (!ppace)
 			return;
 
 		for (i = 0; i < num_aces; ++i) {
-			if (end_of_acl - acl_base < acl_size)
-				break;
-
 			ppace[i] = (struct smb_ace *) (acl_base + acl_size);
-			acl_base = (char *)ppace[i];
-			acl_size = offsetof(struct smb_ace, sid) +
-				offsetof(struct smb_sid, sub_auth);
-
-			if (end_of_acl - acl_base < acl_size ||
-			    ppace[i]->sid.num_subauth == 0 ||
-			    ppace[i]->sid.num_subauth > SID_MAX_SUB_AUTHORITIES ||
-			    (end_of_acl - acl_base <
-			     acl_size + sizeof(__le32) * ppace[i]->sid.num_subauth) ||
-			    (le16_to_cpu(ppace[i]->size) <
-			     acl_size + sizeof(__le32) * ppace[i]->sid.num_subauth))
-				break;
 
 #ifdef CONFIG_CIFS_DEBUG2
-			dump_ace(ppace[i], end_of_acl);
+			dump_ace(ppace[i], end_of_dacl);
 #endif
 			if (mode_from_special_sid &&
 			    ppace[i]->sid.num_subauth >= 3 &&
@@ -871,6 +919,7 @@ static void parse_dacl(struct smb_acl *p
 				(void *)ppace[i],
 				sizeof(struct smb_ace)); */
 
+			acl_base = (char *)ppace[i];
 			acl_size = le16_to_cpu(ppace[i]->size);
 		}
 
@@ -1294,10 +1343,9 @@ static int build_sec_desc(struct smb_nts
 	dacloffset = le32_to_cpu(pntsd->dacloffset);
 	if (dacloffset) {
 		dacl_ptr = (struct smb_acl *)((char *)pntsd + dacloffset);
-		if (end_of_acl < (char *)dacl_ptr + le16_to_cpu(dacl_ptr->size)) {
-			cifs_dbg(VFS, "Server returned illegal ACL size\n");
-			return -EINVAL;
-		}
+		rc = validate_dacl(dacl_ptr, end_of_acl);
+		if (rc)
+			return rc;
 	}
 
 	owner_sid_ptr = (struct smb_sid *)((char *)pntsd +
@@ -1663,6 +1711,12 @@ id_mode_to_cifs_acl(struct inode *inode,
 		dacloffset = le32_to_cpu(pntsd->dacloffset);
 		if (dacloffset) {
 			dacl_ptr = (struct smb_acl *)((char *)pntsd + dacloffset);
+			rc = validate_dacl(dacl_ptr, (char *)pntsd + secdesclen);
+			if (rc) {
+				kfree(pntsd);
+				cifs_put_tlink(tlink);
+				return rc;
+			}
 			if (mode_from_sid)
 				nsecdesclen +=
 					le16_to_cpu(dacl_ptr->num_aces) * sizeof(struct smb_ace);



  parent reply	other threads:[~2026-04-24 13:32 UTC|newest]

Thread overview: 55+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-04-24 13:30 [PATCH 7.0 00/42] 7.0.2-rc1 review Greg Kroah-Hartman
2026-04-24 13:30 ` [PATCH 7.0 01/42] crypto: authencesn - Fix src offset when decrypting in-place Greg Kroah-Hartman
2026-04-24 13:30 ` [PATCH 7.0 02/42] pwm: th1520: fix `CLIPPY=1` warning Greg Kroah-Hartman
2026-04-24 13:30 ` [PATCH 7.0 03/42] drm/amdgpu: replace PASID IDR with XArray Greg Kroah-Hartman
2026-04-24 13:30 ` [PATCH 7.0 04/42] crypto: krb5enc - fix sleepable flag handling in encrypt dispatch Greg Kroah-Hartman
2026-04-24 13:30 ` [PATCH 7.0 05/42] crypto: krb5enc - fix async decrypt skipping hash verification Greg Kroah-Hartman
2026-04-24 13:30 ` [PATCH 7.0 06/42] ksmbd: fix use-after-free in __ksmbd_close_fd() via durable scavenger Greg Kroah-Hartman
2026-04-24 13:30 ` [PATCH 7.0 07/42] ksmbd: validate owner of durable handle on reconnect Greg Kroah-Hartman
2026-04-24 13:30 ` [PATCH 7.0 08/42] scripts: generate_rust_analyzer.py: define scripts Greg Kroah-Hartman
2026-04-24 13:30 ` [PATCH 7.0 09/42] scripts/dtc: Remove unused dts_version in dtc-lexer.l Greg Kroah-Hartman
2026-04-24 13:30 ` [PATCH 7.0 10/42] fs/ntfs3: validate rec->used in journal-replay file record check Greg Kroah-Hartman
2026-04-24 13:30 ` [PATCH 7.0 11/42] f2fs: fix to do sanity check on dcc->discard_cmd_cnt conditionally Greg Kroah-Hartman
2026-04-24 13:30 ` [PATCH 7.0 12/42] f2fs: fix UAF caused by decrementing sbi->nr_pages[] in f2fs_write_end_io() Greg Kroah-Hartman
2026-04-24 13:30 ` [PATCH 7.0 13/42] f2fs: fix to avoid memory leak in f2fs_rename() Greg Kroah-Hartman
2026-04-24 13:30 ` [PATCH 7.0 14/42] f2fs: fix to avoid uninit-value access in f2fs_sanity_check_node_footer Greg Kroah-Hartman
2026-04-24 13:30 ` [PATCH 7.0 15/42] fuse: reject oversized dirents in page cache Greg Kroah-Hartman
2026-04-24 13:30 ` [PATCH 7.0 16/42] fuse: abort on fatal signal during sync init Greg Kroah-Hartman
2026-04-24 13:30 ` [PATCH 7.0 17/42] fuse: Check for large folio with SPLICE_F_MOVE Greg Kroah-Hartman
2026-04-24 13:30 ` [PATCH 7.0 18/42] fuse: quiet down complaints in fuse_conn_limit_write Greg Kroah-Hartman
2026-04-24 13:30 ` [PATCH 7.0 19/42] fuse: fuse_dev_ioctl_clone() should wait for device file to be initialized Greg Kroah-Hartman
2026-04-24 13:30 ` [PATCH 7.0 20/42] ksmbd: require minimum ACE size in smb_check_perm_dacl() Greg Kroah-Hartman
2026-04-24 13:30 ` [PATCH 7.0 21/42] smb: server: fix active_num_conn leak on transport allocation failure Greg Kroah-Hartman
2026-04-24 13:30 ` [PATCH 7.0 22/42] smb: client: fix dir separator in SMB1 UNIX mounts Greg Kroah-Hartman
2026-04-24 13:30 ` [PATCH 7.0 23/42] smb: server: fix max_connections off-by-one in tcp accept path Greg Kroah-Hartman
2026-04-24 13:30 ` [PATCH 7.0 24/42] smb: client: require a full NFS mode SID before reading mode bits Greg Kroah-Hartman
2026-04-24 13:30 ` Greg Kroah-Hartman [this message]
2026-04-24 13:30 ` [PATCH 7.0 26/42] smb: client: fix OOB read in smb2_ioctl_query_info QUERY_INFO path Greg Kroah-Hartman
2026-04-24 13:30 ` [PATCH 7.0 27/42] ksmbd: validate response sizes in ipc_validate_msg() Greg Kroah-Hartman
2026-04-24 13:30 ` [PATCH 7.0 28/42] ksmbd: validate num_aces and harden ACE walk in smb_inherit_dacl() Greg Kroah-Hartman
2026-04-24 13:30 ` [PATCH 7.0 29/42] ksmbd: fix out-of-bounds write in smb2_get_ea() EA alignment Greg Kroah-Hartman
2026-04-24 13:30 ` [PATCH 7.0 30/42] ksmbd: use check_add_overflow() to prevent u16 DACL size overflow Greg Kroah-Hartman
2026-04-24 13:30 ` [PATCH 7.0 31/42] ksmbd: reset rcount per connection in ksmbd_conn_wait_idle_sess_id() Greg Kroah-Hartman
2026-04-24 13:30 ` [PATCH 7.0 32/42] writeback: Fix use after free in inode_switch_wbs_work_fn() Greg Kroah-Hartman
2026-04-24 13:30 ` [PATCH 7.0 33/42] f2fs: fix use-after-free of sbi in f2fs_compress_write_end_io() Greg Kroah-Hartman
2026-04-24 13:30 ` [PATCH 7.0 34/42] ALSA: usb-audio: apply quirk for MOONDROP JU Jiu Greg Kroah-Hartman
2026-04-24 13:31 ` [PATCH 7.0 35/42] ALSA: hda/realtek: Add quirk for Legion S7 15IMH Greg Kroah-Hartman
2026-04-24 13:31 ` [PATCH 7.0 36/42] ALSA: caiaq: take a reference on the USB device in create_card() Greg Kroah-Hartman
2026-04-24 13:31 ` [PATCH 7.0 37/42] net/packet: fix TOCTOU race on mmapd vnet_hdr in tpacket_snd() Greg Kroah-Hartman
2026-04-24 13:31 ` [PATCH 7.0 38/42] crypto: ccp: Dont attempt to copy CSR to userspace if PSP command failed Greg Kroah-Hartman
2026-04-24 13:31 ` [PATCH 7.0 39/42] crypto: ccp: Dont attempt to copy PDH cert " Greg Kroah-Hartman
2026-04-24 13:31 ` [PATCH 7.0 40/42] crypto: ccp: Dont attempt to copy ID " Greg Kroah-Hartman
2026-04-24 13:31 ` [PATCH 7.0 41/42] rxrpc: Fix missing validation of ticket length in non-XDR key preparsing Greg Kroah-Hartman
2026-04-24 13:31 ` [PATCH 7.0 42/42] mshv_vtl: Fix vmemmap_shift exceeding MAX_FOLIO_ORDER Greg Kroah-Hartman
2026-04-24 14:09 ` [PATCH 7.0 00/42] 7.0.2-rc1 review Ronald Warsow
2026-04-24 16:19 ` Takeshi Ogasawara
2026-04-24 21:04 ` Florian Fainelli
2026-04-24 21:22 ` Mark Brown
2026-04-24 22:16 ` Peter Schneider
2026-04-24 22:22 ` Shuah Khan
2026-04-25  7:33 ` Brett A C Sheffield
2026-04-25 11:49 ` Miguel Ojeda
2026-04-25 19:53 ` Ron Economos
2026-04-25 22:19 ` Dileep malepu
2026-04-26  6:58 ` Barry K. Nathan
2026-04-26 18:19 ` Justin Forbes

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260424132425.661095423@linuxfoundation.org \
    --to=gregkh@linuxfoundation.org \
    --cc=michael.bommarito@gmail.com \
    --cc=patches@lists.linux.dev \
    --cc=stable@vger.kernel.org \
    --cc=stfrench@microsoft.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.