FAILED: patch "[PATCH] smb: client: fix create context out-of-bounds reads" failed to apply to 6.1-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 6.1-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.1.y
git checkout FETCH_HEAD
git cherry-pick -x 67f4c1c6a1b51e203d986779299824d1c2c590a6
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026092929-survey-cost-ee4b@gregkh' --subject-prefix 'PATCH 6.1.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 67f4c1c6a1b51e203d986779299824d1c2c590a6 Mon Sep 17 00:00:00 2001
From: Zihan Xi <[email protected]>
Date: Wed, 16 Sep 2026 15:29:24 +0000
Subject: [PATCH] smb: client: fix create context out-of-bounds reads
smb2_parse_contexts() validates the complete create-context area but does not limit each record to its Next field before dispatching it. A malformed chain can therefore expose bytes beyond the current context to a handler. The QFid handler also used a full response-structure cast although it only reads DiskFileId.
The SMB2/SMB3 lease parsers made the same layout assumption: they read LeaseState and LeaseFlags at canonical offsets rather than at DataOffset. A valid non-canonical DataOffset could therefore yield unrelated in-bounds data, while a short DataLength was still accepted.
Limit each context to its Next value, reject offsets before the context header, and reject malformed chains. Bound the name range by the current context and do not dispatch a known handler when DataLength is zero. Read the QFid DiskFileId only when the context data covers that field. Parse the lease context from DataOffset and require DataLength to match the v1 or v2 lease_context size used by ksmbd. A size mismatch skips lease parsing without failing the open.
fs/smb/client/smb2ops.c +20 -8
@@ -4572,25 +4572,37 @@ smb3_create_lease_buf(u8 *lease_key, u8 oplock, u8 *parent_lease_key, __le32 flastatic __u8 smb2_parse_lease_buf (void *buf,__u16 *epoch,char *lease_key) { -struct create_lease *lc = (struct create_lease *)buf; +struct create_context *cc = buf; +struct lease_context lc; *epoch =0 ;/* not used */ -if (lc->lcontext.LeaseFlags &SMB2_LEASE_FLAG_BREAK_IN_PROGRESS_LE ) +if (le32_to_cpu (cc->DataLength) !=sizeof (lc)) +return 0 ; + +memcpy (&lc, (u8 *)cc +le16_to_cpu (cc->DataOffset),sizeof (lc)); +if (lc.LeaseFlags &SMB2_LEASE_FLAG_BREAK_IN_PROGRESS_LE )return SMB2_OPLOCK_LEVEL_NOCHANGE ; -return le32_to_cpu (lc->lcontext.LeaseState); +return le32_to_cpu (lc.LeaseState); }static __u8 smb3_parse_lease_buf (void *buf,__u16 *epoch,char *lease_key) { -struct create_lease_v2 *lc = (struct create_lease_v2 *)buf; +struct create_context *cc = buf; +struct lease_context_v2 lc; - *epoch =le16_to_cpu (lc->lcontext.Epoch); -if (lc->lcontext.LeaseFlags &SMB2_LEASE_FLAG_BREAK_IN_PROGRESS_LE ) +if (le32_to_cpu (cc->DataLength) !=sizeof (lc)) { + *epoch =0 ; +return 0 ; + } + +memcpy (&lc, (u8 *)cc +le16_to_cpu (cc->DataOffset),sizeof (lc)); + *epoch =le16_to_cpu (lc.Epoch); +if (lc.LeaseFlags &SMB2_LEASE_FLAG_BREAK_IN_PROGRESS_LE )return SMB2_OPLOCK_LEVEL_NOCHANGE ;if (lease_key) -memcpy (lease_key, &lc->lcontext.LeaseKey,SMB2_LEASE_KEY_SIZE ); -return le32_to_cpu (lc->lcontext.LeaseState); +memcpy (lease_key, lc.LeaseKey,SMB2_LEASE_KEY_SIZE ); +return le32_to_cpu (lc.LeaseState); } static unsigned int
fs/smb/client/smb2pdu.c +34 -10
93 lines not on this page · raw message
Sasha Levin
maintainerPATCH 1/2 smb3: make query_on_disk_id open context consistent and move to common code
From: Steve French <[email protected]>
[ Upstream commit 1149c8467ddebfb6bb9aab37830f70a49cab7085 ]
cifs and ksmbd were using a slightly different version of the query_on_disk_id struct which could be confusing. Use the ksmbd version of this struct, and move it to common code.
Stable-dep-of: 67f4c1c6a1b5 ("smb: client: fix create context out-of-bounds reads")
--- fs/smb/client/smb2pdu.c | 2 +- fs/smb/client/smb2pdu.h | 9 --------- fs/smb/common/smb2pdu.h | 11 +++++++++++ fs/smb/server/smb2pdu.h | 8 -------- 4 files changed, 12 insertions(+), 18 deletions(-)
fs/smb/client/smb2pdu.c +1 -1
@@ -2179,7 +2179,7 @@ create_reconnect_durable_buf(struct cifs_fid *fid)static void parse_query_id_ctxt (struct create_context *cc,struct smb2_file_all_info *buf) { -struct create_on_disk_id *pdisk_id = (struct create_on_disk_id *)cc; +struct create_disk_id_rsp *pdisk_id = (struct create_disk_id_rsp *)cc;cifs_dbg (FYI ,"parse query id context 0x%llx 0x%llx\n" , pdisk_id->DiskFileId, pdisk_id->VolumeId);
fs/smb/client/smb2pdu.h +0 -9
@@ -170,15 +170,6 @@ struct durable_reconnect_context_v2 {__le32 Flags;/* see above DHANDLE_FLAG_PERSISTENT */ } __packed; -/* See MS-SMB2 2.2.14.2.9 */ -struct create_on_disk_id { -struct create_context ccontext; -__u8 Name[8 ]; -__le64 DiskFileId; -__le64 VolumeId; -__u32 Reserved[4 ]; -} __packed; -/* See MS-SMB2 2.2.14.2.12 */ struct durable_reconnect_context_v2_rsp {__le32 Timeout;
fs/smb/common/smb2pdu.h +11 -0
@@ -1240,6 +1240,7 @@ struct create_posix {#define SMB2_LEASE_KEY_SIZE 16 +/* See MS-SMB2 2.2.13.2.8 */ struct lease_context {__u8 LeaseKey[SMB2_LEASE_KEY_SIZE ];__le32 LeaseState;
@@ -1247,6 +1248,7 @@ struct lease_context {__le64 LeaseDuration; } __packed; +/* See MS-SMB2 2.2.13.2.10 */ struct lease_context_v2 {__u8 LeaseKey[SMB2_LEASE_KEY_SIZE ];__le32 LeaseState;
@@ -1270,6 +1272,15 @@ struct create_lease_v2 {__u8 Pad[4 ]; } __packed; +/* See MS-SMB2 2.2.14.2.9 */ +struct create_disk_id_rsp { +struct create_context ccontext; +__u8 Name[8 ]; +__le64 DiskFileId; +__le64 VolumeId; +__u8 Reserved[16 ]; +} __packed; +/* See MS-SMB2 2.2.31 and 2.2.32 */ struct smb2_ioctl_req {struct smb2_hdr hdr;
fs/smb/server/smb2pdu.h +0 -8
@@ -146,14 +146,6 @@ struct create_mxac_rsp {__le32 MaximalAccess; } __packed; -struct create_disk_id_rsp { -struct create_context ccontext; -__u8 Name[8 ]; -__le64 DiskFileId; -__le64 VolumeId; -__u8 Reserved[16 ]; -} __packed; -/* equivalent of the contents of SMB3.1.1 POSIX open context response */ struct create_posix_rsp {struct create_context ccontext;
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 2/2 smb: client: fix create context out-of-bounds reads
From: Zihan Xi <[email protected]>
[ Upstream commit 67f4c1c6a1b51e203d986779299824d1c2c590a6 ]
smb2_parse_contexts() validates the complete create-context area but does not limit each record to its Next field before dispatching it. A malformed chain can therefore expose bytes beyond the current context to a handler. The QFid handler also used a full response-structure cast although it only reads DiskFileId.
The SMB2/SMB3 lease parsers made the same layout assumption: they read LeaseState and LeaseFlags at canonical offsets rather than at DataOffset. A valid non-canonical DataOffset could therefore yield unrelated in-bounds data, while a short DataLength was still accepted.
Limit each context to its Next value, reject offsets before the context header, and reject malformed chains. Bound the name range by the current context and do not dispatch a known handler when DataLength is zero. Read the QFid DiskFileId only when the context data covers that field. Parse the lease context from DataOffset and require DataLength to match the v1 or v2 lease_context size used by ksmbd. A size mismatch skips lease parsing without failing the open.
--- fs/smb/client/smb2ops.c | 28 ++++++++++++++++++-------- fs/smb/client/smb2pdu.c | 44 +++++++++++++++++++++++++++++++---------- 2 files changed, 54 insertions(+), 18 deletions(-)
fs/smb/client/smb2ops.c +20 -8
@@ -4372,25 +4372,37 @@ smb3_create_lease_buf(u8 *lease_key, u8 oplock)static __u8 smb2_parse_lease_buf (void *buf,__u16 *epoch,char *lease_key) { -struct create_lease *lc = (struct create_lease *)buf; +struct create_context *cc = buf; +struct lease_context lc; *epoch =0 ;/* not used */ -if (lc->lcontext.LeaseFlags &SMB2_LEASE_FLAG_BREAK_IN_PROGRESS_LE ) +if (le32_to_cpu (cc->DataLength) !=sizeof (lc)) +return 0 ; + +memcpy (&lc, (u8 *)cc +le16_to_cpu (cc->DataOffset),sizeof (lc)); +if (lc.LeaseFlags &SMB2_LEASE_FLAG_BREAK_IN_PROGRESS_LE )return SMB2_OPLOCK_LEVEL_NOCHANGE ; -return le32_to_cpu (lc->lcontext.LeaseState); +return le32_to_cpu (lc.LeaseState); }static __u8 smb3_parse_lease_buf (void *buf,__u16 *epoch,char *lease_key) { -struct create_lease_v2 *lc = (struct create_lease_v2 *)buf; +struct create_context *cc = buf; +struct lease_context_v2 lc; + +if (le32_to_cpu (cc->DataLength) !=sizeof (lc)) { + *epoch =0 ; +return 0 ; + } - *epoch =le16_to_cpu (lc->lcontext.Epoch); -if (lc->lcontext.LeaseFlags &SMB2_LEASE_FLAG_BREAK_IN_PROGRESS_LE ) +memcpy (&lc, (u8 *)cc +le16_to_cpu (cc->DataOffset),sizeof (lc)); + *epoch =le16_to_cpu (lc.Epoch); +if (lc.LeaseFlags &SMB2_LEASE_FLAG_BREAK_IN_PROGRESS_LE )return SMB2_OPLOCK_LEVEL_NOCHANGE ;if (lease_key) -memcpy (lease_key, &lc->lcontext.LeaseKey,SMB2_LEASE_KEY_SIZE ); -return le32_to_cpu (lc->lcontext.LeaseState); +memcpy (lease_key, lc.LeaseKey,SMB2_LEASE_KEY_SIZE ); +return le32_to_cpu (lc.LeaseState); } static unsigned int
fs/smb/client/smb2pdu.c +34 -10
93 lines not on this page · raw message
Signature · 1 line
2.53.0