From: Jeremy Allison Date: Thu, 6 Jan 2022 23:11:20 +0000 (-0800) Subject: tests: Add 2 tests for unique fileid's with top bit set (generated from itime) for... X-Git-Tag: tdb-1.4.6~186 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=30fea0d31117c1a899cd333a9b8a62ba765dbb02;p=thirdparty%2Fsamba.git tests: Add 2 tests for unique fileid's with top bit set (generated from itime) for files and directories. 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 Reviewed-by: Christof Schmitt --- diff --git a/selftest/knownfail.d/fileid-unique b/selftest/knownfail.d/fileid-unique new file mode 100644 index 00000000000..a29c4a0bb55 --- /dev/null +++ b/selftest/knownfail.d/fileid-unique @@ -0,0 +1,2 @@ +^samba3.smb2.fileid_unique.fileid_unique\(fileserver\) +^samba3.smb2.fileid_unique.fileid_unique-dir\(fileserver\) diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py index df39fdaa53a..69cdc5b7f85 100755 --- a/source3/selftest/tests.py +++ b/source3/selftest/tests.py @@ -953,6 +953,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": diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py index e496499da23..a13a7ced0e5 100755 --- a/source4/selftest/tests.py +++ b/source4/selftest/tests.py @@ -377,6 +377,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] diff --git a/source4/torture/smb2/create.c b/source4/torture/smb2/create.c index aba3f69a28a..41a6ed6e4e4 100644 --- a/source4/torture/smb2/create.c +++ b/source4/torture/smb2/create.c @@ -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; +} diff --git a/source4/torture/smb2/smb2.c b/source4/torture/smb2/smb2.c index f3a5c8ac875..95a7b49952f 100644 --- a/source4/torture/smb2/smb2.c +++ b/source4/torture/smb2/smb2.c @@ -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");