1
0
mirror of https://github.com/samba-team/samba.git synced 2025-02-08 05:57:51 +03:00

s4: torture: Add an async SMB2_OP_FLUSH + SMB2_OP_CLOSE test to smb2.compound_async.

Shows we fail sending an SMB2_OP_FLUSH + SMB2_OP_CLOSE
compound. Internally the flush goes async and
we free the req, then we process the close.
When the flush completes it tries to access
already freed data.

Found using the Apple MacOSX client at SNIA SDC 2022.

Add knownfail.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=15172

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
(cherry picked from commit 17a110c1b58196eb8ecf3c76eb97e8508976c544)
This commit is contained in:
Jeremy Allison 2022-10-18 16:22:33 -07:00 committed by Jule Anger
parent 7b29d4077d
commit 67d388c71f
4 changed files with 121 additions and 0 deletions

View File

@ -0,0 +1 @@
^samba3.smb2.compound_async.flush_close\(fileserver\)

View File

@ -1052,6 +1052,8 @@ for t in tests:
plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/tmp -U$USERNAME%$PASSWORD')
plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/aio -U$USERNAME%$PASSWORD', 'aio')
plansmbtorture4testsuite(t, "ad_dc", '//$SERVER/tmp -U$USERNAME%$PASSWORD')
elif t == "smb2.compound_async":
plansmbtorture4testsuite(t, "fileserver", '//$SERVER_IP/tmp -U$USERNAME%$PASSWORD')
elif t == "smb2.ea":
plansmbtorture4testsuite(t, "fileserver", '//$SERVER/ea_acl_xattr --option=torture:acl_xattr_name=hackme -U$USERNAME%$PASSWORD')
elif t == "rpc.samba3.netlogon" or t == "rpc.samba3.sessionkey":

View File

@ -2057,6 +2057,110 @@ done:
return ret;
}
static bool test_compound_async_flush_close(struct torture_context *tctx,
struct smb2_tree *tree)
{
struct smb2_handle fhandle = { .data = { 0, 0 } };
struct smb2_handle relhandle = { .data = { UINT64_MAX, UINT64_MAX } };
struct smb2_close cl;
struct smb2_flush fl;
const char *fname = "compound_async_flush_close";
struct smb2_request *req[2];
NTSTATUS status;
bool ret = false;
/* Start clean. */
smb2_util_unlink(tree, fname);
/* Create a file. */
status = torture_smb2_testfile_access(tree,
fname,
&fhandle,
SEC_RIGHTS_FILE_ALL);
CHECK_STATUS(status, NT_STATUS_OK);
/* Now do a compound flush + close handle. */
smb2_transport_compound_start(tree->session->transport, 2);
ZERO_STRUCT(fl);
fl.in.file.handle = fhandle;
req[0] = smb2_flush_send(tree, &fl);
torture_assert_not_null_goto(tctx, req[0], ret, done,
"smb2_flush_send failed\n");
smb2_transport_compound_set_related(tree->session->transport, true);
ZERO_STRUCT(cl);
cl.in.file.handle = relhandle;
req[1] = smb2_close_send(tree, &cl);
torture_assert_not_null_goto(tctx, req[1], ret, done,
"smb2_close_send failed\n");
status = smb2_flush_recv(req[0], &fl);
/*
* On Windows, this flush will usually
* succeed as we have nothing to flush,
* so allow NT_STATUS_OK. Once bug #15172
* is fixed Samba will do the flush synchronously
* so allow NT_STATUS_OK.
*/
if (!NT_STATUS_IS_OK(status)) {
/*
* If we didn't get NT_STATUS_OK, we *must*
* get NT_STATUS_INTERNAL_ERROR if the flush
* goes async.
*
* For pre-bugfix #15172 Samba, the flush goes async and
* we should get NT_STATUS_INTERNAL_ERROR.
*/
torture_assert_ntstatus_equal_goto(tctx,
status,
NT_STATUS_INTERNAL_ERROR,
ret,
done,
"smb2_flush_recv didn't return "
"NT_STATUS_INTERNAL_ERROR.\n");
}
status = smb2_close_recv(req[1], &cl);
torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
"smb2_close_recv failed.");
ZERO_STRUCT(fhandle);
/*
* Do several more operations on the tree, spaced
* out by 1 sec sleeps to make sure the server didn't
* crash on the close. The sleeps are required to
* make test test for a crash reliable, as we ensure
* the pthread fsync internally finishes and accesses
* freed memory. Without them the test occassionally
* passes as we disconnect before the pthread fsync
* finishes.
*/
status = smb2_util_unlink(tree, fname);
CHECK_STATUS(status, NT_STATUS_OK);
sleep(1);
status = smb2_util_unlink(tree, fname);
CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
sleep(1);
status = smb2_util_unlink(tree, fname);
CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
ret = true;
done:
if (fhandle.data[0] != 0) {
smb2_util_close(tree, fhandle);
}
smb2_util_unlink(tree, fname);
return ret;
}
struct torture_suite *torture_smb2_compound_init(TALLOC_CTX *ctx)
{
struct torture_suite *suite = torture_suite_create(ctx, "compound");
@ -2107,3 +2211,16 @@ struct torture_suite *torture_smb2_compound_find_init(TALLOC_CTX *ctx)
return suite;
}
struct torture_suite *torture_smb2_compound_async_init(TALLOC_CTX *ctx)
{
struct torture_suite *suite = torture_suite_create(ctx,
"compound_async");
torture_suite_add_1smb2_test(suite, "flush_close",
test_compound_async_flush_close);
suite->description = talloc_strdup(suite, "SMB2-COMPOUND-ASYNC tests");
return suite;
}

View File

@ -174,6 +174,7 @@ NTSTATUS torture_smb2_init(TALLOC_CTX *ctx)
torture_suite_add_suite(suite, torture_smb2_lease_init(suite));
torture_suite_add_suite(suite, torture_smb2_compound_init(suite));
torture_suite_add_suite(suite, torture_smb2_compound_find_init(suite));
torture_suite_add_suite(suite, torture_smb2_compound_async_init(suite));
torture_suite_add_suite(suite, torture_smb2_oplocks_init(suite));
torture_suite_add_suite(suite, torture_smb2_kernel_oplocks_init(suite));
torture_suite_add_suite(suite, torture_smb2_streams_init(suite));