diff options
author | Volker Lendecke <vlendec@samba.org> | 2005-08-24 13:15:01 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 13:34:32 -0500 |
commit | 11f4803d002bf5a4bba24103d6c472ea638e196e (patch) | |
tree | c3516a362d4e07aa6c155483cab7009bb2d6d78e /source4/torture | |
parent | ca71549d5af608a280645f69016749ae9da89747 (diff) | |
download | samba-11f4803d002bf5a4bba24103d6c472ea638e196e.tar.gz samba-11f4803d002bf5a4bba24103d6c472ea638e196e.tar.bz2 samba-11f4803d002bf5a4bba24103d6c472ea638e196e.zip |
r9584: Fix a race condition in Samba 3. If two files are opened simultaneously with
NTCREATEX_DISP_CREATE (create if not exists, else fail) they might end up with
two or more times NT_STATUS_OK as EEXIST is not correctly handled.
Jeremy, please look closely at this. You can easily verify this by adding a
smb_msleep(100) to the top of open_file_ntcreate and run the new samba4
torture test. It does also happen without the msleep, but not as reliably.
Thanks,
Volker
(This used to be commit c803d4c9a588e39a90ddfe900be9b9de1a861f82)
Diffstat (limited to 'source4/torture')
-rw-r--r-- | source4/torture/raw/open.c | 126 | ||||
-rw-r--r-- | source4/torture/torture.c | 19 |
2 files changed, 137 insertions, 8 deletions
diff --git a/source4/torture/raw/open.c b/source4/torture/raw/open.c index 6795fbdee9..9433232bc8 100644 --- a/source4/torture/raw/open.c +++ b/source4/torture/raw/open.c @@ -23,6 +23,7 @@ #include "system/time.h" #include "system/filesys.h" #include "librpc/gen_ndr/ndr_security.h" +#include "lib/events/events.h" /* enum for whether reads/writes are possible on a file */ enum rdwr_mode {RDWR_NONE, RDWR_RDONLY, RDWR_WRONLY, RDWR_RDWR}; @@ -1236,6 +1237,130 @@ done: return ret; } +/* A little torture test to expose a race condition in Samba 3.0.20 ... :-) */ + +static BOOL test_raw_open_multi(void) +{ + struct smbcli_state *cli; + TALLOC_CTX *mem_ctx = talloc_init("torture_test_oplock_multi"); + const char *fname = "\\test_oplock.dat"; + NTSTATUS status; + BOOL ret = True; + union smb_open io; + struct smbcli_state **clients; + struct smbcli_request **requests; + union smb_open *ios; + const char *host = lp_parm_string(-1, "torture", "host"); + const char *share = lp_parm_string(-1, "torture", "share"); + int i, num_files = 3; + struct event_context *ev; + int num_ok = 0; + int num_collision = 0; + + ev = event_context_init(mem_ctx); + clients = talloc_array(mem_ctx, struct smbcli_state *, num_files); + requests = talloc_array(mem_ctx, struct smbcli_request *, num_files); + ios = talloc_array(mem_ctx, union smb_open, num_files); + if ((ev == NULL) || (clients == NULL) || (requests == NULL) || + (ios == NULL)) { + DEBUG(0, ("talloc failed\n")); + return False; + } + + if (!torture_open_connection_share(mem_ctx, &cli, host, share, ev)) { + return False; + } + + cli->tree->session->transport->options.request_timeout = 60000; + + for (i=0; i<num_files; i++) { + if (!torture_open_connection_share(mem_ctx, &(clients[i]), + host, share, ev)) { + DEBUG(0, ("Could not open %d'th connection\n", i)); + return False; + } + clients[i]->tree->session->transport-> + options.request_timeout = 60000; + } + + /* cleanup */ + smbcli_unlink(cli->tree, fname); + + /* + base ntcreatex parms + */ + io.generic.level = RAW_OPEN_NTCREATEX; + io.ntcreatex.in.root_fid = 0; + io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL; + io.ntcreatex.in.alloc_size = 0; + io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL; + io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ| + NTCREATEX_SHARE_ACCESS_WRITE| + NTCREATEX_SHARE_ACCESS_DELETE; + io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE; + io.ntcreatex.in.create_options = 0; + io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS; + io.ntcreatex.in.security_flags = 0; + io.ntcreatex.in.fname = fname; + io.ntcreatex.in.flags = 0; + + for (i=0; i<num_files; i++) { + ios[i] = io; + requests[i] = smb_raw_open_send(clients[i]->tree, &ios[i]); + if (requests[i] == NULL) { + DEBUG(0, ("could not send %d'th request\n", i)); + return False; + } + } + + DEBUG(10, ("waiting for replies\n")); + while (1) { + BOOL unreplied = False; + for (i=0; i<num_files; i++) { + if (requests[i] == NULL) { + continue; + } + if (requests[i]->state < SMBCLI_REQUEST_DONE) { + unreplied = True; + break; + } + status = smb_raw_open_recv(requests[i], mem_ctx, + &ios[i]); + + DEBUG(0, ("File %d returned status %s\n", i, + nt_errstr(status))); + + if (NT_STATUS_IS_OK(status)) { + num_ok += 1; + } + + if (NT_STATUS_EQUAL(status, + NT_STATUS_OBJECT_NAME_COLLISION)) { + num_collision += 1; + } + + requests[i] = NULL; + } + if (!unreplied) { + break; + } + + if (event_loop_once(ev) != 0) { + DEBUG(0, ("event_loop_once failed\n")); + return False; + } + } + + if ((num_ok != 1) || (num_ok + num_collision != num_files)) { + ret = False; + } + + for (i=0; i<num_files; i++) { + torture_close_connection(clients[i]); + } + talloc_free(mem_ctx); + return ret; +} /* basic testing of all RAW_OPEN_* calls */ @@ -1257,6 +1382,7 @@ BOOL torture_raw_open(void) ret &= test_ntcreatex_brlocked(cli, mem_ctx); ret &= test_open(cli, mem_ctx); + ret &= test_raw_open_multi(); ret &= test_openx(cli, mem_ctx); ret &= test_ntcreatex(cli, mem_ctx); ret &= test_nttrans_create(cli, mem_ctx); diff --git a/source4/torture/torture.c b/source4/torture/torture.c index 436c7281bd..dde3c7bd5b 100644 --- a/source4/torture/torture.c +++ b/source4/torture/torture.c @@ -76,16 +76,17 @@ failed: return NULL; } -BOOL torture_open_connection_share(struct smbcli_state **c, +BOOL torture_open_connection_share(TALLOC_CTX *mem_ctx, + struct smbcli_state **c, const char *hostname, - const char *sharename) + const char *sharename, + struct event_context *ev) { NTSTATUS status; - status = smbcli_full_connection(NULL, - c, hostname, + status = smbcli_full_connection(mem_ctx, c, hostname, sharename, NULL, - cmdline_credentials, NULL); + cmdline_credentials, ev); if (!NT_STATUS_IS_OK(status)) { printf("Failed to open connection - %s\n", nt_errstr(status)); return False; @@ -102,7 +103,7 @@ BOOL torture_open_connection(struct smbcli_state **c) const char *host = lp_parm_string(-1, "torture", "host"); const char *share = lp_parm_string(-1, "torture", "share"); - return torture_open_connection_share(c, host, share); + return torture_open_connection_share(NULL, c, host, share, NULL); } @@ -2107,9 +2108,11 @@ double torture_create_procs(BOOL (*fn)(struct smbcli_state *, int), BOOL *result while (1) { if (hostname) { - if (torture_open_connection_share(¤t_cli, + if (torture_open_connection_share(NULL, + ¤t_cli, hostname, - sharename)) { + sharename, + NULL)) { break; } } else if (torture_open_connection(¤t_cli)) { |