summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/selftest/knownfail2
-rw-r--r--source4/torture/raw/lock.c155
-rw-r--r--source4/torture/smb2/lock.c120
3 files changed, 276 insertions, 1 deletions
diff --git a/source4/selftest/knownfail b/source4/selftest/knownfail
index b9d40f2409..ef3c10c32d 100644
--- a/source4/selftest/knownfail
+++ b/source4/selftest/knownfail
@@ -67,3 +67,5 @@ samba4.raw.lock.*.async # bug 6960
samba4.smb2.lock.*.MULTIPLE-UNLOCK # bug 6959
samba4.raw.sfileinfo.*.END-OF-FILE # bug 6962
samba4.raw.oplock.*.BATCH22 # bug 6963
+samba4.raw.lock.*.zerobyteread # bug 6974
+samba4.smb2.lock.*.ZEROBYTEREAD # bug 6974
diff --git a/source4/torture/raw/lock.c b/source4/torture/raw/lock.c
index 05d9beda30..34b05b70e4 100644
--- a/source4/torture/raw/lock.c
+++ b/source4/torture/raw/lock.c
@@ -1997,7 +1997,158 @@ done:
return ret;
}
-/*
+/**
+ * Test how 0-byte read requests contend with byte range locks
+ */
+static bool test_zerobyteread(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ union smb_lock io;
+ union smb_read rd;
+ NTSTATUS status;
+ bool ret = true;
+ int fnum1, fnum2;
+ const char *fname = BASEDIR "\\zerobyteread.txt";
+ struct smb_lock_entry lock1;
+ uint8_t c = 1;
+
+ if (!torture_setup_dir(cli, BASEDIR)) {
+ return false;
+ }
+
+ io.generic.level = RAW_LOCK_LOCKX;
+
+ fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+ torture_assert(tctx,(fnum1 != -1), talloc_asprintf(tctx,
+ "Failed to create %s - %s\n",
+ fname, smbcli_errstr(cli->tree)));
+
+ fnum2 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+ torture_assert(tctx,(fnum2 != -1), talloc_asprintf(tctx,
+ "Failed to create %s - %s\n",
+ fname, smbcli_errstr(cli->tree)));
+
+ /* Setup initial parameters */
+ io.lockx.level = RAW_LOCK_LOCKX;
+ io.lockx.in.timeout = 0;
+
+ lock1.pid = cli->session->pid;
+ lock1.offset = 0;
+ lock1.count = 10;
+
+ ZERO_STRUCT(rd);
+ rd.readx.level = RAW_READ_READX;
+
+ torture_comment(tctx, "Testing zero byte read on lock range:\n");
+
+ /* Take an exclusive lock */
+ torture_comment(tctx, " taking exclusive lock.\n");
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ io.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK;
+ io.lockx.in.file.fnum = fnum1;
+ io.lockx.in.locks = &lock1;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Try a zero byte read */
+ torture_comment(tctx, " reading 0 bytes.\n");
+ rd.readx.in.file.fnum = fnum2;
+ rd.readx.in.offset = 5;
+ rd.readx.in.mincnt = 0;
+ rd.readx.in.maxcnt = 0;
+ rd.readx.in.remaining = 0;
+ rd.readx.in.read_for_execute = false;
+ rd.readx.out.data = &c;
+ status = smb_raw_read(cli->tree, &rd);
+ torture_assert_int_equal_goto(tctx, rd.readx.out.nread, 0, ret, done,
+ "zero byte read did not return 0 bytes");
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Unlock lock */
+ io.lockx.in.ulock_cnt = 1;
+ io.lockx.in.lock_cnt = 0;
+ io.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK;
+ io.lockx.in.file.fnum = fnum1;
+ io.lockx.in.locks = &lock1;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "Testing zero byte read on zero byte lock "
+ "range:\n");
+
+ /* Take an exclusive lock */
+ torture_comment(tctx, " taking exclusive 0-byte lock.\n");
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ io.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK;
+ io.lockx.in.file.fnum = fnum1;
+ io.lockx.in.locks = &lock1;
+ lock1.offset = 5;
+ lock1.count = 0;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Try a zero byte read before the lock */
+ torture_comment(tctx, " reading 0 bytes before the lock.\n");
+ rd.readx.in.file.fnum = fnum2;
+ rd.readx.in.offset = 4;
+ rd.readx.in.mincnt = 0;
+ rd.readx.in.maxcnt = 0;
+ rd.readx.in.remaining = 0;
+ rd.readx.in.read_for_execute = false;
+ rd.readx.out.data = &c;
+ status = smb_raw_read(cli->tree, &rd);
+ torture_assert_int_equal_goto(tctx, rd.readx.out.nread, 0, ret, done,
+ "zero byte read did not return 0 bytes");
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Try a zero byte read on the lock */
+ torture_comment(tctx, " reading 0 bytes on the lock.\n");
+ rd.readx.in.file.fnum = fnum2;
+ rd.readx.in.offset = 5;
+ rd.readx.in.mincnt = 0;
+ rd.readx.in.maxcnt = 0;
+ rd.readx.in.remaining = 0;
+ rd.readx.in.read_for_execute = false;
+ rd.readx.out.data = &c;
+ status = smb_raw_read(cli->tree, &rd);
+ torture_assert_int_equal_goto(tctx, rd.readx.out.nread, 0, ret, done,
+ "zero byte read did not return 0 bytes");
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Try a zero byte read after the lock */
+ torture_comment(tctx, " reading 0 bytes after the lock.\n");
+ rd.readx.in.file.fnum = fnum2;
+ rd.readx.in.offset = 6;
+ rd.readx.in.mincnt = 0;
+ rd.readx.in.maxcnt = 0;
+ rd.readx.in.remaining = 0;
+ rd.readx.in.read_for_execute = false;
+ rd.readx.out.data = &c;
+ status = smb_raw_read(cli->tree, &rd);
+ torture_assert_int_equal_goto(tctx, rd.readx.out.nread, 0, ret, done,
+ "zero byte read did not return 0 bytes");
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Unlock lock */
+ io.lockx.in.ulock_cnt = 1;
+ io.lockx.in.lock_cnt = 0;
+ io.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK;
+ io.lockx.in.file.fnum = fnum1;
+ io.lockx.in.locks = &lock1;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+done:
+ smbcli_close(cli->tree, fnum1);
+ smbcli_close(cli->tree, fnum2);
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR);
+ return ret;
+}
+
+/*
basic testing of lock calls
*/
struct torture_suite *torture_raw_lock(TALLOC_CTX *mem_ctx)
@@ -2017,6 +2168,8 @@ struct torture_suite *torture_raw_lock(TALLOC_CTX *mem_ctx)
test_multiple_unlock);
torture_suite_add_1smb_test(suite, "zerobytelocks",
test_zerobytelocks);
+ torture_suite_add_1smb_test(suite, "zerobyteread",
+ test_zerobyteread);
return suite;
}
diff --git a/source4/torture/smb2/lock.c b/source4/torture/smb2/lock.c
index 35a08d3d8c..508358ea61 100644
--- a/source4/torture/smb2/lock.c
+++ b/source4/torture/smb2/lock.c
@@ -1453,6 +1453,124 @@ done:
return ret;
}
+static bool test_zerobyteread(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ bool ret = true;
+ struct smb2_handle h, h2;
+ uint8_t buf[200];
+ struct smb2_lock lck;
+ struct smb2_lock_element el[1];
+ struct smb2_read rd;
+
+ const char *fname = BASEDIR "\\zerobyteread.txt";
+
+ status = torture_smb2_testdir(tree, BASEDIR, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree, h);
+
+ status = torture_smb2_testfile(tree, fname, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ZERO_STRUCT(buf);
+ status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = torture_smb2_testfile(tree, fname, &h2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Setup initial parameters */
+ lck.in.locks = el;
+ lck.in.lock_count = 0x0001;
+ lck.in.lock_sequence = 0x00000000;
+ lck.in.file.handle = h;
+
+ ZERO_STRUCT(rd);
+ rd.in.file.handle = h2;
+
+ torture_comment(torture, "Testing zero byte read on lock range:\n");
+
+ /* Take an exclusive lock */
+ torture_comment(torture, " taking exclusive lock.\n");
+ el[0].offset = 0;
+ el[0].length = 10;
+ el[0].reserved = 0x00000000;
+ el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(lck.out.reserved, 0);
+
+ /* Try a zero byte read */
+ torture_comment(torture, " reading 0 bytes.\n");
+ rd.in.offset = 5;
+ rd.in.length = 0;
+ status = smb2_read(tree, tree, &rd);
+ torture_assert_int_equal_goto(torture, rd.out.data.length, 0, ret, done,
+ "zero byte read did not return 0 bytes");
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Unlock lock */
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(lck.out.reserved, 0);
+
+ torture_comment(torture, "Testing zero byte read on zero byte lock "
+ "range:\n");
+
+ /* Take an exclusive lock */
+ torture_comment(torture, " taking exclusive 0-byte lock.\n");
+ el[0].offset = 5;
+ el[0].length = 0;
+ el[0].reserved = 0x00000000;
+ el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(lck.out.reserved, 0);
+
+ /* Try a zero byte read before the lock */
+ torture_comment(torture, " reading 0 bytes before the lock.\n");
+ rd.in.offset = 4;
+ rd.in.length = 0;
+ status = smb2_read(tree, tree, &rd);
+ torture_assert_int_equal_goto(torture, rd.out.data.length, 0, ret, done,
+ "zero byte read did not return 0 bytes");
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Try a zero byte read on the lock */
+ torture_comment(torture, " reading 0 bytes on the lock.\n");
+ rd.in.offset = 5;
+ rd.in.length = 0;
+ status = smb2_read(tree, tree, &rd);
+ torture_assert_int_equal_goto(torture, rd.out.data.length, 0, ret, done,
+ "zero byte read did not return 0 bytes");
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Try a zero byte read after the lock */
+ torture_comment(torture, " reading 0 bytes after the lock.\n");
+ rd.in.offset = 6;
+ rd.in.length = 0;
+ status = smb2_read(tree, tree, &rd);
+ torture_assert_int_equal_goto(torture, rd.out.data.length, 0, ret, done,
+ "zero byte read did not return 0 bytes");
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Unlock lock */
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(lck.out.reserved, 0);
+
+done:
+ smb2_util_close(tree, h2);
+ smb2_util_close(tree, h);
+ smb2_deltree(tree, BASEDIR);
+ return ret;
+}
+
static bool test_unlock(struct torture_context *torture,
struct smb2_tree *tree)
{
@@ -2750,6 +2868,8 @@ struct torture_suite *torture_smb2_lock_init(void)
torture_suite_add_1smb2_test(suite, "ERRORCODE", test_errorcode);
torture_suite_add_1smb2_test(suite, "ZEROBYTELENGTH",
test_zerobytelength);
+ torture_suite_add_1smb2_test(suite, "ZEROBYTEREAD",
+ test_zerobyteread);
torture_suite_add_1smb2_test(suite, "UNLOCK", test_unlock);
torture_suite_add_1smb2_test(suite, "MULTIPLE-UNLOCK",
test_multiple_unlock);