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  }