[PATCH 4/8] ksmbd: validate out_buf_len before FSCTL_CREATE_OR_GET_OBJECT_ID and FSCTL_GET_REPARSE_POINT writes
"Gaël Blivet-Bailly" <[email protected]>
| Newsgroups | org.kernel.vger.linux-cifs |
|---|---|
| Message-ID | <[email protected]> |
From: Gael Blivet <[email protected]> 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. Signed-off-by: Gael Blivet <[email protected]> --- fs/smb/server/smb2pdu.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index 190fde409..ffdae74b6 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -9390,6 +9390,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; @@ -9585,6 +9590,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) { -- 2.43.0