github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/fsimpl/ext/ext.go (about) 1 // Copyright 2019 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 ext implements readonly ext(2/3/4) filesystems. 16 package ext 17 18 import ( 19 "errors" 20 "fmt" 21 "io" 22 23 "github.com/SagerNet/gvisor/pkg/abi/linux" 24 "github.com/SagerNet/gvisor/pkg/context" 25 "github.com/SagerNet/gvisor/pkg/errors/linuxerr" 26 "github.com/SagerNet/gvisor/pkg/fd" 27 "github.com/SagerNet/gvisor/pkg/log" 28 "github.com/SagerNet/gvisor/pkg/sentry/fsimpl/ext/disklayout" 29 "github.com/SagerNet/gvisor/pkg/sentry/kernel/auth" 30 "github.com/SagerNet/gvisor/pkg/sentry/vfs" 31 ) 32 33 // Name is the name of this filesystem. 34 const Name = "ext" 35 36 // FilesystemType implements vfs.FilesystemType. 37 // 38 // +stateify savable 39 type FilesystemType struct{} 40 41 // getDeviceFd returns an io.ReaderAt to the underlying device. 42 // Currently there are two ways of mounting an ext(2/3/4) fs: 43 // 1. Specify a mount with our internal special MountType in the OCI spec. 44 // 2. Expose the device to the container and mount it from application layer. 45 func getDeviceFd(source string, opts vfs.GetFilesystemOptions) (io.ReaderAt, error) { 46 if opts.InternalData == nil { 47 // User mount call. 48 // TODO(b/134676337): Open the device specified by `source` and return that. 49 panic("unimplemented") 50 } 51 52 // GetFilesystem call originated from within the sentry. 53 devFd, ok := opts.InternalData.(int) 54 if !ok { 55 return nil, errors.New("internal data for ext fs must be an int containing the file descriptor to device") 56 } 57 58 if devFd < 0 { 59 return nil, fmt.Errorf("ext device file descriptor is not valid: %d", devFd) 60 } 61 62 // The fd.ReadWriter returned from fd.NewReadWriter() does not take ownership 63 // of the file descriptor and hence will not close it when it is garbage 64 // collected. 65 return fd.NewReadWriter(devFd), nil 66 } 67 68 // isCompatible checks if the superblock has feature sets which are compatible. 69 // We only need to check the superblock incompatible feature set since we are 70 // mounting readonly. We will also need to check readonly compatible feature 71 // set when mounting for read/write. 72 func isCompatible(sb disklayout.SuperBlock) bool { 73 // Please note that what is being checked is limited based on the fact that we 74 // are mounting readonly and that we are not journaling. When mounting 75 // read/write or with a journal, this must be reevaluated. 76 incompatFeatures := sb.IncompatibleFeatures() 77 if incompatFeatures.MetaBG { 78 log.Warningf("ext fs: meta block groups are not supported") 79 return false 80 } 81 if incompatFeatures.MMP { 82 log.Warningf("ext fs: multiple mount protection is not supported") 83 return false 84 } 85 if incompatFeatures.Encrypted { 86 log.Warningf("ext fs: encrypted inodes not supported") 87 return false 88 } 89 if incompatFeatures.InlineData { 90 log.Warningf("ext fs: inline files not supported") 91 return false 92 } 93 return true 94 } 95 96 // Name implements vfs.FilesystemType.Name. 97 func (FilesystemType) Name() string { 98 return Name 99 } 100 101 // Release implements vfs.FilesystemType.Release. 102 func (FilesystemType) Release(ctx context.Context) {} 103 104 // GetFilesystem implements vfs.FilesystemType.GetFilesystem. 105 func (fsType FilesystemType) GetFilesystem(ctx context.Context, vfsObj *vfs.VirtualFilesystem, creds *auth.Credentials, source string, opts vfs.GetFilesystemOptions) (*vfs.Filesystem, *vfs.Dentry, error) { 106 // TODO(b/134676337): Ensure that the user is mounting readonly. If not, 107 // EACCESS should be returned according to mount(2). Filesystem independent 108 // flags (like readonly) are currently not available in pkg/sentry/vfs. 109 110 devMinor, err := vfsObj.GetAnonBlockDevMinor() 111 if err != nil { 112 return nil, nil, err 113 } 114 115 dev, err := getDeviceFd(source, opts) 116 if err != nil { 117 return nil, nil, err 118 } 119 120 fs := filesystem{ 121 dev: dev, 122 inodeCache: make(map[uint32]*inode), 123 devMinor: devMinor, 124 } 125 fs.vfsfs.Init(vfsObj, &fsType, &fs) 126 fs.sb, err = readSuperBlock(dev) 127 if err != nil { 128 fs.vfsfs.DecRef(ctx) 129 return nil, nil, err 130 } 131 132 if fs.sb.Magic() != linux.EXT_SUPER_MAGIC { 133 // mount(2) specifies that EINVAL should be returned if the superblock is 134 // invalid. 135 fs.vfsfs.DecRef(ctx) 136 return nil, nil, linuxerr.EINVAL 137 } 138 139 // Refuse to mount if the filesystem is incompatible. 140 if !isCompatible(fs.sb) { 141 fs.vfsfs.DecRef(ctx) 142 return nil, nil, linuxerr.EINVAL 143 } 144 145 fs.bgs, err = readBlockGroups(dev, fs.sb) 146 if err != nil { 147 fs.vfsfs.DecRef(ctx) 148 return nil, nil, err 149 } 150 151 rootInode, err := fs.getOrCreateInodeLocked(disklayout.RootDirInode) 152 if err != nil { 153 fs.vfsfs.DecRef(ctx) 154 return nil, nil, err 155 } 156 rootInode.incRef() 157 158 return &fs.vfsfs, &newDentry(rootInode).vfsd, nil 159 }