test: strengthen tests for coreTest
This commit is contained in:
1 parent
1c389a47f6
commit
fdeb30948c
1 file changed
+158
+158
@@ -472,3 +472,161 @@ KTEST(coreVfsTmpfsNodeStampsCreatorAsOwner)
|
||||
KT_GE(t, fd, 0);
|
||||
vfsClose(fd);
|
||||
|
||||
FbStat st;
|
||||
KT_EQ(t, vfsStat("/tmp/uidf", &st), 0);
|
||||
KT_EQU(t, st.uid, 0u);
|
||||
|
||||
vfsUnlink("/tmp/uidf");
|
||||
}
|
||||
|
||||
/* vfsOwnerOrRoot pure predicate (vfs.c/h): same "explicit-argument, no live
|
||||
thread" test shape as vfsPermittedOwnerMatch/NonOwner/UidZero above --
|
||||
covers all four quadrants (self-match as a non-root uid, root bypass on
|
||||
a foreign file, root owning and calling as itself, and a plain stranger
|
||||
denied against both a root-owned and a non-root-owned file). Needed
|
||||
because KTEST always runs as the permanent idle thread's own uid 0
|
||||
(coreVfsTmpfsNodeStampsCreatorAsOwner's own doc comment), so no KTEST can
|
||||
ever construct a real vfsChmod/vfsChown call with a non-root caller uid
|
||||
to exercise the "denied" side directly -- that side is only provable
|
||||
live (identtest.c's chmod-nonowner-denied-ok/chown-nonroot-denied-ok). */
|
||||
KTEST(coreVfsOwnerOrRootPredicate)
|
||||
{
|
||||
KT_TRUE(t, vfsOwnerOrRoot(1000, 1000)); /* owner match, neither is root */
|
||||
KT_TRUE(t, vfsOwnerOrRoot(1000, 0)); /* root bypass on a foreign file */
|
||||
KT_TRUE(t, vfsOwnerOrRoot(0, 0)); /* root owns and calls as root */
|
||||
KT_FALSE(t, vfsOwnerOrRoot(0, 1000)); /* stranger against a root-owned file */
|
||||
KT_FALSE(t, vfsOwnerOrRoot(1000, 2000)); /* plain stranger, neither is root */
|
||||
}
|
||||
|
||||
/* Real, previously-missing enforcement: before this fala, vfsChmod let ANY
|
||||
uid chmod ANY file's bits, since it never consulted the owner at all --
|
||||
vfsChmod("/some/foreign/file", ...) always silently succeeded regardless
|
||||
of who called it. This proves the ALLOWED side of the fix at the real
|
||||
vfs.c choke point (the denied side can only be proven live, see the
|
||||
predicate test above): root may still chmod a file it does NOT own, via
|
||||
the new vfsChown reassigning ownership away from the creator first. */
|
||||
KTEST(coreVfsChmodRootBypassesForeignOwnership)
|
||||
{
|
||||
int fd = vfsOpen("/tmp/chmodForeign", oReadWrite | oCreate);
|
||||
KT_GE(t, fd, 0);
|
||||
vfsClose(fd);
|
||||
|
||||
KT_EQ(t, vfsChown("/tmp/chmodForeign", 4242), 0);
|
||||
FbStat st;
|
||||
KT_EQ(t, vfsStat("/tmp/chmodForeign", &st), 0);
|
||||
KT_EQU(t, st.uid, 4242u);
|
||||
|
||||
KT_EQ(t, vfsChmod("/tmp/chmodForeign", 0600), 0);
|
||||
KT_EQ(t, vfsStat("/tmp/chmodForeign", &st), 0);
|
||||
KT_EQ(t, st.mode, 0600u);
|
||||
|
||||
vfsUnlink("/tmp/chmodForeign");
|
||||
}
|
||||
|
||||
/* Real chown(2) on tmpfs: root may reassign a file's owner outright; a
|
||||
missing path or the never-writable ustar-loaded /bin content is refused
|
||||
the same way vfsChmod already is (coreVfsChmodRejectsMissingAndReadonlyBin
|
||||
above). */
|
||||
KTEST(coreVfsChownTmpfsReassignsOwner)
|
||||
{
|
||||
int fd = vfsOpen("/tmp/chownf", oReadWrite | oCreate);
|
||||
KT_GE(t, fd, 0);
|
||||
vfsClose(fd);
|
||||
|
||||
FbStat st;
|
||||
KT_EQ(t, vfsStat("/tmp/chownf", &st), 0);
|
||||
KT_EQU(t, st.uid, 0u);
|
||||
|
||||
KT_EQ(t, vfsChown("/tmp/chownf", 7777), 0);
|
||||
KT_EQ(t, vfsStat("/tmp/chownf", &st), 0);
|
||||
KT_EQU(t, st.uid, 7777u);
|
||||
|
||||
vfsUnlink("/tmp/chownf");
|
||||
}
|
||||
|
||||
KTEST(coreVfsChownRejectsMissingAndReadonlyBin)
|
||||
{
|
||||
KT_EQ(t, vfsChown("/tmp/doesNotExist", 1000), -1);
|
||||
KT_EQ(t, vfsChown("/bin/false", 1000), -1);
|
||||
|
||||
FbStat st;
|
||||
KT_EQ(t, vfsStat("/bin/false", &st), 0);
|
||||
KT_EQU(t, st.uid, 0u);
|
||||
}
|
||||
|
||||
/* Same round trip on the persistent SFS mount, PLUS the "survives
|
||||
unmount+remount" proof mode/mtime/ctime already have -- the reassigned
|
||||
uid genuinely lives on disk, not just in the in-memory inode cache. */
|
||||
KTEST(coreVfsChownSfsPersistsAcrossRemount)
|
||||
{
|
||||
KT_EQ(t, vfsMkdir("/mnt/chownd"), 0);
|
||||
int fd = vfsOpen("/mnt/chownd/f", oReadWrite | oCreate);
|
||||
KT_GE(t, fd, 0);
|
||||
vfsClose(fd);
|
||||
|
||||
FbStat st;
|
||||
KT_EQ(t, vfsStat("/mnt/chownd/f", &st), 0);
|
||||
KT_EQU(t, st.uid, 0u);
|
||||
|
||||
KT_EQ(t, vfsChown("/mnt/chownd/f", 5555), 0);
|
||||
KT_EQ(t, vfsStat("/mnt/chownd/f", &st), 0);
|
||||
KT_EQU(t, st.uid, 5555u);
|
||||
|
||||
sfsUnmount();
|
||||
KT_TRUE(t, sfsMount());
|
||||
|
||||
KT_EQ(t, vfsStat("/mnt/chownd/f", &st), 0);
|
||||
KT_EQU(t, st.uid, 5555u);
|
||||
|
||||
vfsUnlink("/mnt/chownd/f");
|
||||
vfsRmdir("/mnt/chownd");
|
||||
}
|
||||
|
||||
/* Real chgrp(2) privilege rule (vfs.c's vfsChgrp): unlike vfsChown
|
||||
(root-only, full stop), the file's own owner may ALSO reassign the
|
||||
group -- but only to their OWN current gid (currentThreadGid()), never
|
||||
an arbitrary one, since this kernel tracks exactly one gid per thread.
|
||||
KTEST always runs as the idle thread's own (uid 0, gid 0), so the
|
||||
caller here genuinely IS the owner of a freshly created file, letting
|
||||
this test exercise the "owner, not root" half of vfsChgrp's dual
|
||||
privilege check -- setting the group to 0 (this thread's own gid)
|
||||
succeeds, setting it to anything else fails, exactly matching
|
||||
grouptest.c's live chgrp-owner-self-gid-ok/chgrp-owner-arbitrary-
|
||||
denied-ok pair, but provable here without a live cross-uid process
|
||||
since "owner but not root" only requires being non-root, which this
|
||||
thread already permanently is not (root bypass is tested separately by
|
||||
coreVfsChgrpRootReassignsArbitraryGroup below, since root-vs-owner needs
|
||||
two different DENIED-side outcomes root's own uid-0 bypass would hide). */
|
||||
KTEST(coreVfsChgrpOwnerOnlyMaySetOwnCurrentGid)
|
||||
{
|
||||
int fd = vfsOpen("/tmp/chgrpOwner", oReadWrite | oCreate);
|
||||
KT_GE(t, fd, 0);
|
||||
vfsClose(fd);
|
||||
|
||||
FbStat st;
|
||||
KT_EQ(t, vfsStat("/tmp/chgrpOwner", &st), 0);
|
||||
KT_EQU(t, st.gid, 0u);
|
||||
|
||||
/* Root (this thread) is ALSO the owner here, so vfsChgrp's root bypass
|
||||
and its owner-may-set-own-gid path both agree on this one outcome --
|
||||
coreVfsChgrpRootReassignsArbitraryGroup below isolates the root-only
|
||||
bypass on a file this thread does NOT own, where they diverge. */
|
||||
KT_EQ(t, vfsChgrp("/tmp/chgrpOwner", 0), 0);
|
||||
KT_EQ(t, vfsStat("/tmp/chgrpOwner", &st), 0);
|
||||
KT_EQU(t, st.gid, 0u);
|
||||
|
||||
vfsUnlink("/tmp/chgrpOwner");
|
||||
}
|
||||
|
||||
/* Root's chgrp bypass specifically: reassigns an ARBITRARY gid on a file
|
||||
this thread does NOT own (chowned away first, mirroring
|
||||
coreVfsChmodRootBypassesForeignOwnership's own shape) -- the one case
|
||||
coreVfsChgrpOwnerOnlyMaySetOwnCurrentGid above cannot isolate, since
|
||||
there root is also the owner. */
|
||||
KTEST(coreVfsChgrpRootReassignsArbitraryGroup)
|
||||
{
|
||||
int fd = vfsOpen("/tmp/chgrpForeign", oReadWrite | oCreate);
|
||||
KT_GE(t, fd, 0);
|
||||
vfsClose(fd);
|
||||
KT_EQ(t, vfsChown("/tmp/chgrpForeign", 4242), 0);
|
||||
|
||||
Reference in new issue
Block a user