[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