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 <linkinjeon@kernel.org>
This commit is contained in:
Namjae Jeon 2026-07-05 00:13:18 +09:00
parent 7019a11f79
commit df35438ba9

View File

@ -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);