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 }