summaryrefslogtreecommitdiff
path: root/source4
diff options
context:
space:
mode:
authorJeremy Allison <jra@samba.org>2022-10-18 16:22:33 -0700
committerJule Anger <janger@samba.org>2023-01-16 09:41:10 +0000
commit67d388c71f75aad94b3019b1dbbab261c01e6604 (patch)
tree170eeca470cd50856b301845489d9184d52c8127 /source4
parent7b29d4077d80093c4493f8b40a0729bd8541ff6e (diff)
downloadsamba-67d388c71f75aad94b3019b1dbbab261c01e6604.tar.gz
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)
Diffstat (limited to 'source4')
-rw-r--r--source4/torture/smb2/compound.c117
-rw-r--r--source4/torture/smb2/smb2.c1
2 files changed, 118 insertions, 0 deletions
diff --git a/source4/torture/smb2/compound.c b/source4/torture/smb2/compound.c
index cf19361130f..e78d78e3a98 100644
--- a/source4/torture/smb2/compound.c
+++ b/source4/torture/smb2/compound.c
@@ -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;
+}
diff --git a/source4/torture/smb2/smb2.c b/source4/torture/smb2/smb2.c
index 21e03360cd9..0ca5078a941 100644
--- a/source4/torture/smb2/smb2.c
+++ b/source4/torture/smb2/smb2.c
@@ -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));