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