gitee.com/leisunstar/runtime@v0.0.0-20200521203717-5cef3e7b53f9/virtcontainers/utils/utils_linux.go (about) 1 // Copyright (c) 2018 Intel Corporation 2 // 3 // SPDX-License-Identifier: Apache-2.0 4 // 5 6 package utils 7 8 import ( 9 "bufio" 10 "crypto/rand" 11 "fmt" 12 "io" 13 "math/big" 14 "os" 15 "strings" 16 "syscall" 17 "unsafe" 18 19 "golang.org/x/sys/unix" 20 ) 21 22 var ioctlFunc = Ioctl 23 24 // maxUInt represents the maximum valid value for the context ID. 25 // The upper 32 bits of the CID are reserved and zeroed. 26 // See http://stefanha.github.io/virtio/ 27 var maxUInt uint64 = 1<<32 - 1 28 29 func Ioctl(fd uintptr, request, data uintptr) error { 30 if _, _, errno := unix.Syscall(unix.SYS_IOCTL, fd, request, data); errno != 0 { 31 //uintptr(request) 32 //uintptr(unsafe.Pointer(&arg1)), 33 //); errno != 0 { 34 return os.NewSyscallError("ioctl", fmt.Errorf("%d", int(errno))) 35 } 36 37 return nil 38 } 39 40 // FindContextID finds a unique context ID by generating a random number between 3 and max unsigned int (maxUint). 41 // Using the ioctl VHOST_VSOCK_SET_GUEST_CID, findContextID asks to the kernel if the given 42 // context ID (N) is available, when the context ID is not available, incrementing by 1 findContextID 43 // iterates from N to maxUint until an available context ID is found, otherwise decrementing by 1 44 // findContextID iterates from N to 3 until an available context ID is found, this is the last chance 45 // to find a context ID available. 46 // On success vhost file and a context ID greater or equal than 3 are returned, otherwise 0 and an error are returned. 47 // vhost file can be used to send vhost file decriptor to QEMU. It's the caller's responsibility to 48 // close vhost file descriptor. 49 // 50 // Benefits of using random context IDs: 51 // - Reduce the probability of a *DoS attack*, since other processes don't know whatis the initial context ID 52 // used by findContextID to find a context ID available 53 // 54 func FindContextID() (*os.File, uint64, error) { 55 // context IDs 0x0, 0x1 and 0x2 are reserved, 0x3 is the first context ID usable. 56 var firstContextID uint64 = 0x3 57 var contextID = firstContextID 58 59 // Generate a random number 60 n, err := rand.Int(rand.Reader, big.NewInt(int64(maxUInt))) 61 if err == nil && n.Int64() >= int64(firstContextID) { 62 contextID = uint64(n.Int64()) 63 } 64 65 // Open vhost-vsock device to check what context ID is available. 66 // This file descriptor holds/locks the context ID and it should be 67 // inherited by QEMU process. 68 vsockFd, err := os.OpenFile(VHostVSockDevicePath, syscall.O_RDWR, 0666) 69 if err != nil { 70 return nil, 0, err 71 } 72 73 // Looking for the first available context ID. 74 for cid := contextID; cid <= maxUInt; cid++ { 75 if err = ioctlFunc(vsockFd.Fd(), ioctlVhostVsockSetGuestCid, uintptr(unsafe.Pointer(&cid))); err == nil { 76 return vsockFd, cid, nil 77 } 78 } 79 80 ioctlVhostVsockSetGuestCid := getIoctlVhostVsockGuestCid() 81 // Last chance to get a free context ID. 82 for cid := contextID - 1; cid >= firstContextID; cid-- { 83 if err = ioctlFunc(vsockFd.Fd(), ioctlVhostVsockSetGuestCid, uintptr(unsafe.Pointer(&cid))); err == nil { 84 return vsockFd, cid, nil 85 } 86 } 87 88 vsockFd.Close() 89 return nil, 0, fmt.Errorf("Could not get a unique context ID for the vsock : %s", err) 90 } 91 92 const ( 93 procMountsFile = "/proc/mounts" 94 95 fieldsPerLine = 6 96 ) 97 98 const ( 99 procDeviceIndex = iota 100 procPathIndex 101 procTypeIndex 102 ) 103 104 // GetDevicePathAndFsType gets the device for the mount point and the file system type 105 // of the mount. 106 func GetDevicePathAndFsType(mountPoint string) (devicePath, fsType string, err error) { 107 if mountPoint == "" { 108 err = fmt.Errorf("Mount point cannot be empty") 109 return 110 } 111 112 var file *os.File 113 114 file, err = os.Open(procMountsFile) 115 if err != nil { 116 return 117 } 118 119 defer file.Close() 120 121 reader := bufio.NewReader(file) 122 for { 123 var line string 124 125 line, err = reader.ReadString('\n') 126 if err == io.EOF { 127 err = fmt.Errorf("Mount %s not found", mountPoint) 128 return 129 } 130 131 fields := strings.Fields(line) 132 if len(fields) != fieldsPerLine { 133 err = fmt.Errorf("Incorrect no of fields (expected %d, got %d)) :%s", fieldsPerLine, len(fields), line) 134 return 135 } 136 137 if mountPoint == fields[procPathIndex] { 138 devicePath = fields[procDeviceIndex] 139 fsType = fields[procTypeIndex] 140 return 141 } 142 } 143 }