[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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.