From 2924b4f84d76898ddfeaa096bf540adae4617030 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 22 Sep 2015 18:02:53 -0700 Subject: [PATCH 1/2] s3: smbd: Fix mkdir race condition. Found by Max of LoadDynamix BUG: https://bugzilla.samba.org/show_bug.cgi?id=11486 Signed-off-by: Jeremy Allison Reviewed-by: Volker Lendecke (cherry picked from commit b1c823dc8c2824ec89921601d8e5e95f6d18fca8) --- source3/smbd/open.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/source3/smbd/open.c b/source3/smbd/open.c index 809fa35..162e834 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -3488,6 +3488,25 @@ static NTSTATUS open_directory(connection_struct *conn, nt_errstr(status))); return status; } + + /* + * If mkdir_internal() returned + * NT_STATUS_OBJECT_NAME_COLLISION + * we still must lstat the path. + */ + + if (SMB_VFS_LSTAT(conn, smb_dname) + == -1) { + DEBUG(2, ("Could not stat " + "directory '%s' just " + "opened: %s\n", + smb_fname_str_dbg( + smb_dname), + strerror(errno))); + return map_nt_error_from_unix( + errno); + } + info = FILE_WAS_OPENED; } } -- 2.1.4 From a622531c1d076d957efb44ede90c0dc1742dae9e Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 22 Sep 2015 18:01:22 -0700 Subject: [PATCH 2/2] s4: torture: Test mkdir race condition. Found by Max of LoadDynamix BUG: https://bugzilla.samba.org/show_bug.cgi?id=11486 Signed-off-by: Jeremy Allison Reviewed-by: Volker Lendecke Autobuild-User(master): Volker Lendecke Autobuild-Date(master): Thu Sep 24 06:13:22 CEST 2015 on sn-devel-104 (cherry picked from commit 969d043596c0a382325d54d16dbd5e049f884fa9) --- selftest/knownfail | 1 + source4/torture/smb2/create.c | 151 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 152 insertions(+) diff --git a/selftest/knownfail b/selftest/knownfail index 447544e..bf73176 100644 --- a/selftest/knownfail +++ b/selftest/knownfail @@ -143,6 +143,7 @@ ^samba4.raw.acls.*.create_file ^samba4.smb2.create.*.acldir ^samba4.smb2.create.*.impersonation +^samba4.smb2.create.*.mkdir-dup # bug 11486 ^samba4.smb2.acls.*.generic ^samba4.smb2.acls.*.inheritflags ^samba4.smb2.acls.*.owner diff --git a/source4/torture/smb2/create.c b/source4/torture/smb2/create.c index 44650b5..68dbbc1 100644 --- a/source4/torture/smb2/create.c +++ b/source4/torture/smb2/create.c @@ -1518,6 +1518,156 @@ done: } /* + test SMB2 mkdir with OPEN_IF on the same name twice. + Must use 2 connections to hit the race. +*/ + +static bool test_mkdir_dup(struct torture_context *tctx, + struct smb2_tree *tree) +{ + const char *fname = "mkdir_dup"; + NTSTATUS status; + bool ret = true; + union smb_open io; + struct smb2_tree **trees; + struct smb2_request **requests; + union smb_open *ios; + int i, num_files = 2; + int num_ok = 0; + int num_created = 0; + int num_existed = 0; + + torture_comment(tctx, + "Testing SMB2 Create Directory with multiple connections\n"); + trees = talloc_array(tctx, struct smb2_tree *, num_files); + requests = talloc_array(tctx, struct smb2_request *, num_files); + ios = talloc_array(tctx, union smb_open, num_files); + if ((tctx->ev == NULL) || (trees == NULL) || (requests == NULL) || + (ios == NULL)) { + torture_fail(tctx, ("talloc failed\n")); + ret = false; + goto done; + } + + tree->session->transport->options.request_timeout = 60; + + for (i=0; isession->transport->options.request_timeout = 60; + } + + /* cleanup */ + smb2_util_unlink(tree, fname); + smb2_util_rmdir(tree, fname); + + /* + base ntcreatex parms + */ + ZERO_STRUCT(io.smb2); + io.generic.level = RAW_OPEN_SMB2; + io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL; + io.smb2.in.alloc_size = 0; + io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL; + io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ| + NTCREATEX_SHARE_ACCESS_WRITE| + NTCREATEX_SHARE_ACCESS_DELETE; + io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF; + io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY; + io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS; + io.smb2.in.security_flags = 0; + io.smb2.in.fname = fname; + io.smb2.in.create_flags = 0; + + for (i=0; istate < SMB2_REQUEST_DONE) { + unreplied = true; + break; + } + status = smb2_create_recv(requests[i], tctx, + &(ios[i].smb2)); + + if (NT_STATUS_IS_OK(status)) { + num_ok += 1; + + if (ios[i].smb2.out.create_action == + NTCREATEX_ACTION_CREATED) { + num_created++; + } + if (ios[i].smb2.out.create_action == + NTCREATEX_ACTION_EXISTED) { + num_existed++; + } + } else { + torture_fail(tctx, + talloc_asprintf(tctx, + "File %d returned status %s\n", i, + nt_errstr(status))); + } + + + requests[i] = NULL; + } + if (!unreplied) { + break; + } + + if (tevent_loop_once(tctx->ev) != 0) { + torture_fail(tctx, "tevent_loop_once failed\n"); + ret = false; + goto done; + } + } + + if (num_ok != 2) { + torture_fail(tctx, + talloc_asprintf(tctx, + "num_ok == %d\n", num_ok)); + ret = false; + } + if (num_created != 1) { + torture_fail(tctx, + talloc_asprintf(tctx, + "num_created == %d\n", num_created)); + ret = false; + } + if (num_existed != 1) { + torture_fail(tctx, + talloc_asprintf(tctx, + "num_existed == %d\n", num_existed)); + ret = false; + } +done: + smb2_deltree(tree, fname); + + return ret; +} + + +/* basic testing of SMB2 read */ struct torture_suite *torture_smb2_create_init(void) @@ -1535,6 +1685,7 @@ struct torture_suite *torture_smb2_create_init(void) torture_suite_add_1smb2_test(suite, "aclfile", test_create_acl_file); torture_suite_add_1smb2_test(suite, "acldir", test_create_acl_dir); torture_suite_add_1smb2_test(suite, "nulldacl", test_create_null_dacl); + torture_suite_add_1smb2_test(suite, "mkdir-dup", test_mkdir_dup); suite->description = talloc_strdup(suite, "SMB2-CREATE tests"); -- 2.1.4