github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/vfs/memxattr/xattr.go (about)

     1  // Copyright 2020 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 memxattr provides a default, in-memory extended attribute
    16  // implementation.
    17  package memxattr
    18  
    19  import (
    20  	"strings"
    21  
    22  	"github.com/SagerNet/gvisor/pkg/abi/linux"
    23  	"github.com/SagerNet/gvisor/pkg/errors/linuxerr"
    24  	"github.com/SagerNet/gvisor/pkg/sentry/kernel/auth"
    25  	"github.com/SagerNet/gvisor/pkg/sentry/vfs"
    26  	"github.com/SagerNet/gvisor/pkg/sync"
    27  	"github.com/SagerNet/gvisor/pkg/syserror"
    28  )
    29  
    30  // SimpleExtendedAttributes implements extended attributes using a map of
    31  // names to values.
    32  //
    33  // SimpleExtendedAttributes calls vfs.CheckXattrPermissions, so callers are not
    34  // required to do so.
    35  //
    36  // +stateify savable
    37  type SimpleExtendedAttributes struct {
    38  	// mu protects the below fields.
    39  	mu     sync.RWMutex `state:"nosave"`
    40  	xattrs map[string]string
    41  }
    42  
    43  // GetXattr returns the value at 'name'.
    44  func (x *SimpleExtendedAttributes) GetXattr(creds *auth.Credentials, mode linux.FileMode, kuid auth.KUID, opts *vfs.GetXattrOptions) (string, error) {
    45  	if err := vfs.CheckXattrPermissions(creds, vfs.MayRead, mode, kuid, opts.Name); err != nil {
    46  		return "", err
    47  	}
    48  
    49  	x.mu.RLock()
    50  	value, ok := x.xattrs[opts.Name]
    51  	x.mu.RUnlock()
    52  	if !ok {
    53  		return "", linuxerr.ENODATA
    54  	}
    55  	// Check that the size of the buffer provided in getxattr(2) is large enough
    56  	// to contain the value.
    57  	if opts.Size != 0 && uint64(len(value)) > opts.Size {
    58  		return "", syserror.ERANGE
    59  	}
    60  	return value, nil
    61  }
    62  
    63  // SetXattr sets 'value' at 'name'.
    64  func (x *SimpleExtendedAttributes) SetXattr(creds *auth.Credentials, mode linux.FileMode, kuid auth.KUID, opts *vfs.SetXattrOptions) error {
    65  	if err := vfs.CheckXattrPermissions(creds, vfs.MayWrite, mode, kuid, opts.Name); err != nil {
    66  		return err
    67  	}
    68  
    69  	x.mu.Lock()
    70  	defer x.mu.Unlock()
    71  	if x.xattrs == nil {
    72  		if opts.Flags&linux.XATTR_REPLACE != 0 {
    73  			return linuxerr.ENODATA
    74  		}
    75  		x.xattrs = make(map[string]string)
    76  	}
    77  
    78  	_, ok := x.xattrs[opts.Name]
    79  	if ok && opts.Flags&linux.XATTR_CREATE != 0 {
    80  		return syserror.EEXIST
    81  	}
    82  	if !ok && opts.Flags&linux.XATTR_REPLACE != 0 {
    83  		return linuxerr.ENODATA
    84  	}
    85  
    86  	x.xattrs[opts.Name] = opts.Value
    87  	return nil
    88  }
    89  
    90  // ListXattr returns all names in xattrs.
    91  func (x *SimpleExtendedAttributes) ListXattr(creds *auth.Credentials, size uint64) ([]string, error) {
    92  	// Keep track of the size of the buffer needed in listxattr(2) for the list.
    93  	listSize := 0
    94  	x.mu.RLock()
    95  	names := make([]string, 0, len(x.xattrs))
    96  	haveCap := creds.HasCapability(linux.CAP_SYS_ADMIN)
    97  	for n := range x.xattrs {
    98  		// Hide extended attributes in the "trusted" namespace from
    99  		// non-privileged users. This is consistent with Linux's
   100  		// fs/xattr.c:simple_xattr_list().
   101  		if !haveCap && strings.HasPrefix(n, linux.XATTR_TRUSTED_PREFIX) {
   102  			continue
   103  		}
   104  		names = append(names, n)
   105  		// Add one byte per null terminator.
   106  		listSize += len(n) + 1
   107  	}
   108  	x.mu.RUnlock()
   109  	if size != 0 && uint64(listSize) > size {
   110  		return nil, syserror.ERANGE
   111  	}
   112  	return names, nil
   113  }
   114  
   115  // RemoveXattr removes the xattr at 'name'.
   116  func (x *SimpleExtendedAttributes) RemoveXattr(creds *auth.Credentials, mode linux.FileMode, kuid auth.KUID, name string) error {
   117  	if err := vfs.CheckXattrPermissions(creds, vfs.MayWrite, mode, kuid, name); err != nil {
   118  		return err
   119  	}
   120  
   121  	x.mu.Lock()
   122  	defer x.mu.Unlock()
   123  	if _, ok := x.xattrs[name]; !ok {
   124  		return linuxerr.ENODATA
   125  	}
   126  	delete(x.xattrs, name)
   127  	return nil
   128  }