diff options
author | Nicolas Lacasse <nlacasse@google.com> | 2018-10-15 17:41:34 -0700 |
---|---|---|
committer | Shentubot <shentubot@google.com> | 2018-10-15 17:42:30 -0700 |
commit | ecd94ea7a693d49a0edce8607241a8e2ac22bfe0 (patch) | |
tree | da07122898da0d3770f8cdbfdf967b1a3242db3d /pkg/sentry/syscalls | |
parent | 3f0532595679c388362203bbce1d4b6c4d2e336b (diff) |
Clean up Rename and Unlink checks for EBUSY.
- Change Dirent.Busy => Dirent.isMountPoint. The function body is unchanged,
and it is no longer exported.
- fs.MayDelete now checks that the victim is not the process root. This aligns
with Linux's namei.c:may_delete().
- Fix "is-ancestor" checks to actually compare all ancestors, not just the
parents.
- Fix handling of paths that end in dots, which are handled differently in
Rename vs. Unlink.
PiperOrigin-RevId: 217239274
Change-Id: I7a0eb768e70a1b2915017ce54f7f95cbf8edf1fb
Diffstat (limited to 'pkg/sentry/syscalls')
-rw-r--r-- | pkg/sentry/syscalls/linux/sys_file.go | 43 |
1 files changed, 24 insertions, 19 deletions
diff --git a/pkg/sentry/syscalls/linux/sys_file.go b/pkg/sentry/syscalls/linux/sys_file.go index 015afda9b..64704bb88 100644 --- a/pkg/sentry/syscalls/linux/sys_file.go +++ b/pkg/sentry/syscalls/linux/sys_file.go @@ -1042,11 +1042,9 @@ func rmdirAt(t *kernel.Task, dirFD kdefs.FD, addr usermem.Addr) error { return err } - // Special case: rmdir rejects anything with '.' as last component. - // This would be handled by the busy check for the current working - // directory, but this is how it's done. - if (len(path) == 1 && path == ".") || (len(path) > 1 && path[len(path)-2:] == "/.") { - return syserror.EINVAL + // Special case: removing the root always returns EBUSY. + if path == "/" { + return syserror.EBUSY } return fileOpAt(t, dirFD, path, func(root *fs.Dirent, d *fs.Dirent, name string) error { @@ -1054,6 +1052,15 @@ func rmdirAt(t *kernel.Task, dirFD kdefs.FD, addr usermem.Addr) error { return syserror.ENOTDIR } + // Linux returns different ernos when the path ends in single + // dot vs. double dots. + switch name { + case ".": + return syserror.EINVAL + case "..": + return syserror.ENOTEMPTY + } + if err := fs.MayDelete(t, root, d, name); err != nil { return err } @@ -1829,27 +1836,25 @@ func renameAt(t *kernel.Task, oldDirFD kdefs.FD, oldAddr usermem.Addr, newDirFD return syserror.ENOTDIR } - // Root cannot be renamed to anything. - // - // TODO: This catches the case when the rename - // argument is exactly "/", but we should return EBUSY when - // renaming any mount point, or when the argument is not - // exactly "/" but still resolves to the root, like "/.." or - // "/bin/..". - if oldParent == root && oldName == "." { - return syscall.EBUSY + // Rename rejects paths that end in ".", "..", or empty (i.e. + // the root) with EBUSY. + switch oldName { + case "", ".", "..": + return syserror.EBUSY } + return fileOpAt(t, newDirFD, newPath, func(root *fs.Dirent, newParent *fs.Dirent, newName string) error { if !fs.IsDir(newParent.Inode.StableAttr) { return syserror.ENOTDIR } - // Nothing can be renamed to root. - // - // TODO: Same as above. - if newParent == root && newName == "." { - return syscall.EBUSY + // Rename rejects paths that end in ".", "..", or empty + // (i.e. the root) with EBUSY. + switch newName { + case "", ".", "..": + return syserror.EBUSY } + return fs.Rename(t, root, oldParent, oldName, newParent, newName) }) }) |