[PATCH] smbXcli_base plumbing and torture tests for SMB2 credits
Jeremy Allison
jra at samba.org
Fri Mar 3 20:55:45 UTC 2017
On Fri, Mar 03, 2017 at 04:20:34PM +0100, Ralph Böhme wrote:
> Hi!
>
> I thought it would be nice to have some tests for SMB2 creditting, so I started
> to work on this.
>
> As a prerequisite I had to do some plumbing through the SMB2 client layers with
> the goal of giving smbtorture control over the initial credits.
>
> A few tests then use this plumbing to verify Windows 2016 Server creditting
> behaviour. It grants up to 8192 credits by default, so the tests are marked
> failing against Samba as we only grant a maximum of 512.
>
> I discussed with metze whether we might want to raise our limit, but we don't
> see a need, as even with conservative SMB2 IO RTT of 5 ms the bandwith-delay
> product for 10 (!) Gbit ethernet is
>
> SMB2 BDP = 5 ms * 10 GBit/s = 6.25 MB
>
> 6.25 MB / (64 KB / credit) ~= 98 credits
>
> So with 98 credits granted the client's mid window is already large enough to
> saturate the link. 512 should give enough room for higher average latency or
> hiccups. Once we get to 100 Gbit ethernet in real world we'll have to revisit
> this.
Great work Ralph, but we might want to make ourselves closer
to Windows sooner rather than later. 100 Gbit ethernet isn't
as far off as you think ! :-).
RB+ and pushed.
> From 1fb27bf5c248d71373f28f7781927ff806c1d8bb Mon Sep 17 00:00:00 2001
> From: Ralph Boehme <slow at samba.org>
> Date: Mon, 27 Feb 2017 16:14:39 +0100
> Subject: [PATCH 1/5] libcli/smb: add max_credits arg to smbXcli_negprot_send()
>
> This allows source4/torture code to set the option for tests by
> preparing a struct smbcli_options with max_credits set to some value and
> pass that to a torture_smb2_connection_ext().
>
> This will be used in subsequent smbtorture test for SMB2 creditting.
>
> Behaviour of existing upper layers is unchanged, they simply pass the
> wanted max credits value to smbXcli_negprot_send() instead of
> retrofitting it with a call to smb2cli_conn_set_max_credits().
>
> Signed-off-by: Ralph Boehme <slow at samba.org>
> ---
> libcli/smb/smbXcli_base.c | 20 ++++++++------------
> libcli/smb/smbXcli_base.h | 3 ++-
> source3/libsmb/cliconnect.c | 4 +++-
> source3/torture/torture.c | 2 +-
> source4/libcli/raw/libcliraw.h | 1 +
> source4/libcli/raw/rawnegotiate.c | 3 ++-
> source4/libcli/smb2/connect.c | 6 ++----
> source4/param/loadparm.c | 2 ++
> 8 files changed, 21 insertions(+), 20 deletions(-)
>
> diff --git a/libcli/smb/smbXcli_base.c b/libcli/smb/smbXcli_base.c
> index a7b24f0..70285e6 100644
> --- a/libcli/smb/smbXcli_base.c
> +++ b/libcli/smb/smbXcli_base.c
> @@ -4092,7 +4092,8 @@ struct tevent_req *smbXcli_negprot_send(TALLOC_CTX *mem_ctx,
> struct smbXcli_conn *conn,
> uint32_t timeout_msec,
> enum protocol_types min_protocol,
> - enum protocol_types max_protocol)
> + enum protocol_types max_protocol,
> + uint16_t max_credits)
> {
> struct tevent_req *req, *subreq;
> struct smbXcli_negprot_state *state;
> @@ -4125,6 +4126,10 @@ struct tevent_req *smbXcli_negprot_send(TALLOC_CTX *mem_ctx,
> conn->max_protocol = max_protocol;
> conn->protocol = PROTOCOL_NONE;
>
> + if (max_protocol >= PROTOCOL_SMB2_02) {
> + conn->smb2.max_credits = max_credits;
> + }
> +
> if ((min_protocol < PROTOCOL_SMB2_02) &&
> (max_protocol < PROTOCOL_SMB2_02)) {
> /*
> @@ -4147,16 +4152,6 @@ struct tevent_req *smbXcli_negprot_send(TALLOC_CTX *mem_ctx,
> */
> conn->dispatch_incoming = smb2cli_conn_dispatch_incoming;
>
> - /*
> - * As we're starting with an SMB2 negprot, emulate Windows
> - * and ask for 31 credits in the initial SMB2 negprot.
> - * If we don't and leave requested credits at
> - * zero, MacOSX servers return zero credits on
> - * the negprot reply and we fail to connect.
> - */
> - smb2cli_conn_set_max_credits(conn,
> - WINDOWS_CLIENT_PURE_SMB2_NEGPROT_INITIAL_CREDIT_ASK);
> -
> subreq = smbXcli_negprot_smb2_subreq(state);
> if (tevent_req_nomem(subreq, req)) {
> return tevent_req_post(req, ev);
> @@ -5137,7 +5132,8 @@ NTSTATUS smbXcli_negprot(struct smbXcli_conn *conn,
> goto fail;
> }
> req = smbXcli_negprot_send(frame, ev, conn, timeout_msec,
> - min_protocol, max_protocol);
> + min_protocol, max_protocol,
> + WINDOWS_CLIENT_PURE_SMB2_NEGPROT_INITIAL_CREDIT_ASK);
> if (req == NULL) {
> goto fail;
> }
> diff --git a/libcli/smb/smbXcli_base.h b/libcli/smb/smbXcli_base.h
> index 702eedf..6041ae5 100644
> --- a/libcli/smb/smbXcli_base.h
> +++ b/libcli/smb/smbXcli_base.h
> @@ -436,7 +436,8 @@ struct tevent_req *smbXcli_negprot_send(TALLOC_CTX *mem_ctx,
> struct smbXcli_conn *conn,
> uint32_t timeout_msec,
> enum protocol_types min_protocol,
> - enum protocol_types max_protocol);
> + enum protocol_types max_protocol,
> + uint16_t max_credits);
> NTSTATUS smbXcli_negprot_recv(struct tevent_req *req);
> NTSTATUS smbXcli_negprot(struct smbXcli_conn *conn,
> uint32_t timeout_msec,
> diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c
> index a9451fb..029c3d4 100644
> --- a/source3/libsmb/cliconnect.c
> +++ b/source3/libsmb/cliconnect.c
> @@ -39,6 +39,7 @@
> #include "../libcli/smb/smbXcli_base.h"
> #include "../libcli/smb/smb_seal.h"
> #include "lib/param/param.h"
> +#include "../libcli/smb/smb2_negotiate_context.h"
>
> #define STAR_SMBSERVER "*SMBSERVER"
>
> @@ -2754,7 +2755,8 @@ static void cli_start_connection_connected(struct tevent_req *subreq)
> subreq = smbXcli_negprot_send(state, state->ev, state->cli->conn,
> state->cli->timeout,
> state->min_protocol,
> - state->max_protocol);
> + state->max_protocol,
> + WINDOWS_CLIENT_PURE_SMB2_NEGPROT_INITIAL_CREDIT_ASK);
> if (tevent_req_nomem(subreq, req)) {
> return;
> }
> diff --git a/source3/torture/torture.c b/source3/torture/torture.c
> index 3062122..4e6576c 100644
> --- a/source3/torture/torture.c
> +++ b/source3/torture/torture.c
> @@ -2990,7 +2990,7 @@ static bool run_negprot_nowait(int dummy)
> struct tevent_req *req;
>
> req = smbXcli_negprot_send(ev, ev, cli->conn, cli->timeout,
> - PROTOCOL_CORE, PROTOCOL_NT1);
> + PROTOCOL_CORE, PROTOCOL_NT1, 0);
> if (req == NULL) {
> TALLOC_FREE(ev);
> return false;
> diff --git a/source4/libcli/raw/libcliraw.h b/source4/libcli/raw/libcliraw.h
> index 8220cd7..96dfcd4 100644
> --- a/source4/libcli/raw/libcliraw.h
> +++ b/source4/libcli/raw/libcliraw.h
> @@ -103,6 +103,7 @@ struct smbcli_options {
> enum smb_signing_setting signing;
> uint32_t smb2_capabilities;
> struct GUID client_guid;
> + uint64_t max_credits;
> };
>
> /* this is the context for the client transport layer */
> diff --git a/source4/libcli/raw/rawnegotiate.c b/source4/libcli/raw/rawnegotiate.c
> index 4b42c26..f6a189f 100644
> --- a/source4/libcli/raw/rawnegotiate.c
> +++ b/source4/libcli/raw/rawnegotiate.c
> @@ -60,7 +60,8 @@ struct tevent_req *smb_raw_negotiate_send(TALLOC_CTX *mem_ctx,
> transport->conn,
> timeout_msec,
> minprotocol,
> - maxprotocol);
> + maxprotocol,
> + transport->options.max_credits);
> if (tevent_req_nomem(subreq, req)) {
> return tevent_req_post(req, ev);
> }
> diff --git a/source4/libcli/smb2/connect.c b/source4/libcli/smb2/connect.c
> index 1a6ae34..8ff56c9 100644
> --- a/source4/libcli/smb2/connect.c
> +++ b/source4/libcli/smb2/connect.c
> @@ -155,7 +155,8 @@ static void smb2_connect_socket_done(struct composite_context *creq)
> subreq = smbXcli_negprot_send(state, state->ev,
> state->transport->conn, timeout_msec,
> min_protocol,
> - state->transport->options.max_protocol);
> + state->transport->options.max_protocol,
> + state->transport->options.max_credits);
> if (tevent_req_nomem(subreq, req)) {
> return;
> }
> @@ -181,9 +182,6 @@ static void smb2_connect_negprot_done(struct tevent_req *subreq)
> return;
> }
>
> - /* This is a hack... */
> - smb2cli_conn_set_max_credits(transport->conn, 30);
> -
> state->session = smb2_session_init(transport, state->gensec_settings, state);
> if (tevent_req_nomem(state->session, req)) {
> return;
> diff --git a/source4/param/loadparm.c b/source4/param/loadparm.c
> index f53b2dd..1044a07 100644
> --- a/source4/param/loadparm.c
> +++ b/source4/param/loadparm.c
> @@ -30,6 +30,7 @@
> #include "lib/param/param.h"
> #include "libcli/raw/libcliraw.h"
> #include "librpc/ndr/libndr.h"
> +#include "libcli/smb/smb2_negotiate_context.h"
>
> void lpcfg_smbcli_options(struct loadparm_context *lp_ctx,
> struct smbcli_options *options)
> @@ -47,6 +48,7 @@ void lpcfg_smbcli_options(struct loadparm_context *lp_ctx,
> options->use_level2_oplocks = true;
> options->smb2_capabilities = SMB2_CAP_ALL;
> options->client_guid = GUID_random();
> + options->max_credits = WINDOWS_CLIENT_PURE_SMB2_NEGPROT_INITIAL_CREDIT_ASK;
> }
>
> void lpcfg_smbcli_session_options(struct loadparm_context *lp_ctx,
> --
> 2.9.3
>
>
> From 5384cb6a6e253375dcaac77a0d8f4a0d112626e0 Mon Sep 17 00:00:00 2001
> From: Ralph Boehme <slow at samba.org>
> Date: Mon, 27 Feb 2017 12:29:25 +0100
> Subject: [PATCH 2/5] libcli/smb: add smb2cli_conn_get_cur_credits
>
> Signed-off-by: Ralph Boehme <slow at samba.org>
> ---
> libcli/smb/smbXcli_base.c | 5 +++++
> libcli/smb/smbXcli_base.h | 1 +
> 2 files changed, 6 insertions(+)
>
> diff --git a/libcli/smb/smbXcli_base.c b/libcli/smb/smbXcli_base.c
> index 70285e6..0b83a13 100644
> --- a/libcli/smb/smbXcli_base.c
> +++ b/libcli/smb/smbXcli_base.c
> @@ -2782,6 +2782,11 @@ void smb2cli_conn_set_max_credits(struct smbXcli_conn *conn,
> conn->smb2.max_credits = max_credits;
> }
>
> +uint16_t smb2cli_conn_get_cur_credits(struct smbXcli_conn *conn)
> +{
> + return conn->smb2.cur_credits;
> +}
> +
> uint8_t smb2cli_conn_get_io_priority(struct smbXcli_conn *conn)
> {
> if (conn->protocol < PROTOCOL_SMB3_11) {
> diff --git a/libcli/smb/smbXcli_base.h b/libcli/smb/smbXcli_base.h
> index 6041ae5..12dd7de 100644
> --- a/libcli/smb/smbXcli_base.h
> +++ b/libcli/smb/smbXcli_base.h
> @@ -368,6 +368,7 @@ uint32_t smb2cli_conn_max_read_size(struct smbXcli_conn *conn);
> uint32_t smb2cli_conn_max_write_size(struct smbXcli_conn *conn);
> void smb2cli_conn_set_max_credits(struct smbXcli_conn *conn,
> uint16_t max_credits);
> +uint16_t smb2cli_conn_get_cur_credits(struct smbXcli_conn *conn);
> uint8_t smb2cli_conn_get_io_priority(struct smbXcli_conn *conn);
> void smb2cli_conn_set_io_priority(struct smbXcli_conn *conn,
> uint8_t io_priority);
> --
> 2.9.3
>
>
> From a8e6b39ef284d4f67d75d768f631738e3695e222 Mon Sep 17 00:00:00 2001
> From: Ralph Boehme <slow at samba.org>
> Date: Mon, 27 Feb 2017 07:12:09 +0100
> Subject: [PATCH 3/5] s4/torture: add some SMB2 crediting tests
>
> These tests verify that a server grants at least 8192 credits in a
> successfull session setup and in a single SMB2 request. Both tests pass
> against Windows 2016 Server but currently fail against Samba.
>
> Signed-off-by: Ralph Boehme <slow at samba.org>
> ---
> selftest/knownfail | 2 +
> source4/torture/smb2/credits.c | 162 +++++++++++++++++++++++++++++++++++++
> source4/torture/smb2/smb2.c | 1 +
> source4/torture/smb2/wscript_build | 1 +
> 4 files changed, 166 insertions(+)
> create mode 100644 source4/torture/smb2/credits.c
>
> diff --git a/selftest/knownfail b/selftest/knownfail
> index d96e238..a5e2dd4 100644
> --- a/selftest/knownfail
> +++ b/selftest/knownfail
> @@ -312,3 +312,5 @@
> ^samba.tests.dcerpc.dnsserver.samba.tests.dcerpc.dnsserver.DnsserverTests.test_add_duplicate_different_type.*
> ^samba.tests.dcerpc.dnsserver.samba.tests.dcerpc.dnsserver.DnsserverTests.test_rank_none.*
> ^samba.tests.dcerpc.dnsserver.samba.tests.dcerpc.dnsserver.DnsserverTests.test_security_descriptor.*
> +^samba3.smb2.credits.session_setup_credits_granted.*
> +^samba3.smb2.credits.single_req_credits_granted.*
> diff --git a/source4/torture/smb2/credits.c b/source4/torture/smb2/credits.c
> new file mode 100644
> index 0000000..d34b1d5
> --- /dev/null
> +++ b/source4/torture/smb2/credits.c
> @@ -0,0 +1,162 @@
> +/*
> + Unix SMB/CIFS implementation.
> +
> + test suite for SMB2 credits
> +
> + Copyright (C) Ralph Boehme 2017
> +
> + This program is free software; you can redistribute it and/or modify
> + it under the terms of the GNU General Public License as published by
> + the Free Software Foundation; either version 3 of the License, or
> + (at your option) any later version.
> +
> + This program is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + GNU General Public License for more details.
> +
> + You should have received a copy of the GNU General Public License
> + along with this program. If not, see <http://www.gnu.org/licenses/>.
> +*/
> +
> +#include "includes.h"
> +#include "libcli/smb2/smb2.h"
> +#include "libcli/smb2/smb2_calls.h"
> +#include "torture/torture.h"
> +#include "torture/smb2/proto.h"
> +#include "../libcli/smb/smbXcli_base.h"
> +#include "lib/param/param.h"
> +
> +/**
> + * Request 64k credits in negprot/sessionsetup and require at least 8k
> + *
> + * This passes against Windows 2016
> + **/
> +static bool test_session_setup_credits_granted(struct torture_context *tctx,
> + struct smb2_tree *_tree)
> +{
> + struct smbcli_options options;
> + struct smb2_transport *transport = NULL;
> + struct smb2_tree *tree = NULL;
> + uint16_t cur_credits;
> + NTSTATUS status;
> + bool ret = true;
> +
> + transport = _tree->session->transport;
> + options = transport->options;
> +
> + status = smb2_logoff(_tree->session);
> + torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
> + "smb2_logoff failed\n");
> + TALLOC_FREE(_tree);
> +
> + options.max_credits = 65535;
> +
> + ret = torture_smb2_connection_ext(tctx, 0, &options, &tree);
> + torture_assert_goto(tctx, ret == true, ret, done,
> + "torture_smb2_connection_ext failed\n");
> +
> + transport = tree->session->transport;
> +
> + cur_credits = smb2cli_conn_get_cur_credits(transport->conn);
> + if (cur_credits < 8192) {
> + torture_result(tctx, TORTURE_FAIL,
> + "Server only granted %" PRIu16" credits\n",
> + cur_credits);
> + ret = false;
> + goto done;
> + }
> +
> +done:
> + TALLOC_FREE(tree);
> + return ret;
> +}
> +
> +/**
> + * Request 64K credits in a single SMB2 request and requite at least 8192
> + *
> + * This passes against Windows 2016
> + **/
> +static bool test_single_req_credits_granted(struct torture_context *tctx,
> + struct smb2_tree *_tree)
> +{
> + struct smbcli_options options;
> + struct smb2_transport *transport = NULL;
> + struct smb2_tree *tree = NULL;
> + struct smb2_handle h = {{0}};
> + struct smb2_create create;
> + const char *fname = "single_req_credits_granted.dat";
> + uint16_t cur_credits;
> + NTSTATUS status;
> + bool ret = true;
> +
> + smb2_util_unlink(_tree, fname);
> +
> + transport = _tree->session->transport;
> + options = transport->options;
> +
> + status = smb2_logoff(_tree->session);
> + torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
> + "smb2_logoff failed\n");
> + TALLOC_FREE(_tree);
> +
> + options.max_credits = 1;
> +
> + ret = torture_smb2_connection_ext(tctx, 0, &options, &tree);
> + torture_assert_goto(tctx, ret == true, ret, done,
> + "torture_smb2_connection_ext failed\n");
> +
> + transport = tree->session->transport;
> +
> + cur_credits = smb2cli_conn_get_cur_credits(transport->conn);
> + if (cur_credits != 1) {
> + torture_result(tctx, TORTURE_FAIL,
> + "Only wanted 1 credit but server granted %" PRIu16"\n",
> + cur_credits);
> + ret = false;
> + goto done;
> + }
> +
> + smb2cli_conn_set_max_credits(transport->conn, 65535);
> +
> + ZERO_STRUCT(create);
> + create.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION;
> + create.in.desired_access = SEC_RIGHTS_FILE_ALL;
> + create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
> + create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
> + create.in.fname = fname;
> +
> + status = smb2_create(tree, tctx, &create);
> + torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
> + "smb2_create failed\n");
> + h = create.out.file.handle;
> +
> + cur_credits = smb2cli_conn_get_cur_credits(transport->conn);
> + if (cur_credits < 8192) {
> + torture_result(tctx, TORTURE_FAIL,
> + "Server only granted %" PRIu16" credits\n",
> + cur_credits);
> + ret = false;
> + goto done;
> + }
> +
> +done:
> + if (!smb2_util_handle_empty(h)) {
> + smb2_util_close(tree, h);
> + }
> + smb2_util_unlink(tree, fname);
> + TALLOC_FREE(tree);
> + return ret;
> +}
> +
> +struct torture_suite *torture_smb2_crediting_init(void)
> +{
> + struct torture_suite *suite = torture_suite_create(talloc_autofree_context(), "credits");
> +
> + torture_suite_add_1smb2_test(suite, "session_setup_credits_granted", test_session_setup_credits_granted);
> + torture_suite_add_1smb2_test(suite, "single_req_credits_granted", test_single_req_credits_granted);
> +
> + suite->description = talloc_strdup(suite, "SMB2-CREDITS tests");
> +
> + return suite;
> +}
> diff --git a/source4/torture/smb2/smb2.c b/source4/torture/smb2/smb2.c
> index ca07992..9f0f6b3 100644
> --- a/source4/torture/smb2/smb2.c
> +++ b/source4/torture/smb2/smb2.c
> @@ -172,6 +172,7 @@ NTSTATUS torture_smb2_init(void)
> torture_suite_add_suite(suite, torture_smb2_replay_init());
> torture_suite_add_simple_test(suite, "dosmode", torture_smb2_dosmode);
> torture_suite_add_simple_test(suite, "maxfid", torture_smb2_maxfid);
> + torture_suite_add_suite(suite, torture_smb2_crediting_init());
>
> torture_suite_add_suite(suite, torture_smb2_doc_init());
>
> diff --git a/source4/torture/smb2/wscript_build b/source4/torture/smb2/wscript_build
> index ba7a9bd..e26ac30 100644
> --- a/source4/torture/smb2/wscript_build
> +++ b/source4/torture/smb2/wscript_build
> @@ -6,6 +6,7 @@ bld.SAMBA_MODULE('TORTURE_SMB2',
> compound.c
> connect.c
> create.c
> + credits.c
> delete-on-close.c
> dir.c
> dosmode.c
> --
> 2.9.3
>
>
> From 91f96f6d2ea17e83f9d4eca48ef98a5f23a76b46 Mon Sep 17 00:00:00 2001
> From: Ralph Boehme <slow at samba.org>
> Date: Sun, 26 Feb 2017 09:28:12 +0100
> Subject: [PATCH 4/5] libcli/smb: add smb2cli_conn_get_mid and
> smb2cli_conn_set_mid
>
> This will be needed for a torture test in the next commit.
>
> Signed-off-by: Ralph Boehme <slow at samba.org>
> ---
> libcli/smb/smbXcli_base.c | 10 ++++++++++
> libcli/smb/smbXcli_base.h | 2 ++
> 2 files changed, 12 insertions(+)
>
> diff --git a/libcli/smb/smbXcli_base.c b/libcli/smb/smbXcli_base.c
> index 0b83a13..9521fc6 100644
> --- a/libcli/smb/smbXcli_base.c
> +++ b/libcli/smb/smbXcli_base.c
> @@ -6248,3 +6248,13 @@ bool smb2cli_tcon_is_encryption_on(struct smbXcli_tcon *tcon)
> {
> return tcon->smb2.should_encrypt;
> }
> +
> +void smb2cli_conn_set_mid(struct smbXcli_conn *conn, uint64_t mid)
> +{
> + conn->smb2.mid = mid;
> +}
> +
> +uint64_t smb2cli_conn_get_mid(struct smbXcli_conn *conn)
> +{
> + return conn->smb2.mid;
> +}
> diff --git a/libcli/smb/smbXcli_base.h b/libcli/smb/smbXcli_base.h
> index 12dd7de..84f4a6b 100644
> --- a/libcli/smb/smbXcli_base.h
> +++ b/libcli/smb/smbXcli_base.h
> @@ -378,6 +378,8 @@ void smb2cli_conn_set_cc_chunk_len(struct smbXcli_conn *conn,
> uint32_t smb2cli_conn_cc_max_chunks(struct smbXcli_conn *conn);
> void smb2cli_conn_set_cc_max_chunks(struct smbXcli_conn *conn,
> uint32_t max_chunks);
> +void smb2cli_conn_set_mid(struct smbXcli_conn *conn, uint64_t mid);
> +uint64_t smb2cli_conn_get_mid(struct smbXcli_conn *conn);
>
> struct tevent_req *smb2cli_req_create(TALLOC_CTX *mem_ctx,
> struct tevent_context *ev,
> --
> 2.9.3
>
>
> From 0c19edce3d72f5d089f09e3da9893ed933d2ea3a Mon Sep 17 00:00:00 2001
> From: Ralph Boehme <slow at samba.org>
> Date: Mon, 27 Feb 2017 12:55:04 +0100
> Subject: [PATCH 5/5] s4/torture: add a creditting test skipping a SMB2 MID
>
> This tests that skipping a SMB2 MID the client's usable MID window is
>
> [unused mid, unused mid + 8192]
>
> The test currently fails against Samba as we only grant up to 512
> credits. It passes against Windows 2016 as that grants up to 8192
> credits by default.
>
> Signed-off-by: Ralph Boehme <slow at samba.org>
> ---
> selftest/knownfail | 1 +
> source4/selftest/tests.py | 2 +-
> source4/torture/smb2/credits.c | 105 +++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 107 insertions(+), 1 deletion(-)
>
> diff --git a/selftest/knownfail b/selftest/knownfail
> index a5e2dd4..7c5417b 100644
> --- a/selftest/knownfail
> +++ b/selftest/knownfail
> @@ -314,3 +314,4 @@
> ^samba.tests.dcerpc.dnsserver.samba.tests.dcerpc.dnsserver.DnsserverTests.test_security_descriptor.*
> ^samba3.smb2.credits.session_setup_credits_granted.*
> ^samba3.smb2.credits.single_req_credits_granted.*
> +^samba3.smb2.credits.skipped_mid.*
> diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py
> index 83eff52..d52c873 100755
> --- a/source4/selftest/tests.py
> +++ b/source4/selftest/tests.py
> @@ -303,7 +303,7 @@ for t in nbt_tests:
> ntvfsargs = ["--option=torture:sharedelay=100000", "--option=torture:oplocktimeout=3", "--option=torture:writetimeupdatedelay=500000"]
>
> # Filter smb2 tests that should not run against ad_dc_ntvfs
> -smb2_s3only = ["smb2.change_notify_disabled", "smb2.dosmode"]
> +smb2_s3only = ["smb2.change_notify_disabled", "smb2.dosmode", "smb2.credits"]
> smb2 = [x for x in smbtorture4_testsuites("smb2.") if x not in smb2_s3only]
>
> #The QFILEINFO-IPC test needs to be on ipc$
> diff --git a/source4/torture/smb2/credits.c b/source4/torture/smb2/credits.c
> index d34b1d5..5aa3586 100644
> --- a/source4/torture/smb2/credits.c
> +++ b/source4/torture/smb2/credits.c
> @@ -149,12 +149,117 @@ done:
> return ret;
> }
>
> +static bool test_crediting_skipped_mid(struct torture_context *tctx,
> + struct smb2_tree *_tree)
> +{
> + struct smbcli_options options;
> + struct smb2_transport *transport = NULL;
> + struct smb2_tree *tree = NULL;
> + struct smb2_handle h = {{0}};
> + struct smb2_create create;
> + const char *fname = "skipped_mid.dat";
> + uint64_t mid;
> + uint16_t cur_credits;
> + NTSTATUS status;
> + bool ret = true;
> +
> + smb2_util_unlink(_tree, fname);
> +
> + transport = _tree->session->transport;
> + options = transport->options;
> +
> + status = smb2_logoff(_tree->session);
> + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_logoff failed\n");
> + TALLOC_FREE(_tree);
> +
> + options.max_credits = 8192;
> +
> + ret = torture_smb2_connection_ext(tctx, 0, &options, &tree);
> + torture_assert_goto(tctx, ret == true, ret, done, "torture_smb2_connection_ext failed\n");
> +
> + transport = tree->session->transport;
> +
> + cur_credits = smb2cli_conn_get_cur_credits(transport->conn);
> + if (cur_credits != 8192) {
> + torture_result(tctx, TORTURE_FAIL, "Server only granted %" PRIu16" credits\n", cur_credits);
> + ret = false;
> + goto done;
> + }
> +
> + ZERO_STRUCT(create);
> + create.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION;
> + create.in.desired_access = SEC_RIGHTS_FILE_ALL;
> + create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
> + create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
> + create.in.fname = fname;
> +
> + status = smb2_create(tree, tctx, &create);
> + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create failed\n");
> + h = create.out.file.handle;
> +
> + /*
> + * See what happens if we skip a mid. As we want to avoid triggering our
> + * client side mid window check we keep conn->smb2.cur_credits
> + * unchanged so the server keeps granting credits until it's max mid
> + * windows size is reached at which point it will disconnect us:
> + *
> + * o Windows 2016 currently has a maximum mid window size of 8192 by
> + * default
> + *
> + * o Samba's limit is 512
> + *
> + * o Windows 2008r2 uses some special algorithm (MS-SMB2 3.3.1.1
> + * footnote <167>) that kicks in once a mid is skipped, resulting in a
> + * maximum window size of 100-300 depending on the number of granted
> + * credits at the moment of skipping a mid.
> + */
> +
> + mid = smb2cli_conn_get_mid(tree->session->transport->conn);
> + smb2cli_conn_set_mid(tree->session->transport->conn, mid + 1);
> +
> + for (int i = 0; i < 8191; i++) {
> + status = smb2_util_write(tree, h, "\0", 0, 1);
> + if (!NT_STATUS_IS_OK(status)) {
> + torture_result(tctx, TORTURE_FAIL, "Server only allowed %d writes\n", i);
> + ret = false;
> + goto done;
> + }
> + }
> +
> + /*
> + * Now use the skipped mid (the smb2_util_close...), we should
> + * immediately get a full mid window of size 8192.
> + */
> + smb2cli_conn_set_mid(tree->session->transport->conn, mid);
> + status = smb2_util_close(tree, h);
> + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_close failed\n");
> + ZERO_STRUCT(h);
> +
> + cur_credits = smb2cli_conn_get_cur_credits(transport->conn);
> + if (cur_credits != 8192) {
> + torture_result(tctx, TORTURE_FAIL, "Server only granted %" PRIu16" credits\n", cur_credits);
> + ret = false;
> + goto done;
> + }
> +
> + smb2cli_conn_set_mid(tree->session->transport->conn, mid + 8192);
> +
> +done:
> + if (!smb2_util_handle_empty(h)) {
> + smb2_util_close(tree, h);
> + }
> + smb2_util_unlink(tree, fname);
> + TALLOC_FREE(tree);
> + return ret;
> +}
> +
> struct torture_suite *torture_smb2_crediting_init(void)
> {
> struct torture_suite *suite = torture_suite_create(talloc_autofree_context(), "credits");
>
> torture_suite_add_1smb2_test(suite, "session_setup_credits_granted", test_session_setup_credits_granted);
> torture_suite_add_1smb2_test(suite, "single_req_credits_granted", test_single_req_credits_granted);
> + torture_suite_add_1smb2_test(suite, "skipped_mid", test_crediting_skipped_mid);
>
> suite->description = talloc_strdup(suite, "SMB2-CREDITS tests");
>
> --
> 2.9.3
>
More information about the samba-technical
mailing list