github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/fs/tmpfs/fs.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 tmpfs 16 17 import ( 18 "fmt" 19 "strconv" 20 21 "github.com/SagerNet/gvisor/pkg/abi/linux" 22 "github.com/SagerNet/gvisor/pkg/context" 23 "github.com/SagerNet/gvisor/pkg/sentry/fs" 24 "github.com/SagerNet/gvisor/pkg/sentry/kernel/auth" 25 ) 26 27 const ( 28 // Set initial permissions for the root directory. 29 modeKey = "mode" 30 31 // UID for the root directory. 32 rootUIDKey = "uid" 33 34 // GID for the root directory. 35 rootGIDKey = "gid" 36 37 // cacheKey sets the caching policy for the mount. 38 cacheKey = "cache" 39 40 // cacheAll uses the virtual file system cache for everything (default). 41 cacheAll = "cache" 42 43 // cacheRevalidate allows dirents to be cached, but revalidates them on each 44 // lookup. 45 cacheRevalidate = "revalidate" 46 47 // Permissions that exceed modeMask will be rejected. 48 modeMask = 01777 49 50 // Default permissions are read/write/execute. 51 defaultMode = 0777 52 ) 53 54 // Filesystem is a tmpfs. 55 // 56 // +stateify savable 57 type Filesystem struct{} 58 59 var _ fs.Filesystem = (*Filesystem)(nil) 60 61 func init() { 62 fs.RegisterFilesystem(&Filesystem{}) 63 } 64 65 // FilesystemName is the name under which the filesystem is registered. 66 // Name matches mm/shmem.c:shmem_fs_type.name. 67 const FilesystemName = "tmpfs" 68 69 // Name is the name of the file system. 70 func (*Filesystem) Name() string { 71 return FilesystemName 72 } 73 74 // AllowUserMount allows users to mount(2) this file system. 75 func (*Filesystem) AllowUserMount() bool { 76 return true 77 } 78 79 // AllowUserList allows this filesystem to be listed in /proc/filesystems. 80 func (*Filesystem) AllowUserList() bool { 81 return true 82 } 83 84 // Flags returns that there is nothing special about this file system. 85 // 86 // In Linux, tmpfs returns FS_USERNS_MOUNT, see mm/shmem.c. 87 func (*Filesystem) Flags() fs.FilesystemFlags { 88 return 0 89 } 90 91 // Mount returns a tmpfs root that can be positioned in the vfs. 92 func (f *Filesystem) Mount(ctx context.Context, device string, flags fs.MountSourceFlags, data string, _ interface{}) (*fs.Inode, error) { 93 // device is always ignored. 94 95 // Parse generic comma-separated key=value options, this file system expects them. 96 options := fs.GenericMountSourceOptions(data) 97 98 // Parse the root directory permissions. 99 perms := fs.FilePermsFromMode(defaultMode) 100 if m, ok := options[modeKey]; ok { 101 i, err := strconv.ParseUint(m, 8, 32) 102 if err != nil { 103 return nil, fmt.Errorf("mode value not parsable 'mode=%s': %v", m, err) 104 } 105 if i&^modeMask != 0 { 106 return nil, fmt.Errorf("invalid mode %q: must be less than %o", m, modeMask) 107 } 108 perms = fs.FilePermsFromMode(linux.FileMode(i)) 109 delete(options, modeKey) 110 } 111 112 creds := auth.CredentialsFromContext(ctx) 113 owner := fs.FileOwnerFromContext(ctx) 114 if uidstr, ok := options[rootUIDKey]; ok { 115 uid, err := strconv.ParseInt(uidstr, 10, 32) 116 if err != nil { 117 return nil, fmt.Errorf("uid value not parsable 'uid=%d': %v", uid, err) 118 } 119 owner.UID = creds.UserNamespace.MapToKUID(auth.UID(uid)) 120 delete(options, rootUIDKey) 121 } 122 123 if gidstr, ok := options[rootGIDKey]; ok { 124 gid, err := strconv.ParseInt(gidstr, 10, 32) 125 if err != nil { 126 return nil, fmt.Errorf("gid value not parsable 'gid=%d': %v", gid, err) 127 } 128 owner.GID = creds.UserNamespace.MapToKGID(auth.GID(gid)) 129 delete(options, rootGIDKey) 130 } 131 132 // Construct a mount which will follow the cache options provided. 133 // 134 // TODO(github.com/SagerNet/issue/179): There should be no reason to disable 135 // caching once bind mounts are properly supported. 136 var msrc *fs.MountSource 137 switch options[cacheKey] { 138 case "", cacheAll: 139 msrc = fs.NewCachingMountSource(ctx, f, flags) 140 case cacheRevalidate: 141 msrc = fs.NewRevalidatingMountSource(ctx, f, flags) 142 default: 143 return nil, fmt.Errorf("invalid cache policy option %q", options[cacheKey]) 144 } 145 delete(options, cacheKey) 146 147 // Fail if the caller passed us more options than we can parse. They may be 148 // expecting us to set something we can't set. 149 if len(options) > 0 { 150 return nil, fmt.Errorf("unsupported mount options: %v", options) 151 } 152 153 // Construct the tmpfs root. 154 return NewDir(ctx, nil, owner, perms, msrc, nil /* parent */) 155 }