github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/fs/host/util.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 host 16 17 import ( 18 "os" 19 20 "golang.org/x/sys/unix" 21 "github.com/SagerNet/gvisor/pkg/abi/linux" 22 "github.com/SagerNet/gvisor/pkg/errors/linuxerr" 23 "github.com/SagerNet/gvisor/pkg/log" 24 "github.com/SagerNet/gvisor/pkg/sentry/device" 25 "github.com/SagerNet/gvisor/pkg/sentry/fs" 26 "github.com/SagerNet/gvisor/pkg/sentry/kernel/auth" 27 ktime "github.com/SagerNet/gvisor/pkg/sentry/kernel/time" 28 ) 29 30 func nodeType(s *unix.Stat_t) fs.InodeType { 31 switch x := (s.Mode & unix.S_IFMT); x { 32 case unix.S_IFLNK: 33 return fs.Symlink 34 case unix.S_IFIFO: 35 return fs.Pipe 36 case unix.S_IFCHR: 37 return fs.CharacterDevice 38 case unix.S_IFBLK: 39 return fs.BlockDevice 40 case unix.S_IFSOCK: 41 return fs.Socket 42 case unix.S_IFDIR: 43 return fs.Directory 44 case unix.S_IFREG: 45 return fs.RegularFile 46 default: 47 // This shouldn't happen, but just in case... 48 log.Warningf("unknown host file type %d: assuming regular", x) 49 return fs.RegularFile 50 } 51 } 52 53 func wouldBlock(s *unix.Stat_t) bool { 54 typ := nodeType(s) 55 return typ == fs.Pipe || typ == fs.Socket || typ == fs.CharacterDevice 56 } 57 58 func stableAttr(s *unix.Stat_t) fs.StableAttr { 59 return fs.StableAttr{ 60 Type: nodeType(s), 61 DeviceID: hostFileDevice.DeviceID(), 62 InodeID: hostFileDevice.Map(device.MultiDeviceKey{ 63 Device: s.Dev, 64 Inode: s.Ino, 65 }), 66 BlockSize: int64(s.Blksize), 67 } 68 } 69 70 func owner(s *unix.Stat_t) fs.FileOwner { 71 return fs.FileOwner{ 72 UID: auth.KUID(s.Uid), 73 GID: auth.KGID(s.Gid), 74 } 75 } 76 77 func unstableAttr(s *unix.Stat_t) fs.UnstableAttr { 78 return fs.UnstableAttr{ 79 Size: s.Size, 80 Usage: s.Blocks * 512, 81 Perms: fs.FilePermsFromMode(linux.FileMode(s.Mode)), 82 Owner: owner(s), 83 AccessTime: ktime.FromUnix(s.Atim.Sec, s.Atim.Nsec), 84 ModificationTime: ktime.FromUnix(s.Mtim.Sec, s.Mtim.Nsec), 85 StatusChangeTime: ktime.FromUnix(s.Ctim.Sec, s.Ctim.Nsec), 86 Links: uint64(s.Nlink), 87 } 88 } 89 90 type dirInfo struct { 91 buf []byte // buffer for directory I/O. 92 nbuf int // length of buf; return value from ReadDirent. 93 bufp int // location of next record in buf. 94 } 95 96 // LINT.IfChange 97 98 // isBlockError unwraps os errors and checks if they are caused by EAGAIN or 99 // EWOULDBLOCK. This is so they can be transformed into syserror.ErrWouldBlock. 100 func isBlockError(err error) bool { 101 if linuxerr.Equals(linuxerr.EAGAIN, err) || linuxerr.Equals(linuxerr.EWOULDBLOCK, err) { 102 return true 103 } 104 if pe, ok := err.(*os.PathError); ok { 105 return isBlockError(pe.Err) 106 } 107 return false 108 } 109 110 // LINT.ThenChange(../../fsimpl/host/util.go) 111 112 func hostEffectiveKIDs() (uint32, []uint32, error) { 113 gids, err := os.Getgroups() 114 if err != nil { 115 return 0, nil, err 116 } 117 egids := make([]uint32, len(gids)) 118 for i, gid := range gids { 119 egids[i] = uint32(gid) 120 } 121 return uint32(os.Geteuid()), append(egids, uint32(os.Getegid())), nil 122 } 123 124 var hostUID uint32 125 var hostGIDs []uint32 126 127 func init() { 128 hostUID, hostGIDs, _ = hostEffectiveKIDs() 129 }