From c0e81ec1917582c2deb4a8000e2a2f7a2a4859ed Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Thu, 7 Jan 2021 17:22:42 +0100 Subject: [PATCH 1/2] reproducer for bug 14607 --- source3/smbd/smb2_ioctl.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/source3/smbd/smb2_ioctl.c b/source3/smbd/smb2_ioctl.c index 01ae6d64ac5..8f182f3bbdb 100644 --- a/source3/smbd/smb2_ioctl.c +++ b/source3/smbd/smb2_ioctl.c @@ -284,6 +284,7 @@ static void smbd_smb2_request_ioctl_done(struct tevent_req *subreq) NTSTATUS status; NTSTATUS error; /* transport error */ bool disconnect = false; + size_t padding = 0; status = smbd_smb2_ioctl_recv(subreq, req, &out_output_buffer, @@ -333,6 +334,22 @@ static void smbd_smb2_request_ioctl_done(struct tevent_req *subreq) return; } + { + uint8_t *tmp = NULL; + + padding = 8; + + tmp = talloc_zero_array( + req, uint8_t, out_output_buffer.length + padding); + if (tmp != NULL) { + memcpy(tmp + padding, + out_output_buffer.data, + out_output_buffer.length); + out_output_buffer.data = tmp; + out_output_buffer.length += padding; + } + } + SSVAL(outbody.data, 0x00, 0x30 + 1); /* struct size */ SSVAL(outbody.data, 0x02, 0); /* reserved */ SIVAL(outbody.data, 0x04, @@ -345,9 +362,9 @@ static void smbd_smb2_request_ioctl_done(struct tevent_req *subreq) out_input_offset); /* input offset */ SIVAL(outbody.data, 0x1C, 0); /* input count */ SIVAL(outbody.data, 0x20, - out_output_offset); /* output offset */ + out_output_offset + padding); /* output offset */ SIVAL(outbody.data, 0x24, - out_output_buffer.length); /* output count */ + out_output_buffer.length - padding); /* output count */ SIVAL(outbody.data, 0x28, 0); /* flags */ SIVAL(outbody.data, 0x2C, 0); /* reserved */ -- 2.20.1 From 5d75e46ef4824bf69945ec29d791ce12e443774b Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 15 Dec 2020 11:59:57 +0100 Subject: [PATCH 2/2] libcli/smb/smb2cli_ioctl.c crazy server --- libcli/smb/smb2cli_ioctl.c | 45 ++++++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/libcli/smb/smb2cli_ioctl.c b/libcli/smb/smb2cli_ioctl.c index 2b572baeb23..47dc254e783 100644 --- a/libcli/smb/smb2cli_ioctl.c +++ b/libcli/smb/smb2cli_ioctl.c @@ -212,6 +212,7 @@ static void smb2cli_ioctl_done(struct tevent_req *subreq) .body_size = 0x31 }, }; + bool oob; status = smb2cli_req_recv(subreq, state, &iov, expected, ARRAY_SIZE(expected)); @@ -256,16 +257,15 @@ static void smb2cli_ioctl_done(struct tevent_req *subreq) output_buffer_length = IVAL(fixed, 0x24); if ((input_buffer_offset > 0) && (input_buffer_length > 0)) { - uint32_t ofs; + uint32_t diff_ofs; + uint32_t next_ofs; - if (input_buffer_offset != dyn_ofs) { + if (input_buffer_offset < dyn_ofs) { tevent_req_nterror( req, NT_STATUS_INVALID_NETWORK_RESPONSE); return; } - - ofs = input_buffer_length; - ofs = NDR_ROUND(ofs, 8); + diff_ofs = input_buffer_offset - dyn_ofs; if (state->max_input_length == 0) { /* @@ -278,7 +278,10 @@ static void smb2cli_ioctl_done(struct tevent_req *subreq) input_buffer_length = 0; } - if (input_buffer_length > dyn_len) { + oob = smb_buffer_oob(dyn_ofs + dyn_len, + input_buffer_offset, + input_buffer_length); + if (oob) { tevent_req_nterror( req, NT_STATUS_INVALID_NETWORK_RESPONSE); return; @@ -290,27 +293,38 @@ static void smb2cli_ioctl_done(struct tevent_req *subreq) return; } + dyn_ofs += diff_ofs; + dyn += diff_ofs; + dyn_len -= diff_ofs; + state->out_input_buffer.data = dyn; state->out_input_buffer.length = input_buffer_length; - if (ofs > dyn_len) { + next_ofs = input_buffer_length; + next_ofs = NDR_ROUND(next_ofs, 8); + + if (next_ofs > dyn_len) { tevent_req_nterror( req, NT_STATUS_INVALID_NETWORK_RESPONSE); return; } - dyn_ofs += ofs; - dyn += ofs; - dyn_len -= ofs; + dyn_ofs += next_ofs; + dyn += next_ofs; + dyn_len -= next_ofs; } if ((output_buffer_offset > 0) && (output_buffer_length > 0)) { - if (output_buffer_offset != dyn_ofs) { + uint32_t diff_ofs; + + if (output_buffer_offset < dyn_ofs) { tevent_req_nterror( req, NT_STATUS_INVALID_NETWORK_RESPONSE); return; } + diff_ofs = output_buffer_offset - dyn_ofs; + if (state->max_output_length == 0) { /* * We do the same logic as for @@ -319,7 +333,10 @@ static void smb2cli_ioctl_done(struct tevent_req *subreq) output_buffer_length = 0; } - if (output_buffer_length > dyn_len) { + oob = smb_buffer_oob(dyn_ofs + dyn_len, + output_buffer_offset, + output_buffer_length); + if (oob) { tevent_req_nterror( req, NT_STATUS_INVALID_NETWORK_RESPONSE); return; @@ -331,6 +348,10 @@ static void smb2cli_ioctl_done(struct tevent_req *subreq) return; } + dyn_ofs += diff_ofs; + dyn += diff_ofs; + dyn_len -= diff_ofs; + state->out_output_buffer.data = dyn; state->out_output_buffer.length = output_buffer_length; } -- 2.20.1