tests: Add 2 tests for unique fileid's with top bit set (generated from itime) for...
authorJeremy Allison <jra@samba.org>
Thu, 6 Jan 2022 23:11:20 +0000 (15:11 -0800)
committerJule Anger <janger@samba.org>
Wed, 12 Jan 2022 11:48:14 +0000 (11:48 +0000)
smb2.fileid_unique.fileid_unique
smb2.fileid_unique.fileid_unique-dir

Create 100 files or directories as fast as we can
against a "normal" share, then read info on them
and ensure (a) top bit is set (generated from itime)
and (b) uniqueness across all generated objects
(checks poor timestamp resolution doesn't create
duplicate fileids).

This shows that even on ext4, this is enough to
cause duplicate fileids to be returned.

Add knownfail.d/fileid-unique

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14928

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Christof Schmitt <cs@samba.org>
(cherry picked from commit 30fea0d31117c1a899cd333a9b8a62ba765dbb02)

selftest/knownfail.d/fileid-unique [new file with mode: 0644]
source3/selftest/tests.py
source4/selftest/tests.py
source4/torture/smb2/create.c
source4/torture/smb2/smb2.c

diff --git a/selftest/knownfail.d/fileid-unique b/selftest/knownfail.d/fileid-unique
new file mode 100644 (file)
index 0000000..a29c4a0
--- /dev/null
@@ -0,0 +1,2 @@
+^samba3.smb2.fileid_unique.fileid_unique\(fileserver\)
+^samba3.smb2.fileid_unique.fileid_unique-dir\(fileserver\)
index 32f0239600400615eea11504690743fe3e773a53..cc47a7f4d6bed8f48fc976a35c489d198b6ab733 100755 (executable)
@@ -935,6 +935,8 @@ for t in tests:
         plansmbtorture4testsuite(t, "ad_dc", '//$SERVER/tmp -U$USERNAME%$PASSWORD')
     elif t == "smb2.fileid":
         plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/vfs_fruit_xattr -U$USERNAME%$PASSWORD')
+    elif t == "smb2.fileid_unique":
+        plansmbtorture4testsuite(t, "fileserver", '//$SERVER_IP/tmp -U$USERNAME%$PASSWORD')
     elif t == "smb2.acls_non_canonical":
         plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/acls_non_canonical -U$USERNAME%$PASSWORD')
     elif t == "rpc.wkssvc":
index a16b2879bd2d3cc52a7e62aef9841c2eb4385ee9..61cbca43132dc363b2f4639a15a31259c9957f82 100755 (executable)
@@ -369,6 +369,7 @@ smb2_s3only = [
     "smb2.durable-v2-delay",
     "smb2.aio_delay",
     "smb2.fileid",
+    "smb2.fileid_unique",
     "smb2.timestamps",
 ]
 smb2 = [x for x in smbtorture4_testsuites("smb2.") if x not in smb2_s3only]
index aba3f69a28abae752c88df10986d9d9122e7a08d..41a6ed6e4e407fb458435bc21c96113b0a17138a 100644 (file)
@@ -2707,6 +2707,191 @@ done:
        return ret;
 }
 
+static bool test_fileid_unique_object(
+                       struct torture_context *tctx,
+                       struct smb2_tree *tree,
+                       unsigned int num_objs,
+                       bool create_dirs)
+{
+       TALLOC_CTX *mem_ctx = talloc_new(tctx);
+       char *fname = NULL;
+       struct smb2_handle testdirh;
+       struct smb2_handle h1;
+       struct smb2_create create;
+       unsigned int i;
+       uint64_t fileid_array[num_objs];
+       NTSTATUS status;
+       bool ret = true;
+
+       smb2_deltree(tree, DNAME);
+
+       status = torture_smb2_testdir(tree, DNAME, &testdirh);
+       torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+                                       "test_fileid_unique failed\n");
+       smb2_util_close(tree, testdirh);
+
+       /* Create num_obj files as rapidly as we can. */
+       for (i = 0; i < num_objs; i++) {
+               fname = talloc_asprintf(mem_ctx,
+                                       "%s\\testfile.%u",
+                                       DNAME,
+                                       i);
+               torture_assert_goto(tctx,
+                               fname != NULL,
+                               ret,
+                               done,
+                               "talloc failed\n");
+
+               create = (struct smb2_create) {
+                       .in.desired_access = SEC_FILE_READ_ATTRIBUTE,
+                       .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+                       .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+                       .in.create_disposition = NTCREATEX_DISP_CREATE,
+                       .in.fname = fname,
+               };
+
+               if (create_dirs) {
+                       create.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
+                       create.in.create_options = FILE_DIRECTORY_FILE;
+               }
+
+               status = smb2_create(tree, tctx, &create);
+               if (!NT_STATUS_IS_OK(status)) {
+                       torture_fail(tctx,
+                               talloc_asprintf(tctx,
+                                       "test file %s could not be created\n",
+                                       fname));
+                       TALLOC_FREE(fname);
+                       ret = false;
+                       goto done;
+               }
+
+               h1 = create.out.file.handle;
+               smb2_util_close(tree, h1);
+               TALLOC_FREE(fname);
+       }
+
+       /*
+        * Get the file ids.
+        */
+       for (i = 0; i < num_objs; i++) {
+               union smb_fileinfo finfo;
+
+               fname = talloc_asprintf(mem_ctx,
+                                       "%s\\testfile.%u",
+                                       DNAME,
+                                       i);
+               torture_assert_goto(tctx,
+                               fname != NULL,
+                               ret,
+                               done,
+                               "talloc failed\n");
+
+               create = (struct smb2_create) {
+                       .in.desired_access = SEC_FILE_READ_ATTRIBUTE,
+                       .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+                       .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+                       .in.create_disposition = NTCREATEX_DISP_OPEN,
+                       .in.fname = fname,
+               };
+
+               if (create_dirs) {
+                       create.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
+                       create.in.create_options = FILE_DIRECTORY_FILE;
+               }
+
+               status = smb2_create(tree, tctx, &create);
+               if (!NT_STATUS_IS_OK(status)) {
+                       torture_fail(tctx,
+                               talloc_asprintf(tctx,
+                                       "test file %s could not "
+                                       "be opened: %s\n",
+                                       fname,
+                                       nt_errstr(status)));
+                       TALLOC_FREE(fname);
+                       ret = false;
+                       goto done;
+               }
+
+               h1 = create.out.file.handle;
+
+               finfo = (union smb_fileinfo) {
+                       .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
+                       .generic.in.file.handle = h1,
+               };
+
+               status = smb2_getinfo_file(tree, tctx, &finfo);
+               if (!NT_STATUS_IS_OK(status)) {
+                       torture_fail(tctx,
+                               talloc_asprintf(tctx,
+                                       "failed to get fileid for "
+                                       "test file %s: %s\n",
+                                       fname,
+                                       nt_errstr(status)));
+                       TALLOC_FREE(fname);
+                       ret = false;
+                       goto done;
+               }
+               smb2_util_close(tree, h1);
+               /*
+                * Samba created files on a "normal" share
+                * using itime should have the top bit of the fileid set.
+                */
+               fileid_array[i] = finfo.all_info2.out.file_id;
+
+               if ((fileid_array[i] & 0x8000000000000000) == 0) {
+                       torture_fail(tctx,
+                               talloc_asprintf(tctx,
+                                       "test file %s fileid 0x%lx top "
+                                       "bit not set\n",
+                                       fname,
+                                       fileid_array[i]));
+                       TALLOC_FREE(fname);
+                       ret = false;
+                       goto done;
+               }
+               TALLOC_FREE(fname);
+       }
+
+       /* All returned fileids must be unique. 100 is small so brute force. */
+       for (i = 0; i < num_objs - 1; i++) {
+               unsigned int j;
+               for (j = i + 1; j < num_objs; j++) {
+                       if (fileid_array[i] == fileid_array[j]) {
+                               torture_fail(tctx,
+                                       talloc_asprintf(tctx,
+                                               "fileid %u == fileid %u (0x%lu)\n",
+                                               i,
+                                               j,
+                                               fileid_array[i]));
+                               ret = false;
+                               goto done;
+                       }
+               }
+       }
+
+done:
+
+       smb2_util_close(tree, testdirh);
+       smb2_deltree(tree, DNAME);
+       talloc_free(mem_ctx);
+       return ret;
+}
+
+static bool test_fileid_unique(
+                       struct torture_context *tctx,
+                       struct smb2_tree *tree)
+{
+       return test_fileid_unique_object(tctx, tree, 100, false);
+}
+
+static bool test_fileid_unique_dir(
+                       struct torture_context *tctx,
+                       struct smb2_tree *tree)
+{
+       return test_fileid_unique_object(tctx, tree, 100, true);
+}
+
 /*
   test opening quota fakefile handle and returned attributes
 */
@@ -2823,3 +3008,23 @@ struct torture_suite *torture_smb2_fileid_init(TALLOC_CTX *ctx)
 
        return suite;
 }
+
+/*
+   Testing for uniqueness of SMB2 File-IDs
+*/
+struct torture_suite *torture_smb2_fileid_unique_init(TALLOC_CTX *ctx)
+{
+       struct torture_suite *suite = torture_suite_create(ctx,
+                                       "fileid_unique");
+
+       torture_suite_add_1smb2_test(suite,
+                                       "fileid_unique",
+                                       test_fileid_unique);
+       torture_suite_add_1smb2_test(suite,
+                                       "fileid_unique-dir",
+                                       test_fileid_unique_dir);
+
+       suite->description = talloc_strdup(suite, "SMB2-FILEID-UNIQUE tests");
+
+       return suite;
+}
index f3a5c8ac87510cbf7061fc5277ce079b1f48d2af..95a7b49952f765308cd583fdd481010a3f0877ed 100644 (file)
@@ -213,6 +213,7 @@ NTSTATUS torture_smb2_init(TALLOC_CTX *ctx)
        torture_suite_add_1smb2_test(suite, "secleak", torture_smb2_sec_leak);
        torture_suite_add_1smb2_test(suite, "session-id", run_sessidtest);
        torture_suite_add_suite(suite, torture_smb2_deny_init(suite));
+       torture_suite_add_suite(suite, torture_smb2_fileid_unique_init(suite));
 
        suite->description = talloc_strdup(suite, "SMB2-specific tests");