github.com/metacubex/gvisor@v0.0.0-20240320004321-933faba989ec/pkg/sentry/socket/hostinet/socket_unsafe.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 hostinet 16 17 import ( 18 "unsafe" 19 20 "golang.org/x/sys/unix" 21 "github.com/metacubex/gvisor/pkg/abi/linux" 22 "github.com/metacubex/gvisor/pkg/context" 23 "github.com/metacubex/gvisor/pkg/errors/linuxerr" 24 "github.com/metacubex/gvisor/pkg/hostarch" 25 "github.com/metacubex/gvisor/pkg/sentry/arch" 26 "github.com/metacubex/gvisor/pkg/sentry/inet" 27 "github.com/metacubex/gvisor/pkg/sentry/kernel" 28 "github.com/metacubex/gvisor/pkg/sentry/socket" 29 "github.com/metacubex/gvisor/pkg/syserr" 30 "github.com/metacubex/gvisor/pkg/usermem" 31 ) 32 33 func firstBytePtr(bs []byte) unsafe.Pointer { 34 if len(bs) == 0 { 35 return nil 36 } 37 return unsafe.Pointer(&bs[0]) 38 } 39 40 // Preconditions: len(dsts) != 0. 41 func readv(fd int, dsts []unix.Iovec) (uint64, error) { 42 n, _, errno := unix.Syscall(unix.SYS_READV, uintptr(fd), uintptr(unsafe.Pointer(&dsts[0])), uintptr(len(dsts))) 43 if errno != 0 { 44 return 0, translateIOSyscallError(errno) 45 } 46 return uint64(n), nil 47 } 48 49 // Preconditions: len(srcs) != 0. 50 func writev(fd int, srcs []unix.Iovec) (uint64, error) { 51 n, _, errno := unix.Syscall(unix.SYS_WRITEV, uintptr(fd), uintptr(unsafe.Pointer(&srcs[0])), uintptr(len(srcs))) 52 if errno != 0 { 53 return 0, translateIOSyscallError(errno) 54 } 55 return uint64(n), nil 56 } 57 58 func ioctl(ctx context.Context, fd int, io usermem.IO, sysno uintptr, args arch.SyscallArguments) (uintptr, error) { 59 switch cmd := uintptr(args[1].Int()); cmd { 60 case unix.TIOCINQ, unix.TIOCOUTQ: 61 var val int32 62 if _, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(fd), cmd, uintptr(unsafe.Pointer(&val))); errno != 0 { 63 return 0, translateIOSyscallError(errno) 64 } 65 var buf [4]byte 66 hostarch.ByteOrder.PutUint32(buf[:], uint32(val)) 67 _, err := io.CopyOut(ctx, args[2].Pointer(), buf[:], usermem.IOOpts{ 68 AddressSpaceActive: true, 69 }) 70 return 0, err 71 case linux.SIOCGIFFLAGS, 72 linux.SIOCGIFHWADDR, 73 linux.SIOCGIFINDEX, 74 linux.SIOCGIFMTU, 75 linux.SIOCGIFNAME, 76 linux.SIOCGIFNETMASK, 77 linux.SIOCGIFTXQLEN: 78 cc := &usermem.IOCopyContext{ 79 Ctx: ctx, 80 IO: io, 81 Opts: usermem.IOOpts{ 82 AddressSpaceActive: true, 83 }, 84 } 85 var ifr linux.IFReq 86 if _, err := ifr.CopyIn(cc, args[2].Pointer()); err != nil { 87 return 0, err 88 } 89 if _, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(fd), cmd, uintptr(unsafe.Pointer(&ifr))); errno != 0 { 90 return 0, translateIOSyscallError(errno) 91 } 92 _, err := ifr.CopyOut(cc, args[2].Pointer()) 93 return 0, err 94 case linux.SIOCGIFCONF: 95 cc := &usermem.IOCopyContext{ 96 Ctx: ctx, 97 IO: io, 98 Opts: usermem.IOOpts{ 99 AddressSpaceActive: true, 100 }, 101 } 102 var ifc linux.IFConf 103 if _, err := ifc.CopyIn(cc, args[2].Pointer()); err != nil { 104 return 0, err 105 } 106 107 // The user's ifconf can have a nullable pointer to a buffer. Use a Sentry array if non-null. 108 ifcNested := linux.IFConf{Len: ifc.Len} 109 var ifcBuf []byte 110 if ifc.Ptr != 0 { 111 ifcBuf = make([]byte, ifc.Len) 112 ifcNested.Ptr = uint64(uintptr(unsafe.Pointer(&ifcBuf[0]))) 113 } 114 if _, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(fd), cmd, uintptr(unsafe.Pointer(&ifcNested))); errno != 0 { 115 return 0, translateIOSyscallError(errno) 116 } 117 // Copy out the buffer if it was non-null. 118 if ifc.Ptr != 0 { 119 if _, err := cc.CopyOutBytes(hostarch.Addr(ifc.Ptr), ifcBuf); err != nil { 120 return 0, err 121 } 122 } 123 ifc.Len = ifcNested.Len 124 _, err := ifc.CopyOut(cc, args[2].Pointer()) 125 return 0, err 126 case linux.SIOCETHTOOL: 127 cc := &usermem.IOCopyContext{ 128 Ctx: ctx, 129 IO: io, 130 Opts: usermem.IOOpts{ 131 AddressSpaceActive: true, 132 }, 133 } 134 var ifr linux.IFReq 135 if _, err := ifr.CopyIn(cc, args[2].Pointer()); err != nil { 136 return 0, err 137 } 138 // SIOCETHTOOL commands specify the subcommand in the first 32 bytes pointed 139 // to by ifr.ifr_data. We need to copy it in first to understand the actual 140 // structure pointed by ifr.ifr_data. 141 ifrData := hostarch.Addr(hostarch.ByteOrder.Uint64(ifr.Data[:8])) 142 var ethtoolCmd linux.EthtoolCmd 143 if _, err := ethtoolCmd.CopyIn(cc, ifrData); err != nil { 144 return 0, err 145 } 146 // We only support ETHTOOL_GFEATURES. 147 if ethtoolCmd != linux.ETHTOOL_GFEATURES { 148 return 0, linuxerr.EOPNOTSUPP 149 } 150 var gfeatures linux.EthtoolGFeatures 151 if _, err := gfeatures.CopyIn(cc, ifrData); err != nil { 152 return 0, err 153 } 154 155 // Find the requested device. 156 stk := inet.StackFromContext(ctx) 157 if stk == nil { 158 return 0, linuxerr.ENODEV 159 } 160 161 var ( 162 iface inet.Interface 163 found bool 164 ) 165 for _, iface = range stk.Interfaces() { 166 if iface.Name == ifr.Name() { 167 found = true 168 break 169 } 170 } 171 if !found { 172 return 0, linuxerr.ENODEV 173 } 174 175 // Copy out the feature blocks to the memory pointed to by ifrData. 176 blksToCopy := int(gfeatures.Size) 177 if blksToCopy > len(iface.Features) { 178 blksToCopy = len(iface.Features) 179 } 180 gfeatures.Size = uint32(blksToCopy) 181 if _, err := gfeatures.CopyOut(cc, ifrData); err != nil { 182 return 0, err 183 } 184 next, ok := ifrData.AddLength(uint64(unsafe.Sizeof(linux.EthtoolGFeatures{}))) 185 for i := 0; i < blksToCopy; i++ { 186 if !ok { 187 return 0, linuxerr.EFAULT 188 } 189 if _, err := iface.Features[i].CopyOut(cc, next); err != nil { 190 return 0, err 191 } 192 next, ok = next.AddLength(uint64(unsafe.Sizeof(linux.EthtoolGetFeaturesBlock{}))) 193 } 194 195 return 0, nil 196 default: 197 return 0, linuxerr.ENOTTY 198 } 199 } 200 201 func accept4(fd int, addr *byte, addrlen *uint32, flags int) (int, error) { 202 afd, _, errno := unix.Syscall6(unix.SYS_ACCEPT4, uintptr(fd), uintptr(unsafe.Pointer(addr)), uintptr(unsafe.Pointer(addrlen)), uintptr(flags), 0, 0) 203 if errno != 0 { 204 return 0, translateIOSyscallError(errno) 205 } 206 return int(afd), nil 207 } 208 209 func getsockopt(fd int, level, name int, opt []byte) ([]byte, error) { 210 optlen32 := int32(len(opt)) 211 _, _, errno := unix.Syscall6(unix.SYS_GETSOCKOPT, uintptr(fd), uintptr(level), uintptr(name), uintptr(firstBytePtr(opt)), uintptr(unsafe.Pointer(&optlen32)), 0) 212 if errno != 0 { 213 return nil, errno 214 } 215 return opt[:optlen32], nil 216 } 217 218 // GetSockName implements socket.Socket.GetSockName. 219 func (s *Socket) GetSockName(t *kernel.Task) (linux.SockAddr, uint32, *syserr.Error) { 220 addr := make([]byte, sizeofSockaddr) 221 addrlen := uint32(len(addr)) 222 _, _, errno := unix.Syscall(unix.SYS_GETSOCKNAME, uintptr(s.fd), uintptr(unsafe.Pointer(&addr[0])), uintptr(unsafe.Pointer(&addrlen))) 223 if errno != 0 { 224 return nil, 0, syserr.FromError(errno) 225 } 226 return socket.UnmarshalSockAddr(s.family, addr), addrlen, nil 227 } 228 229 // GetPeerName implements socket.Socket.GetPeerName. 230 func (s *Socket) GetPeerName(t *kernel.Task) (linux.SockAddr, uint32, *syserr.Error) { 231 addr := make([]byte, sizeofSockaddr) 232 addrlen := uint32(len(addr)) 233 _, _, errno := unix.Syscall(unix.SYS_GETPEERNAME, uintptr(s.fd), uintptr(unsafe.Pointer(&addr[0])), uintptr(unsafe.Pointer(&addrlen))) 234 if errno != 0 { 235 return nil, 0, syserr.FromError(errno) 236 } 237 return socket.UnmarshalSockAddr(s.family, addr), addrlen, nil 238 } 239 240 func recvfrom(fd int, dst []byte, flags int, from *[]byte) (uint64, error) { 241 fromLen := uint32(len(*from)) 242 n, _, errno := unix.Syscall6(unix.SYS_RECVFROM, uintptr(fd), uintptr(firstBytePtr(dst)), uintptr(len(dst)), uintptr(flags), uintptr(firstBytePtr(*from)), uintptr(unsafe.Pointer(&fromLen))) 243 if errno != 0 { 244 return 0, translateIOSyscallError(errno) 245 } 246 *from = (*from)[:fromLen] 247 return uint64(n), nil 248 } 249 250 func recvmsg(fd int, msg *unix.Msghdr, flags int) (uint64, error) { 251 n, _, errno := unix.Syscall(unix.SYS_RECVMSG, uintptr(fd), uintptr(unsafe.Pointer(msg)), uintptr(flags)) 252 if errno != 0 { 253 return 0, translateIOSyscallError(errno) 254 } 255 return uint64(n), nil 256 } 257 258 func sendmsg(fd int, msg *unix.Msghdr, flags int) (uint64, error) { 259 n, _, errno := unix.Syscall(unix.SYS_SENDMSG, uintptr(fd), uintptr(unsafe.Pointer(msg)), uintptr(flags)) 260 if errno != 0 { 261 return 0, translateIOSyscallError(errno) 262 } 263 return uint64(n), nil 264 }