ksmbd: validate out_buf_len before FSCTL_CREATE_OR_GET_OBJECT_ID and FSCTL_GET_REPARSE_POINT writes

Both cases write a fixed-size response structure into rsp->Buffer
without first checking that out_buf_len (the space smb2_ioctl()
actually has available, computed by smb2_calc_max_out_buf_len() from
the client's OutputBufferLength minus space already consumed earlier
in a compound request) is large enough. Every comparable case in this
same switch (FSCTL_SRV_ENUMERATE_SNAPSHOTS, FSCTL_GET_COMPRESSION,
FSCTL_VALIDATE_NEGOTIATE_INFO, FSCTL_SRV_REQUEST_RESUME_KEY,
FSCTL_SRV_COPYCHUNK) validates this first; these two don't.

A client can send a compound SMB2 request where an earlier command in
the same compound chain consumes most of work->response_buf, leaving
smb2_calc_max_out_buf_len() only a few bytes of out_buf_len for a
trailing FSCTL_CREATE_OR_GET_OBJECT_ID or FSCTL_GET_REPARSE_POINT.
Both then unconditionally write their full fixed-size structure
(64 bytes and 8 bytes respectively) at rsp->Buffer[0] regardless,
overflowing past the actual remaining space in the response buffer.

Add the same out_buf_len check used by every other fixed-size-response
case in this function, before the write.

Assisted-by: Claude:claude-sonnet-5
Signed-off-by: Gael Blivet <gael.blivet@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
This commit is contained in:
Gael Blivet 2026-07-09 02:01:07 +02:00 committed by Namjae Jeon
parent c1d7bbfc5e
commit 5838cfd611

View File

@ -9396,6 +9396,11 @@ int smb2_ioctl(struct ksmbd_work *work)
struct file_object_buf_type1_ioctl_rsp *obj_buf;
struct ksmbd_file *fp;
if (out_buf_len < sizeof(struct file_object_buf_type1_ioctl_rsp)) {
ret = -EINVAL;
goto out;
}
fp = ksmbd_lookup_fd_fast(work, id);
if (!fp) {
ret = -EBADF;
@ -9591,6 +9596,11 @@ int smb2_ioctl(struct ksmbd_work *work)
struct reparse_data_buffer *reparse_ptr;
struct ksmbd_file *fp;
if (out_buf_len < sizeof(struct reparse_data_buffer)) {
ret = -EINVAL;
goto out;
}
reparse_ptr = (struct reparse_data_buffer *)&rsp->Buffer[0];
fp = ksmbd_lookup_fd_fast(work, id);
if (!fp) {