[SCM] Samba Shared Repository - branch master updated

Ralph Böhme slow at samba.org
Thu Nov 17 05:56:01 UTC 2022


The branch, master has been updated
       via  26adf334433 s3: smbd: Cause SMB2_OP_FLUSH to go synchronous in a compound anywhere but the last operation in the list.
       via  e668c3a82cd s3: smbd: Add utility function smbd_smb2_is_last_in_compound().
       via  6f149dfd9d8 s4: torture: Add an async SMB2_OP_FLUSH + SMB2_OP_FLUSH test to smb2.compound_async.
       via  17a110c1b58 s4: torture: Add an async SMB2_OP_FLUSH + SMB2_OP_CLOSE test to smb2.compound_async.
      from  f6284877ce0 nsswitch: Fix uninitialized memory when allocating pwdlastset_prelim

https://git.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit 26adf3344337f4e8d5d2107e6ba42e5ea7656372
Author: Jeremy Allison <jra at samba.org>
Date:   Thu Oct 20 15:19:05 2022 -0700

    s3: smbd: Cause SMB2_OP_FLUSH to go synchronous in a compound anywhere but the last operation in the list.
    
    Async read and write go synchronous in the same case,
    so do the same here.
    
    Remove knownfail.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15172
    
    Signed-off-by: Jeremy Allison <jra at samba.org>
    Reviewed-by: Ralph Boehme <slow at samba.org>
    
    Autobuild-User(master): Ralph Böhme <slow at samba.org>
    Autobuild-Date(master): Thu Nov 17 05:55:42 UTC 2022 on sn-devel-184

commit e668c3a82cd566b405c976d45659dd79786948de
Author: Jeremy Allison <jra at samba.org>
Date:   Thu Oct 20 15:08:14 2022 -0700

    s3: smbd: Add utility function smbd_smb2_is_last_in_compound().
    
    Not yet used. Returns true if we're processing the last SMB2 request in a
    compound.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15172
    
    Signed-off-by: Jeremy Allison <jra at samba.org>
    Reviewed-by: Ralph Boehme <slow at samba.org>

commit 6f149dfd9d8d2619a9e18975ebcf5e69df2b7766
Author: Jeremy Allison <jra at samba.org>
Date:   Thu Oct 20 14:22:25 2022 -0700

    s4: torture: Add an async SMB2_OP_FLUSH + SMB2_OP_FLUSH test to smb2.compound_async.
    
    Shows we fail sending an SMB2_OP_FLUSH + SMB2_OP_FLUSH
    compound if we immediately close the file afterward.
    
    Internally the flushes go async and we free the req, then
    we process the close. When the flushes complete they try to access
    already freed data.
    
    Extra test which will allow me to test when the final
    component (flush) of the compound goes async and returns
    NT_STATUS_PENDING.
    
    Add knownfail.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15172
    
    Signed-off-by: Jeremy Allison <jra at samba.org>
    Reviewed-by: Ralph Boehme <slow at samba.org>

commit 17a110c1b58196eb8ecf3c76eb97e8508976c544
Author: Jeremy Allison <jra at samba.org>
Date:   Tue Oct 18 16:22:33 2022 -0700

    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 at samba.org>
    Reviewed-by: Ralph Boehme <slow at samba.org>

-----------------------------------------------------------------------

Summary of changes:
 source3/selftest/tests.py       |   2 +
 source3/smbd/globals.h          |   1 +
 source3/smbd/smb2_flush.c       |  14 +++
 source3/smbd/smb2_server.c      |   6 ++
 source4/torture/smb2/compound.c | 232 ++++++++++++++++++++++++++++++++++++++++
 source4/torture/smb2/smb2.c     |   1 +
 6 files changed, 256 insertions(+)


Changeset truncated at 500 lines:

diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py
index 67ba7b10484..f6cc6e0c639 100755
--- a/source3/selftest/tests.py
+++ b/source3/selftest/tests.py
@@ -1169,6 +1169,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":
diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h
index efcf02f0d24..125ef64f070 100644
--- a/source3/smbd/globals.h
+++ b/source3/smbd/globals.h
@@ -238,6 +238,7 @@ void smbd_server_disconnect_client_ex(struct smbXsrv_client *client,
 const char *smb2_opcode_name(uint16_t opcode);
 bool smbd_is_smb2_header(const uint8_t *inbuf, size_t size);
 bool smbd_smb2_is_compound(const struct smbd_smb2_request *req);
+bool smbd_smb2_is_last_in_compound(const struct smbd_smb2_request *req);
 
 NTSTATUS smbd_add_connection(struct smbXsrv_client *client, int sock_fd,
 			     NTTIME now, struct smbXsrv_connection **_xconn);
diff --git a/source3/smbd/smb2_flush.c b/source3/smbd/smb2_flush.c
index e73666f0afc..5c8c171e418 100644
--- a/source3/smbd/smb2_flush.c
+++ b/source3/smbd/smb2_flush.c
@@ -126,6 +126,8 @@ static struct tevent_req *smbd_smb2_flush_send(TALLOC_CTX *mem_ctx,
 	struct tevent_req *subreq;
 	struct smbd_smb2_flush_state *state;
 	struct smb_request *smbreq;
+	bool is_compound = false;
+	bool is_last_in_compound = false;
 
 	req = tevent_req_create(mem_ctx, &state,
 				struct smbd_smb2_flush_state);
@@ -195,6 +197,18 @@ static struct tevent_req *smbd_smb2_flush_send(TALLOC_CTX *mem_ctx,
 
 	tevent_req_set_callback(subreq, smbd_smb2_flush_done, req);
 
+	is_compound = smbd_smb2_is_compound(smb2req);
+	is_last_in_compound = smbd_smb2_is_last_in_compound(smb2req);
+
+	if (is_compound && !is_last_in_compound) {
+		/*
+		 * Can't go async if we're not the
+		 * last request in a compound request.
+		 * Cause this request to complete synchronously.
+		 */
+		smb2_request_set_async_internal(state->smb2req, true);
+	}
+
 	/* Ensure any close request knows about this outstanding IO. */
 	if (!aio_add_req_to_fsp(fsp, req)) {
 		tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c
index 1cd5953f116..8e32a477947 100644
--- a/source3/smbd/smb2_server.c
+++ b/source3/smbd/smb2_server.c
@@ -229,6 +229,12 @@ bool smbd_smb2_is_compound(const struct smbd_smb2_request *req)
 	return req->in.vector_count >= (2*SMBD_SMB2_NUM_IOV_PER_REQ);
 }
 
+bool smbd_smb2_is_last_in_compound(const struct smbd_smb2_request *req)
+{
+	return (req->current_idx + SMBD_SMB2_NUM_IOV_PER_REQ ==
+		req->in.vector_count);
+}
+
 static NTSTATUS smbd_initialize_smb2(struct smbXsrv_connection *xconn,
 				     uint64_t expected_seq_low)
 {
diff --git a/source4/torture/smb2/compound.c b/source4/torture/smb2/compound.c
index cf19361130f..47a550f0873 100644
--- a/source4/torture/smb2/compound.c
+++ b/source4/torture/smb2/compound.c
@@ -2057,6 +2057,223 @@ 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;
+}
+
+static bool test_compound_async_flush_flush(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_flush fl1;
+	struct smb2_flush fl2;
+	const char *fname = "compound_async_flush_flush";
+	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 + flush handle. */
+	smb2_transport_compound_start(tree->session->transport, 2);
+
+	ZERO_STRUCT(fl1);
+	fl1.in.file.handle = fhandle;
+
+	req[0] = smb2_flush_send(tree, &fl1);
+	torture_assert_not_null_goto(tctx, req[0], ret, done,
+		"smb2_flush_send (1) failed\n");
+
+	smb2_transport_compound_set_related(tree->session->transport, true);
+
+	ZERO_STRUCT(fl2);
+	fl2.in.file.handle = relhandle;
+
+	req[1] = smb2_flush_send(tree, &fl2);
+	torture_assert_not_null_goto(tctx, req[1], ret, done,
+		"smb2_flush_send (2) failed\n");
+
+	status = smb2_flush_recv(req[0], &fl1);
+	/*
+	 * 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 (1) didn't return "
+			"NT_STATUS_INTERNAL_ERROR.\n");
+	}
+
+	/*
+	 * If the flush is the last entry in a compound,
+	 * it should always succeed even if it goes async.
+	 */
+	status = smb2_flush_recv(req[1], &fl2);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+		"smb2_flush_recv (2) failed.");
+
+	status = smb2_util_close(tree, fhandle);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+		"smb2_util_close 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 +2324,18 @@ 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);
+	torture_suite_add_1smb2_test(suite, "flush_flush",
+		test_compound_async_flush_flush);
+
+	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 d7476ec6b89..911cd0b5352 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));


-- 
Samba Shared Repository



More information about the samba-cvs mailing list