[PATCH v3 2/2] smb: client: validate POSIX create context length

From: Zihan Xi

Date: Fri Sep 04 2026 - 10:17:20 EST


parse_posix_ctxt() reads the fixed nlink, reparse-tag, and mode fields
before checking that the POSIX create context contains them. A short
context can pass the generic create-context checks and still make these
fixed-width reads run past the declared data.

The current in-tree smb2_open_file() path passes a NULL posix pointer,
so this handler is not reached on ordinary open. Still require the
POSIX context data to cover the three fixed fields before reading them,
because the helper itself performs those unguarded reads. Keep the
handler's existing soft-failure behavior for malformed metadata so a
bad optional context does not fail the open.

Fixes: 69dda3059e7a ("cifs: add SMB2_open() arg to return POSIX data")
Cc: stable@xxxxxxxxxxxxxxx
Reported-by: Vega <vega@xxxxxxxxxx>
Assisted-by: LLM
Signed-off-by: Zihan Xi <zihanx@xxxxxxxxxx>
---
changes in v3:
- Resend after no response on v2; no functional code changes.
- v2 Link: https://lore.kernel.org/all/cover.1787486936.git.zihanx@xxxxxxxxxx/
changes in v2:
- Add a handler-level DataLength check before reading the three fixed POSIX fields.
- Attribute the fixed-field read to the POSIX create-context introduction.
- Preserve the existing soft-failure behavior for malformed optional metadata.
- v1 Link: https://lore.kernel.org/all/eb1bc35611f91bd10a4772400b37fac26f660956.1782579150.git.xizh2024@xxxxxxxxxx/
---
fs/smb/client/smb2pdu.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c
index 95d862a1241be..e3973d331633d 100644
--- a/fs/smb/client/smb2pdu.c
+++ b/fs/smb/client/smb2pdu.c
@@ -2405,11 +2405,14 @@ parse_posix_ctxt(struct create_context *cc, struct smb2_file_all_info *info,
struct create_posix_rsp *posix)
{
int sid_len;
+ u32 dlen = le32_to_cpu(cc->DataLength);
u8 *beg = (u8 *)cc + le16_to_cpu(cc->DataOffset);
- u8 *end = beg + le32_to_cpu(cc->DataLength);
+ u8 *end = beg + dlen;
u8 *sid;

memset(posix, 0, sizeof(*posix));
+ if (dlen < 3 * sizeof(__le32))
+ return;

posix->nlink = get_unaligned_le32(beg);
posix->reparse_tag = get_unaligned_le32(beg + 4);

--
2.43.0