github.com/nicocha30/gvisor-ligolo@v0.0.0-20230726075806-989fa2c0a413/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/nicocha30/gvisor-ligolo/pkg/abi/linux"
    22  	"github.com/nicocha30/gvisor-ligolo/pkg/context"
    23  	"github.com/nicocha30/gvisor-ligolo/pkg/errors/linuxerr"
    24  	"github.com/nicocha30/gvisor-ligolo/pkg/hostarch"
    25  	"github.com/nicocha30/gvisor-ligolo/pkg/sentry/arch"
    26  	"github.com/nicocha30/gvisor-ligolo/pkg/sentry/inet"
    27  	"github.com/nicocha30/gvisor-ligolo/pkg/sentry/kernel"
    28  	"github.com/nicocha30/gvisor-ligolo/pkg/sentry/socket"
    29  	"github.com/nicocha30/gvisor-ligolo/pkg/syserr"
    30  	"github.com/nicocha30/gvisor-ligolo/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  }