s3:smb2_ioctl: add more validation checks
authorStefan Metzmacher <metze@samba.org>
Tue, 29 May 2012 11:25:31 +0000 (13:25 +0200)
committerStefan Metzmacher <metze@samba.org>
Tue, 29 May 2012 15:02:13 +0000 (17:02 +0200)
metze

source3/smbd/smb2_ioctl.c

index 521b13119e7c8ed38dfa4a75a807018208e71cbe..c83162e368004ae27fe43417d10031ad1307d2bc 100644 (file)
@@ -46,12 +46,21 @@ NTSTATUS smbd_smb2_request_process_ioctl(struct smbd_smb2_request *req)
        NTSTATUS status;
        const uint8_t *inbody;
        int i = req->current_idx;
+       uint32_t min_buffer_offset;
+       uint32_t max_buffer_offset;
+       uint32_t min_output_offset;
+       uint32_t allowed_length_in;
+       uint32_t allowed_length_out;
        uint32_t in_ctl_code;
        uint64_t in_file_id_persistent;
        uint64_t in_file_id_volatile;
        uint32_t in_input_offset;
        uint32_t in_input_length;
-       DATA_BLOB in_input_buffer;
+       DATA_BLOB in_input_buffer = data_blob_null;
+       uint32_t in_max_input_length;
+       uint32_t in_output_offset;
+       uint32_t in_output_length;
+       DATA_BLOB in_output_buffer = data_blob_null;
        uint32_t in_max_output_length;
        uint32_t in_flags;
        struct tevent_req *subreq;
@@ -67,9 +76,16 @@ NTSTATUS smbd_smb2_request_process_ioctl(struct smbd_smb2_request *req)
        in_file_id_volatile     = BVAL(inbody, 0x10);
        in_input_offset         = IVAL(inbody, 0x18);
        in_input_length         = IVAL(inbody, 0x1C);
+       in_max_input_length     = IVAL(inbody, 0x20);
+       in_output_offset        = IVAL(inbody, 0x24);
+       in_output_length        = IVAL(inbody, 0x28);
        in_max_output_length    = IVAL(inbody, 0x2C);
        in_flags                = IVAL(inbody, 0x30);
 
+       min_buffer_offset = SMB2_HDR_BODY + req->in.vector[i+1].iov_len;
+       max_buffer_offset = min_buffer_offset + req->in.vector[i+2].iov_len;
+       min_output_offset = min_buffer_offset;
+
        /*
         * InputOffset (4 bytes): The offset, in bytes, from the beginning of
         * the SMB2 header to the input data buffer. If no input data is
@@ -78,17 +94,62 @@ NTSTATUS smbd_smb2_request_process_ioctl(struct smbd_smb2_request *req)
         * <49> If no input data is required for the FSCTL/IOCTL command being
         * issued, Windows-based clients set this field to any value.
         */
-       if ((in_input_length > 0)
-        && (in_input_offset != (SMB2_HDR_BODY + req->in.vector[i+1].iov_len))) {
+       allowed_length_in = 0;
+       if ((in_input_offset > 0) && (in_input_length > 0)) {
+               uint32_t tmp_ofs;
+
+               if (in_input_offset < min_buffer_offset) {
+                       return smbd_smb2_request_error(req,
+                                       NT_STATUS_INVALID_PARAMETER);
+               }
+               if (in_input_offset > max_buffer_offset) {
+                       return smbd_smb2_request_error(req,
+                                       NT_STATUS_INVALID_PARAMETER);
+               }
+               allowed_length_in = max_buffer_offset - in_input_offset;
+
+               tmp_ofs = in_input_offset - min_buffer_offset;
+               in_input_buffer.data = (uint8_t *)req->in.vector[i+2].iov_base;
+               in_input_buffer.data += tmp_ofs;
+               in_input_buffer.length = in_input_length;
+               min_output_offset += tmp_ofs;
+               min_output_offset += in_input_length;
+       }
+
+       if (in_input_length > allowed_length_in) {
                return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
        }
 
-       if (in_input_length > req->in.vector[i+2].iov_len) {
+       allowed_length_out = 0;
+       if (in_output_offset > 0) {
+               if (in_output_offset < min_buffer_offset) {
+                       return smbd_smb2_request_error(req,
+                                       NT_STATUS_INVALID_PARAMETER);
+               }
+               if (in_output_offset > max_buffer_offset) {
+                       return smbd_smb2_request_error(req,
+                                       NT_STATUS_INVALID_PARAMETER);
+               }
+               allowed_length_out = max_buffer_offset - in_output_offset;
+       }
+
+       if (in_output_length > allowed_length_out) {
                return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
        }
 
-       in_input_buffer.data = (uint8_t *)req->in.vector[i+2].iov_base;
-       in_input_buffer.length = in_input_length;
+       if (in_output_length > 0) {
+               uint32_t tmp_ofs;
+
+               if (in_output_offset < min_output_offset) {
+                       return smbd_smb2_request_error(req,
+                                       NT_STATUS_INVALID_PARAMETER);
+               }
+
+               tmp_ofs = in_output_offset - min_buffer_offset;
+               in_output_buffer.data = (uint8_t *)req->in.vector[i+2].iov_base;
+               in_output_buffer.data += tmp_ofs;
+               in_output_buffer.length = in_output_length;
+       }
 
        /*
         * If the Flags field of the request is not SMB2_0_IOCTL_IS_FSCTL the