diff options
author | Ayush Ranjan <ayushranjan@google.com> | 2021-02-05 17:14:59 -0800 |
---|---|---|
committer | gVisor bot <gvisor-bot@google.com> | 2021-02-05 17:17:30 -0800 |
commit | 09afd68326898f783927c65f86f813d815d8c16c (patch) | |
tree | 4cea9f27b4d37f15441aadae7c1bc5f5f5a9ec8a | |
parent | 24416032ab848cff7696b3f37e4c18220aeee2c0 (diff) |
[vfs] Handle `.` and `..` as last path component names in kernfs Rename.
According to vfs.FilesystemImpl.RenameAt documentation:
- If the last path component in rp is "." or "..", and opts.Flags contains
RENAME_NOREPLACE, RenameAt returns EEXIST.
- If the last path component in rp is "." or "..", and opts.Flags does not
contain RENAME_NOREPLACE, RenameAt returns EBUSY.
Reported-by: syzbot+6189786e64fe13fe43f8@syzkaller.appspotmail.com
PiperOrigin-RevId: 355959266
-rw-r--r-- | pkg/sentry/fsimpl/kernfs/filesystem.go | 6 | ||||
-rw-r--r-- | test/syscalls/linux/rename.cc | 33 |
2 files changed, 39 insertions, 0 deletions
diff --git a/pkg/sentry/fsimpl/kernfs/filesystem.go b/pkg/sentry/fsimpl/kernfs/filesystem.go index a7a553619..d6dd6bc41 100644 --- a/pkg/sentry/fsimpl/kernfs/filesystem.go +++ b/pkg/sentry/fsimpl/kernfs/filesystem.go @@ -668,6 +668,12 @@ func (fs *Filesystem) RenameAt(ctx context.Context, rp *vfs.ResolvingPath, oldPa // Can we create the dst dentry? var dst *Dentry pc := rp.Component() + if pc == "." || pc == ".." { + if noReplace { + return syserror.EEXIST + } + return syserror.EBUSY + } switch err := checkCreateLocked(ctx, rp.Credentials(), pc, dstDir); err { case nil: // Ok, continue with rename as replacement. diff --git a/test/syscalls/linux/rename.cc b/test/syscalls/linux/rename.cc index 5458f54ad..22c8c19cf 100644 --- a/test/syscalls/linux/rename.cc +++ b/test/syscalls/linux/rename.cc @@ -391,6 +391,39 @@ TEST(RenameTest, FileWithOpenFd) { EXPECT_EQ(absl::string_view(buf, sizeof(buf) - 1), kContents); } +// Tests that calling rename with file path ending with . or .. causes EBUSY. +TEST(RenameTest, PathEndingWithDots) { + TempPath root_dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); + TempPath dir1 = + ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(root_dir.path())); + TempPath dir2 = + ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(root_dir.path())); + + // Try to move dir1 into dir2 but mess up the paths. + auto dir1Dot = JoinPath(dir1.path(), "."); + auto dir2Dot = JoinPath(dir2.path(), "."); + auto dir1DotDot = JoinPath(dir1.path(), ".."); + auto dir2DotDot = JoinPath(dir2.path(), ".."); + ASSERT_THAT(rename(dir1.path().c_str(), dir2Dot.c_str()), + SyscallFailsWithErrno(EBUSY)); + ASSERT_THAT(rename(dir1.path().c_str(), dir2DotDot.c_str()), + SyscallFailsWithErrno(EBUSY)); + ASSERT_THAT(rename(dir1Dot.c_str(), dir2.path().c_str()), + SyscallFailsWithErrno(EBUSY)); + ASSERT_THAT(rename(dir1DotDot.c_str(), dir2.path().c_str()), + SyscallFailsWithErrno(EBUSY)); +} + +// Calling rename with file path ending with . or .. causes EBUSY in sysfs. +TEST(RenameTest, SysfsPathEndingWithDots) { + // If a non-root user tries to rename inside /sys then we get EPERM. + SKIP_IF(geteuid() != 0); + ASSERT_THAT(rename("/sys/devices/system/cpu/online", "/sys/."), + SyscallFailsWithErrno(EBUSY)); + ASSERT_THAT(rename("/sys/devices/system/cpu/online", "/sys/.."), + SyscallFailsWithErrno(EBUSY)); +} + } // namespace } // namespace testing |