From 4d7f8aab14da4edb3a425bdcbceae6d950fd50ce Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 30 Mar 2021 15:05:47 -0700 Subject: [PATCH 1/2] s4: torture. Add smb2.lease.rename_wait test to reproduce regression in delay rename for lease break code. Passes against Windows 10. Add to knownfail, the next commit will fix this. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14679 Signed-off-by: Jeremy Allison --- selftest/knownfail.d/samba3.smb2.lease | 1 + source4/torture/smb2/lease.c | 144 +++++++++++++++++++++++++ 2 files changed, 145 insertions(+) create mode 100644 selftest/knownfail.d/samba3.smb2.lease diff --git a/selftest/knownfail.d/samba3.smb2.lease b/selftest/knownfail.d/samba3.smb2.lease new file mode 100644 index 00000000000..4e66e2f6539 --- /dev/null +++ b/selftest/knownfail.d/samba3.smb2.lease @@ -0,0 +1 @@ +^samba3.smb2.lease.rename_wait\(nt4_dc\) diff --git a/source4/torture/smb2/lease.c b/source4/torture/smb2/lease.c index d4374d33c8f..2da320483fe 100644 --- a/source4/torture/smb2/lease.c +++ b/source4/torture/smb2/lease.c @@ -3722,6 +3722,148 @@ static bool test_lease_timeout(struct torture_context *tctx, return ret; } +static bool test_lease_rename_wait(struct torture_context *tctx, + struct smb2_tree *tree) +{ + TALLOC_CTX *mem_ctx = talloc_new(tctx); + struct smb2_create io; + struct smb2_lease ls1; + struct smb2_lease ls2; + struct smb2_lease ls3; + struct smb2_handle h1 = {{0}}; + struct smb2_handle h2 = {{0}}; + struct smb2_handle h3 = {{0}}; + union smb_setfileinfo sinfo; + NTSTATUS status; + const char *fname_src = "lease_rename_src.dat"; + const char *fname_dst = "lease_rename_dst.dat"; + bool ret = true; + struct smb2_lease_break_ack ack = {}; + struct smb2_request *rename_req = NULL; + uint32_t caps; + unsigned int i; + + caps = smb2cli_conn_server_capabilities(tree->session->transport->conn); + if (!(caps & SMB2_CAP_LEASING)) { + torture_skip(tctx, "leases are not supported"); + } + + smb2_util_unlink(tree, fname_src); + smb2_util_unlink(tree, fname_dst); + + /* Short timeout for fails. */ + tree->session->transport->options.request_timeout = 15; + + /* Grab a RH lease. */ + smb2_lease_create(&io, + &ls1, + false, + fname_src, + LEASE1, + smb2_util_lease_state("RH")); + status = smb2_create(tree, mem_ctx, &io); + CHECK_STATUS(status, NT_STATUS_OK); + CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE); + CHECK_LEASE(&io, "RH", true, LEASE1, 0); + h1 = io.out.file.handle; + + /* Second open with a RH lease. */ + smb2_lease_create(&io, + &ls2, + false, + fname_src, + LEASE2, + smb2_util_lease_state("RH")); + io.in.create_disposition = NTCREATEX_DISP_OPEN; + io.in.desired_access = GENERIC_READ_ACCESS; + status = smb2_create(tree, mem_ctx, &io); + CHECK_STATUS(status, NT_STATUS_OK); + CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE); + CHECK_LEASE(&io, "RH", true, LEASE2, 0); + h2 = io.out.file.handle; + + /* + * Don't ack a lease break. + */ + tree->session->transport->lease.handler = torture_lease_handler; + tree->session->transport->lease.private_data = tree; + torture_reset_lease_break_info(tctx, &lease_break_info); + lease_break_info.lease_skip_ack = true; + + /* Break with a rename. */ + ZERO_STRUCT(sinfo); + sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION; + sinfo.rename_information.in.file.handle = h1; + sinfo.rename_information.in.overwrite = true; + sinfo.rename_information.in.new_name = fname_dst; + rename_req = smb2_setinfo_file_send(tree, &sinfo); + + torture_assert(tctx, + rename_req != NULL, + "smb2_setinfo_file_send"); + torture_assert(tctx, + rename_req->state == SMB2_REQUEST_RECV, + "rename pending"); + + /* Try and open the destination with a RH lease. */ + smb2_lease_create(&io, + &ls3, + false, + fname_dst, + LEASE3, + smb2_util_lease_state("RH")); + /* We want to open, not create. */ + io.in.create_disposition = NTCREATEX_DISP_OPEN; + io.in.desired_access = GENERIC_READ_ACCESS; + status = smb2_create(tree, mem_ctx, &io); + CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND); + + /* + * The smb2_create() I/O should have picked up the break request + * caused by the pending rename. + */ + + /* Copy the break request. */ + ack.in.lease.lease_key = + lease_break_info.lease_break.current_lease.lease_key; + ack.in.lease.lease_state = + lease_break_info.lease_break.new_lease_state; + + /* + * Give the server 3 more chances to have renamed + * the file. Better than doing a sleep. + */ + for (i = 0; i < 3; i++) { + status = smb2_create(tree, mem_ctx, &io); + CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND); + } + + /* Ack the break. The server is now free to rename. */ + status = smb2_lease_break_ack(tree, &ack); + CHECK_STATUS(status, NT_STATUS_OK); + + /* Get the rename reply. */ + status = smb2_setinfo_recv(rename_req); + CHECK_STATUS(status, NT_STATUS_OK); + + /* The target should now exist. */ + status = smb2_create(tree, mem_ctx, &io); + CHECK_STATUS(status, NT_STATUS_OK); + h3 = io.out.file.handle; + + done: + smb2_util_close(tree, h1); + smb2_util_close(tree, h2); + smb2_util_close(tree, h3); + + smb2_util_unlink(tree, fname_src); + smb2_util_unlink(tree, fname_dst); + + talloc_free(mem_ctx); + + return ret; +} + static bool test_lease_v2_rename(struct torture_context *tctx, struct smb2_tree *tree) { @@ -4336,6 +4478,8 @@ struct torture_suite *torture_smb2_lease_init(TALLOC_CTX *ctx) torture_suite_add_1smb2_test(suite, "timeout", test_lease_timeout); torture_suite_add_1smb2_test(suite, "unlink", test_lease_unlink); torture_suite_add_1smb2_test(suite, "timeout-disconnect", test_lease_timeout_disconnect); + torture_suite_add_1smb2_test(suite, "rename_wait", + test_lease_rename_wait); suite->description = talloc_strdup(suite, "SMB2-LEASE tests"); -- 2.27.0 From d1b661e682452f65272869e020e8aabe344e2694 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Mon, 29 Mar 2021 12:24:39 +0200 Subject: [PATCH 2/2] s3: smbd: fix deferred renames This was broken by c7a9e0e4cdfb22e66533b5c8e20af3cfdb8ae78c. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14679 Signed-off-by: Ralph Boehme Reviewed-by: Jeremy Allison --- selftest/knownfail.d/samba3.smb2.lease | 1 - source3/smbd/smb2_setinfo.c | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 selftest/knownfail.d/samba3.smb2.lease diff --git a/selftest/knownfail.d/samba3.smb2.lease b/selftest/knownfail.d/samba3.smb2.lease deleted file mode 100644 index 4e66e2f6539..00000000000 --- a/selftest/knownfail.d/samba3.smb2.lease +++ /dev/null @@ -1 +0,0 @@ -^samba3.smb2.lease.rename_wait\(nt4_dc\) diff --git a/source3/smbd/smb2_setinfo.c b/source3/smbd/smb2_setinfo.c index 646e009a746..e490596a2e0 100644 --- a/source3/smbd/smb2_setinfo.c +++ b/source3/smbd/smb2_setinfo.c @@ -214,6 +214,7 @@ static bool delay_rename_lease_break_fn( return false; } + state->delay = true; break_to = (e_lease_type & ~SMB2_LEASE_HANDLE); send_break_message( -- 2.27.0