From df35438ba9d5687335a405418772b6cd30383687 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Sun, 5 Jul 2026 00:13:18 +0900 Subject: [PATCH] ksmbd: validate SMB2 write offsets An SMB2 WRITE request with a negative offset returns -EINVAL directly from smb2_write(). This bypasses the common error response path, leaving the client waiting until the request times out. ksmbd also allows nonempty writes at or beyond MAXFILESIZE as defined by [MS-FSA]. Writes beyond the limit must fail with STATUS_INVALID_PARAMETER. Writes ending at the limit fail with STATUS_DISK_FULL, while a zero-length write remains valid. Route negative offsets through the common error path and validate the end offset of nonempty writes against MAXFILESIZE. This fixes smb2.rw.invalid. Signed-off-by: Namjae Jeon --- fs/smb/server/smb2pdu.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index b30bdeaa8eb7..42660f7ab063 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -64,6 +64,9 @@ static void __wbuf(struct ksmbd_work *work, void **req, void **rsp) /* Windows reports automatic write-time updates at roughly 15 ms resolution. */ #define KSMBD_WRITE_TIME_RESOLUTION (15ULL * 10000) +/* MAXFILESIZE in [MS-FSA] 2.1.5.3 Server Requests a Write. */ +#define SMB2_MAX_FILE_SIZE 0xfffffff0000ULL + /** * check_session_id() - check for valid session id in smb header * @conn: connection instance @@ -7685,8 +7688,10 @@ int smb2_write(struct ksmbd_work *work) } offset = le64_to_cpu(req->Offset); - if (offset < 0) - return -EINVAL; + if (offset < 0) { + err = -EINVAL; + goto out; + } length = le32_to_cpu(req->Length); if (req->Channel == SMB2_CHANNEL_RDMA_V1 || @@ -7700,6 +7705,19 @@ int smb2_write(struct ksmbd_work *work) length = le32_to_cpu(req->RemainingBytes); } + if (length) { + u64 end = (u64)offset + length; + + if (end > SMB2_MAX_FILE_SIZE) { + err = -EINVAL; + goto out; + } + if (end == SMB2_MAX_FILE_SIZE) { + err = -EFBIG; + goto out; + } + } + if (is_rdma_channel == true) { unsigned int ch_offset = le16_to_cpu(req->WriteChannelInfoOffset);