public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/2] smb: some potential bugfixes
@ 2026-04-06 13:49 Greg Kroah-Hartman
  2026-04-06 13:49 ` [PATCH 1/2] smb: client: fix off-by-8 bounds check in check_wsl_eas() Greg Kroah-Hartman
                   ` (2 more replies)
  0 siblings, 3 replies; 15+ messages in thread
From: Greg Kroah-Hartman @ 2026-04-06 13:49 UTC (permalink / raw)
  To: linux-cifs, samba-technical
  Cc: linux-kernel, Greg Kroah-Hartman, Steve French, Paulo Alcantara,
	Ronnie Sahlberg, Shyam Prasad N, Tom Talpey, Bharath SM

I spent the time exercising some new fuzzing tools on the ksmbd and smb
code purely because it's something that is simple to set up and test
locally with virtual machines, and in doing so, potentially found some
minor problems for when you have an "untrusted" client.

Here's some fixes for what I happened to notice.  They pass my very
limited testing here, but please don't trust them at all and verify that
I'm not just making this all up before accepting them.

thanks!

greg k-h

Greg Kroah-Hartman (2):
  smb: client: fix off-by-8 bounds check in check_wsl_eas()
  smb: client: fix OOB reads parsing symlink error response

 fs/smb/client/smb2file.c  | 20 ++++++++++++--------
 fs/smb/client/smb2inode.c |  2 +-
 2 files changed, 13 insertions(+), 9 deletions(-)

-- 
2.53.0


^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH 1/2] smb: client: fix off-by-8 bounds check in check_wsl_eas()
  2026-04-06 13:49 [PATCH 0/2] smb: some potential bugfixes Greg Kroah-Hartman
@ 2026-04-06 13:49 ` Greg Kroah-Hartman
  2026-04-08  2:51   ` ChenXiaoSong
  2026-04-08  9:39   ` Yuanfu Xie
  2026-04-06 13:49 ` [PATCH 2/2] smb: client: fix OOB reads parsing symlink error response Greg Kroah-Hartman
  2026-04-07  3:03 ` [PATCH 0/2] smb: some potential bugfixes Paulo Alcantara
  2 siblings, 2 replies; 15+ messages in thread
From: Greg Kroah-Hartman @ 2026-04-06 13:49 UTC (permalink / raw)
  To: linux-cifs
  Cc: linux-kernel, Greg Kroah-Hartman, Steve French, Paulo Alcantara,
	Ronnie Sahlberg, Shyam Prasad N, Tom Talpey, Bharath SM,
	samba-technical, stable

The bounds check uses (u8 *)ea + nlen + 1 + vlen as the end of the EA
name and value, but ea_data sits at offset sizeof(struct
smb2_file_full_ea_info) = 8 from ea, not at offset 0.  The strncmp()
later reads ea->ea_data[0..nlen-1] and the value bytes follow at
ea_data[nlen+1..nlen+vlen], so the actual end is ea->ea_data + nlen + 1
+ vlen.  Isn't pointer math fun?

The earlier check (u8 *)ea > end - sizeof(*ea) only guarantees the
8-byte header is in bounds, but since the last EA is placed within 8
bytes of the end of the response, the name and value bytes are read past
the end of iov.

Fix this mess all up by using ea->ea_data as the base for the bounds
check.

An "untrusted" server can use this to leak up to 8 bytes of kernel heap
into the EA name comparison and influence which WSL xattr the data is
interpreted as.

Cc: Steve French <sfrench@samba.org>
Cc: Paulo Alcantara <pc@manguebit.org>
Cc: Ronnie Sahlberg <ronniesahlberg@gmail.com>
Cc: Shyam Prasad N <sprasad@microsoft.com>
Cc: Tom Talpey <tom@talpey.com>
Cc: Bharath SM <bharathsm@microsoft.com>
Cc: linux-cifs@vger.kernel.org
Cc: samba-technical@lists.samba.org
Cc: stable <stable@kernel.org>
Assisted-by: gregkh_clanker_t1000
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
 fs/smb/client/smb2inode.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/fs/smb/client/smb2inode.c b/fs/smb/client/smb2inode.c
index 364bdcff9c9d..fe1c9d776580 100644
--- a/fs/smb/client/smb2inode.c
+++ b/fs/smb/client/smb2inode.c
@@ -128,7 +128,7 @@ static int check_wsl_eas(struct kvec *rsp_iov)
 		nlen = ea->ea_name_length;
 		vlen = le16_to_cpu(ea->ea_value_length);
 		if (nlen != SMB2_WSL_XATTR_NAME_LEN ||
-		    (u8 *)ea + nlen + 1 + vlen > end)
+		    (u8 *)ea->ea_data + nlen + 1 + vlen > end)
 			return -EINVAL;
 
 		switch (vlen) {
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 2/2] smb: client: fix OOB reads parsing symlink error response
  2026-04-06 13:49 [PATCH 0/2] smb: some potential bugfixes Greg Kroah-Hartman
  2026-04-06 13:49 ` [PATCH 1/2] smb: client: fix off-by-8 bounds check in check_wsl_eas() Greg Kroah-Hartman
@ 2026-04-06 13:49 ` Greg Kroah-Hartman
  2026-04-08  9:01   ` ChenXiaoSong
  2026-04-07  3:03 ` [PATCH 0/2] smb: some potential bugfixes Paulo Alcantara
  2 siblings, 1 reply; 15+ messages in thread
From: Greg Kroah-Hartman @ 2026-04-06 13:49 UTC (permalink / raw)
  To: linux-cifs
  Cc: linux-kernel, Greg Kroah-Hartman, Steve French, Paulo Alcantara,
	Ronnie Sahlberg, Shyam Prasad N, Tom Talpey, Bharath SM,
	samba-technical, stable

When a CREATE returns STATUS_STOPPED_ON_SYMLINK, smb2_check_message()
returns success without any length validation, leaving the symlink
parsers as the only defense against an untrusted server.

symlink_data() walks SMB 3.1.1 error contexts with the loop test "p <
end", but reads p->ErrorId at offset 4 and p->ErrorDataLength at offset
0.  When the server-controlled ErrorDataLength advances p to within 1-7
bytes of end, the next iteration will read past it.  When the matching
context is found, sym->SymLinkErrorTag is read at offset 4 from
p->ErrorContextData with no check that the symlink header itself fits.

smb2_parse_symlink_response() then bounds-checks the substitute name
using SMB2_SYMLINK_STRUCT_SIZE as the offset of PathBuffer from
iov_base.  That value is computed as sizeof(smb2_err_rsp) +
sizeof(smb2_symlink_err_rsp), which is correct only when
ErrorContextCount == 0.

With at least one error context the symlink data sits 8 bytes deeper,
and each skipped non-matching context shifts it further by 8 +
ALIGN(ErrorDataLength, 8).  The check is too short, allowing the
substitute name read to run past iov_len.  The out-of-bound heap bytes
are UTF-16-decoded into the symlink target and returned to userspace via
readlink(2).

Fix this all up by making the loops test require the full context header
to fit, rejecting sym if its header runs past end, and bound the
substitute name against the actual position of sym->PathBuffer rather
than a fixed offset.

Because sub_offs and sub_len are 16bits, the pointer math will not
overflow here with the new greater-than.

Cc: Steve French <sfrench@samba.org>
Cc: Paulo Alcantara <pc@manguebit.org>
Cc: Ronnie Sahlberg <ronniesahlberg@gmail.com>
Cc: Shyam Prasad N <sprasad@microsoft.com>
Cc: Tom Talpey <tom@talpey.com>
Cc: Bharath SM <bharathsm@microsoft.com>
Cc: linux-cifs@vger.kernel.org
Cc: samba-technical@lists.samba.org
Cc: stable <stable@kernel.org>
Assisted-by: gregkh_clanker_t1000
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
 fs/smb/client/smb2file.c | 20 ++++++++++++--------
 1 file changed, 12 insertions(+), 8 deletions(-)

diff --git a/fs/smb/client/smb2file.c b/fs/smb/client/smb2file.c
index ed651c946251..b292aa94a593 100644
--- a/fs/smb/client/smb2file.c
+++ b/fs/smb/client/smb2file.c
@@ -27,10 +27,11 @@ static struct smb2_symlink_err_rsp *symlink_data(const struct kvec *iov)
 {
 	struct smb2_err_rsp *err = iov->iov_base;
 	struct smb2_symlink_err_rsp *sym = ERR_PTR(-EINVAL);
+	u8 *end = (u8 *)err + iov->iov_len;
 	u32 len;
 
 	if (err->ErrorContextCount) {
-		struct smb2_error_context_rsp *p, *end;
+		struct smb2_error_context_rsp *p;
 
 		len = (u32)err->ErrorContextCount * (offsetof(struct smb2_error_context_rsp,
 							      ErrorContextData) +
@@ -39,8 +40,7 @@ static struct smb2_symlink_err_rsp *symlink_data(const struct kvec *iov)
 			return ERR_PTR(-EINVAL);
 
 		p = (struct smb2_error_context_rsp *)err->ErrorData;
-		end = (struct smb2_error_context_rsp *)((u8 *)err + iov->iov_len);
-		do {
+		while ((u8 *)p + sizeof(*p) <= end) {
 			if (le32_to_cpu(p->ErrorId) == SMB2_ERROR_ID_DEFAULT) {
 				sym = (struct smb2_symlink_err_rsp *)p->ErrorContextData;
 				break;
@@ -50,14 +50,16 @@ static struct smb2_symlink_err_rsp *symlink_data(const struct kvec *iov)
 
 			len = ALIGN(le32_to_cpu(p->ErrorDataLength), 8);
 			p = (struct smb2_error_context_rsp *)(p->ErrorContextData + len);
-		} while (p < end);
+		}
 	} else if (le32_to_cpu(err->ByteCount) >= sizeof(*sym) &&
 		   iov->iov_len >= SMB2_SYMLINK_STRUCT_SIZE) {
 		sym = (struct smb2_symlink_err_rsp *)err->ErrorData;
 	}
 
-	if (!IS_ERR(sym) && (le32_to_cpu(sym->SymLinkErrorTag) != SYMLINK_ERROR_TAG ||
-			     le32_to_cpu(sym->ReparseTag) != IO_REPARSE_TAG_SYMLINK))
+	if (!IS_ERR(sym) &&
+	    ((u8 *)sym + sizeof(*sym) > end ||
+	     le32_to_cpu(sym->SymLinkErrorTag) != SYMLINK_ERROR_TAG ||
+	     le32_to_cpu(sym->ReparseTag) != IO_REPARSE_TAG_SYMLINK))
 		sym = ERR_PTR(-EINVAL);
 
 	return sym;
@@ -128,8 +130,10 @@ int smb2_parse_symlink_response(struct cifs_sb_info *cifs_sb, const struct kvec
 	print_len = le16_to_cpu(sym->PrintNameLength);
 	print_offs = le16_to_cpu(sym->PrintNameOffset);
 
-	if (iov->iov_len < SMB2_SYMLINK_STRUCT_SIZE + sub_offs + sub_len ||
-	    iov->iov_len < SMB2_SYMLINK_STRUCT_SIZE + print_offs + print_len)
+	if ((char *)sym->PathBuffer + sub_offs + sub_len >
+		(char *)iov->iov_base + iov->iov_len ||
+	    (char *)sym->PathBuffer + print_offs + print_len >
+		(char *)iov->iov_base + iov->iov_len)
 		return -EINVAL;
 
 	return smb2_parse_native_symlink(path,
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [PATCH 0/2] smb: some potential bugfixes
  2026-04-06 13:49 [PATCH 0/2] smb: some potential bugfixes Greg Kroah-Hartman
  2026-04-06 13:49 ` [PATCH 1/2] smb: client: fix off-by-8 bounds check in check_wsl_eas() Greg Kroah-Hartman
  2026-04-06 13:49 ` [PATCH 2/2] smb: client: fix OOB reads parsing symlink error response Greg Kroah-Hartman
@ 2026-04-07  3:03 ` Paulo Alcantara
       [not found]   ` <CAH2r5mvXFzWxs70Jmg=yWddmcHs+Bpf8eiBUvyc4oOMLzdCY7w@mail.gmail.com>
  2 siblings, 1 reply; 15+ messages in thread
From: Paulo Alcantara @ 2026-04-07  3:03 UTC (permalink / raw)
  To: Greg Kroah-Hartman, linux-cifs, samba-technical
  Cc: linux-kernel, Greg Kroah-Hartman, Steve French, Ronnie Sahlberg,
	Shyam Prasad N, Tom Talpey, Bharath SM

Greg Kroah-Hartman <gregkh@linuxfoundation.org> writes:

> I spent the time exercising some new fuzzing tools on the ksmbd and smb
> code purely because it's something that is simple to set up and test
> locally with virtual machines, and in doing so, potentially found some
> minor problems for when you have an "untrusted" client.
>
> Here's some fixes for what I happened to notice.  They pass my very
> limited testing here, but please don't trust them at all and verify that
> I'm not just making this all up before accepting them.

Reviewed-by: Paulo Alcantara (Red Hat) <pc@manguebit.org>

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 1/2] smb: client: fix off-by-8 bounds check in check_wsl_eas()
  2026-04-06 13:49 ` [PATCH 1/2] smb: client: fix off-by-8 bounds check in check_wsl_eas() Greg Kroah-Hartman
@ 2026-04-08  2:51   ` ChenXiaoSong
  2026-04-08  5:39     ` Greg Kroah-Hartman
  2026-04-08  9:39   ` Yuanfu Xie
  1 sibling, 1 reply; 15+ messages in thread
From: ChenXiaoSong @ 2026-04-08  2:51 UTC (permalink / raw)
  To: Greg Kroah-Hartman, linux-cifs
  Cc: linux-kernel, Steve French, Paulo Alcantara, Ronnie Sahlberg,
	Shyam Prasad N, Tom Talpey, Bharath SM, samba-technical, stable

Sashiko reported another out-of-bounds issue: 
https://sashiko.dev/#/patchset/2026040635-banking-unsoiled-3250@gregkh

Should we add the following checks in check_wsl_eas()?

```
--- a/fs/smb/client/smb2inode.c
+++ b/fs/smb/client/smb2inode.c
@@ -121,6 +121,9 @@ static int check_wsl_eas(struct kvec *rsp_iov)
         ea = (void *)((u8 *)rsp_iov->iov_base +
                       le16_to_cpu(rsp->OutputBufferOffset));
         end = (u8 *)rsp_iov->iov_base + rsp_iov->iov_len;
+       if (ea + outlen > end)
+               return -EINVAL;
+
         for (;;) {
                 if ((u8 *)ea > end - sizeof(*ea))
                         return -EINVAL;
```

On 4/6/26 21:49, Greg Kroah-Hartman wrote:
> The bounds check uses (u8 *)ea + nlen + 1 + vlen as the end of the EA
> name and value, but ea_data sits at offset sizeof(struct
> smb2_file_full_ea_info) = 8 from ea, not at offset 0.  The strncmp()
> later reads ea->ea_data[0..nlen-1] and the value bytes follow at
> ea_data[nlen+1..nlen+vlen], so the actual end is ea->ea_data + nlen + 1
> + vlen.  Isn't pointer math fun?
> 
> The earlier check (u8 *)ea > end - sizeof(*ea) only guarantees the
> 8-byte header is in bounds, but since the last EA is placed within 8
> bytes of the end of the response, the name and value bytes are read past
> the end of iov.
> 
> Fix this mess all up by using ea->ea_data as the base for the bounds
> check.
> 
> An "untrusted" server can use this to leak up to 8 bytes of kernel heap
> into the EA name comparison and influence which WSL xattr the data is
> interpreted as.
> 
> Cc: Steve French <sfrench@samba.org>
> Cc: Paulo Alcantara <pc@manguebit.org>
> Cc: Ronnie Sahlberg <ronniesahlberg@gmail.com>
> Cc: Shyam Prasad N <sprasad@microsoft.com>
> Cc: Tom Talpey <tom@talpey.com>
> Cc: Bharath SM <bharathsm@microsoft.com>
> Cc: linux-cifs@vger.kernel.org
> Cc: samba-technical@lists.samba.org
> Cc: stable <stable@kernel.org>
> Assisted-by: gregkh_clanker_t1000
> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> ---
>   fs/smb/client/smb2inode.c | 2 +-
>   1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/fs/smb/client/smb2inode.c b/fs/smb/client/smb2inode.c
> index 364bdcff9c9d..fe1c9d776580 100644
> --- a/fs/smb/client/smb2inode.c
> +++ b/fs/smb/client/smb2inode.c
> @@ -128,7 +128,7 @@ static int check_wsl_eas(struct kvec *rsp_iov)
>   		nlen = ea->ea_name_length;
>   		vlen = le16_to_cpu(ea->ea_value_length);
>   		if (nlen != SMB2_WSL_XATTR_NAME_LEN ||
> -		    (u8 *)ea + nlen + 1 + vlen > end)
> +		    (u8 *)ea->ea_data + nlen + 1 + vlen > end)
>   			return -EINVAL;
>   
>   		switch (vlen) {

-- 
ChenXiaoSong <chenxiaosong@kylinos.cn>
Chinese Homepage: chenxiaosong.com
English Homepage: chenxiaosong.com/en


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 1/2] smb: client: fix off-by-8 bounds check in check_wsl_eas()
  2026-04-08  2:51   ` ChenXiaoSong
@ 2026-04-08  5:39     ` Greg Kroah-Hartman
  2026-04-08  5:58       ` ChenXiaoSong
  0 siblings, 1 reply; 15+ messages in thread
From: Greg Kroah-Hartman @ 2026-04-08  5:39 UTC (permalink / raw)
  To: ChenXiaoSong
  Cc: linux-cifs, linux-kernel, Steve French, Paulo Alcantara,
	Ronnie Sahlberg, Shyam Prasad N, Tom Talpey, Bharath SM,
	samba-technical, stable

On Wed, Apr 08, 2026 at 10:51:12AM +0800, ChenXiaoSong wrote:
> Sashiko reported another out-of-bounds issue:
> https://sashiko.dev/#/patchset/2026040635-banking-unsoiled-3250@gregkh
> 
> Should we add the following checks in check_wsl_eas()?
> 
> ```
> --- a/fs/smb/client/smb2inode.c
> +++ b/fs/smb/client/smb2inode.c
> @@ -121,6 +121,9 @@ static int check_wsl_eas(struct kvec *rsp_iov)
>         ea = (void *)((u8 *)rsp_iov->iov_base +
>                       le16_to_cpu(rsp->OutputBufferOffset));
>         end = (u8 *)rsp_iov->iov_base + rsp_iov->iov_len;
> +       if (ea + outlen > end)
> +               return -EINVAL;

Then you would miss any "first" structures here, as I think the for loop
catches this later on with the line:


> +
>         for (;;) {
>                 if ((u8 *)ea > end - sizeof(*ea))
>                         return -EINVAL;

That one, right?

Or am I misreading this?

Pointer math is "fun" :(

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 0/2] smb: some potential bugfixes
       [not found]   ` <CAH2r5mvXFzWxs70Jmg=yWddmcHs+Bpf8eiBUvyc4oOMLzdCY7w@mail.gmail.com>
@ 2026-04-08  5:45     ` Greg Kroah-Hartman
  0 siblings, 0 replies; 15+ messages in thread
From: Greg Kroah-Hartman @ 2026-04-08  5:45 UTC (permalink / raw)
  To: Steve French
  Cc: Paulo Alcantara, linux-cifs, samba-technical, linux-kernel,
	Steve French, Ronnie Sahlberg, Shyam Prasad N, Tom Talpey,
	Bharath SM

On Tue, Apr 07, 2026 at 03:52:21PM -0500, Steve French wrote:
> merged into cifs-2.6.git for-next

Thanks!

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 1/2] smb: client: fix off-by-8 bounds check in check_wsl_eas()
  2026-04-08  5:39     ` Greg Kroah-Hartman
@ 2026-04-08  5:58       ` ChenXiaoSong
  2026-04-08  6:15         ` Greg Kroah-Hartman
  0 siblings, 1 reply; 15+ messages in thread
From: ChenXiaoSong @ 2026-04-08  5:58 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: linux-cifs, linux-kernel, Steve French, Paulo Alcantara,
	Ronnie Sahlberg, Shyam Prasad N, Tom Talpey, Bharath SM,
	samba-technical, stable

The for loop does not seem to catch cases where `outlen` is excessively 
large. In such cases, smb2_compound_op() would use this large `outlen` 
to `memcpy()`, which could lead to OOB.

```
smb2_compound_op()
{
	...
	size[0] = outlen; // very large
	check_wsl_eas()
	memcpy(..., outlen) // out-of-bounds
	...
}
```

On 4/8/26 13:39, Greg Kroah-Hartman wrote:
> On Wed, Apr 08, 2026 at 10:51:12AM +0800, ChenXiaoSong wrote:
>> Sashiko reported another out-of-bounds issue:
>> https://sashiko.dev/#/patchset/2026040635-banking-unsoiled-3250@gregkh
>>
>> Should we add the following checks in check_wsl_eas()?
>>
>> ```
>> --- a/fs/smb/client/smb2inode.c
>> +++ b/fs/smb/client/smb2inode.c
>> @@ -121,6 +121,9 @@ static int check_wsl_eas(struct kvec *rsp_iov)
>>          ea = (void *)((u8 *)rsp_iov->iov_base +
>>                        le16_to_cpu(rsp->OutputBufferOffset));
>>          end = (u8 *)rsp_iov->iov_base + rsp_iov->iov_len;
>> +       if (ea + outlen > end)
>> +               return -EINVAL;
> 
> Then you would miss any "first" structures here, as I think the for loop
> catches this later on with the line:
> 
> 
>> +
>>          for (;;) {
>>                  if ((u8 *)ea > end - sizeof(*ea))
>>                          return -EINVAL;
> 
> That one, right?
> 
> Or am I misreading this?
> 
> Pointer math is "fun" :(
> 
> thanks,
> 
> greg k-h

-- 
ChenXiaoSong <chenxiaosong@kylinos.cn>
Chinese Homepage: chenxiaosong.com
English Homepage: chenxiaosong.com/en


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 1/2] smb: client: fix off-by-8 bounds check in check_wsl_eas()
  2026-04-08  5:58       ` ChenXiaoSong
@ 2026-04-08  6:15         ` Greg Kroah-Hartman
  2026-04-08  6:19           ` ChenXiaoSong
  0 siblings, 1 reply; 15+ messages in thread
From: Greg Kroah-Hartman @ 2026-04-08  6:15 UTC (permalink / raw)
  To: ChenXiaoSong
  Cc: linux-cifs, linux-kernel, Steve French, Paulo Alcantara,
	Ronnie Sahlberg, Shyam Prasad N, Tom Talpey, Bharath SM,
	samba-technical, stable

On Wed, Apr 08, 2026 at 01:58:27PM +0800, ChenXiaoSong wrote:
> The for loop does not seem to catch cases where `outlen` is excessively
> large. In such cases, smb2_compound_op() would use this large `outlen` to
> `memcpy()`, which could lead to OOB.
> 
> ```
> smb2_compound_op()
> {
> 	...
> 	size[0] = outlen; // very large
> 	check_wsl_eas()
> 	memcpy(..., outlen) // out-of-bounds
> 	...
> }
> ```

Ah, I missed the caller site.  Yeah, probably a good thing to check as
well, want to make up a patch?

thanks,
greg k-h

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 1/2] smb: client: fix off-by-8 bounds check in check_wsl_eas()
  2026-04-08  6:15         ` Greg Kroah-Hartman
@ 2026-04-08  6:19           ` ChenXiaoSong
  2026-04-08  6:40             ` Greg Kroah-Hartman
  0 siblings, 1 reply; 15+ messages in thread
From: ChenXiaoSong @ 2026-04-08  6:19 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: linux-cifs, linux-kernel, Steve French, Paulo Alcantara,
	Ronnie Sahlberg, Shyam Prasad N, Tom Talpey, Bharath SM,
	samba-technical, stable

Could you send v2 with this check added?

I am currently reviewing another patch. Perhaps you could wait until I 
have finished reviewing it.

On 4/8/26 14:15, Greg Kroah-Hartman wrote:
> Ah, I missed the caller site.  Yeah, probably a good thing to check as
> well, want to make up a patch?

-- 
ChenXiaoSong <chenxiaosong@kylinos.cn>
Chinese Homepage: chenxiaosong.com
English Homepage: chenxiaosong.com/en


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 1/2] smb: client: fix off-by-8 bounds check in check_wsl_eas()
  2026-04-08  6:19           ` ChenXiaoSong
@ 2026-04-08  6:40             ` Greg Kroah-Hartman
  2026-04-08  6:52               ` ChenXiaoSong
  0 siblings, 1 reply; 15+ messages in thread
From: Greg Kroah-Hartman @ 2026-04-08  6:40 UTC (permalink / raw)
  To: ChenXiaoSong
  Cc: linux-cifs, linux-kernel, Steve French, Paulo Alcantara,
	Ronnie Sahlberg, Shyam Prasad N, Tom Talpey, Bharath SM,
	samba-technical, stable

On Wed, Apr 08, 2026 at 02:19:48PM +0800, ChenXiaoSong wrote:
> Could you send v2 with this check added?

Looks like this was already accepted, and the additional check would be
just that, an additional check :)

> I am currently reviewing another patch. Perhaps you could wait until I have
> finished reviewing it.

I have no problem waiting, but as you found this one, I want to give you
proper credit for the find/fix.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 1/2] smb: client: fix off-by-8 bounds check in check_wsl_eas()
  2026-04-08  6:40             ` Greg Kroah-Hartman
@ 2026-04-08  6:52               ` ChenXiaoSong
  2026-04-08  6:56                 ` Greg Kroah-Hartman
  0 siblings, 1 reply; 15+ messages in thread
From: ChenXiaoSong @ 2026-04-08  6:52 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: linux-cifs, linux-kernel, Steve French, Paulo Alcantara,
	Ronnie Sahlberg, Shyam Prasad N, Tom Talpey, Bharath SM,
	samba-technical, stable

Sashiko found it, I just checked and confirmed it.

Could you create another patch? I enjoy the review process more than 
creating patches :)

On 4/8/26 14:40, Greg Kroah-Hartman wrote:
> On Wed, Apr 08, 2026 at 02:19:48PM +0800, ChenXiaoSong wrote:
>> Could you send v2 with this check added?
> 
> Looks like this was already accepted, and the additional check would be
> just that, an additional check :)
> 
>> I am currently reviewing another patch. Perhaps you could wait until I have
>> finished reviewing it.
> 
> I have no problem waiting, but as you found this one, I want to give you
> proper credit for the find/fix.
> 
> thanks,
> 
> greg k-h

-- 
ChenXiaoSong <chenxiaosong@kylinos.cn>
Chinese Homepage: chenxiaosong.com
English Homepage: chenxiaosong.com/en


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 1/2] smb: client: fix off-by-8 bounds check in check_wsl_eas()
  2026-04-08  6:52               ` ChenXiaoSong
@ 2026-04-08  6:56                 ` Greg Kroah-Hartman
  0 siblings, 0 replies; 15+ messages in thread
From: Greg Kroah-Hartman @ 2026-04-08  6:56 UTC (permalink / raw)
  To: ChenXiaoSong
  Cc: linux-cifs, linux-kernel, Steve French, Paulo Alcantara,
	Ronnie Sahlberg, Shyam Prasad N, Tom Talpey, Bharath SM,
	samba-technical, stable

On Wed, Apr 08, 2026 at 02:52:31PM +0800, ChenXiaoSong wrote:
> Sashiko found it, I just checked and confirmed it.
> 
> Could you create another patch? I enjoy the review process more than
> creating patches :)

Will do, I'll add that to my queue, but might take a few days if someone
wants to "beat" me to it, I'll have no objection at all :)

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 2/2] smb: client: fix OOB reads parsing symlink error response
  2026-04-06 13:49 ` [PATCH 2/2] smb: client: fix OOB reads parsing symlink error response Greg Kroah-Hartman
@ 2026-04-08  9:01   ` ChenXiaoSong
  0 siblings, 0 replies; 15+ messages in thread
From: ChenXiaoSong @ 2026-04-08  9:01 UTC (permalink / raw)
  To: Greg Kroah-Hartman, linux-cifs
  Cc: linux-kernel, Steve French, Paulo Alcantara, Ronnie Sahlberg,
	Shyam Prasad N, Tom Talpey, Bharath SM, samba-technical, stable

Sashiko reported the following out-of-bounds issue. I have checked and 
confirmed that this indeed causes an OOB access.

When create fails on symlink, `len` in `smb2_check_message()` may be 
smaller than `calc_len`. The function flow is as follows:

```
smb2_check_message()
   // ensure StructureSize2 is 9
   if (... pdu->StructureSize2 != SMB2_ERROR_STRUCTURE_SIZE2_LE ...) // 
false
   smb2_calc_size()
     len = le16_to_cpu(shdr->StructureSize) == 64
     len += le16_to_cpu(pdu->StructureSize2) == 64 + 9
     smb2_get_data_area_len
       if (shdr->StructureSize == 9) // true, return NULL
   calc_len == 64 + 9
   if (len != calc_len) { // true
   /* create failed on symlink */
   if (command == SMB2_CREATE_HE && shdr->Status == 
STATUS_STOPPED_ON_SYMLINK) // true
```



Should we add the following check? Or check it in symlink_data()?

```
-- a/fs/smb/client/smb2misc.c
+++ b/fs/smb/client/smb2misc.c
@@ -241,7 +241,8 @@ smb2_check_message(char *buf, unsigned int pdu_len, 
unsigned int len,
         if (len != calc_len) {
                 /* create failed on symlink */
                 if (command == SMB2_CREATE_HE &&
-                   shdr->Status == STATUS_STOPPED_ON_SYMLINK)
+                   shdr->Status == STATUS_STOPPED_ON_SYMLINK &&
+                   len > calc_len)
                         return 0;
                 /* Windows 7 server returns 24 bytes more */
                 if (calc_len + 24 == len && command == 
SMB2_OPLOCK_BREAK_HE)

```

>> --- a/fs/smb/client/smb2file.c
>> +++ b/fs/smb/client/smb2file.c
>> @@ -27,10 +27,11 @@ static struct smb2_symlink_err_rsp *symlink_data(const struct kvec *iov)
>>  {
>>  	struct smb2_err_rsp *err = iov->iov_base;
>>  	struct smb2_symlink_err_rsp *sym = ERR_PTR(-EINVAL);
>> +	u8 *end = (u8 *)err + iov->iov_len;
>>  	u32 len;
>>  
>>  	if (err->ErrorContextCount) {
> Since smb2_check_message() returns success without length validation for
> the symlink error response, is it possible for iov->iov_len to be smaller
> than sizeof(struct smb2_err_rsp)?
> If the buffer only contains the base SMB2 header (64 bytes), does accessing
> err->ErrorContextCount (at offset 66) or err->ByteCount later in this
> function cause an out-of-bounds read?

-- 
ChenXiaoSong <chenxiaosong@kylinos.cn>
Chinese Homepage: chenxiaosong.com
English Homepage: chenxiaosong.com/en


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 1/2] smb: client: fix off-by-8 bounds check in check_wsl_eas()
  2026-04-06 13:49 ` [PATCH 1/2] smb: client: fix off-by-8 bounds check in check_wsl_eas() Greg Kroah-Hartman
  2026-04-08  2:51   ` ChenXiaoSong
@ 2026-04-08  9:39   ` Yuanfu Xie
  1 sibling, 0 replies; 15+ messages in thread
From: Yuanfu Xie @ 2026-04-08  9:39 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: linux-cifs, linux-kernel, Steve French, Paulo Alcantara,
	Ronnie Sahlberg, Shyam Prasad N, Tom Talpey, Bharath SM,
	samba-technical, stable

[PATCH] smb: client: add bounds checks when iterating SMB1 WSL EAs

Add boundary and overflow checks when traversing extended attribute (EA)
entries for SMB1 WSL reparse points in cifs_query_path_info(), to prevent
out-of-bounds memory accesses from malformed next_entry_offset values.

This is necessary because SMB1 WSL EA iteration does not currently have
any explicit bounds checking, unlike SMB2 path which has check_wsl_eas().
The new checks ensure the current EA pointer plus its size does not
exceed the end of the EA buffer during iteration and before parsing.

Signed-off-by: YuanfuXie <yuanfuxie@stu.pku.edu.cn>
---
 fs/smb/client/smb1ops.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/fs/smb/client/smb1ops.c b/fs/smb/client/smb1ops.c
index 9694117050a6..940bae49b2cc 100644
--- a/fs/smb/client/smb1ops.c
+++ b/fs/smb/client/smb1ops.c
@@ -645,13 +645,17 @@ static int cifs_query_path_info(const unsigned int xid,
 	if (!rc && data->reparse_point) {
 		struct smb2_file_full_ea_info *ea;
 		u32 next = 0;
+		u8 *eas_end = data->wsl.eas + data->wsl.eas_len;
 
 		ea = (struct smb2_file_full_ea_info *)data->wsl.eas;
 		do {
 			ea = (void *)((u8 *)ea + next);
+			if ((u8 *)ea + sizeof(*ea) > eas_end)
+				break;
 			next = le32_to_cpu(ea->next_entry_offset);
 		} while (next);
-		if (le16_to_cpu(ea->ea_value_length)) {
+		if ((u8 *)ea + sizeof(*ea) <= eas_end &&
+		    le16_to_cpu(ea->ea_value_length)) {
 			ea->next_entry_offset = cpu_to_le32(ALIGN(sizeof(*ea) +
 						ea->ea_name_length + 1 +
 						le16_to_cpu(ea->ea_value_length), 4));
@@ -691,13 +695,17 @@ static int cifs_query_path_info(const unsigned int xid,
 	if (!rc && data->reparse_point) {
 		struct smb2_file_full_ea_info *ea;
 		u32 next = 0;
+		u8 *eas_end = data->wsl.eas + data->wsl.eas_len;
 
 		ea = (struct smb2_file_full_ea_info *)data->wsl.eas;
 		do {
 			ea = (void *)((u8 *)ea + next);
+			if ((u8 *)ea + sizeof(*ea) > eas_end)
+				break;
 			next = le32_to_cpu(ea->next_entry_offset);
 		} while (next);
-		if (le16_to_cpu(ea->ea_value_length)) {
+		if ((u8 *)ea + sizeof(*ea) <= eas_end &&
+		    le16_to_cpu(ea->ea_value_length)) {
 			ea->next_entry_offset = cpu_to_le32(ALIGN(sizeof(*ea) +
 						ea->ea_name_length + 1 +
 						le16_to_cpu(ea->ea_value_length), 4));
-- 
2.43.0

> On Apr 6, 2026, at 21:49, Greg Kroah-Hartman <gregkh@linuxfoundation.org> wrote:
> 
> The bounds check uses (u8 *)ea + nlen + 1 + vlen as the end of the EA
> name and value, but ea_data sits at offset sizeof(struct
> smb2_file_full_ea_info) = 8 from ea, not at offset 0.  The strncmp()
> later reads ea->ea_data[0..nlen-1] and the value bytes follow at
> ea_data[nlen+1..nlen+vlen], so the actual end is ea->ea_data + nlen + 1
> + vlen.  Isn't pointer math fun?
> 
> The earlier check (u8 *)ea > end - sizeof(*ea) only guarantees the
> 8-byte header is in bounds, but since the last EA is placed within 8
> bytes of the end of the response, the name and value bytes are read past
> the end of iov.
> 
> Fix this mess all up by using ea->ea_data as the base for the bounds
> check.
> 
> An "untrusted" server can use this to leak up to 8 bytes of kernel heap
> into the EA name comparison and influence which WSL xattr the data is
> interpreted as.
> 
> Cc: Steve French <sfrench@samba.org>
> Cc: Paulo Alcantara <pc@manguebit.org>
> Cc: Ronnie Sahlberg <ronniesahlberg@gmail.com>
> Cc: Shyam Prasad N <sprasad@microsoft.com>
> Cc: Tom Talpey <tom@talpey.com>
> Cc: Bharath SM <bharathsm@microsoft.com>
> Cc: linux-cifs@vger.kernel.org
> Cc: samba-technical@lists.samba.org
> Cc: stable <stable@kernel.org>
> Assisted-by: gregkh_clanker_t1000
> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> ---
> fs/smb/client/smb2inode.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/fs/smb/client/smb2inode.c b/fs/smb/client/smb2inode.c
> index 364bdcff9c9d..fe1c9d776580 100644
> --- a/fs/smb/client/smb2inode.c
> +++ b/fs/smb/client/smb2inode.c
> @@ -128,7 +128,7 @@ static int check_wsl_eas(struct kvec *rsp_iov)
> 		nlen = ea->ea_name_length;
> 		vlen = le16_to_cpu(ea->ea_value_length);
> 		if (nlen != SMB2_WSL_XATTR_NAME_LEN ||
> -		    (u8 *)ea + nlen + 1 + vlen > end)
> +		    (u8 *)ea->ea_data + nlen + 1 + vlen > end)
> 			return -EINVAL;
> 
> 		switch (vlen) {
> -- 
> 2.53.0
> 
> 
> 
> 


^ permalink raw reply related	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2026-04-08  9:39 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-06 13:49 [PATCH 0/2] smb: some potential bugfixes Greg Kroah-Hartman
2026-04-06 13:49 ` [PATCH 1/2] smb: client: fix off-by-8 bounds check in check_wsl_eas() Greg Kroah-Hartman
2026-04-08  2:51   ` ChenXiaoSong
2026-04-08  5:39     ` Greg Kroah-Hartman
2026-04-08  5:58       ` ChenXiaoSong
2026-04-08  6:15         ` Greg Kroah-Hartman
2026-04-08  6:19           ` ChenXiaoSong
2026-04-08  6:40             ` Greg Kroah-Hartman
2026-04-08  6:52               ` ChenXiaoSong
2026-04-08  6:56                 ` Greg Kroah-Hartman
2026-04-08  9:39   ` Yuanfu Xie
2026-04-06 13:49 ` [PATCH 2/2] smb: client: fix OOB reads parsing symlink error response Greg Kroah-Hartman
2026-04-08  9:01   ` ChenXiaoSong
2026-04-07  3:03 ` [PATCH 0/2] smb: some potential bugfixes Paulo Alcantara
     [not found]   ` <CAH2r5mvXFzWxs70Jmg=yWddmcHs+Bpf8eiBUvyc4oOMLzdCY7w@mail.gmail.com>
2026-04-08  5:45     ` Greg Kroah-Hartman

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox