mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
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:
committed by
gVisor bot
parent
1e5014d657
commit
9085d334de
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user