Skip to contentSkip to conversation

FAILED: patch "[PATCH] smb: client: fix use-before-check of ReparseDataLength in" failed to apply to 6.6-stable tree

PATCH New [email protected] 2 participants 3 messages Sep 3 – Sep 7

Subsystems (2)
lore
Share & tools
lore

[email protected]

author maintainer
#0 lore raw

The patch below does not apply to the 6.6-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.6.y
git checkout FETCH_HEAD
git cherry-pick -x 05f78e6cf34ea3a285053bd5999e08e8ac298bd5
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026090314-shower-guileless-2d4c@gregkh' --subject-prefix 'PATCH 6.6.y' 'HEAD^..'

Possible dependencies:

thanks,

greg k-h

------------------ original commit in Linus's tree ------------------

From 05f78e6cf34ea3a285053bd5999e08e8ac298bd5 Mon Sep 17 00:00:00 2001
From: Frank Sorenson <[email protected]>
Date: Mon, 17 Aug 2026 12:16:57 -0500
Subject: [PATCH] smb: client: fix use-before-check of ReparseDataLength in
reparse_buf_ptr()

reparse_buf_ptr() reads buf->ReparseDataLength before checking that count covers the full fixed header:

    buf = (struct reparse_data_buffer *)((u8 *)io + off);
    len = sizeof(*buf);                          /* 8 bytes */
    rdlen = le16_to_cpu(buf->ReparseDataLength); /* offset 4, 2 bytes */

    if (count < len || count < rdlen + len)      /* check comes after */

struct reparse_data_buffer has ReparseDataLength at offset 4. If a server returns OutputCount < 6, the read at offset 4-5 reaches past the end of the received data. The off+count bounds against iov_len were already validated, but that does not protect against count being smaller than sizeof(*buf).

Split the check: verify count >= sizeof(*buf) before reading ReparseDataLength, then verify count covers the data region.

Fixes a158bb66b137 ("smb: client: optimise reparse point querying")
fs/smb/client/smb2inode.c +4 -2
index bcaa44814b71..98ea5c6c34af 100644
@@ -41,9 +41,11 @@ static struct reparse_data_buffer *reparse_buf_ptr(struct kvec *iov)
 
 	buf = (struct reparse_data_buffer *)((u8 *)io + off);
 	len = sizeof(*buf);
-	rdlen = le16_to_cpu(buf->ReparseDataLength);
+	if (count < len)
+		return ERR_PTR(smb_EIO2(smb_eio_trace_reparse_rdlen, count, 0));
 
-	if (count < len || count < rdlen + len)
+	rdlen = le16_to_cpu(buf->ReparseDataLength);
+	if (count < rdlen + len)
 		return ERR_PTR(smb_EIO2(smb_eio_trace_reparse_rdlen, count, rdlen));
 	return buf;
 }
maintainer
#1 lore raw

PATCH 1/2 smb: move some duplicate definitions to common/smb2pdu.h

From: ZhangGuoDong <[email protected]>

[ Upstream commit 1172d8598499a006d172bb24bebaa3fdc99064a8 ]

In order to maintain the code more easily, move duplicate definitions to common header file.

There are only 4 different definitions, the client uses cpu_to_le16() but the server does not:

- RSS_CAPABLE
- RDMA_CAPABLE
- INTERNETWORK
- INTERNETWORKV6

The other definitions are exactly the same on both client and server.

The struct smb_hdr is defined in MS-CIFS and MS-SMB, but it's also used by SMB2 and SMB3, so move it to the common smb2pdu.h.

The struct smb_hdr is defined in MS-CIFS and MS-SMB, but it is also used by SMB2 and SMB3, so move it to the common smb2pdu.h.

[ stable: Retain only the smb_hdr consolidation because the stable-specific durable and network-interface definitions differ from upstream. Prepare the existing reparse_buf_ptr() for the follow-up fix with a local smb_EIO2 compatibility macro that preserves the existing -EIO behavior. ]

[ sashal: Reduced backport -- upstream 1172d8598499a touches 6 file(s), this
backport carries 4. Not backported here:
fs/smb/client/smb2pdu.h
fs/smb/server/smb2pdu.c
fs/smb/server/smb2pdu.h
This note is generated from the file lists only; see the resolution record for the reasoning. ]

Stable-dep-of: 05f78e6cf34e ("smb: client: fix use-before-check of ReparseDataLength in reparse_buf_ptr()")

---
 fs/smb/client/cifspdu.h    | 33 +--------------------------------
 fs/smb/client/smb2inode.c  | 11 +++++++++--
 fs/smb/common/smb2pdu.h    | 36 ++++++++++++++++++++++++++++++++++++
 fs/smb/server/smb_common.h | 30 ------------------------------
 4 files changed, 46 insertions(+), 64 deletions(-)
fs/smb/client/cifspdu.h +1 -32
index f4cfb082dfd14..7a3ec22808adf 100644
@@ -12,6 +12,7 @@
 #include <net/sock.h>
 #include <asm/unaligned.h>
 #include "../common/smbfsctl.h"
+#include "../common/smb2pdu.h"
 
 #define CIFS_PROT   0
 #define POSIX_PROT  (CIFS_PROT+1)
@@ -377,38 +378,6 @@
 #define GETU16(var)  (*((__u16 *)var))	/* BB check for endian issues */
 #define GETU32(var)  (*((__u32 *)var))	/* BB check for endian issues */
 
-struct smb_hdr {
-	__be32 smb_buf_length;	/* BB length is only two (rarely three) bytes,
-		with one or two byte "type" preceding it that will be
-		zero - we could mask the type byte off */
-	__u8 Protocol[4];
-	__u8 Command;
-	union {
-		struct {
-			__u8 ErrorClass;
-			__u8 Reserved;
-			__le16 Error;
-		} __attribute__((packed)) DosError;
-		__le32 CifsError;
-	} __attribute__((packed)) Status;
-	__u8 Flags;
-	__le16 Flags2;		/* note: le */
-	__le16 PidHigh;
-	union {
-		struct {
-			__le32 SequenceNumber;  /* le */
-			__u32 Reserved; /* zero */
-		} __attribute__((packed)) Sequence;
-		__u8 SecuritySignature[8];	/* le */
-	} __attribute__((packed)) Signature;
-	__u8 pad[2];
-	__u16 Tid;
-	__le16 Pid;
-	__u16 Uid;
-	__le16 Mid;
-	__u8 WordCount;
-} __attribute__((packed));
-
 /* given a pointer to an smb_hdr, retrieve a void pointer to the ByteCount */
 static inline void *
 BCC(struct smb_hdr *smb)
fs/smb/client/smb2inode.c +9 -2
index 540f4ba81b6ce..927c9c800604f 100644
@@ -26,6 +26,9 @@
 #include "cached_dir.h"
 #include "smb2status.h"
 
+/* Preserve the newer EIO helper call shape while retaining 6.6 semantics. */
+#define smb_EIO2(_trace, _info, _info2) (-EIO)
+
 static inline __u32 file_create_options(struct dentry *dentry)
 {
 	struct cifsInodeInfo *ci;
@@ -43,6 +46,7 @@ static struct reparse_data_buffer *reparse_buf_ptr(struct kvec *iov)
 	struct reparse_data_buffer *buf;
 	struct smb2_ioctl_rsp *io = iov->iov_base;
 	u32 off, count, len;
+	u16 rdlen;
 
 	count = le32_to_cpu(io->OutputCount);
 	off = le32_to_cpu(io->OutputOffset);
@@ -51,10 +55,13 @@ static struct reparse_data_buffer *reparse_buf_ptr(struct kvec *iov)
 
 	buf = (struct reparse_data_buffer *)((u8 *)io + off);
 	len = sizeof(*buf);
-	if (count < len || count < le16_to_cpu(buf->ReparseDataLength) + len)
-		return ERR_PTR(-EIO);
+	rdlen = le16_to_cpu(buf->ReparseDataLength);
+
+	if (count < len || count < rdlen + len)
+		return ERR_PTR(smb_EIO2(smb_eio_trace_reparse_rdlen, count, rdlen));
 	return buf;
 }
+#undef smb_EIO2
 
 /* Parse owner and group from SMB3.1.1 POSIX query info */
 static int parse_posix_sids(struct cifs_open_info_data *data,
fs/smb/common/smb2pdu.h +36 -0
index 1af827ae757e0..dfd50472de30a 100644
@@ -1860,6 +1860,42 @@ struct smb2_lease_ack {
 	__le64 LeaseDuration;
 } __packed;
 
+/*
+ * See MS-CIFS 2.2.3.1
+ *     MS-SMB 2.2.3.1
+ */
+struct smb_hdr {
+	__be32 smb_buf_length;	/* BB length is only two (rarely three) bytes,
+		with one or two byte "type" preceding it that will be
+		zero - we could mask the type byte off */
+	__u8 Protocol[4];
+	__u8 Command;
+	union {
+		struct {
+			__u8 ErrorClass;
+			__u8 Reserved;
+			__le16 Error;
+		} __packed DosError;
+		__le32 CifsError;
+	} __packed Status;
+	__u8 Flags;
+	__le16 Flags2;		/* note: le */
+	__le16 PidHigh;
+	union {
+		struct {
+			__le32 SequenceNumber;  /* le */
+			__u32 Reserved; /* zero */
+		} __packed Sequence;
+		__u8 SecuritySignature[8];	/* le */
+	} __packed Signature;
+	__u8 pad[2];
+	__u16 Tid;
+	__le16 Pid;
+	__u16 Uid;
+	__le16 Mid;
+	__u8 WordCount;
+} __packed;
+
 #define OP_BREAK_STRUCT_SIZE_20		24
 #define OP_BREAK_STRUCT_SIZE_21		36
 #endif				/* _COMMON_SMB2PDU_H */
fs/smb/server/smb_common.h +0 -30
index 8693b5f5b4ac2..577270d9ad9ec 100644
@@ -160,36 +160,6 @@
 #define SMBFLG2_ERR_STATUS	cpu_to_le16(0x4000)
 #define SMBFLG2_UNICODE		cpu_to_le16(0x8000)
 
-struct smb_hdr {
-	__be32 smb_buf_length;
-	__u8 Protocol[4];
-	__u8 Command;
-	union {
-		struct {
-			__u8 ErrorClass;
-			__u8 Reserved;
-			__le16 Error;
-		} __packed DosError;
-		__le32 CifsError;
-	} __packed Status;
-	__u8 Flags;
-	__le16 Flags2;          /* note: le */
-	__le16 PidHigh;
-	union {
-		struct {
-			__le32 SequenceNumber;  /* le */
-			__u32 Reserved; /* zero */
-		} __packed Sequence;
-		__u8 SecuritySignature[8];      /* le */
-	} __packed Signature;
-	__u8 pad[2];
-	__le16 Tid;
-	__le16 Pid;
-	__le16 Uid;
-	__le16 Mid;
-	__u8 WordCount;
-} __packed;
-
 struct smb_negotiate_req {
 	struct smb_hdr hdr;     /* wct = 0 */
 	__le16 ByteCount;
Signature · 1 line
2.53.0
maintainer
#2 lore raw

PATCH 2/2 smb: client: fix use-before-check of ReparseDataLength in reparse_buf_ptr()

From: Frank Sorenson <[email protected]>

[ Upstream commit 05f78e6cf34ea3a285053bd5999e08e8ac298bd5 ]

reparse_buf_ptr() reads buf->ReparseDataLength before checking that count covers the full fixed header:

    buf = (struct reparse_data_buffer *)((u8 *)io + off);
    len = sizeof(*buf);                          /* 8 bytes */
    rdlen = le16_to_cpu(buf->ReparseDataLength); /* offset 4, 2 bytes */

    if (count < len || count < rdlen + len)      /* check comes after */

struct reparse_data_buffer has ReparseDataLength at offset 4. If a server returns OutputCount < 6, the read at offset 4-5 reaches past the end of the received data. The off+count bounds against iov_len were already validated, but that does not protect against count being smaller than sizeof(*buf).

Split the check: verify count >= sizeof(*buf) before reading ReparseDataLength, then verify count covers the data region.

Fixes a158bb66b137 ("smb: client: optimise reparse point querying")
---
 fs/smb/client/smb2inode.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)
fs/smb/client/smb2inode.c +4 -2
index 927c9c800604f..37ad67c417f2f 100644
@@ -55,9 +55,11 @@ static struct reparse_data_buffer *reparse_buf_ptr(struct kvec *iov)
 
 	buf = (struct reparse_data_buffer *)((u8 *)io + off);
 	len = sizeof(*buf);
-	rdlen = le16_to_cpu(buf->ReparseDataLength);
+	if (count < len)
+		return ERR_PTR(smb_EIO2(smb_eio_trace_reparse_rdlen, count, 0));
 
-	if (count < len || count < rdlen + len)
+	rdlen = le16_to_cpu(buf->ReparseDataLength);
+	if (count < rdlen + len)
 		return ERR_PTR(smb_EIO2(smb_eio_trace_reparse_rdlen, count, rdlen));
 	return buf;
 }
Signature · 1 line
2.53.0