Skip to content

[LTS 9.2] smb (cifs): CVE-2026-46195, CVE-2026-46139, CVE-2026-43350, CVE-2026-31709; net: CVE-2026-31419#1380

Open
pvts-mat wants to merge 5 commits into
ctrliq:ciqlts9_2from
pvts-mat:CVE-batch-37_ciqlts9_2
Open

[LTS 9.2] smb (cifs): CVE-2026-46195, CVE-2026-46139, CVE-2026-43350, CVE-2026-31709; net: CVE-2026-31419#1380
pvts-mat wants to merge 5 commits into
ctrliq:ciqlts9_2from
pvts-mat:CVE-batch-37_ciqlts9_2

Conversation

@pvts-mat

Copy link
Copy Markdown
Contributor

[LTS 9.2]

CVE-2026-46195 VULN-188328
CVE-2026-46139 VULN-188853
CVE-2026-43350 VULN-184957
CVE-2026-31709 VULN-183468
CVE-2026-31419 VULN-181412

Commits

CVE-2026-46195

smb: client: validate dacloffset before building DACL pointers

jira VULN-188328
cve CVE-2026-46195
commit-author Michael Bommarito <michael.bommarito@gmail.com>
commit f98b48151cc502ada59d9778f0112d21f2586ca3
upstream-diff Used linux-5.15.y backport
  5de2665e913a10ad70aaeecf736b97276e83d995 for the clean pick

See CVE-2026-31709 section for the discussion of the differences between linux-5.15.y and kernel-mainline.

CVE-2026-46139

smb: client: use kzalloc to zero-initialize security descriptor buffer

jira VULN-188853
cve CVE-2026-46139
commit-author Bjoern Doebel <doebel@amazon.de>
commit 5e489c6c47a2ac15edbaca153b9348e42c1eacab

CVE-2026-43350

smb: client: require a full NFS mode SID before reading mode bits

jira VULN-184957
cve CVE-2026-43350
commit-author Michael Bommarito <michael.bommarito@gmail.com>
commit 2757ad3e4b6f9e0fed4c7739594e702abc5cab21

CVE-2026-31709

smb: client: validate the whole DACL before rewriting it in cifsacl

jira VULN-183468
cve CVE-2026-31709
commit-author Michael Bommarito <michael.bommarito@gmail.com>
commit 0a8cf165566ba55a39fd0f4de172119dd646d39a
upstream-diff Used linux-5.15.y backport
  b8603d9ae6c9087662b098619996bc4a8064319d for a clean pick. Compared to
  the upstream:
  1. Structs `cifs_{acl,ace,sid}' underwent renaming to
     `smb_{acl,ace,sid}' in 7f599d8fb3e087aff5be4e1392baaae3f8d42419,
     251b93ae73805b216e84ed2190b525f319da4c87,
     09bedafc1e2c5c82aad3cbfe1359e2b0bf752f3a. Additionally the `__le32
     num_aces' field of `smb_acl' was split into `__le16 num_aces' and
     `__le16 reserved' in 62e7dd0a39c2d0d7ff03274c36df971f1b3d2d0d. These
     changes were taken into account in the body of `validate_dacl()'
     function.
  2. No removal of validation code fragments in `parse_dacl()'. In the
     upstream those were put into place by
     aa2a739a75ab6f24ef72fb3fdb9192c081eacf06 and
     eeb827f2922eb07ffbf7d53569cc95b38272646f, not backported to LTS
     9.2. In both versions they ultimately landed in the `validate_dacl()'
     function in this fix.

LTS 9.2 cifs module is on roughly the same level feature-and-bugfix-wise as Linux stable 5.15. The differences between the upstream fix and 5.15 backport stem from the evolution of the core data structures - mostly just renaming and moving around the codebase, although there is one change to the smb_acl fielfs as well.

Compare ciqlts9_2:

struct cifs_acl {
__le16 revision; /* revision level */
__le16 size;
__le32 num_aces;
} __attribute__((packed));

struct cifs_ace {
__u8 type; /* see above and MS-DTYP 2.4.4.1 */
__u8 flags;
__le16 size;
__le32 access_req;
struct cifs_sid sid; /* ie UUID of user or group who gets these perms */
} __attribute__((packed));

struct cifs_sid {
__u8 revision; /* revision level */
__u8 num_subauth;
__u8 authority[NUM_AUTHS];
__le32 sub_auth[SID_MAX_SUB_AUTHORITIES]; /* sub_auth[num_subauth] */
} __attribute__((packed));

with upstream:

struct smb_acl {
__le16 revision; /* revision level */
__le16 size;
__le16 num_aces;
__le16 reserved;
} __packed;

struct smb_ace {
__u8 type; /* see above and MS-DTYP 2.4.4.1 */
__u8 flags;
__le16 size;
__le32 access_req;
struct smb_sid sid; /* ie UUID of user or group who gets these perms */
} __packed;

struct smb_sid {
__u8 revision; /* revision level */
__u8 num_subauth;
__u8 authority[NUM_AUTHS];
__le32 sub_auth[SID_MAX_SUB_AUTHORITIES]; /* sub_auth[num_subauth] */
} __packed;

The data structures timeline can be summarized in the following table (from oldest):

kernel-mainline `ciqlts9_2` `*_acl` `*_ace` `*_sid` Change
bf82067 bf82067 - - x Definition of `cifs_sid`
442aa31 442aa31 x x x Definition of `cifs_acl`, `cifs_ace`, fields changed in `cifs_sid`
af6f461 af6f461 x x x Endiannes fixes in `cifs_acl`, `cifs_ace`, `cifs_sid`
38c8a9a - x x x File containing structs definitions moved `fs/cifs/cifsacl.h` → `fs/smb/client/cifsacl.h`
7f599d8 - - x x Renaming: `smb_sid`, `cifs_ace` member type rename: `cifs_sid` → `smb_sid`
251b93a - x - - Renaming: `cifs_acl` → `smb_acl`
09bedaf - - x - Renaming: `cifs_ace` → `smb_ace`
b51174d - x x x Move from `fs/smb/client/cifsacl.h` to `fs/smb/common/smbacl.h`
62e7dd0 - x - - `num_aces` split: `__le32 num_aces` → `__le16 num_aces`, `__le16 reserved`
e7e60e8 - x x x `__attribute__((packed))` → `__packed`

CVE-2026-31419

net: bonding: fix use-after-free in bond_xmit_broadcast()

jira VULN-181412
cve CVE-2026-31419
commit-author Xiang Mei <xmei5@asu.edu>
commit 2884bf72fb8f03409e423397319205de48adca16
upstream-diff Used linux-6.12.y backport
  3453882f36c40d2339267093676585a89808a73d for a clean pick. That commit
  partially includes changes from ce7a381697cb3958ffe0b45e5028ac69444e9288
  ("net: bonding: add broadcast_neighbor option for 802.3ad"), which was
  not backported to LTS 9.2 either.

kABI check: passed

[1/2] kabi_check_kernel	Check ABI of kernel [ciqlts9_2-CVE-batch-37]	_kabi_check_kernel__x86_64--test--ciqlts9_2-CVE-batch-37
+ dist_git_version=el-9.2
+ local_version=ciqlts9_2-CVE-batch-37
+ arch=x86_64
+ user=pvts
+ buildmachine=x86_64--build--ciqlts9_2
+ virsh_timeout=600
+ ssh_daemon_wait=20
+ src_dir=/mnt/code/kernel-dist-git-el-9.2
+ build_dir=/mnt/build_files/kernel-src-tree-ciqlts9_2-CVE-batch-37
+ sudo chmod +x /data/src/ctrliq-github-haskell/kernel-dist-git-el-9.2/SOURCES/check-kabi
+ ninja-back/virssh.xsh --max 8 --shutdown-on-success --shutdown-on-failure --timeout 600 --ssh-daemon-wait 20 pvts x86_64--build--ciqlts9_2 ''\''/mnt/code/kernel-dist-git-el-9.2/SOURCES/check-kabi'\'' -k '\''/mnt/code/kernel-dist-git-el-9.2/SOURCES/Module.kabi_x86_64'\'' -s '\''/mnt/build_files/kernel-src-tree-ciqlts9_2-CVE-batch-37/Module.symvers'\'''
kABI check passed
+ touch state/kernels/ciqlts9_2-CVE-batch-37/x86_64/kabi_checked

Boot test: passed

boot-test.log

Kselftests: passed relative

Reference

kselftests–ciqlts9_2–run1.log

Patch

kselftests–ciqlts9_2-CVE-batch-37–run1.log
kselftests–ciqlts9_2-CVE-batch-37–run2.log

Comparison

The tests results for the reference and the patch are the same.

$ ktests.xsh diff  kselftests*.log

full-test-results-comparison.log

@pvts-mat pvts-mat force-pushed the CVE-batch-37_ciqlts9_2 branch from c6530c1 to a30f15a Compare June 24, 2026 21:32
@PlaidCat

Copy link
Copy Markdown
Collaborator

Could you rebase to the latest 9.2

pvts-mat added 5 commits June 25, 2026 21:37
jira VULN-181412
cve CVE-2026-31419
commit-author Xiang Mei <xmei5@asu.edu>
commit 2884bf7
upstream-diff Used linux-6.12.y backport
  3453882 for a clean pick. That commit
  partially includes changes from ce7a381
  ("net: bonding: add broadcast_neighbor option for 802.3ad"), which was
  not backported to LTS 9.2 either.

bond_xmit_broadcast() reuses the original skb for the last slave
(determined by bond_is_last_slave()) and clones it for others.
Concurrent slave enslave/release can mutate the slave list during
RCU-protected iteration, changing which slave is "last" mid-loop.
This causes the original skb to be double-consumed (double-freed).

Replace the racy bond_is_last_slave() check with a simple index
comparison (i + 1 == slaves_count) against the pre-snapshot slave
count taken via READ_ONCE() before the loop.  This preserves the
zero-copy optimization for the last slave while making the "last"
determination stable against concurrent list mutations.

The UAF can trigger the following crash:

==================================================================
BUG: KASAN: slab-use-after-free in skb_clone
Read of size 8 at addr ffff888100ef8d40 by task exploit/147

CPU: 1 UID: 0 PID: 147 Comm: exploit Not tainted 7.0.0-rc3+ ctrliq#4 PREEMPTLAZY
Call Trace:
 <TASK>
 dump_stack_lvl (lib/dump_stack.c:123)
 print_report (mm/kasan/report.c:379 mm/kasan/report.c:482)
 kasan_report (mm/kasan/report.c:597)
 skb_clone (include/linux/skbuff.h:1724 include/linux/skbuff.h:1792 include/linux/skbuff.h:3396 net/core/skbuff.c:2108)
 bond_xmit_broadcast (drivers/net/bonding/bond_main.c:5334)
 bond_start_xmit (drivers/net/bonding/bond_main.c:5567 drivers/net/bonding/bond_main.c:5593)
 dev_hard_start_xmit (include/linux/netdevice.h:5325 include/linux/netdevice.h:5334 net/core/dev.c:3871 net/core/dev.c:3887)
 __dev_queue_xmit (include/linux/netdevice.h:3601 net/core/dev.c:4838)
 ip6_finish_output2 (include/net/neighbour.h:540 include/net/neighbour.h:554 net/ipv6/ip6_output.c:136)
 ip6_finish_output (net/ipv6/ip6_output.c:208 net/ipv6/ip6_output.c:219)
 ip6_output (net/ipv6/ip6_output.c:250)
 ip6_send_skb (net/ipv6/ip6_output.c:1985)
 udp_v6_send_skb (net/ipv6/udp.c:1442)
 udpv6_sendmsg (net/ipv6/udp.c:1733)
 __sys_sendto (net/socket.c:730 net/socket.c:742 net/socket.c:2206)
 __x64_sys_sendto (net/socket.c:2209)
 do_syscall_64 (arch/x86/entry/syscall_64.c:63 arch/x86/entry/syscall_64.c:94)
 entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:130)
 </TASK>

Allocated by task 147:

Freed by task 147:

The buggy address belongs to the object at ffff888100ef8c80
 which belongs to the cache skbuff_head_cache of size 224
The buggy address is located 192 bytes inside of
 freed 224-byte region [ffff888100ef8c80, ffff888100ef8d60)

Memory state around the buggy address:
 ffff888100ef8c00: fb fb fb fb fc fc fc fc fc fc fc fc fc fc fc fc
 ffff888100ef8c80: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
>ffff888100ef8d00: fb fb fb fb fb fb fb fb fb fb fb fb fc fc fc fc
                                                    ^
 ffff888100ef8d80: fc fc fc fc fc fc fc fc fa fb fb fb fb fb fb fb
 ffff888100ef8e00: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
==================================================================

Fixes: 4e5bd03 ("net: bonding: fix bond_xmit_broadcast return value error bug")
	Reported-by: Weiming Shi <bestswngs@gmail.com>
	Signed-off-by: Xiang Mei <xmei5@asu.edu>
Link: https://patch.msgid.link/20260326075553.3960562-1-xmei5@asu.edu
	Signed-off-by: Paolo Abeni <pabeni@redhat.com>
(cherry picked from commit 3453882)
	Signed-off-by: Marcin Wcisło <marcin.wcislo@conclusive.pl>
jira VULN-183468
cve CVE-2026-31709
commit-author Michael Bommarito <michael.bommarito@gmail.com>
commit 0a8cf16
upstream-diff Used linux-5.15.y backport
  b8603d9ae6c9087662b098619996bc4a8064319d for a clean pick. Compared to
  the upstream:
  1. Structs `cifs_{acl,ace,sid}' underwent renaming to
     `smb_{acl,ace,sid}' in 7f599d8,
     251b93a,
     09bedaf. Additionally the `__le32
     num_aces' field of `smb_acl' was split into `__le16 num_aces' and
     `__le16 reserved' in 62e7dd0. These
     changes were taken into account in the body of `validate_dacl()'
     function.
  2. No removal of validation code fragments in `parse_dacl()'. In the
     upstream those were put into place by
     aa2a739 and
     eeb827f, not backported to LTS
     9.2. In both versions they ultimately landed in the `validate_dacl()'
     function in this fix.

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: bc3e9dd ("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>
(cherry picked from commit b8603d9ae6c9087662b098619996bc4a8064319d)
	Signed-off-by: Marcin Wcisło <marcin.wcislo@conclusive.pl>
jira VULN-184957
cve CVE-2026-43350
commit-author Michael Bommarito <michael.bommarito@gmail.com>
commit 2757ad3

parse_dacl() treats an ACE SID matching sid_unix_NFS_mode as an NFS
mode SID and reads sid.sub_auth[2] to recover the mode bits.

That assumes the ACE carries three subauthorities, but compare_sids()
only compares min(a, b) subauthorities.  A malicious server can return
an ACE with num_subauth = 2 and sub_auth[] = {88, 3}, which still
matches sid_unix_NFS_mode and then drives the sub_auth[2] read four
bytes past the end of the ACE.

Require num_subauth >= 3 before treating the ACE as an NFS mode SID.
This keeps the fix local to the special-SID mode path without changing
compare_sids() semantics for the rest of cifsacl.

Fixes: e2f8fbf ("cifs: get mode bits from special sid on stat")
	Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-opus-4-6
	Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
	Signed-off-by: Steve French <stfrench@microsoft.com>
(cherry picked from commit 2757ad3)
	Signed-off-by: Marcin Wcisło <marcin.wcislo@conclusive.pl>
jira VULN-188853
cve CVE-2026-46139
commit-author Bjoern Doebel <doebel@amazon.de>
commit 5e489c6

Commit 62e7dd0 ("smb: common: change the data type of num_aces
to le16") split struct smb_acl's __le32 num_aces field into __le16
num_aces and __le16 reserved. The reserved field corresponds to Sbz2
in the MS-DTYP ACL wire format, which must be zero [1].

When building an ACL descriptor in build_sec_desc(), we are using a
kmalloc()'ed descriptor buffer and writing the fields explicitly using
le16() writes now. This never writes to the 2 byte reserved field,
leaving it as uninitialized heap data.

When the reserved field happens to contain non-zero slab garbage,
Samba rejects the security descriptor with "ndr_pull_security_descriptor
failed: Range Error", causing chmod to fail with EINVAL.

Change kmalloc() to kzalloc() to ensure the entire buffer is
zero-initialized.

Fixes: 62e7dd0 ("smb: common: change the data type of num_aces to le16")
	Cc: stable@vger.kernel.org

	Signed-off-by: Bjoern Doebel <doebel@amazon.de>
Assisted-by: Kiro:claude-opus-4.6
[1] https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/20233ed8-a6c6-4097-aafa-dd545ed24428
	Signed-off-by: Steve French <stfrench@microsoft.com>
(cherry picked from commit 5e489c6)
	Signed-off-by: Marcin Wcisło <marcin.wcislo@conclusive.pl>
jira VULN-188328
cve CVE-2026-46195
commit-author Michael Bommarito <michael.bommarito@gmail.com>
commit f98b481
upstream-diff Used linux-5.15.y backport
  5de2665e913a10ad70aaeecf736b97276e83d995 for the clean pick

parse_sec_desc(), build_sec_desc(), and the chown path in
id_mode_to_cifs_acl() all add the server-supplied dacloffset to pntsd
before proving a DACL header fits inside the returned security
descriptor.

On 32-bit builds a malicious server can return dacloffset near
U32_MAX, wrap the derived DACL pointer below end_of_acl, and then slip
past the later pointer-based bounds checks. build_sec_desc() and
id_mode_to_cifs_acl() can then dereference DACL fields from the wrapped
pointer in the chmod/chown rewrite paths.

Validate dacloffset numerically before building any DACL pointer and
reuse the same helper at the three DACL entry points.

Fixes: bc3e9dd ("cifs: Change SIDs in ACEs while transferring file ownership.")
	Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-opus-4-6
	Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
	Signed-off-by: Steve French <stfrench@microsoft.com>
(cherry picked from commit 5de2665e913a10ad70aaeecf736b97276e83d995)
	Signed-off-by: Marcin Wcisło <marcin.wcislo@conclusive.pl>
@pvts-mat pvts-mat force-pushed the CVE-batch-37_ciqlts9_2 branch from a30f15a to 257e7e7 Compare June 25, 2026 19:38
@github-actions

Copy link
Copy Markdown

🤖 Validation Checks In Progress Workflow run: https://github.com/ctrliq/kernel-src-tree/actions/runs/28201943999

@github-actions

Copy link
Copy Markdown

🔍 Interdiff Analysis

  • ⚠️ PR commit c0da859f901 (net: bonding: fix use-after-free in bond_xmit_broadcast()) → upstream 2884bf72fb8f
    Differences found:
================================================================================
*    DELTA DIFFERENCES - code changes that differ between the patches          *
================================================================================

--- b/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -5155,16 +5155,12 @@
 				       struct net_device *bond_dev)
 {
 	struct bonding *bond = netdev_priv(bond_dev);
-	struct bond_up_slave *slaves;
+	struct slave *slave = NULL;
+	struct list_head *iter;
 	bool xmit_suc = false;
 	bool skb_used = false;
-	int slaves_count, i;
 
-	slaves = rcu_dereference(bond->all_slaves);
-
-	slaves_count = slaves ? READ_ONCE(slaves->count) : 0;
-	for (i = 0; i < slaves_count; i++) {
-		struct slave *slave = slaves->arr[i];
+	bond_for_each_slave_rcu(bond, slave, iter) {
 		struct sk_buff *skb2;
 
 		if (!(bond_slave_is_up(slave) && slave->link == BOND_LINK_UP))
  • ⚠️ PR commit f141ac4dc8e (smb: client: validate the whole DACL before rewriting it in cifsacl) → upstream 0a8cf165566b
    Differences found:
================================================================================
*    DELTA DIFFERENCES - code changes that differ between the patches          *
================================================================================

--- b/fs/cifs/cifsacl.c
+++ b/fs/smb/client/cifsacl.c
@@ -753,78 +753,6 @@
 }
 #endif
 
-static int validate_dacl(struct cifs_acl *pdacl, char *end_of_acl)
-{
-	int i, ace_hdr_size, ace_size, min_ace_size;
-	u16 dacl_size;
-	u32 num_aces;
-	char *acl_base, *end_of_dacl;
-	struct cifs_ace *pace;
-
-	if (!pdacl)
-		return 0;
-
-	if (end_of_acl < (char *)pdacl + sizeof(struct cifs_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 cifs_acl) ||
-	    end_of_acl < (char *)pdacl + dacl_size) {
-		cifs_dbg(VFS, "ACL too small to parse DACL\n");
-		return -EINVAL;
-	}
-
-	num_aces = le32_to_cpu(pdacl->num_aces);
-	if (!num_aces)
-		return 0;
-
-	ace_hdr_size = offsetof(struct cifs_ace, sid) +
-		offsetof(struct cifs_sid, sub_auth);
-	min_ace_size = ace_hdr_size + sizeof(__le32);
-	if (num_aces > (dacl_size - sizeof(struct cifs_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 cifs_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 cifs_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 cifs_acl *pdacl, char *end_of_acl,
 		       struct cifs_sid *pownersid, struct cifs_sid *pgrpsid,
 		       struct cifs_fattr *fattr, bool mode_from_special_sid)
@@ -844,7 +772,9 @@
 		return;
 	}
 
-	if (validate_dacl(pdacl, end_of_acl))
+	/* validate that we do not go past end of acl */
+	if (end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) {
+		cifs_dbg(VFS, "ACL too small to parse DACL\n");
 		return;
 
 	cifs_dbg(NOISY, "DACL revision %d size %d num aces %d\n",

################################################################################
!    REJECTED PATCH2 HUNKS - could not be compared; manual review needed       !
################################################################################

--- b/fs/cifs/cifsacl.c
+++ b/fs/smb/client/cifsacl.c
@@ -758,6 +758,77 @@
 }
 #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 @@
 	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,10 +848,7 @@
 		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;
 	}
 
@@ -800,11 +868,6 @@
 	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;
@@ -808,9 +871,6 @@
 			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) +
@@ -812,18 +872,6 @@
 				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);
@@ -870,6 +918,7 @@
 				(void *)ppace[i],
 				sizeof(struct smb_ace)); */
 
+			acl_base = (char *)ppace[i];
 			acl_size = le16_to_cpu(ppace[i]->size);
 		}
 
@@ -1293,10 +1342,9 @@
 	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 +
@@ -1662,6 +1710,12 @@
 		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);

================================================================================
*    CONTEXT DIFFERENCES - surrounding code differences between the patches    *
================================================================================

--- b/fs/cifs/cifsacl.c
+++ b/fs/smb/client/cifsacl.c
@@ -752,4 +752,4 @@
 
-static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
-		       struct cifs_sid *pownersid, struct cifs_sid *pgrpsid,
+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)
@@ -756,7 +756,7 @@
 	int i;
-	int num_aces = 0;
+	u16 num_aces = 0;
 	int acl_size;
 	char *acl_base;
-	struct cifs_ace **ppace;
+	struct smb_ace **ppace;
 
 	/* BB need to add parm so we can store the SID BB */
@@ -763,11 +763,12 @@
 		return;
 	}
 
 	/* validate that we do not go past end of acl */
-	if (end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) {
+	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");
 		return;
 	}
 
 	cifs_dbg(NOISY, "DACL revision %d size %d num aces %d\n",
 		 le16_to_cpu(pdacl->revision), le16_to_cpu(pdacl->size),
@@ -777,3 +778,24 @@
 	acl_base = (char *)pdacl;
-	acl_size = sizeof(struct cifs_acl);
+	acl_size = sizeof(struct smb_acl);
+
+	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);
 
@@ -1261,10 +1292,10 @@
 	dacloffset = le32_to_cpu(pntsd->dacloffset);
 	if (dacloffset) {
-		dacl_ptr = (struct cifs_acl *)((char *)pntsd + 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;
 		}
 	}
 
-	owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
+	owner_sid_ptr = (struct smb_sid *)((char *)pntsd +
@@ -1626,6 +1661,6 @@
 		dacloffset = le32_to_cpu(pntsd->dacloffset);
 		if (dacloffset) {
-			dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
+			dacl_ptr = (struct smb_acl *)((char *)pntsd + dacloffset);
 			if (mode_from_sid)
 				nsecdesclen +=
-					le32_to_cpu(dacl_ptr->num_aces) * sizeof(struct cifs_ace);
+					le16_to_cpu(dacl_ptr->num_aces) * sizeof(struct smb_ace);
  • ⚠️ PR commit 257e7e75003 (smb: client: validate dacloffset before building DACL pointers) → upstream f98b48151cc5
    Differences found:
================================================================================
*    DELTA DIFFERENCES - code changes that differ between the patches          *
================================================================================

--- b/fs/cifs/cifsacl.c
+++ b/fs/smb/client/cifsacl.c
@@ -1256,13 +1256,13 @@
 
 static bool dacl_offset_valid(unsigned int acl_len, __u32 dacloffset)
 {
-	if (acl_len < sizeof(struct cifs_acl))
+	if (acl_len < sizeof(struct smb_acl))
 		return false;
 
-	if (dacloffset < sizeof(struct cifs_ntsd))
+	if (dacloffset < sizeof(struct smb_ntsd))
 		return false;
 
-	return dacloffset <= acl_len - sizeof(struct cifs_acl);
+	return dacloffset <= acl_len - sizeof(struct smb_acl);
 }
 
 
@@ -1285,6 +1285,7 @@
 	group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
 				le32_to_cpu(pntsd->gsidoffset));
 	dacloffset = le32_to_cpu(pntsd->dacloffset);
+	dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
 	cifs_dbg(NOISY, "revision %d type 0x%x ooffset 0x%x goffset 0x%x sacloffset 0x%x dacloffset 0x%x\n",
 		 pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset),
 		 le32_to_cpu(pntsd->gsidoffset),
@@ -1321,7 +1322,7 @@
 			return -EINVAL;
 		}
 
-		dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
+		dacl_ptr = (struct smb_acl *)((char *)pntsd + dacloffset);
 		parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr,
 			   group_sid_ptr, fattr, get_mode_from_special_sid);
 	} else {

################################################################################
!    REJECTED PATCH2 HUNKS - could not be compared; manual review needed       !
################################################################################

--- b/fs/cifs/cifsacl.c
+++ b/fs/smb/client/cifsacl.c
@@ -1295,7 +1306,6 @@
 	group_sid_ptr = (struct smb_sid *)((char *)pntsd +
 				le32_to_cpu(pntsd->gsidoffset));
 	dacloffset = le32_to_cpu(pntsd->dacloffset);
-	dacl_ptr = (struct smb_acl *)((char *)pntsd + dacloffset);
 	cifs_dbg(NOISY, "revision %d type 0x%x ooffset 0x%x goffset 0x%x sacloffset 0x%x dacloffset 0x%x\n",
 		 pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset),
 		 le32_to_cpu(pntsd->gsidoffset),
@@ -1360,6 +1377,11 @@
 
 	dacloffset = le32_to_cpu(pntsd->dacloffset);
 	if (dacloffset) {
+		if (!dacl_offset_valid(secdesclen, dacloffset)) {
+			cifs_dbg(VFS, "Server returned illegal DACL offset\n");
+			return -EINVAL;
+		}
+
 		dacl_ptr = (struct smb_acl *)((char *)pntsd + dacloffset);
 		rc = validate_dacl(dacl_ptr, end_of_acl);
 		if (rc)
@@ -1728,6 +1750,12 @@
 		nsecdesclen = sizeof(struct smb_ntsd) + (sizeof(struct smb_sid) * 2);
 		dacloffset = le32_to_cpu(pntsd->dacloffset);
 		if (dacloffset) {
+			if (!dacl_offset_valid(secdesclen, dacloffset)) {
+				cifs_dbg(VFS, "Server returned illegal DACL offset\n");
+				rc = -EINVAL;
+				goto id_mode_to_cifs_acl_exit;
+			}
+
 			dacl_ptr = (struct smb_acl *)((char *)pntsd + dacloffset);
 			rc = validate_dacl(dacl_ptr, (char *)pntsd + secdesclen);
 			if (rc) {

================================================================================
*    CONTEXT DIFFERENCES - surrounding code differences between the patches    *
================================================================================

--- b/fs/cifs/cifsacl.c
+++ b/fs/smb/client/cifsacl.c
@@ -1271,7 +1281,7 @@
-	group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
+	group_sid_ptr = (struct smb_sid *)((char *)pntsd +
 				le32_to_cpu(pntsd->gsidoffset));
 	dacloffset = le32_to_cpu(pntsd->dacloffset);
-	dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
+	dacl_ptr = (struct smb_acl *)((char *)pntsd + dacloffset);
 	cifs_dbg(NOISY, "revision %d type 0x%x ooffset 0x%x goffset 0x%x sacloffset 0x%x dacloffset 0x%x\n",
 		 pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset),
 		 le32_to_cpu(pntsd->gsidoffset),
@@ -1333,5 +1343,5 @@
 	dacloffset = le32_to_cpu(pntsd->dacloffset);
 	if (dacloffset) {
-		dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
+		dacl_ptr = (struct smb_acl *)((char *)pntsd + dacloffset);
 		rc = validate_dacl(dacl_ptr, end_of_acl);
 		if (rc)
@@ -1693,6 +1703,6 @@
-		nsecdesclen = sizeof(struct cifs_ntsd) + (sizeof(struct cifs_sid) * 2);
+		nsecdesclen = sizeof(struct smb_ntsd) + (sizeof(struct smb_sid) * 2);
 		dacloffset = le32_to_cpu(pntsd->dacloffset);
 		if (dacloffset) {
-			dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
+			dacl_ptr = (struct smb_acl *)((char *)pntsd + dacloffset);
 			rc = validate_dacl(dacl_ptr, (char *)pntsd + secdesclen);
 			if (rc) {

This is an automated interdiff check for backported commits.

@github-actions

Copy link
Copy Markdown

JIRA PR Check Results

5 commit(s) with issues found:

Commit 257e7e750039

Summary: smb: client: validate dacloffset before building DACL pointers

❌ Errors:

  • VULN-188328: Status is 'To Do', expected 'In Progress'

⚠️ Warnings:

  • VULN-188328: No time logged - please log time manually

Commit 29195779d9c3

Summary: smb: client: use kzalloc to zero-initialize security descriptor buffer

❌ Errors:

  • VULN-188853: Status is 'To Do', expected 'In Progress'

⚠️ Warnings:

  • VULN-188853: No time logged - please log time manually

Commit e38381c4577b

Summary: smb: client: require a full NFS mode SID before reading mode bits

❌ Errors:

  • VULN-184957: Status is 'To Do', expected 'In Progress'

⚠️ Warnings:

  • VULN-184957: No time logged - please log time manually

Commit f141ac4dc8e0

Summary: smb: client: validate the whole DACL before rewriting it in cifsacl

❌ Errors:

  • VULN-183468: Status is 'To Do', expected 'In Progress'

⚠️ Warnings:

  • VULN-183468: No time logged - please log time manually

Commit c0da859f9010

Summary: net: bonding: fix use-after-free in bond_xmit_broadcast()

❌ Errors:

  • VULN-181412: Status is 'To Do', expected 'In Progress'

⚠️ Warnings:

  • VULN-181412: No time logged - please log time manually

Summary: Checked 5 commit(s) total.

@github-actions

Copy link
Copy Markdown

Validation checks completed with issues View full results: https://github.com/ctrliq/kernel-src-tree/actions/runs/28201943999

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants