summaryrefslogtreecommitdiff
path: root/source4/torture
diff options
context:
space:
mode:
authorVolker Lendecke <vlendec@samba.org>2005-08-24 13:15:01 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 13:34:32 -0500
commit11f4803d002bf5a4bba24103d6c472ea638e196e (patch)
treec3516a362d4e07aa6c155483cab7009bb2d6d78e /source4/torture
parentca71549d5af608a280645f69016749ae9da89747 (diff)
downloadsamba-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.c126
-rw-r--r--source4/torture/torture.c19
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(&current_cli,
+ if (torture_open_connection_share(NULL,
+ &current_cli,
hostname,
- sharename)) {
+ sharename,
+ NULL)) {
break;
}
} else if (torture_open_connection(&current_cli)) {