summaryrefslogtreecommitdiffhomepage
path: root/pkg/sentry/fs/dirent.go
diff options
context:
space:
mode:
authorMichael Pratt <mpratt@google.com>2018-12-05 14:31:07 -0800
committerShentubot <shentubot@google.com>2018-12-05 14:31:58 -0800
commit9f64e64a6ee1fe44a05ed57893785fa9064125e1 (patch)
tree3e37767de300d950f17d053bcf283b3c39db2543 /pkg/sentry/fs/dirent.go
parent23438b36327524ba3e71b6416d71863fb4dfa166 (diff)
Enforce directory accessibility before delete Walk
By Walking before checking that the directory is writable and executable, MayDelete may return the Walk error (e.g., ENOENT) which would normally be masked by a permission error (EACCES). PiperOrigin-RevId: 224222453 Change-Id: I108a7f730e6bdaa7f277eaddb776267c00805475
Diffstat (limited to 'pkg/sentry/fs/dirent.go')
-rw-r--r--pkg/sentry/fs/dirent.go28
1 files changed, 19 insertions, 9 deletions
diff --git a/pkg/sentry/fs/dirent.go b/pkg/sentry/fs/dirent.go
index 4c0482036..c4918a11b 100644
--- a/pkg/sentry/fs/dirent.go
+++ b/pkg/sentry/fs/dirent.go
@@ -1461,6 +1461,10 @@ func checkSticky(ctx context.Context, dir *Dirent, victim *Dirent) error {
//
// Compare Linux kernel fs/namei.c:may_delete.
func MayDelete(ctx context.Context, root, dir *Dirent, name string) error {
+ if err := dir.Inode.CheckPermission(ctx, PermMask{Write: true, Execute: true}); err != nil {
+ return err
+ }
+
victim, err := dir.Walk(ctx, root, name)
if err != nil {
return err
@@ -1470,11 +1474,11 @@ func MayDelete(ctx context.Context, root, dir *Dirent, name string) error {
return mayDelete(ctx, dir, victim)
}
+// mayDelete determines whether `victim`, a child of `dir`, can be deleted or
+// renamed by `ctx`.
+//
+// Preconditions: `dir` is writable and executable by `ctx`.
func mayDelete(ctx context.Context, dir, victim *Dirent) error {
- if err := dir.Inode.CheckPermission(ctx, PermMask{Write: true, Execute: true}); err != nil {
- return err
- }
-
if err := checkSticky(ctx, dir, victim); err != nil {
return err
}
@@ -1512,6 +1516,15 @@ func Rename(ctx context.Context, root *Dirent, oldParent *Dirent, oldName string
return syscall.ENOENT
}
+ // Do we have general permission to remove from oldParent and
+ // create/replace in newParent?
+ if err := oldParent.Inode.CheckPermission(ctx, PermMask{Write: true, Execute: true}); err != nil {
+ return err
+ }
+ if err := newParent.Inode.CheckPermission(ctx, PermMask{Write: true, Execute: true}); err != nil {
+ return err
+ }
+
// renamed is the dirent that will be renamed to something else.
renamed, err := oldParent.walk(ctx, root, oldName, false /* may unlock */)
if err != nil {
@@ -1549,10 +1562,7 @@ func Rename(ctx context.Context, root *Dirent, oldParent *Dirent, oldName string
return err
}
- // Make sure we can create a new child in the new parent.
- if err := newParent.Inode.CheckPermission(ctx, PermMask{Write: true, Execute: true}); err != nil {
- return err
- }
+ // newName doesn't exist; simply create it below.
} else {
// Check constraints on the dirent being replaced.
@@ -1560,7 +1570,7 @@ func Rename(ctx context.Context, root *Dirent, oldParent *Dirent, oldName string
// across the Rename, so must call DecRef manually (no defer).
// Check that we can delete replaced.
- if err := mayDelete(ctx, oldParent, renamed); err != nil {
+ if err := mayDelete(ctx, newParent, replaced); err != nil {
replaced.DecRef()
return err
}