diff options
author | Michael Pratt <mpratt@google.com> | 2018-12-05 14:31:07 -0800 |
---|---|---|
committer | Shentubot <shentubot@google.com> | 2018-12-05 14:31:58 -0800 |
commit | 9f64e64a6ee1fe44a05ed57893785fa9064125e1 (patch) | |
tree | 3e37767de300d950f17d053bcf283b3c39db2543 /pkg/sentry/fs/dirent.go | |
parent | 23438b36327524ba3e71b6416d71863fb4dfa166 (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.go | 28 |
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 } |