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 */
|
KT_GE(t, wfd2, 0); /* write-only still works -- the two bits are independent */
|
||||||
vfsClose(wfd2);
|
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