mirror of
https://github.com/samba-team/samba.git
synced 2025-03-20 22:50:26 +03:00
s4:torture/smb2: add smb2.multichannel.bugs.bug_15346
This demonstrates the race quite easily against Samba and works fine against Windows Server 2022. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15346 Signed-off-by: Stefan Metzmacher <metze@samba.org> Reviewed-by: Andreas Schneider <asn@samba.org> (cherry picked from commit 4028d6582907cf582730ceec56872d8584ad02e6)
This commit is contained in:
parent
3c23c7f36c
commit
534f136303
1
selftest/knownfail.d/samba3.smb2.multichannel
Normal file
1
selftest/knownfail.d/samba3.smb2.multichannel
Normal file
@ -0,0 +1 @@
|
||||
^samba3.smb2.multichannel.bugs.bug_15346
|
@ -31,6 +31,7 @@
|
||||
#include "lib/cmdline/cmdline.h"
|
||||
#include "libcli/security/security.h"
|
||||
#include "libcli/resolve/resolve.h"
|
||||
#include "lib/socket/socket.h"
|
||||
#include "lib/param/param.h"
|
||||
#include "lib/events/events.h"
|
||||
#include "oplock_break_handler.h"
|
||||
@ -2345,6 +2346,315 @@ done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Test channel merging race
|
||||
* This is a regression test for
|
||||
* https://bugzilla.samba.org/show_bug.cgi?id=15346
|
||||
*/
|
||||
struct test_multichannel_bug_15346_conn;
|
||||
|
||||
struct test_multichannel_bug_15346_state {
|
||||
struct torture_context *tctx;
|
||||
struct test_multichannel_bug_15346_conn *conns;
|
||||
size_t num_conns;
|
||||
size_t num_ready;
|
||||
bool asserted;
|
||||
bool looping;
|
||||
};
|
||||
|
||||
struct test_multichannel_bug_15346_conn {
|
||||
struct test_multichannel_bug_15346_state *state;
|
||||
size_t idx;
|
||||
struct smbXcli_conn *smbXcli;
|
||||
struct tevent_req *nreq;
|
||||
struct tevent_req *ereq;
|
||||
};
|
||||
|
||||
static void test_multichannel_bug_15346_ndone(struct tevent_req *subreq);
|
||||
static void test_multichannel_bug_15346_edone(struct tevent_req *subreq);
|
||||
|
||||
static void test_multichannel_bug_15346_ndone(struct tevent_req *subreq)
|
||||
{
|
||||
struct test_multichannel_bug_15346_conn *conn =
|
||||
(struct test_multichannel_bug_15346_conn *)
|
||||
tevent_req_callback_data_void(subreq);
|
||||
struct test_multichannel_bug_15346_state *state = conn->state;
|
||||
struct torture_context *tctx = state->tctx;
|
||||
NTSTATUS status;
|
||||
bool ok = false;
|
||||
|
||||
SMB_ASSERT(conn->nreq == subreq);
|
||||
conn->nreq = NULL;
|
||||
|
||||
status = smbXcli_negprot_recv(subreq, NULL, NULL);
|
||||
TALLOC_FREE(subreq);
|
||||
torture_assert_ntstatus_ok_goto(tctx, status, ok, asserted,
|
||||
"smbXcli_negprot_recv failed");
|
||||
|
||||
torture_comment(tctx, "conn[%zu]: negprot done\n", conn->idx);
|
||||
|
||||
conn->ereq = smb2cli_echo_send(conn->smbXcli,
|
||||
tctx->ev,
|
||||
conn->smbXcli,
|
||||
state->num_conns * 2 * 1000);
|
||||
torture_assert_goto(tctx, conn->ereq != NULL, ok, asserted,
|
||||
"smb2cli_echo_send");
|
||||
tevent_req_set_callback(conn->ereq,
|
||||
test_multichannel_bug_15346_edone,
|
||||
conn);
|
||||
|
||||
return;
|
||||
|
||||
asserted:
|
||||
SMB_ASSERT(!ok);
|
||||
state->asserted = true;
|
||||
state->looping = false;
|
||||
return;
|
||||
}
|
||||
|
||||
static void test_multichannel_bug_15346_edone(struct tevent_req *subreq)
|
||||
{
|
||||
struct test_multichannel_bug_15346_conn *conn =
|
||||
(struct test_multichannel_bug_15346_conn *)
|
||||
tevent_req_callback_data_void(subreq);
|
||||
struct test_multichannel_bug_15346_state *state = conn->state;
|
||||
struct torture_context *tctx = state->tctx;
|
||||
NTSTATUS status;
|
||||
bool ok = false;
|
||||
|
||||
SMB_ASSERT(conn->ereq == subreq);
|
||||
conn->ereq = NULL;
|
||||
|
||||
status = smb2cli_echo_recv(subreq);
|
||||
TALLOC_FREE(subreq);
|
||||
torture_assert_ntstatus_ok_goto(tctx, status, ok, asserted,
|
||||
"smb2cli_echo_recv failed");
|
||||
|
||||
torture_comment(tctx, "conn[%zu]: echo done\n", conn->idx);
|
||||
|
||||
state->num_ready += 1;
|
||||
if (state->num_ready < state->num_conns) {
|
||||
return;
|
||||
}
|
||||
|
||||
state->looping = false;
|
||||
return;
|
||||
|
||||
asserted:
|
||||
SMB_ASSERT(!ok);
|
||||
state->asserted = true;
|
||||
state->looping = false;
|
||||
return;
|
||||
}
|
||||
|
||||
static bool test_multichannel_bug_15346(struct torture_context *tctx,
|
||||
struct smb2_tree *tree1)
|
||||
{
|
||||
const char *host = torture_setting_string(tctx, "host", NULL);
|
||||
const char *share = torture_setting_string(tctx, "share", NULL);
|
||||
struct resolve_context *resolve_ctx = lpcfg_resolve_context(tctx->lp_ctx);
|
||||
const char *socket_options = lpcfg_socket_options(tctx->lp_ctx);
|
||||
struct gensec_settings *gsettings = NULL;
|
||||
bool ret = true;
|
||||
NTSTATUS status;
|
||||
struct smb2_transport *transport1 = tree1->session->transport;
|
||||
struct test_multichannel_bug_15346_state *state = NULL;
|
||||
uint32_t server_capabilities;
|
||||
struct smb2_handle root_handle = {{0}};
|
||||
size_t i;
|
||||
|
||||
if (smbXcli_conn_protocol(transport1->conn) < PROTOCOL_SMB3_00) {
|
||||
torture_fail(tctx,
|
||||
"SMB 3.X Dialect family required for Multichannel"
|
||||
" tests\n");
|
||||
}
|
||||
|
||||
server_capabilities = smb2cli_conn_server_capabilities(
|
||||
tree1->session->transport->conn);
|
||||
if (!(server_capabilities & SMB2_CAP_MULTI_CHANNEL)) {
|
||||
torture_fail(tctx,
|
||||
"Server does not support multichannel.");
|
||||
}
|
||||
|
||||
torture_comment(tctx, "Testing for BUG 15346\n");
|
||||
|
||||
state = talloc_zero(tctx, struct test_multichannel_bug_15346_state);
|
||||
torture_assert_goto(tctx, state != NULL, ret, done,
|
||||
"talloc_zero");
|
||||
state->tctx = tctx;
|
||||
|
||||
gsettings = lpcfg_gensec_settings(state, tctx->lp_ctx);
|
||||
torture_assert_goto(tctx, gsettings != NULL, ret, done,
|
||||
"lpcfg_gensec_settings");
|
||||
|
||||
/*
|
||||
* 32 is the W2K12R2 and W2K16 limit
|
||||
* add 31 additional connections
|
||||
*/
|
||||
state->num_conns = 31;
|
||||
state->conns = talloc_zero_array(state,
|
||||
struct test_multichannel_bug_15346_conn,
|
||||
state->num_conns);
|
||||
torture_assert_goto(tctx, state->conns != NULL, ret, done,
|
||||
"talloc_zero_array");
|
||||
|
||||
/*
|
||||
* First we open additional the tcp connections
|
||||
*/
|
||||
|
||||
for (i = 0; i < state->num_conns; i++) {
|
||||
struct test_multichannel_bug_15346_conn *conn = &state->conns[i];
|
||||
struct socket_context *sock = NULL;
|
||||
uint16_t port = 445;
|
||||
struct smbcli_options options = transport1->options;
|
||||
|
||||
conn->state = state;
|
||||
conn->idx = i;
|
||||
|
||||
status = socket_connect_multi(state->conns,
|
||||
host,
|
||||
1, &port,
|
||||
resolve_ctx,
|
||||
tctx->ev,
|
||||
&sock,
|
||||
&port);
|
||||
torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
|
||||
"socket_connect_multi failed");
|
||||
|
||||
conn->smbXcli = smbXcli_conn_create(state->conns,
|
||||
sock->fd,
|
||||
host,
|
||||
SMB_SIGNING_OFF,
|
||||
0,
|
||||
&options.client_guid,
|
||||
options.smb2_capabilities,
|
||||
&options.smb3_capabilities);
|
||||
torture_assert_goto(tctx, conn->smbXcli != NULL, ret, done,
|
||||
"smbXcli_conn_create failed");
|
||||
sock->fd = -1;
|
||||
TALLOC_FREE(sock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Now prepare the async SMB2 Negotiate requests
|
||||
*/
|
||||
for (i = 0; i < state->num_conns; i++) {
|
||||
struct test_multichannel_bug_15346_conn *conn = &state->conns[i];
|
||||
|
||||
conn->nreq = smbXcli_negprot_send(conn->smbXcli,
|
||||
tctx->ev,
|
||||
conn->smbXcli,
|
||||
state->num_conns * 2 * 1000,
|
||||
smbXcli_conn_protocol(transport1->conn),
|
||||
smbXcli_conn_protocol(transport1->conn),
|
||||
33, /* max_credits */
|
||||
NULL);
|
||||
torture_assert_goto(tctx, conn->nreq != NULL, ret, done, "smbXcli_negprot_send");
|
||||
tevent_req_set_callback(conn->nreq,
|
||||
test_multichannel_bug_15346_ndone,
|
||||
conn);
|
||||
}
|
||||
|
||||
/*
|
||||
* now we loop until all negprot and the first round
|
||||
* of echos are done.
|
||||
*/
|
||||
state->looping = true;
|
||||
while (state->looping) {
|
||||
torture_assert_goto(tctx, tevent_loop_once(tctx->ev) == 0,
|
||||
ret, done, "tevent_loop_once");
|
||||
}
|
||||
|
||||
if (state->asserted) {
|
||||
ret = false;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* No we check that the connections are still usable
|
||||
*/
|
||||
for (i = 0; i < state->num_conns; i++) {
|
||||
struct test_multichannel_bug_15346_conn *conn = &state->conns[i];
|
||||
|
||||
torture_comment(tctx, "conn[%zu]: checking echo again1\n", conn->idx);
|
||||
|
||||
status = smb2cli_echo(conn->smbXcli, 1000);
|
||||
torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
|
||||
"smb2cli_echo failed");
|
||||
}
|
||||
|
||||
status = smb2_util_roothandle(tree1, &root_handle);
|
||||
torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
|
||||
"smb2_util_roothandle failed");
|
||||
|
||||
/*
|
||||
* No we check that the connections are still usable
|
||||
*/
|
||||
for (i = 0; i < state->num_conns; i++) {
|
||||
struct test_multichannel_bug_15346_conn *conn = &state->conns[i];
|
||||
struct smbcli_options options = transport1->options;
|
||||
struct smb2_session *session = NULL;
|
||||
struct smb2_tree *tree = NULL;
|
||||
union smb_fileinfo io;
|
||||
|
||||
torture_comment(tctx, "conn[%zu]: checking session bind\n", conn->idx);
|
||||
|
||||
/*
|
||||
* Prepare smb2_{tree,session,transport} structures
|
||||
* for the existing connection.
|
||||
*/
|
||||
options.only_negprot = true;
|
||||
status = smb2_connect_ext(state->conns,
|
||||
host,
|
||||
NULL, /* ports */
|
||||
share,
|
||||
resolve_ctx,
|
||||
samba_cmdline_get_creds(),
|
||||
&conn->smbXcli,
|
||||
0, /* previous_session_id */
|
||||
&tree,
|
||||
tctx->ev,
|
||||
&options,
|
||||
socket_options,
|
||||
gsettings);
|
||||
torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
|
||||
"smb2_connect_ext failed");
|
||||
conn->smbXcli = tree->session->transport->conn;
|
||||
|
||||
session = smb2_session_channel(tree->session->transport,
|
||||
lpcfg_gensec_settings(tree, tctx->lp_ctx),
|
||||
tree,
|
||||
tree1->session);
|
||||
torture_assert_goto(tctx, session != NULL, ret, done,
|
||||
"smb2_session_channel failed");
|
||||
|
||||
status = smb2_session_setup_spnego(session,
|
||||
samba_cmdline_get_creds(),
|
||||
0 /* previous_session_id */);
|
||||
torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
|
||||
"smb2_session_setup_spnego failed");
|
||||
|
||||
/*
|
||||
* Fix up the bound smb2_tree
|
||||
*/
|
||||
tree->session = session;
|
||||
tree->smbXcli = tree1->smbXcli;
|
||||
|
||||
ZERO_STRUCT(io);
|
||||
io.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
|
||||
io.generic.in.file.handle = root_handle;
|
||||
|
||||
status = smb2_getinfo_file(tree, tree, &io);
|
||||
torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
|
||||
"smb2_getinfo_file failed");
|
||||
}
|
||||
|
||||
done:
|
||||
talloc_free(state);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct torture_suite *torture_smb2_multichannel_init(TALLOC_CTX *ctx)
|
||||
{
|
||||
struct torture_suite *suite = torture_suite_create(ctx, "multichannel");
|
||||
@ -2354,10 +2664,13 @@ struct torture_suite *torture_smb2_multichannel_init(TALLOC_CTX *ctx)
|
||||
"oplocks");
|
||||
struct torture_suite *suite_leases = torture_suite_create(ctx,
|
||||
"leases");
|
||||
struct torture_suite *suite_bugs = torture_suite_create(ctx,
|
||||
"bugs");
|
||||
|
||||
torture_suite_add_suite(suite, suite_generic);
|
||||
torture_suite_add_suite(suite, suite_oplocks);
|
||||
torture_suite_add_suite(suite, suite_leases);
|
||||
torture_suite_add_suite(suite, suite_bugs);
|
||||
|
||||
torture_suite_add_1smb2_test(suite_generic, "interface_info",
|
||||
test_multichannel_interface_info);
|
||||
@ -2379,6 +2692,8 @@ struct torture_suite *torture_smb2_multichannel_init(TALLOC_CTX *ctx)
|
||||
test_multichannel_lease_break_test3);
|
||||
torture_suite_add_1smb2_test(suite_leases, "test4",
|
||||
test_multichannel_lease_break_test4);
|
||||
torture_suite_add_1smb2_test(suite_bugs, "bug_15346",
|
||||
test_multichannel_bug_15346);
|
||||
|
||||
suite->description = talloc_strdup(suite, "SMB2 Multichannel tests");
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user