From 804bd0acf8f9e48bc855e17604c576d7d52aaa03 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 6 Jul 2021 16:24:59 +0200 Subject: [PATCH 1/5] s4:torture/smb2: add smb2.read.bug14607 test This test will use a FSCTL_SMBTORTURE_GLOBAL_READ_RESPONSE_BODY_PADDING8 in order to change the server behavior of READ responses regarding the data offset. It will demonstrate the problem in smb2cli_read*() triggered by NetApp Ontap servers. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14607 Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison (cherry picked from commit b3c9823d907b91632679e6f0ffce1b7192e4b9b6) --- libcli/smb/smb_constants.h | 2 + source4/torture/smb2/read.c | 136 ++++++++++++++++++++++++++++++++++++ 2 files changed, 138 insertions(+) diff --git a/libcli/smb/smb_constants.h b/libcli/smb/smb_constants.h index d2345f094e10..af8e7204013b 100644 --- a/libcli/smb/smb_constants.h +++ b/libcli/smb/smb_constants.h @@ -591,6 +591,8 @@ enum csc_policy { (FSCTL_SMBTORTURE | FSCTL_ACCESS_WRITE | 0x0000 | FSCTL_METHOD_NEITHER) #define FSCTL_SMBTORTURE_IOCTL_RESPONSE_BODY_PADDING8 \ (FSCTL_SMBTORTURE | FSCTL_ACCESS_WRITE | 0x0010 | FSCTL_METHOD_NEITHER) +#define FSCTL_SMBTORTURE_GLOBAL_READ_RESPONSE_BODY_PADDING8 \ + (FSCTL_SMBTORTURE | FSCTL_ACCESS_WRITE | 0x0020 | FSCTL_METHOD_NEITHER) /* * A few values from [MS-FSCC] 2.1.2.1 Reparse Tags diff --git a/source4/torture/smb2/read.c b/source4/torture/smb2/read.c index 2899a491663b..2bc0dc98bbac 100644 --- a/source4/torture/smb2/read.c +++ b/source4/torture/smb2/read.c @@ -26,6 +26,8 @@ #include "torture/torture.h" #include "torture/smb2/proto.h" +#include "../libcli/smb/smbXcli_base.h" +#include "librpc/gen_ndr/ndr_ioctl.h" #define CHECK_STATUS(_status, _expected) \ @@ -303,6 +305,138 @@ done: return ret; } +/* + basic regression test for BUG 14607 + https://bugzilla.samba.org/show_bug.cgi?id=14607 +*/ +static bool test_read_bug14607(struct torture_context *torture, + struct smb2_tree *tree) +{ + bool ret = true; + NTSTATUS status; + struct smb2_handle h; + uint8_t buf[64 * 1024]; + struct smb2_read rd; + uint32_t timeout_msec; + DATA_BLOB out_input_buffer = data_blob_null; + DATA_BLOB out_output_buffer = data_blob_null; + TALLOC_CTX *tmp_ctx = talloc_new(tree); + uint8_t *data = NULL; + uint32_t data_length = 0; + + memset(buf, 0x1f, ARRAY_SIZE(buf)); + + /* create a file */ + smb2_util_unlink(tree, FNAME); + + status = torture_smb2_testfile(tree, FNAME, &h); + CHECK_STATUS(status, NT_STATUS_OK); + + status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf)); + CHECK_STATUS(status, NT_STATUS_OK); + + ZERO_STRUCT(rd); + rd.in.file.handle = h; + rd.in.length = ARRAY_SIZE(buf); + rd.in.offset = 0; + status = smb2_read(tree, tree, &rd); + CHECK_STATUS(status, NT_STATUS_OK); + CHECK_VALUE(rd.out.data.length, ARRAY_SIZE(buf)); + torture_assert_mem_equal_goto(torture, rd.out.data.data, + buf, ARRAY_SIZE(buf), + ret, done, + "Invalid content smb2_read"); + + timeout_msec = tree->session->transport->options.request_timeout * 1000; + + status = smb2cli_read(tree->session->transport->conn, + timeout_msec, + tree->session->smbXcli, + tree->smbXcli, + rd.in.length, + rd.in.offset, + h.data[0], + h.data[1], + rd.in.min_count, + rd.in.remaining, + tmp_ctx, + &data, &data_length); + CHECK_STATUS(status, NT_STATUS_OK); + CHECK_VALUE(data_length, ARRAY_SIZE(buf)); + torture_assert_mem_equal_goto(torture, data, + buf, ARRAY_SIZE(buf), + ret, done, + "Invalid content smb2cli_read"); + + status = smb2cli_ioctl(tree->session->transport->conn, + timeout_msec, + tree->session->smbXcli, + tree->smbXcli, + UINT64_MAX, /* in_fid_persistent */ + UINT64_MAX, /* in_fid_volatile */ + FSCTL_SMBTORTURE_GLOBAL_READ_RESPONSE_BODY_PADDING8, + 0, /* in_max_input_length */ + NULL, /* in_input_buffer */ + 1, /* in_max_output_length */ + NULL, /* in_output_buffer */ + SMB2_IOCTL_FLAG_IS_FSCTL, + tmp_ctx, + &out_input_buffer, + &out_output_buffer); + if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED) || + NT_STATUS_EQUAL(status, NT_STATUS_FILE_CLOSED) || + NT_STATUS_EQUAL(status, NT_STATUS_FS_DRIVER_REQUIRED) || + NT_STATUS_EQUAL(status, NT_STATUS_INVALID_DEVICE_REQUEST)) + { + torture_comment(torture, + "FSCTL_SMBTORTURE_GLOBAL_READ_RESPONSE_BODY_PADDING8: %s\n", + nt_errstr(status)); + torture_skip(torture, "server doesn't support FSCTL_SMBTORTURE_GLOBAL_READ_RESPONSE_BODY_PADDING8\n"); + } + torture_assert_ntstatus_ok(torture, status, "FSCTL_SMBTORTURE_GLOBAL_READ_RESPONSE_BODY_PADDING8"); + + torture_assert_int_equal(torture, out_output_buffer.length, 0, + "output length"); + + ZERO_STRUCT(rd); + rd.in.file.handle = h; + rd.in.length = ARRAY_SIZE(buf); + rd.in.offset = 0; + status = smb2_read(tree, tree, &rd); + CHECK_STATUS(status, NT_STATUS_OK); + CHECK_VALUE(rd.out.data.length, ARRAY_SIZE(buf)); + torture_assert_mem_equal_goto(torture, rd.out.data.data, + buf, ARRAY_SIZE(buf), + ret, done, + "Invalid content after padding smb2_read"); + + status = smb2cli_read(tree->session->transport->conn, + timeout_msec, + tree->session->smbXcli, + tree->smbXcli, + rd.in.length, + rd.in.offset, + h.data[0], + h.data[1], + rd.in.min_count, + rd.in.remaining, + tmp_ctx, + &data, &data_length); + CHECK_STATUS(status, NT_STATUS_OK); + CHECK_VALUE(data_length, ARRAY_SIZE(buf)); + torture_assert_mem_equal_goto(torture, data, + buf, ARRAY_SIZE(buf), + ret, done, + "Invalid content after padding smb2cli_read"); + + status = smb2_util_close(tree, h); + CHECK_STATUS(status, NT_STATUS_OK); + +done: + talloc_free(tmp_ctx); + return ret; +} + /* basic testing of SMB2 read */ @@ -314,6 +448,8 @@ struct torture_suite *torture_smb2_read_init(TALLOC_CTX *ctx) torture_suite_add_1smb2_test(suite, "position", test_read_position); torture_suite_add_1smb2_test(suite, "dir", test_read_dir); torture_suite_add_1smb2_test(suite, "access", test_read_access); + torture_suite_add_1smb2_test(suite, "bug14607", + test_read_bug14607); suite->description = talloc_strdup(suite, "SMB2-READ tests"); -- 2.25.1 From 0a99284dac30a36f89119f3e325a13cc61fc491d Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 5 Jul 2021 17:49:00 +0200 Subject: [PATCH 2/5] s3:smbd: introduce a body_size variable in smbd_smb2_request_read_done This will simplify the following changes. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14607 Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison (cherry picked from commit 5ecac656fde4e81aa6e51e7b3134ea3fb75f564a) --- source3/smbd/smb2_read.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/source3/smbd/smb2_read.c b/source3/smbd/smb2_read.c index cd590a52c951..8372188f58d7 100644 --- a/source3/smbd/smb2_read.c +++ b/source3/smbd/smb2_read.c @@ -116,6 +116,7 @@ static void smbd_smb2_request_read_done(struct tevent_req *subreq) { struct smbd_smb2_request *req = tevent_req_callback_data(subreq, struct smbd_smb2_request); + uint16_t body_size; DATA_BLOB outbody; DATA_BLOB outdyn; uint8_t out_data_offset; @@ -139,9 +140,10 @@ static void smbd_smb2_request_read_done(struct tevent_req *subreq) return; } - out_data_offset = SMB2_HDR_BODY + 0x10; + body_size = 0x10; + out_data_offset = SMB2_HDR_BODY + body_size; - outbody = smbd_smb2_generate_outbody(req, 0x10); + outbody = smbd_smb2_generate_outbody(req, body_size); if (outbody.data == NULL) { error = smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY); if (!NT_STATUS_IS_OK(error)) { -- 2.25.1 From fab9cf3acd25557eb1ceeb89d9a1c0c537f36d82 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 5 Jul 2021 17:49:00 +0200 Subject: [PATCH 3/5] s3:smbd: implement FSCTL_SMBTORTURE_GLOBAL_READ_RESPONSE_BODY_PADDING8 This turns the 'smb2.read.bug14607' test from 'skip' into 'xfailure', as the 2nd smb2cli_read() function will now return NT_STATUS_INVALID_NETWORK_RESPONSE. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14607 Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison (cherry picked from commit ef57fba5dbf359b204ba952451e1e33ed68f1c91) --- selftest/knownfail.d/smb2-read-bug14607 | 1 + source3/smbd/globals.h | 4 ++++ source3/smbd/smb2_ioctl.c | 10 ++++++++++ source3/smbd/smb2_read.c | 10 +++++++++- 4 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 selftest/knownfail.d/smb2-read-bug14607 diff --git a/selftest/knownfail.d/smb2-read-bug14607 b/selftest/knownfail.d/smb2-read-bug14607 new file mode 100644 index 000000000000..05b8adfa8cd9 --- /dev/null +++ b/selftest/knownfail.d/smb2-read-bug14607 @@ -0,0 +1 @@ +samba3.smb2.read.bug14607 diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h index fcf33a699c68..ae935f413e04 100644 --- a/source3/smbd/globals.h +++ b/source3/smbd/globals.h @@ -534,6 +534,10 @@ struct smbXsrv_connection { struct smbXsrv_preauth preauth; struct smbd_smb2_request *requests; + + struct { + uint8_t read_body_padding; + } smbtorture; } smb2; }; diff --git a/source3/smbd/smb2_ioctl.c b/source3/smbd/smb2_ioctl.c index 8b65a6916386..d29ff5d0303b 100644 --- a/source3/smbd/smb2_ioctl.c +++ b/source3/smbd/smb2_ioctl.c @@ -197,6 +197,7 @@ NTSTATUS smbd_smb2_request_process_ioctl(struct smbd_smb2_request *req) case FSCTL_QUERY_NETWORK_INTERFACE_INFO: case FSCTL_SMBTORTURE_FORCE_UNACKED_TIMEOUT: case FSCTL_SMBTORTURE_IOCTL_RESPONSE_BODY_PADDING8: + case FSCTL_SMBTORTURE_GLOBAL_READ_RESPONSE_BODY_PADDING8: /* * Some SMB2 specific CtlCodes like FSCTL_DFS_GET_REFERRALS or * FSCTL_PIPE_WAIT does not take a file handle. @@ -424,6 +425,15 @@ static struct tevent_req *smb2_ioctl_smbtorture(uint32_t ctl_code, tevent_req_done(req); return tevent_req_post(req, ev); + case FSCTL_SMBTORTURE_GLOBAL_READ_RESPONSE_BODY_PADDING8: + if (state->in_input.length != 0) { + tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); + return tevent_req_post(req, ev); + } + + state->smb2req->xconn->smb2.smbtorture.read_body_padding = 8; + tevent_req_done(req); + return tevent_req_post(req, ev); default: goto not_supported; } diff --git a/source3/smbd/smb2_read.c b/source3/smbd/smb2_read.c index 8372188f58d7..a846215b0eca 100644 --- a/source3/smbd/smb2_read.c +++ b/source3/smbd/smb2_read.c @@ -117,6 +117,7 @@ static void smbd_smb2_request_read_done(struct tevent_req *subreq) struct smbd_smb2_request *req = tevent_req_callback_data(subreq, struct smbd_smb2_request); uint16_t body_size; + uint8_t body_padding = req->xconn->smb2.smbtorture.read_body_padding; DATA_BLOB outbody; DATA_BLOB outdyn; uint8_t out_data_offset; @@ -140,7 +141,11 @@ static void smbd_smb2_request_read_done(struct tevent_req *subreq) return; } - body_size = 0x10; + /* + * Only FSCTL_SMBTORTURE_GLOBAL_READ_RESPONSE_BODY_PADDING8 + * sets body_padding to a value different from 0. + */ + body_size = 0x10 + body_padding; out_data_offset = SMB2_HDR_BODY + body_size; outbody = smbd_smb2_generate_outbody(req, body_size); @@ -163,6 +168,9 @@ static void smbd_smb2_request_read_done(struct tevent_req *subreq) SIVAL(outbody.data, 0x08, out_data_remaining); /* data remaining */ SIVAL(outbody.data, 0x0C, 0); /* reserved */ + if (body_padding != 0) { + memset(outbody.data + 0x10, 0, body_padding); + } outdyn = out_data_buffer; -- 2.25.1 From bff1a9451bfb388c81a8fb80e99249bd33954838 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 29 Jun 2021 15:24:13 +0200 Subject: [PATCH 4/5] libcli/smb: make smb2cli_ioctl_parse_buffer() available as smb2cli_parse_dyn_buffer() It will be used in smb2cli_read.c soon... BUG: https://bugzilla.samba.org/show_bug.cgi?id=14607 Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison (cherry picked from commit 1faf15b3d0f41fa8a94b76d1616a4460ce0c6fa4) --- libcli/smb/smb2cli_ioctl.c | 123 +++++-------------------------------- libcli/smb/smbXcli_base.c | 91 +++++++++++++++++++++++++++ libcli/smb/smbXcli_base.h | 9 +++ 3 files changed, 116 insertions(+), 107 deletions(-) diff --git a/libcli/smb/smb2cli_ioctl.c b/libcli/smb/smb2cli_ioctl.c index f9abcc57bab3..d638b2816780 100644 --- a/libcli/smb/smb2cli_ioctl.c +++ b/libcli/smb/smb2cli_ioctl.c @@ -160,97 +160,6 @@ struct tevent_req *smb2cli_ioctl_send(TALLOC_CTX *mem_ctx, return req; } -static NTSTATUS smb2cli_ioctl_parse_buffer(uint32_t dyn_offset, - const DATA_BLOB dyn_buffer, - uint32_t min_offset, - uint32_t buffer_offset, - uint32_t buffer_length, - uint32_t max_length, - uint32_t *next_offset, - DATA_BLOB *buffer) -{ - uint32_t offset; - bool oob; - - *buffer = data_blob_null; - *next_offset = dyn_offset; - - if (buffer_offset == 0) { - /* - * If the offset is 0, we better ignore - * the buffer_length field. - */ - return NT_STATUS_OK; - } - - if (buffer_length == 0) { - /* - * If the length is 0, we better ignore - * the buffer_offset field. - */ - return NT_STATUS_OK; - } - - if ((buffer_offset % 8) != 0) { - /* - * The offset needs to be 8 byte aligned. - */ - return NT_STATUS_INVALID_NETWORK_RESPONSE; - } - - /* - * We used to enforce buffer_offset to be - * an exact match of the expected minimum, - * but the NetApp Ontap 7.3.7 SMB server - * gets the padding wrong and aligns the - * input_buffer_offset by a value of 8. - * - * So we just enforce that the offset is - * not lower than the expected value. - */ - SMB_ASSERT(min_offset >= dyn_offset); - if (buffer_offset < min_offset) { - return NT_STATUS_INVALID_NETWORK_RESPONSE; - } - - /* - * Make [input|output]_buffer_offset relative to "dyn_buffer" - */ - offset = buffer_offset - dyn_offset; - oob = smb_buffer_oob(dyn_buffer.length, offset, buffer_length); - if (oob) { - return NT_STATUS_INVALID_NETWORK_RESPONSE; - } - - /* - * Give the caller a hint what we consumed, - * the caller may need to add possible padding. - */ - *next_offset = buffer_offset + buffer_length; - - if (max_length == 0) { - /* - * If max_input_length is 0 we ignore the - * input_buffer_length, because Windows 2008 echos the - * DCERPC request from the requested input_buffer to - * the response input_buffer. - * - * We just use the same logic also for max_output_length... - */ - buffer_length = 0; - } - - if (buffer_length > max_length) { - return NT_STATUS_INVALID_NETWORK_RESPONSE; - } - - *buffer = (DATA_BLOB) { - .data = dyn_buffer.data + offset, - .length = buffer_length, - }; - return NT_STATUS_OK; -} - static void smb2cli_ioctl_done(struct tevent_req *subreq) { struct tevent_req *req = @@ -352,14 +261,14 @@ static void smb2cli_ioctl_done(struct tevent_req *subreq) input_min_offset = dyn_ofs; input_next_offset = dyn_ofs; - error = smb2cli_ioctl_parse_buffer(dyn_ofs, - dyn_buffer, - input_min_offset, - input_buffer_offset, - input_buffer_length, - state->max_input_length, - &input_next_offset, - &state->out_input_buffer); + error = smb2cli_parse_dyn_buffer(dyn_ofs, + dyn_buffer, + input_min_offset, + input_buffer_offset, + input_buffer_length, + state->max_input_length, + &input_next_offset, + &state->out_input_buffer); if (tevent_req_nterror(req, error)) { return; } @@ -370,14 +279,14 @@ static void smb2cli_ioctl_done(struct tevent_req *subreq) */ output_min_offset = NDR_ROUND(input_next_offset, 8); output_next_offset = 0; /* this variable is completely ignored */ - error = smb2cli_ioctl_parse_buffer(dyn_ofs, - dyn_buffer, - output_min_offset, - output_buffer_offset, - output_buffer_length, - state->max_output_length, - &output_next_offset, - &state->out_output_buffer); + error = smb2cli_parse_dyn_buffer(dyn_ofs, + dyn_buffer, + output_min_offset, + output_buffer_offset, + output_buffer_length, + state->max_output_length, + &output_next_offset, + &state->out_output_buffer); if (tevent_req_nterror(req, error)) { return; } diff --git a/libcli/smb/smbXcli_base.c b/libcli/smb/smbXcli_base.c index 4909797543c1..bcb601dde59c 100644 --- a/libcli/smb/smbXcli_base.c +++ b/libcli/smb/smbXcli_base.c @@ -6664,3 +6664,94 @@ uint64_t smb2cli_conn_get_mid(struct smbXcli_conn *conn) { return conn->smb2.mid; } + +NTSTATUS smb2cli_parse_dyn_buffer(uint32_t dyn_offset, + const DATA_BLOB dyn_buffer, + uint32_t min_offset, + uint32_t buffer_offset, + uint32_t buffer_length, + uint32_t max_length, + uint32_t *next_offset, + DATA_BLOB *buffer) +{ + uint32_t offset; + bool oob; + + *buffer = data_blob_null; + *next_offset = dyn_offset; + + if (buffer_offset == 0) { + /* + * If the offset is 0, we better ignore + * the buffer_length field. + */ + return NT_STATUS_OK; + } + + if (buffer_length == 0) { + /* + * If the length is 0, we better ignore + * the buffer_offset field. + */ + return NT_STATUS_OK; + } + + if ((buffer_offset % 8) != 0) { + /* + * The offset needs to be 8 byte aligned. + */ + return NT_STATUS_INVALID_NETWORK_RESPONSE; + } + + /* + * We used to enforce buffer_offset to be + * an exact match of the expected minimum, + * but the NetApp Ontap 7.3.7 SMB server + * gets the padding wrong and aligns the + * input_buffer_offset by a value of 8. + * + * So we just enforce that the offset is + * not lower than the expected value. + */ + SMB_ASSERT(min_offset >= dyn_offset); + if (buffer_offset < min_offset) { + return NT_STATUS_INVALID_NETWORK_RESPONSE; + } + + /* + * Make [input|output]_buffer_offset relative to "dyn_buffer" + */ + offset = buffer_offset - dyn_offset; + oob = smb_buffer_oob(dyn_buffer.length, offset, buffer_length); + if (oob) { + return NT_STATUS_INVALID_NETWORK_RESPONSE; + } + + /* + * Give the caller a hint what we consumed, + * the caller may need to add possible padding. + */ + *next_offset = buffer_offset + buffer_length; + + if (max_length == 0) { + /* + * If max_input_length is 0 we ignore the + * input_buffer_length, because Windows 2008 echos the + * DCERPC request from the requested input_buffer to + * the response input_buffer. + * + * We just use the same logic also for max_output_length... + */ + buffer_length = 0; + } + + if (buffer_length > max_length) { + return NT_STATUS_INVALID_NETWORK_RESPONSE; + } + + *buffer = (DATA_BLOB) { + .data = dyn_buffer.data + offset, + .length = buffer_length, + }; + return NT_STATUS_OK; +} diff --git a/libcli/smb/smbXcli_base.h b/libcli/smb/smbXcli_base.h index 2afc7165cd97..4452cd808ea1 100644 --- a/libcli/smb/smbXcli_base.h +++ b/libcli/smb/smbXcli_base.h @@ -390,6 +390,15 @@ void smb2cli_conn_set_cc_max_chunks(struct smbXcli_conn *conn, void smb2cli_conn_set_mid(struct smbXcli_conn *conn, uint64_t mid); uint64_t smb2cli_conn_get_mid(struct smbXcli_conn *conn); +NTSTATUS smb2cli_parse_dyn_buffer(uint32_t dyn_offset, + const DATA_BLOB dyn_buffer, + uint32_t min_offset, + uint32_t buffer_offset, + uint32_t buffer_length, + uint32_t max_length, + uint32_t *next_offset, + DATA_BLOB *buffer); + struct tevent_req *smb2cli_req_create(TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct smbXcli_conn *conn, -- 2.25.1 From 794bf156fae570e6cdc9d3680ac4d6599d85ec1e Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 29 Jun 2021 15:42:56 +0200 Subject: [PATCH 5/5] libcli/smb: allow unexpected padding in SMB2 READ responses Make use of smb2cli_parse_dyn_buffer() in smb2cli_read_done() as it was exactly introduced for a similar problem see: commit 4c6c71e1378401d66bf2ed230544a75f7b04376f Author: Stefan Metzmacher AuthorDate: Thu Jan 14 17:32:15 2021 +0100 Commit: Volker Lendecke CommitDate: Fri Jan 15 08:36:34 2021 +0000 libcli/smb: allow unexpected padding in SMB2 IOCTL responses A NetApp Ontap 7.3.7 SMB server add 8 padding bytes to an offset that's already 8 byte aligned. RN: Work around special SMB2 IOCTL response behavior of NetApp Ontap 7.3.7 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14607 Pair-Programmed-With: Volker Lendecke Signed-off-by: Stefan Metzmacher Signed-off-by: Volker Lendecke Autobuild-User(master): Volker Lendecke Autobuild-Date(master): Fri Jan 15 08:36:34 UTC 2021 on sn-devel-184 RN: Work around special SMB2 READ response behavior of NetApp Ontap 7.3.7 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14607 Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison Autobuild-User(master): Jeremy Allison Autobuild-Date(master): Thu Jul 15 23:53:55 UTC 2021 on sn-devel-184 (cherry picked from commit 155348cda65b441a6c4db1ed84dbf1682d02973c) --- libcli/smb/smb2cli_read.c | 22 ++++++++++++++++++---- selftest/knownfail.d/smb2-read-bug14607 | 1 - 2 files changed, 18 insertions(+), 5 deletions(-) delete mode 100644 selftest/knownfail.d/smb2-read-bug14607 diff --git a/libcli/smb/smb2cli_read.c b/libcli/smb/smb2cli_read.c index 8110b65d4322..c7f48741b875 100644 --- a/libcli/smb/smb2cli_read.c +++ b/libcli/smb/smb2cli_read.c @@ -90,8 +90,13 @@ static void smb2cli_read_done(struct tevent_req *subreq) tevent_req_data(req, struct smb2cli_read_state); NTSTATUS status; + NTSTATUS error; struct iovec *iov; + const uint8_t dyn_ofs = SMB2_HDR_BODY + 0x10; + DATA_BLOB dyn_buffer = data_blob_null; uint8_t data_offset; + DATA_BLOB data_buffer = data_blob_null; + uint32_t next_offset = 0; /* this variable is completely ignored */ static const struct smb2cli_req_expected_response expected[] = { { .status = STATUS_BUFFER_OVERFLOW, @@ -117,14 +122,23 @@ static void smb2cli_read_done(struct tevent_req *subreq) data_offset = CVAL(iov[1].iov_base, 2); state->data_length = IVAL(iov[1].iov_base, 4); - if ((data_offset != SMB2_HDR_BODY + 16) || - (state->data_length > iov[2].iov_len)) { - tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); + dyn_buffer = data_blob_const((uint8_t *)iov[2].iov_base, + iov[2].iov_len); + + error = smb2cli_parse_dyn_buffer(dyn_ofs, + dyn_buffer, + dyn_ofs, /* min_offset */ + data_offset, + state->data_length, + dyn_buffer.length, /* max_length */ + &next_offset, + &data_buffer); + if (tevent_req_nterror(req, error)) { return; } state->recv_iov = iov; - state->data = (uint8_t *)iov[2].iov_base; + state->data = data_buffer.data; state->out_valid = true; diff --git a/selftest/knownfail.d/smb2-read-bug14607 b/selftest/knownfail.d/smb2-read-bug14607 deleted file mode 100644 index 05b8adfa8cd9..000000000000 --- a/selftest/knownfail.d/smb2-read-bug14607 +++ /dev/null @@ -1 +0,0 @@ -samba3.smb2.read.bug14607 -- 2.25.1