kernfs: Handle duplicate unlink on orphaned directories.

Also don't print kernfs inode internals on panic, when we can't
acquire the necessary locks.

Reported-by: syzbot+101505e52936904e7d9f@syzkaller.appspotmail.com
Reported-by: syzbot+b9fe0fa83736b77030d2@syzkaller.appspotmail.com
PiperOrigin-RevId: 436869482
This commit is contained in:
Rahat Mahmood
2022-03-23 17:26:14 -07:00
committed by gVisor bot
parent 1e5014d657
commit 9085d334de
5 changed files with 35 additions and 1 deletions
+9
View File
@@ -242,6 +242,15 @@ func checkDeleteLocked(ctx context.Context, rp *vfs.ResolvingPath, d *Dentry) er
if parent.vfsd.IsDead() {
return linuxerr.ENOENT
}
if d.vfsd.IsDead() {
// This implies a duplicate unlink on an orphaned dentry, where the path
// resolution was successful. This is possible when the orphan is
// replaced by a new node of the same name (so the path resolution
// succeeds), and the orphan is unlinked again through a dirfd using
// unlinkat(2) (so the unlink refers to the orphan and not the new
// node). See Linux, fs/namei.c:do_rmdir().
return linuxerr.EINVAL
}
if err := parent.inode.CheckPermissions(ctx, rp.Credentials(), vfs.MayWrite|vfs.MayExec); err != nil {
return err
}
+1 -1
View File
@@ -590,7 +590,7 @@ func (o *OrderedChildren) checkExistingLocked(name string, child Inode) error {
return linuxerr.ENOENT
}
if s.inode != child {
panic(fmt.Sprintf("Inode doesn't match what kernfs thinks! OrderedChild: %+v, kernfs: %+v", s.inode, child))
panic(fmt.Sprintf("Inode doesn't match what kernfs thinks! Name: %q, OrderedChild: %p, kernfs: %p", name, s.inode, child))
}
return nil
}
+20
View File
@@ -403,6 +403,26 @@ TEST(Cgroup, MigrateToSubcontainerThread) {
EXPECT_FALSE(tasks.contains(tid));
}
// Regression test for b/222278194.
TEST(Cgroup, DuplicateUnlinkOnDirFD) {
SKIP_IF(!CgroupsAvailable());
Mounter m(ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()));
Cgroup c = ASSERT_NO_ERRNO_AND_VALUE(m.MountCgroupfs(""));
Cgroup child = ASSERT_NO_ERRNO_AND_VALUE(c.CreateChild("child"));
// Orphan child directory by opening FD to it then deleting it.
const FileDescriptor dirfd =
ASSERT_NO_ERRNO_AND_VALUE(Open(child.Path(), 0, 0));
ASSERT_NO_ERRNO(child.Delete());
// Replace orphan with new directory of same name, so path resolution
// succeeds.
Cgroup child_new = ASSERT_NO_ERRNO_AND_VALUE(c.CreateChild("child"));
// Attempt to delete orphaned child again through dirfd.
EXPECT_THAT(UnlinkAt(dirfd, ".", AT_REMOVEDIR), PosixErrorIs(EINVAL));
}
TEST(MemoryCgroup, MemoryUsageInBytes) {
SKIP_IF(!CgroupsAvailable());
+2
View File
@@ -41,6 +41,8 @@ PosixErrorOr<Cgroup> Cgroup::Create(absl::string_view path) {
return Cgroup(path);
}
PosixError Cgroup::Delete() { return Rmdir(cgroup_path_); }
PosixErrorOr<Cgroup> Cgroup::CreateChild(absl::string_view name) const {
return Cgroup::Create(JoinPath(Path(), name));
}
+3
View File
@@ -43,6 +43,9 @@ class Cgroup {
// cgroupfs directory.
static PosixErrorOr<Cgroup> Create(std::string_view path);
// Deletes the current cgroup represented by this object.
PosixError Delete();
const std::string& Path() const { return cgroup_path_; }
// Creates a child cgroup under this cgroup with the given name.