github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/fs/context.go (about)

     1  // Copyright 2018 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package fs
    16  
    17  import (
    18  	"github.com/SagerNet/gvisor/pkg/abi/linux"
    19  	"github.com/SagerNet/gvisor/pkg/context"
    20  	"github.com/SagerNet/gvisor/pkg/sentry/kernel/auth"
    21  )
    22  
    23  // contextID is the fs package's type for context.Context.Value keys.
    24  type contextID int
    25  
    26  const (
    27  	// CtxRoot is a Context.Value key for a Dirent.
    28  	CtxRoot contextID = iota
    29  
    30  	// CtxDirentCacheLimiter is a Context.Value key for DirentCacheLimiter.
    31  	CtxDirentCacheLimiter
    32  )
    33  
    34  // ContextCanAccessFile determines whether `file` can be accessed in the requested way
    35  // (for reading, writing, or execution) using the caller's credentials and user
    36  // namespace, as does Linux's fs/namei.c:generic_permission.
    37  func ContextCanAccessFile(ctx context.Context, inode *Inode, reqPerms PermMask) bool {
    38  	creds := auth.CredentialsFromContext(ctx)
    39  	uattr, err := inode.UnstableAttr(ctx)
    40  	if err != nil {
    41  		return false
    42  	}
    43  
    44  	p := uattr.Perms.Other
    45  	// Are we owner or in group?
    46  	if uattr.Owner.UID == creds.EffectiveKUID {
    47  		p = uattr.Perms.User
    48  	} else if creds.InGroup(uattr.Owner.GID) {
    49  		p = uattr.Perms.Group
    50  	}
    51  
    52  	// Do not allow programs to be executed if MS_NOEXEC is set.
    53  	if IsFile(inode.StableAttr) && reqPerms.Execute && inode.MountSource.Flags.NoExec {
    54  		return false
    55  	}
    56  
    57  	// Are permissions satisfied without capability checks?
    58  	if p.SupersetOf(reqPerms) {
    59  		return true
    60  	}
    61  
    62  	if IsDir(inode.StableAttr) {
    63  		// CAP_DAC_OVERRIDE can override any perms on directories.
    64  		if inode.CheckCapability(ctx, linux.CAP_DAC_OVERRIDE) {
    65  			return true
    66  		}
    67  
    68  		// CAP_DAC_READ_SEARCH can normally only override Read perms,
    69  		// but for directories it can also override execution.
    70  		if !reqPerms.Write && inode.CheckCapability(ctx, linux.CAP_DAC_READ_SEARCH) {
    71  			return true
    72  		}
    73  	}
    74  
    75  	// CAP_DAC_OVERRIDE can always override Read/Write.
    76  	// Can override executable only when at least one execute bit is set.
    77  	if !reqPerms.Execute || uattr.Perms.AnyExecute() {
    78  		if inode.CheckCapability(ctx, linux.CAP_DAC_OVERRIDE) {
    79  			return true
    80  		}
    81  	}
    82  
    83  	// Read perms can be overridden by CAP_DAC_READ_SEARCH.
    84  	if reqPerms.OnlyRead() && inode.CheckCapability(ctx, linux.CAP_DAC_READ_SEARCH) {
    85  		return true
    86  	}
    87  	return false
    88  }
    89  
    90  // FileOwnerFromContext returns a FileOwner using the effective user and group
    91  // IDs used by ctx.
    92  func FileOwnerFromContext(ctx context.Context) FileOwner {
    93  	creds := auth.CredentialsFromContext(ctx)
    94  	return FileOwner{creds.EffectiveKUID, creds.EffectiveKGID}
    95  }
    96  
    97  // RootFromContext returns the root of the virtual filesystem observed by ctx,
    98  // or nil if ctx is not associated with a virtual filesystem. If
    99  // RootFromContext returns a non-nil fs.Dirent, a reference is taken on it.
   100  func RootFromContext(ctx context.Context) *Dirent {
   101  	if v := ctx.Value(CtxRoot); v != nil {
   102  		return v.(*Dirent)
   103  	}
   104  	return nil
   105  }
   106  
   107  // DirentCacheLimiterFromContext returns the DirentCacheLimiter used by ctx, or
   108  // nil if ctx does not have a dirent cache limiter.
   109  func DirentCacheLimiterFromContext(ctx context.Context) *DirentCacheLimiter {
   110  	if v := ctx.Value(CtxDirentCacheLimiter); v != nil {
   111  		return v.(*DirentCacheLimiter)
   112  	}
   113  	return nil
   114  }
   115  
   116  type rootContext struct {
   117  	context.Context
   118  	root *Dirent
   119  }
   120  
   121  // WithRoot returns a copy of ctx with the given root.
   122  func WithRoot(ctx context.Context, root *Dirent) context.Context {
   123  	return &rootContext{
   124  		Context: ctx,
   125  		root:    root,
   126  	}
   127  }
   128  
   129  // Value implements Context.Value.
   130  func (rc rootContext) Value(key interface{}) interface{} {
   131  	switch key {
   132  	case CtxRoot:
   133  		rc.root.IncRef()
   134  		return rc.root
   135  	default:
   136  		return rc.Context.Value(key)
   137  	}
   138  }