The branch, v4-7-test has been updated via b21740a torture: Demonstrate the invalid lock order panic via 8ef80a0 vfs_fruit: Fix a leak of "br_lck" via a73d973 selftest: Load time_audit and full_audit modules for all tests via 0470afa s3: vfs: time_audit: fix handling of token_blob in smb_time_audit_offload_read_recv() via a329764 g_lock: Fix lock upgrades via cc4eed2 torture3: Extend the g_lock6 test to also cover upgrades via 72a4177 torture3: add LOCAL-G-LOCK6 test from 50b081a selftest: subunithelper needs to follow the subunit spec more closely
https://git.samba.org/?p=samba.git;a=shortlog;h=v4-7-test - Log ----------------------------------------------------------------- commit b21740a25ac098735fbf27ae4d6063885405a977 Author: Volker Lendecke <v...@samba.org> Date: Mon Aug 6 14:35:15 2018 +0200 torture: Demonstrate the invalid lock order panic BUG: https://bugzilla.samba.org/show_bug.cgi?id=13584 Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> Autobuild-User(master): Jeremy Allison <j...@samba.org> Autobuild-Date(master): Tue Aug 21 02:33:05 CEST 2018 on sn-devel-144 (cherry picked from commit ec3c37ee53f21d8c0e80b1d3b3d7e95a4ac8e0bc) Autobuild-User(v4-7-test): Karolin Seeger <ksee...@samba.org> Autobuild-Date(v4-7-test): Thu Aug 23 15:48:56 CEST 2018 on sn-devel-144 commit 8ef80a001b961309d820a61404d41e23bef9ad1c Author: Volker Lendecke <v...@samba.org> Date: Mon Aug 6 14:33:34 2018 +0200 vfs_fruit: Fix a leak of "br_lck" Fix a panic if fruit_access_check detects a locking conflict. do_lock() returns a valid br_lck even in case of a locking conflict. Not free'ing it leads to a invalid lock order panic later, because "br_lck" corresponds to a dbwrap lock on brlock.tdb. BUG: https://bugzilla.samba.org/show_bug.cgi?id=13584 Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> (cherry picked from commit 51d57073798f76ec4f1261945e0ba779b2530009) commit a73d973f0869f2222b92723bf5acf86a9eaf4029 Author: Christof Schmitt <c...@samba.org> Date: Fri Aug 10 10:38:28 2018 -0700 selftest: Load time_audit and full_audit modules for all tests Previously the only test was to load these modules to trigger the smb_vfs_assert_all_fns check. As these modules just pass through the calls, they can be loaded for all tests to ensure that the codepaths are exercised. This would have found the problem in smb_time_audit_offload_read_recv. BUG: https://bugzilla.samba.org/show_bug.cgi?id=13568 Signed-off-by: Christof Schmitt <c...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> Autobuild-User(master): Jeremy Allison <j...@samba.org> Autobuild-Date(master): Mon Aug 13 22:35:20 CEST 2018 on sn-devel-144 (cherry picked from commit a98f09a09db2fc7be85f9171b586e65344a39e92) commit 0470afae4398c2bae388dd30d31d85bd6cf469c9 Author: Ralph Wuerthner <ralph.wuerth...@de.ibm.com> Date: Wed Aug 8 17:42:18 2018 +0200 s3: vfs: time_audit: fix handling of token_blob in smb_time_audit_offload_read_recv() BUG: https://bugzilla.samba.org/show_bug.cgi?id=13568 Signed-off-by: Ralph Wuerthner <ralph.wuerth...@de.ibm.com> Reviewed-by: Christof Schmitt <c...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> (cherry picked from commit 4909b966050c921b0a6a32285fee55f5f14dc3ff) commit a3297648fa049471cc6b3767e34d9b8731473bd9 Author: Volker Lendecke <v...@samba.org> Date: Tue Aug 14 14:31:01 2018 +0200 g_lock: Fix lock upgrades Master has changed significantly, this is a minimum fix for 4.7 without cleaning up the code BUG: https://bugzilla.samba.org/show_bug.cgi?id=13195 Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Stefan Metzmacher <me...@samba.org> commit cc4eed27367822c1829778cb0599c962b54e17f6 Author: Volker Lendecke <v...@samba.org> Date: Tue Aug 14 13:54:56 2018 +0200 torture3: Extend the g_lock6 test to also cover upgrades The fixes for #13195 were incomplete and did not cover upgrades properly. It's all gone in master with the new code. BUG: https://bugzilla.samba.org/show_bug.cgi?id=13195 Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Stefan Metzmacher <me...@samba.org> commit 72a417741bf90b1a20e4d28cf720d43a3a358d03 Author: Stefan Metzmacher <me...@samba.org> Date: Wed Dec 20 09:44:40 2017 +0100 torture3: add LOCAL-G-LOCK6 test This is a regression test for bug #13195. BUG: https://bugzilla.samba.org/show_bug.cgi?id=13195 Signed-off-by: Stefan Metzmacher <me...@samba.org> Reviewed-by: Volker Lendecke <v...@samba.org> ----------------------------------------------------------------------- Summary of changes: selftest/target/Samba3.pm | 12 +-- source3/lib/g_lock.c | 4 + source3/modules/vfs_fruit.c | 24 ++++-- source3/modules/vfs_time_audit.c | 12 +-- source3/selftest/tests.py | 1 + source3/torture/proto.h | 1 + source3/torture/test_g_lock.c | 168 +++++++++++++++++++++++++++++++++++++++ source3/torture/torture.c | 1 + source4/torture/vfs/fruit.c | 89 +++++++++++++++++++++ 9 files changed, 289 insertions(+), 23 deletions(-) Changeset truncated at 500 lines: diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm index 39a8f49..9c41b8c 100755 --- a/selftest/target/Samba3.pm +++ b/selftest/target/Samba3.pm @@ -700,14 +700,10 @@ sub setup_simpleserver($$) my $simpleserver_options = " lanman auth = yes ntlm auth = yes - vfs objects = xattr_tdb streams_depot time_audit full_audit + vfs objects = xattr_tdb streams_depot change notify = no smb encrypt = off - full_audit:syslog = no - full_audit:success = none - full_audit:failure = none - [vfs_aio_fork] path = $prefix_abs/share vfs objects = aio_fork @@ -1641,7 +1637,11 @@ sub provision($$$$$$$$$) dos filemode = yes strict rename = yes strict sync = yes - vfs objects = acl_xattr fake_acls xattr_tdb streams_depot + vfs objects = acl_xattr fake_acls xattr_tdb streams_depot time_audit full_audit + + full_audit:syslog = no + full_audit:success = none + full_audit:failure = none printing = vlp print command = $bindir_abs/vlp tdbfile=$lockdir/vlp.tdb print %p %s diff --git a/source3/lib/g_lock.c b/source3/lib/g_lock.c index 76b4af5..a53f6a1 100644 --- a/source3/lib/g_lock.c +++ b/source3/lib/g_lock.c @@ -329,6 +329,10 @@ static NTSTATUS g_lock_trylock(struct db_record *rec, struct server_id self, * Delete stale conflicting entry */ locks[i] = locks[num_locks-1]; + if (my_lock == num_locks-1) { + /* We just moved */ + my_lock = i; + } num_locks -= 1; modified = true; continue; diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c index 47034de..684fcd6 100644 --- a/source3/modules/vfs_fruit.c +++ b/source3/modules/vfs_fruit.c @@ -2372,7 +2372,6 @@ static NTSTATUS fruit_check_access(vfs_handle_struct *handle, uint32_t deny_mode) { NTSTATUS status = NT_STATUS_OK; - struct byte_range_lock *br_lck = NULL; bool open_for_reading, open_for_writing, deny_read, deny_write; off_t off; bool have_read = false; @@ -2430,6 +2429,8 @@ static NTSTATUS fruit_check_access(vfs_handle_struct *handle, /* Set locks */ if ((access_mask & FILE_READ_DATA) && have_read) { + struct byte_range_lock *br_lck = NULL; + off = access_to_netatalk_brl(fork_type, FILE_READ_DATA); br_lck = do_lock( handle->conn->sconn->msg_ctx, fsp, @@ -2437,13 +2438,16 @@ static NTSTATUS fruit_check_access(vfs_handle_struct *handle, READ_LOCK, POSIX_LOCK, false, &status, NULL); + TALLOC_FREE(br_lck); + if (!NT_STATUS_IS_OK(status)) { return status; } - TALLOC_FREE(br_lck); } if ((deny_mode & DENY_READ) && have_read) { + struct byte_range_lock *br_lck = NULL; + off = denymode_to_netatalk_brl(fork_type, DENY_READ); br_lck = do_lock( handle->conn->sconn->msg_ctx, fsp, @@ -2451,10 +2455,11 @@ static NTSTATUS fruit_check_access(vfs_handle_struct *handle, READ_LOCK, POSIX_LOCK, false, &status, NULL); + TALLOC_FREE(br_lck); + if (!NT_STATUS_IS_OK(status)) { return status; } - TALLOC_FREE(br_lck); } } @@ -2480,6 +2485,8 @@ static NTSTATUS fruit_check_access(vfs_handle_struct *handle, /* Set locks */ if ((access_mask & FILE_WRITE_DATA) && have_read) { + struct byte_range_lock *br_lck = NULL; + off = access_to_netatalk_brl(fork_type, FILE_WRITE_DATA); br_lck = do_lock( handle->conn->sconn->msg_ctx, fsp, @@ -2487,13 +2494,15 @@ static NTSTATUS fruit_check_access(vfs_handle_struct *handle, READ_LOCK, POSIX_LOCK, false, &status, NULL); + TALLOC_FREE(br_lck); + if (!NT_STATUS_IS_OK(status)) { return status; } - TALLOC_FREE(br_lck); - } if ((deny_mode & DENY_WRITE) && have_read) { + struct byte_range_lock *br_lck = NULL; + off = denymode_to_netatalk_brl(fork_type, DENY_WRITE); br_lck = do_lock( handle->conn->sconn->msg_ctx, fsp, @@ -2501,15 +2510,14 @@ static NTSTATUS fruit_check_access(vfs_handle_struct *handle, READ_LOCK, POSIX_LOCK, false, &status, NULL); + TALLOC_FREE(br_lck); + if (!NT_STATUS_IS_OK(status)) { return status; } - TALLOC_FREE(br_lck); } } - TALLOC_FREE(br_lck); - return status; } diff --git a/source3/modules/vfs_time_audit.c b/source3/modules/vfs_time_audit.c index 7116796..59d5911 100644 --- a/source3/modules/vfs_time_audit.c +++ b/source3/modules/vfs_time_audit.c @@ -1946,13 +1946,12 @@ static NTSTATUS smb_time_audit_offload_read_recv( struct tevent_req *req, struct vfs_handle_struct *handle, TALLOC_CTX *mem_ctx, - DATA_BLOB *_token_blob) + DATA_BLOB *token_blob) { struct time_audit_offload_read_state *state = tevent_req_data( req, struct time_audit_offload_read_state); struct timespec ts_recv; double timediff; - DATA_BLOB token_blob; NTSTATUS status; clock_gettime_mono(&ts_recv); @@ -1966,13 +1965,8 @@ static NTSTATUS smb_time_audit_offload_read_recv( return status; } - token_blob = data_blob_talloc(mem_ctx, - state->token_blob.data, - state->token_blob.length); - if (token_blob.data == NULL) { - tevent_req_received(req); - return NT_STATUS_NO_MEMORY; - } + token_blob->length = state->token_blob.length; + token_blob->data = talloc_move(mem_ctx, &state->token_blob.data); tevent_req_received(req); return NT_STATUS_OK; diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py index 696c44b..9362627 100755 --- a/source3/selftest/tests.py +++ b/source3/selftest/tests.py @@ -161,6 +161,7 @@ local_tests = [ "LOCAL-G-LOCK3", "LOCAL-G-LOCK4", "LOCAL-G-LOCK5", + "LOCAL-G-LOCK6", "LOCAL-hex_encode_buf", "LOCAL-remove_duplicate_addrs2"] diff --git a/source3/torture/proto.h b/source3/torture/proto.h index a840038..327fa3d 100644 --- a/source3/torture/proto.h +++ b/source3/torture/proto.h @@ -132,5 +132,6 @@ bool run_g_lock2(int dummy); bool run_g_lock3(int dummy); bool run_g_lock4(int dummy); bool run_g_lock5(int dummy); +bool run_g_lock6(int dummy); #endif /* __TORTURE_H__ */ diff --git a/source3/torture/test_g_lock.c b/source3/torture/test_g_lock.c index ca37312..b3b0d79 100644 --- a/source3/torture/test_g_lock.c +++ b/source3/torture/test_g_lock.c @@ -642,3 +642,171 @@ bool run_g_lock5(int dummy) return true; } + +struct lock6_parser_state { + size_t num_locks; +}; + +static void lock6_parser(const struct g_lock_rec *locks, + size_t num_locks, + const uint8_t *data, + size_t datalen, + void *private_data) +{ + struct lock6_parser_state *state = private_data; + state->num_locks = num_locks; +} + +/* + * Test cleanup with contention and stale locks + */ + +bool run_g_lock6(int dummy) +{ + struct tevent_context *ev = NULL; + struct messaging_context *msg = NULL; + struct g_lock_ctx *ctx = NULL; + const char *lockname = "lock6"; + pid_t child; + int exit_pipe[2], ready_pipe[2]; + NTSTATUS status; + size_t i, nprocs; + int ret; + bool ok; + ssize_t nread; + char c; + + if ((pipe(exit_pipe) != 0) || (pipe(ready_pipe) != 0)) { + perror("pipe failed"); + return false; + } + + ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx); + if (!ok) { + fprintf(stderr, "get_g_lock_ctx failed"); + return false; + } + + nprocs = 2; + for (i=0; i<nprocs; i++) { + + child = fork(); + + if (child == -1) { + perror("fork failed"); + return false; + } + + if (child == 0) { + TALLOC_FREE(ctx); + + status = reinit_after_fork(msg, ev, false, ""); + if (!NT_STATUS_IS_OK(status)) { + fprintf(stderr, "reinit_after_fork failed: %s\n", + nt_errstr(status)); + exit(1); + } + + close(ready_pipe[0]); + close(exit_pipe[1]); + + ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx); + if (!ok) { + fprintf(stderr, "get_g_lock_ctx failed"); + exit(1); + } + status = g_lock_lock(ctx, lockname, G_LOCK_READ, + (struct timeval) { .tv_sec = 1 }); + if (!NT_STATUS_IS_OK(status)) { + fprintf(stderr, + "child g_lock_lock failed %s\n", + nt_errstr(status)); + exit(1); + } + if (i == 0) { + exit(0); + } + close(ready_pipe[1]); + nread = sys_read(exit_pipe[0], &c, sizeof(c)); + if (nread != 0) { + fprintf(stderr, "sys_read returned %zu (%s)\n", + nread, strerror(errno)); + exit(1); + } + exit(0); + } + } + + close(ready_pipe[1]); + + nread = sys_read(ready_pipe[0], &c, sizeof(c)); + if (nread != 0) { + fprintf(stderr, "sys_read returned %zd (%s)\n", + nread, strerror(errno)); + return false; + } + + { + int child_status; + ret = waitpid(-1, &child_status, 0); + if (ret == -1) { + perror("waitpid failed"); + return false; + } + } + + { + struct lock6_parser_state state; + + status = g_lock_dump(ctx, lockname, lock6_parser, &state); + if (!NT_STATUS_IS_OK(status)) { + fprintf(stderr, "g_lock_dump returned %s\n", + nt_errstr(status)); + return false; + } + + if (state.num_locks != nprocs) { + fprintf(stderr, "nlocks=%zu, expected %zu\n", + state.num_locks, nprocs); + return false; + } + + status = g_lock_lock(ctx, lockname, G_LOCK_WRITE, + (struct timeval) { .tv_sec = 1 }); + if (!NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) { + fprintf(stderr, "g_lock_lock should have failed with %s - %s\n", + nt_errstr(NT_STATUS_IO_TIMEOUT), + nt_errstr(status)); + return false; + } + + status = g_lock_lock(ctx, lockname, G_LOCK_READ, + (struct timeval) { .tv_sec = 1 }); + if (!NT_STATUS_IS_OK(status)) { + fprintf(stderr, "g_lock_lock failed: %s\n", + nt_errstr(status)); + return false; + } + } + + close(exit_pipe[1]); + + { + int child_status; + ret = waitpid(-1, &child_status, 0); + if (ret == -1) { + perror("waitpid failed"); + return false; + } + } + + status = g_lock_lock(ctx, lockname, G_LOCK_WRITE, + (struct timeval) { .tv_sec = 1 }); + if (!NT_STATUS_IS_OK(status)) { + fprintf(stderr, "g_lock_lock failed: %s\n", + nt_errstr(status)); + return false; + } + + return true; +} diff --git a/source3/torture/torture.c b/source3/torture/torture.c index f0eb059..7c3e8c4 100644 --- a/source3/torture/torture.c +++ b/source3/torture/torture.c @@ -11848,6 +11848,7 @@ static struct { { "LOCAL-G-LOCK3", run_g_lock3, 0 }, { "LOCAL-G-LOCK4", run_g_lock4, 0 }, { "LOCAL-G-LOCK5", run_g_lock5, 0 }, + { "LOCAL-G-LOCK6", run_g_lock6, 0 }, { "LOCAL-CANONICALIZE-PATH", run_local_canonicalize_path, 0 }, { "qpathinfo-bufsize", run_qpathinfo_bufsize, 0 }, {NULL, NULL, 0}}; diff --git a/source4/torture/vfs/fruit.c b/source4/torture/vfs/fruit.c index 7f6a8ef..9dec254 100644 --- a/source4/torture/vfs/fruit.c +++ b/source4/torture/vfs/fruit.c @@ -4886,6 +4886,93 @@ done: return ret; } +static bool test_fruit_locking_conflict(struct torture_context *tctx, + struct smb2_tree *tree) +{ + TALLOC_CTX *mem_ctx; + struct smb2_create create; + struct smb2_handle h; + struct smb2_lock lck; + struct smb2_lock_element el; + const char *fname = BASEDIR "\\locking_conflict.txt"; + NTSTATUS status; + bool ret = false; + + mem_ctx = talloc_new(tctx); + torture_assert_not_null(tctx, mem_ctx, "talloc_new failed"); + + /* clean slate ...*/ + smb2_util_unlink(tree, fname); + smb2_deltree(tree, fname); + smb2_deltree(tree, BASEDIR); + + status = torture_smb2_testdir(tree, BASEDIR, &h); + CHECK_STATUS(status, NT_STATUS_OK); + smb2_util_close(tree, h); + + create = (struct smb2_create) { + .in.desired_access = SEC_RIGHTS_FILE_READ, + .in.file_attributes = FILE_ATTRIBUTE_NORMAL, + .in.share_access = + NTCREATEX_SHARE_ACCESS_READ| + NTCREATEX_SHARE_ACCESS_WRITE, + .in.create_disposition = NTCREATEX_DISP_CREATE, + .in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS, + .in.fname = fname, + }; + + status = smb2_create(tree, mem_ctx, &create); + CHECK_STATUS(status, NT_STATUS_OK); + h = create.out.file.handle; + + el = (struct smb2_lock_element) { + .offset = 0xfffffffffffffffc, + .length = 1, + .flags = SMB2_LOCK_FLAG_EXCLUSIVE, + }; + lck = (struct smb2_lock) { + .in.lock_count = 1, + .in.file.handle = h, + .in.locks = &el, + }; + + status = smb2_lock(tree, &lck); + CHECK_STATUS(status, NT_STATUS_OK); + + el = (struct smb2_lock_element) { + .offset = 0, + .length = 0x7fffffffffffffff, + .flags = SMB2_LOCK_FLAG_EXCLUSIVE, + }; + status = smb2_lock(tree, &lck); + CHECK_STATUS(status, NT_STATUS_OK); + + create = (struct smb2_create) { + .in.desired_access = + SEC_RIGHTS_FILE_READ|SEC_RIGHTS_FILE_WRITE, + .in.file_attributes = FILE_ATTRIBUTE_NORMAL, + .in.share_access = NTCREATEX_SHARE_ACCESS_READ, + .in.create_disposition = NTCREATEX_DISP_OPEN, + .in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS, + .in.fname = fname, + }; + + status = smb2_create(tree, mem_ctx, &create); + CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); + + { + struct smb2_close cl = { + .level = RAW_CLOSE_SMB2, + .in.file.handle = h, + }; + smb2_close(tree, &cl); + } + + ret = true; +done: + return ret; +} + struct torture_suite *torture_vfs_fruit_netatalk(TALLOC_CTX *ctx) { struct torture_suite *suite = torture_suite_create( @@ -4895,6 +4982,8 @@ struct torture_suite *torture_vfs_fruit_netatalk(TALLOC_CTX *ctx) torture_suite_add_1smb2_test(suite, "read netatalk metadata", test_read_netatalk_metadata); torture_suite_add_1smb2_test(suite, "stream names with locally created xattr", test_stream_names_local); + torture_suite_add_1smb2_test( + suite, "locking conflict", test_fruit_locking_conflict); return suite; } -- Samba Shared Repository