test: test more of coreTest
This commit is contained in:
1 parent
fdeb30948c
commit
e6f36d52d3
1 file changed
+188
+188
@@ -630,3 +630,191 @@ KTEST(coreVfsChgrpRootReassignsArbitraryGroup)
|
||||
vfsClose(fd);
|
||||
KT_EQ(t, vfsChown("/tmp/chgrpForeign", 4242), 0);
|
||||
|
||||
KT_EQ(t, vfsChgrp("/tmp/chgrpForeign", 9999), 0);
|
||||
FbStat st;
|
||||
KT_EQ(t, vfsStat("/tmp/chgrpForeign", &st), 0);
|
||||
KT_EQU(t, st.gid, 9999u);
|
||||
|
||||
vfsUnlink("/tmp/chgrpForeign");
|
||||
}
|
||||
|
||||
/* Same round trip on the persistent SFS mount, PLUS the "survives
|
||||
unmount+remount" proof every other SFS metadata field already has --
|
||||
mirrors coreVfsChownSfsPersistsAcrossRemount exactly, one field over. */
|
||||
KTEST(coreVfsChgrpSfsPersistsAcrossRemount)
|
||||
{
|
||||
KT_EQ(t, vfsMkdir("/mnt/chgrpd"), 0);
|
||||
int fd = vfsOpen("/mnt/chgrpd/f", oReadWrite | oCreate);
|
||||
KT_GE(t, fd, 0);
|
||||
vfsClose(fd);
|
||||
|
||||
FbStat st;
|
||||
KT_EQ(t, vfsStat("/mnt/chgrpd/f", &st), 0);
|
||||
KT_EQU(t, st.gid, 0u);
|
||||
|
||||
KT_EQ(t, vfsChgrp("/mnt/chgrpd/f", 6666), 0);
|
||||
KT_EQ(t, vfsStat("/mnt/chgrpd/f", &st), 0);
|
||||
KT_EQU(t, st.gid, 6666u);
|
||||
|
||||
sfsUnmount();
|
||||
KT_TRUE(t, sfsMount());
|
||||
|
||||
KT_EQ(t, vfsStat("/mnt/chgrpd/f", &st), 0);
|
||||
KT_EQU(t, st.gid, 6666u);
|
||||
|
||||
vfsUnlink("/mnt/chgrpd/f");
|
||||
vfsRmdir("/mnt/chgrpd");
|
||||
}
|
||||
|
||||
/* Real directory-write enforcement (vfs.c's vfsMkdir/resolveOpen create
|
||||
branch), the gap FALA 44 explicitly flagged as stored-but-unenforced --
|
||||
creating a NEW entry (file or subdirectory) needs the owner-write bit on
|
||||
the PARENT directory, checked against the CALLING thread's own uid, not
|
||||
just "the parent is a writable tmpfs node". KTEST always runs as the
|
||||
permanent idle thread's own uid 0 (coreVfsTmpfsNodeStampsCreatorAsOwner's
|
||||
own doc comment), and vfsPermitted has no uid-0 bypass
|
||||
(coreVfsPermittedUidZeroIsNotASuperuser), so removing root's OWN
|
||||
owner-write bit on a directory it owns genuinely denies root itself --
|
||||
the same "no superuser bypass" story chmod's own tests already prove for
|
||||
files, now proven for directories too, entirely from KTEST without
|
||||
needing a live non-root caller. */
|
||||
KTEST(coreVfsMkdirAndCreateRequireParentWrite)
|
||||
{
|
||||
KT_EQ(t, vfsMkdir("/tmp/dwParent"), 0);
|
||||
KT_EQ(t, vfsChmod("/tmp/dwParent", 0555), 0); /* r-x, no owner-write */
|
||||
|
||||
KT_EQ(t, vfsMkdir("/tmp/dwParent/child"), -1);
|
||||
KT_EQ(t, vfsOpen("/tmp/dwParent/f", oWriteOnly | oCreate), -1);
|
||||
|
||||
KT_EQ(t, vfsChmod("/tmp/dwParent", fsModeDefaultDir), 0);
|
||||
KT_EQ(t, vfsMkdir("/tmp/dwParent/child"), 0);
|
||||
int fd = vfsOpen("/tmp/dwParent/f", oWriteOnly | oCreate);
|
||||
KT_GE(t, fd, 0);
|
||||
vfsClose(fd);
|
||||
|
||||
vfsUnlink("/tmp/dwParent/f");
|
||||
vfsRmdir("/tmp/dwParent/child");
|
||||
vfsRmdir("/tmp/dwParent");
|
||||
}
|
||||
|
||||
/* Real unlink(2)/rmdir(2) semantics: removing an entry needs write
|
||||
permission on the PARENT directory, never the entry's own mode -- proven
|
||||
here by a file that is itself still perfectly writable (0644) but whose
|
||||
PARENT has lost its own write bit, matching real Unix's own "you can
|
||||
delete a read-only file if you can write its directory, and you canNOT
|
||||
delete a writable file if you can't" rule the file-level mode never
|
||||
governs on its own. */
|
||||
KTEST(coreVfsUnlinkAndRmdirRequireParentWrite)
|
||||
{
|
||||
KT_EQ(t, vfsMkdir("/tmp/dwParent2"), 0);
|
||||
int fd = vfsOpen("/tmp/dwParent2/f", oReadWrite | oCreate);
|
||||
KT_GE(t, fd, 0);
|
||||
vfsClose(fd);
|
||||
KT_EQ(t, vfsMkdir("/tmp/dwParent2/sub"), 0);
|
||||
|
||||
KT_EQ(t, vfsChmod("/tmp/dwParent2", 0555), 0);
|
||||
KT_EQ(t, vfsUnlink("/tmp/dwParent2/f"), -1);
|
||||
KT_EQ(t, vfsRmdir("/tmp/dwParent2/sub"), -1);
|
||||
|
||||
KT_EQ(t, vfsChmod("/tmp/dwParent2", fsModeDefaultDir), 0);
|
||||
KT_EQ(t, vfsUnlink("/tmp/dwParent2/f"), 0);
|
||||
KT_EQ(t, vfsRmdir("/tmp/dwParent2/sub"), 0);
|
||||
KT_EQ(t, vfsRmdir("/tmp/dwParent2"), 0);
|
||||
}
|
||||
|
||||
/* Real POSIX search permission (vfs.c's lookupNode, checked on every
|
||||
directory ANCESTOR a path walks through): removing the exec bit on a
|
||||
directory makes every path THROUGH it fail, even though the target file
|
||||
inside it never changed at all -- proven by chmod'ing the ancestor away
|
||||
and back around an otherwise-untouched file. */
|
||||
KTEST(coreVfsLookupRequiresAncestorExec)
|
||||
{
|
||||
KT_EQ(t, vfsMkdir("/tmp/dxAncestor"), 0);
|
||||
int fd = vfsOpen("/tmp/dxAncestor/leaf", oReadWrite | oCreate);
|
||||
KT_GE(t, fd, 0);
|
||||
KT_EQ(t, vfsWrite(fd, "x", 1), 1);
|
||||
vfsClose(fd);
|
||||
|
||||
KT_EQ(t, vfsChmod("/tmp/dxAncestor", 0600), 0); /* rw-, no exec at all */
|
||||
FbStat st;
|
||||
KT_EQ(t, vfsStat("/tmp/dxAncestor/leaf", &st), -1);
|
||||
KT_EQ(t, vfsOpen("/tmp/dxAncestor/leaf", oReadOnly), -1);
|
||||
|
||||
KT_EQ(t, vfsChmod("/tmp/dxAncestor", fsModeDefaultDir), 0);
|
||||
KT_EQ(t, vfsStat("/tmp/dxAncestor/leaf", &st), 0);
|
||||
int rfd = vfsOpen("/tmp/dxAncestor/leaf", oReadOnly);
|
||||
KT_GE(t, rfd, 0);
|
||||
vfsClose(rfd);
|
||||
|
||||
vfsUnlink("/tmp/dxAncestor/leaf");
|
||||
vfsRmdir("/tmp/dxAncestor");
|
||||
}
|
||||
|
||||
/* Real distinction between search (exec) and list (read) on a directory --
|
||||
the subtlest part of this feature, and the one most likely to be
|
||||
accidentally conflated: a directory with exec but no read lets a caller
|
||||
open a KNOWN child by name (resolveOpen never needs read on `cur` for
|
||||
that, only exec on it as an ANCESTOR of the leaf) while refusing to open
|
||||
the directory itself for listing (vfsGetdents). Mirrors dirpermtest.c's
|
||||
own live list-denied-ok/search-without-list-ok pair, but here entirely
|
||||
from KTEST since both sides are root-vs-its-own-directory, not root-vs-
|
||||
another-uid. */
|
||||
KTEST(coreVfsOpendirRequiresDirReadNotJustExec)
|
||||
{
|
||||
KT_EQ(t, vfsMkdir("/tmp/dxListable"), 0);
|
||||
int fd = vfsOpen("/tmp/dxListable/known", oReadWrite | oCreate);
|
||||
KT_GE(t, fd, 0);
|
||||
vfsClose(fd);
|
||||
|
||||
KT_EQ(t, vfsChmod("/tmp/dxListable", 0311), 0); /* -wx, no owner-read */
|
||||
KT_EQ(t, vfsOpen("/tmp/dxListable", oReadOnly), -1);
|
||||
int kfd = vfsOpen("/tmp/dxListable/known", oReadOnly);
|
||||
KT_GE(t, kfd, 0);
|
||||
vfsClose(kfd);
|
||||
|
||||
KT_EQ(t, vfsChmod("/tmp/dxListable", fsModeDefaultDir), 0);
|
||||
int dd = vfsOpen("/tmp/dxListable", oReadOnly);
|
||||
KT_GE(t, dd, 0);
|
||||
FbDirent ents[8];
|
||||
KT_TRUE(t, vfsGetdents(dd, ents, sizeof(ents)) >= (int64)sizeof(FbDirent));
|
||||
vfsClose(dd);
|
||||
|
||||
vfsUnlink("/tmp/dxListable/known");
|
||||
vfsRmdir("/tmp/dxListable");
|
||||
}
|
||||
|
||||
/* Same three checks as the four tmpfs tests directly above (parent-write
|
||||
for create/remove, ancestor-exec for traversal, dir-read-vs-exec for
|
||||
listing), run once through the SFS dispatch branch of vfs.c's own
|
||||
choke points (resolveOpen/vfsMkdir/vfsUnlink/vfsRmdir/lookupNode's
|
||||
isSfsPath fork) instead of sfs.c's raw primitives directly -- sfsTest.c's
|
||||
sfsCreateNodeRequiresParentWrite/sfsRemoveRequiresParentWrite/
|
||||
sfsLookupRequiresAncestorExec already cover the on-disk layer itself;
|
||||
this is the "does the /mnt dispatch actually reach it" parity proof, the
|
||||
same relationship coreVfsChmodSfsPersistsAcrossRemount already has to
|
||||
its own tmpfs sibling above. */
|
||||
KTEST(coreVfsSfsDirectoryPermissionParity)
|
||||
{
|
||||
KT_EQ(t, vfsMkdir("/mnt/dpTop"), 0);
|
||||
int fd = vfsOpen("/mnt/dpTop/leaf", oReadWrite | oCreate);
|
||||
KT_GE(t, fd, 0);
|
||||
vfsClose(fd);
|
||||
|
||||
KT_EQ(t, vfsChmod("/mnt/dpTop", 0555), 0);
|
||||
KT_EQ(t, vfsOpen("/mnt/dpTop/newfile", oWriteOnly | oCreate), -1);
|
||||
KT_EQ(t, vfsUnlink("/mnt/dpTop/leaf"), -1);
|
||||
|
||||
KT_EQ(t, vfsChmod("/mnt/dpTop", 0600), 0);
|
||||
FbStat st;
|
||||
KT_EQ(t, vfsStat("/mnt/dpTop/leaf", &st), -1);
|
||||
|
||||
KT_EQ(t, vfsChmod("/mnt/dpTop", 0311), 0);
|
||||
KT_EQ(t, vfsOpen("/mnt/dpTop", oReadOnly), -1);
|
||||
int kfd = vfsOpen("/mnt/dpTop/leaf", oReadOnly);
|
||||
KT_GE(t, kfd, 0);
|
||||
vfsClose(kfd);
|
||||
|
||||
KT_EQ(t, vfsChmod("/mnt/dpTop", fsModeDefaultDir), 0);
|
||||
KT_EQ(t, vfsUnlink("/mnt/dpTop/leaf"), 0);
|
||||
KT_EQ(t, vfsRmdir("/mnt/dpTop"), 0);
|
||||
}
|
||||
Reference in new issue
Block a user