test: add more cases for coreTest
This commit is contained in:
1 parent
5f60d0e517
commit
1c389a47f6
1 file changed
+158
+158
@@ -314,3 +314,161 @@ KTEST(coreVfsResolveOpenRequiresFileReadPermission)
|
||||
KT_GE(t, wfd2, 0); /* write-only still works -- the two bits are independent */
|
||||
vfsClose(wfd2);
|
||||
|
||||
KT_EQ(t, vfsChmod("/tmp/readf", fsModeDefaultFile), 0);
|
||||
int rfd2 = vfsOpen("/tmp/readf", oReadOnly);
|
||||
KT_GE(t, rfd2, 0);
|
||||
vfsClose(rfd2);
|
||||
|
||||
vfsUnlink("/tmp/readf");
|
||||
}
|
||||
|
||||
/* chmod on a missing path, or on the never-writable ustar-loaded /bin
|
||||
content, is rejected exactly like every other tmpfs mutation already
|
||||
gates on node->writable (vfsUnlink, vfsWrite's write path) -- chmod is a
|
||||
metadata mutation too, so it obeys the same rule. Also proves every
|
||||
ustar-loaded binary really does get the owner-exec bit by default
|
||||
(vfs.c's ustarAdd), the fact loadImageByPath/jobctlSpawn's own exec-
|
||||
permission check depends on for every existing spawnUser/userSpawn call
|
||||
in this kernel to keep working at all. */
|
||||
KTEST(coreVfsChmodRejectsMissingAndReadonlyBin)
|
||||
{
|
||||
KT_EQ(t, vfsChmod("/tmp/doesNotExist", 0644), -1);
|
||||
KT_EQ(t, vfsChmod("/bin/false", 0777), -1);
|
||||
|
||||
FbStat st;
|
||||
KT_EQ(t, vfsStat("/bin/false", &st), 0);
|
||||
KT_EQ(t, st.mode, fsModeDefaultExec);
|
||||
}
|
||||
|
||||
/* Same round trip on the persistent SFS mount, PLUS the "survives
|
||||
unmount+remount" proof every other SFS-persisted field (mtime/ctime,
|
||||
FALA 39) already has -- mode genuinely lives on disk, not just in the
|
||||
in-memory inode cache. */
|
||||
KTEST(coreVfsChmodSfsPersistsAcrossRemount)
|
||||
{
|
||||
KT_EQ(t, vfsMkdir("/mnt/chmodd"), 0);
|
||||
int fd = vfsOpen("/mnt/chmodd/f", oReadWrite | oCreate);
|
||||
KT_GE(t, fd, 0);
|
||||
vfsClose(fd);
|
||||
|
||||
FbStat st;
|
||||
KT_EQ(t, vfsStat("/mnt/chmodd/f", &st), 0);
|
||||
KT_EQ(t, st.mode, fsModeDefaultFile);
|
||||
|
||||
KT_EQ(t, vfsChmod("/mnt/chmodd/f", 0400), 0);
|
||||
KT_EQ(t, vfsOpen("/mnt/chmodd/f", oWriteOnly), -1);
|
||||
|
||||
sfsUnmount();
|
||||
KT_TRUE(t, sfsMount());
|
||||
|
||||
KT_EQ(t, vfsStat("/mnt/chmodd/f", &st), 0);
|
||||
KT_EQ(t, st.mode, 0400u);
|
||||
KT_EQ(t, vfsOpen("/mnt/chmodd/f", oWriteOnly), -1);
|
||||
|
||||
KT_EQ(t, vfsChmod("/mnt/chmodd/f", fsModeDefaultFile), 0);
|
||||
int wfd = vfsOpen("/mnt/chmodd/f", oWriteOnly);
|
||||
KT_GE(t, wfd, 0);
|
||||
vfsClose(wfd);
|
||||
|
||||
vfsUnlink("/mnt/chmodd/f");
|
||||
vfsRmdir("/mnt/chmodd");
|
||||
}
|
||||
|
||||
/* Real Unix owner/group/other permission algorithm (vfs.c's vfsPermitted)
|
||||
-- pure-logic coverage of the whole decision matrix, since the function
|
||||
takes every credential as an explicit argument instead of reading a live
|
||||
thread (see its own doc comment). Deliberately includes uid 0 on BOTH
|
||||
sides of the owner/other split (coreVfsPermittedUidZeroIsNotASuperuser
|
||||
below) -- uid 0 gets no special treatment at all, the one property that
|
||||
distinguishes this from real Unix's root and the exact regression this
|
||||
test guards: an earlier version of vfsPermitted let uid 0 bypass every
|
||||
bit unconditionally, which silently broke every OTHER permission test in
|
||||
this file (coreVfsChmodTmpfsWritePermission,
|
||||
coreVfsChmodSfsPersistsAcrossRemount both run as ktestRunAll's own idle
|
||||
thread, uid 0) the moment chmod took away the write bit on a file that
|
||||
same uid-0 caller had just created. Every "hits the other branch" case
|
||||
below deliberately gives a MISMATCHED gid too (not just a mismatched
|
||||
uid) -- otherwise an incidental gid match would silently redirect the
|
||||
check into the new group branch instead of exercising other at all. */
|
||||
KTEST(coreVfsPermittedOwnerMatchChecksOwnerBitOnly)
|
||||
{
|
||||
/* Owner-uid match short-circuits before gid is ever consulted, so gid
|
||||
values here are deliberately irrelevant -- 0 on both sides. */
|
||||
/* Owner bit set, other bit clear: an owning caller passes. */
|
||||
KT_TRUE(t, vfsPermitted(0600, 1000, 0, 1000, 0, fsModeOwnerWrite));
|
||||
/* Owner bit clear, other bit set: an owning caller still fails --
|
||||
owning the file never grants what the OTHER bits happen to allow. */
|
||||
KT_FALSE(t, vfsPermitted(0004, 1000, 0, 1000, 0, fsModeOwnerWrite));
|
||||
}
|
||||
|
||||
KTEST(coreVfsPermittedNonOwnerChecksOtherBitOnly)
|
||||
{
|
||||
/* Other-write set, owner-write clear, DIFFERENT uid AND gid: passes on
|
||||
the other bit even though the owner bit alone would refuse. */
|
||||
KT_TRUE(t, vfsPermitted(0002, 1000, 10, 2000, 20, fsModeOwnerWrite));
|
||||
/* Neither bit helps a stranger if the other bit is the one clear. */
|
||||
KT_FALSE(t, vfsPermitted(0600, 1000, 10, 2000, 20, fsModeOwnerWrite));
|
||||
KT_FALSE(t, vfsPermitted(0000, 1000, 10, 2000, 20, fsModeOwnerExec));
|
||||
}
|
||||
|
||||
KTEST(coreVfsPermittedUidZeroIsNotASuperuser)
|
||||
{
|
||||
/* uid 0 as OWNER: governed by the owner bit exactly like any other
|
||||
uid, matching every existing chmod test's own assumption (every
|
||||
boot-time process, including ktestRunAll itself, starts at uid 0). */
|
||||
KT_TRUE(t, vfsPermitted(0600, 0, 0, 0, 0, fsModeOwnerWrite));
|
||||
KT_FALSE(t, vfsPermitted(0000, 0, 0, 0, 0, fsModeOwnerWrite));
|
||||
/* uid 0 as a NON-owner (and non-group-member): governed by the other
|
||||
bit, no bypass at all -- a mode of 0 denies even uid 0 against
|
||||
someone else's file. */
|
||||
KT_FALSE(t, vfsPermitted(0700, 1000, 10, 0, 20, fsModeOwnerWrite));
|
||||
KT_TRUE(t, vfsPermitted(0702, 1000, 10, 0, 20, fsModeOwnerWrite));
|
||||
/* And symmetrically: owning a file as a non-zero uid is not somehow
|
||||
MORE privileged than uid 0 owning one -- same algorithm either way. */
|
||||
KT_FALSE(t, vfsPermitted(0600, 42, 10, 0, 20, fsModeOwnerWrite));
|
||||
}
|
||||
|
||||
/* Every fsModeOwner/fsModeOther pair used by a real choke point
|
||||
(resolveOpen's write check, loadImageByPath/jobctlSpawn's exec check)
|
||||
round-trips through the exact bit-shift vfsPermitted derives one from
|
||||
the other with -- not just fsModeOwnerWrite from the test above. */
|
||||
KTEST(coreVfsPermittedExecBitFollowsSameOwnerOtherSplit)
|
||||
{
|
||||
KT_TRUE(t, vfsPermitted(fsModeOtherExec, 1, 10, 2, 20, fsModeOwnerExec));
|
||||
KT_FALSE(t, vfsPermitted(fsModeOwnerExec, 1, 10, 2, 20, fsModeOwnerExec));
|
||||
KT_TRUE(t, vfsPermitted(fsModeOwnerExec, 1, 10, 1, 10, fsModeOwnerExec));
|
||||
}
|
||||
|
||||
/* The new middle branch: a caller whose UID does not match the owner but
|
||||
whose GID matches the node's group is governed by the fsModeGroup* bit
|
||||
(wantOwnerBit >> 3), never falling all the way through to other -- and a
|
||||
group bit set does NOT imply the other bit is, proving this is a
|
||||
genuinely separate check, not just "not owner" collapsing to one
|
||||
fallback like the pre-group-model version of this function used to. */
|
||||
KTEST(coreVfsPermittedGroupMatchChecksGroupBitOnly)
|
||||
{
|
||||
/* Group-write set, owner/other-write clear: different uid, same gid. */
|
||||
KT_TRUE(t, vfsPermitted(0020, 1000, 10, 2000, 10, fsModeOwnerWrite));
|
||||
/* Group bit clear: a gid match alone grants nothing by itself. */
|
||||
KT_FALSE(t, vfsPermitted(0602, 1000, 10, 2000, 10, fsModeOwnerWrite));
|
||||
/* Every fsModeOwner/fsModeGroup pair round-trips through the >>3 shift,
|
||||
not just write above. */
|
||||
KT_TRUE(t, vfsPermitted(fsModeGroupExec, 1, 10, 2, 10, fsModeOwnerExec));
|
||||
/* Owner-uid match takes priority over a coincidental gid match: the
|
||||
caller here is BOTH the owner AND shares the owner's own gid, but the
|
||||
decision must still come from the owner bit, not group. */
|
||||
KT_TRUE(t, vfsPermitted(0100, 1, 10, 1, 10, fsModeOwnerExec));
|
||||
KT_FALSE(t, vfsPermitted(0010, 1, 10, 1, 10, fsModeOwnerExec));
|
||||
}
|
||||
|
||||
/* Real owner identity (fs.h's FbStat.uid, vfs.c's vfsUid): a fresh tmpfs
|
||||
node is stamped with whoever created it -- ktestRunAll always runs as
|
||||
the permanent idle thread (id 0, uid 0, "root"), the same context
|
||||
schedTest.c's own pgid-default tests already document relying on, so
|
||||
every node created here is root-owned by construction. */
|
||||
KTEST(coreVfsTmpfsNodeStampsCreatorAsOwner)
|
||||
{
|
||||
int fd = vfsOpen("/tmp/uidf", oReadWrite | oCreate);
|
||||
KT_GE(t, fd, 0);
|
||||
vfsClose(fd);
|
||||
|
||||
Reference in new issue
Block a user