Re: [PATCH 1/2] smb: client: fix off-by-8 bounds check in check_wsl_eas()

From: ChenXiaoSong

Date: Tue Apr 07 2026 - 22:52:58 EST


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@xxxxxxxxx>
Cc: Paulo Alcantara <pc@xxxxxxxxxxxxx>
Cc: Ronnie Sahlberg <ronniesahlberg@xxxxxxxxx>
Cc: Shyam Prasad N <sprasad@xxxxxxxxxxxxx>
Cc: Tom Talpey <tom@xxxxxxxxxx>
Cc: Bharath SM <bharathsm@xxxxxxxxxxxxx>
Cc: linux-cifs@xxxxxxxxxxxxxxx
Cc: samba-technical@xxxxxxxxxxxxxxx
Cc: stable <stable@xxxxxxxxxx>
Assisted-by: gregkh_clanker_t1000
Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx>
---
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@xxxxxxxxxx>
Chinese Homepage: chenxiaosong.com
English Homepage: chenxiaosong.com/en