From: Werner Kasselman <werner@verivus.ai>
To: Steve French <smfrench@gmail.com>
Cc: Werner Kasselman <werner@verivus.ai>,
"stable@vger.kernel.org" <stable@vger.kernel.org>
Subject: [PATCH v2 1/1] smb: client: fix OOB read in symlink error response parsing
Date: Tue, 14 Apr 2026 23:24:30 +0000 [thread overview]
Message-ID: <20260414232426.640314-2-werner@verivus.com> (raw)
In-Reply-To: <20260414232426.640314-1-werner@verivus.com>
symlink_data() walks server-supplied SMB2 error contexts to locate the
smb2_symlink_err_rsp before returning it to smb2_parse_symlink_response().
When ErrorContextCount is non-zero, sym can land at an attacker-chosen
offset past the smb2_err_rsp header, bounded only by iov_len.
Reads of err->ErrorContextCount and err->ByteCount occur without checking
that the smb2_err_rsp header and required trailing byte fit in the response
buffer. Reads of p->ErrorId and p->ErrorDataLength in the walk loop occur
without checking that the smb2_error_context_rsp header fits, and sym is
dereferenced for SymLinkErrorTag/ReparseTag without checking that sym itself
fits. A context header placed near iov_end produces an OOB read.
The walk to the next context is also driven by attacker-controlled
ErrorDataLength. Without bounding that step against the remaining response
buffer, p can be advanced outside the response before the next iteration.
The bounds check in smb2_parse_symlink_response() uses the compile-time
SMB2_SYMLINK_STRUCT_SIZE as the base for SubstituteName and PrintName
ranges. That only matches the fixed layout when ErrorContextCount is zero;
with contexts, the actual PathBuffer offset in iov is larger, and the read
of sym->PathBuffer + sub_offs for sub_len bytes can extend past iov_len
into adjacent slab memory. The copied bytes reach userspace via readlink()
on data->symlink_target.
STATUS_STOPPED_ON_SYMLINK responses are served from the 448-byte small
buffer pool, so the overread reliably crosses the slab object boundary.
Validate the smb2_err_rsp header before reading its fields, bound each
context header and each step to the next context during the walk, verify
sym fits in the response before dereferencing its length fields, and
compute the PathBuffer bound from sym->PathBuffer's actual offset into iov.
Fixes: 76894f3e2f71 ("cifs: improve symlink handling for smb2+")
Cc: stable@vger.kernel.org
Signed-off-by: Werner Kasselman <werner@verivus.com>
---
fs/smb/client/smb2file.c | 34 ++++++++++++++++++++++++++--------
1 file changed, 26 insertions(+), 8 deletions(-)
diff --git a/fs/smb/client/smb2file.c b/fs/smb/client/smb2file.c
index ed651c946251..6680c8a0ccc9 100644
--- a/fs/smb/client/smb2file.c
+++ b/fs/smb/client/smb2file.c
@@ -29,8 +29,12 @@ static struct smb2_symlink_err_rsp *symlink_data(const struct kvec *iov)
struct smb2_symlink_err_rsp *sym = ERR_PTR(-EINVAL);
u32 len;
+ if (iov->iov_len < offsetof(struct smb2_err_rsp, ErrorData) + 1)
+ return ERR_PTR(-EINVAL);
+
if (err->ErrorContextCount) {
- struct smb2_error_context_rsp *p, *end;
+ struct smb2_error_context_rsp *p;
+ u8 *end;
len = (u32)err->ErrorContextCount * (offsetof(struct smb2_error_context_rsp,
ErrorContextData) +
@@ -39,8 +43,10 @@ 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);
+ end = (u8 *)err + iov->iov_len;
do {
+ if ((u8 *)p + sizeof(*p) > end)
+ return ERR_PTR(-EINVAL);
if (le32_to_cpu(p->ErrorId) == SMB2_ERROR_ID_DEFAULT) {
sym = (struct smb2_symlink_err_rsp *)p->ErrorContextData;
break;
@@ -49,16 +55,24 @@ static struct smb2_symlink_err_rsp *symlink_data(const struct kvec *iov)
__func__, le32_to_cpu(p->ErrorId));
len = ALIGN(le32_to_cpu(p->ErrorDataLength), 8);
+ if (len > end - p->ErrorContextData)
+ return ERR_PTR(-EINVAL);
p = (struct smb2_error_context_rsp *)(p->ErrorContextData + len);
- } while (p < end);
+ } while ((u8 *)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))
- sym = ERR_PTR(-EINVAL);
+ if (IS_ERR(sym))
+ return sym;
+
+ if ((u8 *)sym + sizeof(*sym) > (u8 *)err + iov->iov_len)
+ return ERR_PTR(-EINVAL);
+
+ if (le32_to_cpu(sym->SymLinkErrorTag) != SYMLINK_ERROR_TAG ||
+ le32_to_cpu(sym->ReparseTag) != IO_REPARSE_TAG_SYMLINK)
+ return ERR_PTR(-EINVAL);
return sym;
}
@@ -115,6 +129,7 @@ int smb2_parse_symlink_response(struct cifs_sb_info *cifs_sb, const struct kvec
struct smb2_symlink_err_rsp *sym;
unsigned int sub_offs, sub_len;
unsigned int print_offs, print_len;
+ size_t pathbuf_off;
if (!cifs_sb || !iov || !iov->iov_base || !iov->iov_len || !path)
return -EINVAL;
@@ -128,8 +143,11 @@ 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)
+ pathbuf_off = (const u8 *)sym->PathBuffer - (const u8 *)iov->iov_base;
+
+ if (pathbuf_off > iov->iov_len ||
+ iov->iov_len - pathbuf_off < sub_offs + sub_len ||
+ iov->iov_len - pathbuf_off < print_offs + print_len)
return -EINVAL;
return smb2_parse_native_symlink(path,
--
2.43.0
parent reply other threads:[~2026-04-14 23:24 UTC|newest]
Thread overview: expand[flat|nested] mbox.gz Atom feed
[parent not found: <20260414232426.640314-1-werner@verivus.com>]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260414232426.640314-2-werner@verivus.com \
--to=werner@verivus.ai \
--cc=smfrench@gmail.com \
--cc=stable@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox