github.com/nicocha30/gvisor-ligolo@v0.0.0-20230726075806-989fa2c0a413/pkg/sentry/syscalls/linux/sys_iouring.go (about)

     1  // Copyright 2022 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 linux
    16  
    17  import (
    18  	"github.com/nicocha30/gvisor-ligolo/pkg/abi/linux"
    19  	"github.com/nicocha30/gvisor-ligolo/pkg/errors/linuxerr"
    20  	"github.com/nicocha30/gvisor-ligolo/pkg/hostarch"
    21  	"github.com/nicocha30/gvisor-ligolo/pkg/sentry/arch"
    22  	"github.com/nicocha30/gvisor-ligolo/pkg/sentry/fsimpl/iouringfs"
    23  	"github.com/nicocha30/gvisor-ligolo/pkg/sentry/kernel"
    24  )
    25  
    26  // IOUringSetup implements linux syscall io_uring_setup(2).
    27  func IOUringSetup(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
    28  	if !kernel.IOUringEnabled {
    29  		return 0, nil, linuxerr.ENOSYS
    30  	}
    31  
    32  	entries := uint32(args[0].Uint())
    33  	paramsAddr := args[1].Pointer()
    34  	var params linux.IOUringParams
    35  
    36  	if entries == 0 {
    37  		return 0, nil, linuxerr.EINVAL
    38  	}
    39  	if _, err := params.CopyIn(t, paramsAddr); err != nil {
    40  		return 0, nil, err
    41  	}
    42  
    43  	for i := int(0); i < len(params.Resv); i++ {
    44  		if params.Resv[i] != 0 {
    45  			return 0, nil, linuxerr.EINVAL
    46  		}
    47  	}
    48  
    49  	// List of currently supported flags in our IO_URING implementation.
    50  	const supportedFlags = 0 // Currently support none
    51  
    52  	// Since we don't implement everything, we fail explicitly on flags that are unimplemented.
    53  	if params.Flags|supportedFlags != supportedFlags {
    54  		return 0, nil, linuxerr.EINVAL
    55  	}
    56  
    57  	vfsObj := t.Kernel().VFS()
    58  	iouringfd, err := iouringfs.New(t, vfsObj, entries, &params)
    59  
    60  	if err != nil {
    61  		// return 0, nil, err
    62  		return 0, nil, linuxerr.EPERM
    63  	}
    64  	defer iouringfd.DecRef(t)
    65  
    66  	fd, err := t.NewFDFrom(0, iouringfd, kernel.FDFlags{
    67  		// O_CLOEXEC is always set up. See io_uring/io_uring.c:io_uring_install_fd().
    68  		CloseOnExec: true,
    69  	})
    70  
    71  	if err != nil {
    72  		return 0, nil, err
    73  	}
    74  
    75  	if _, err := params.CopyOut(t, paramsAddr); err != nil {
    76  		return 0, nil, err
    77  	}
    78  
    79  	return uintptr(fd), nil, nil
    80  }
    81  
    82  // IOUringEnter implements linux syscall io_uring_enter(2).
    83  func IOUringEnter(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
    84  	if !kernel.IOUringEnabled {
    85  		return 0, nil, linuxerr.ENOSYS
    86  	}
    87  
    88  	fd := int32(args[0].Int())
    89  	toSubmit := uint32(args[1].Uint())
    90  	minComplete := uint32(args[2].Uint())
    91  	flags := uint32(args[3].Uint())
    92  	sigSet := args[4].Pointer()
    93  
    94  	ret := -1
    95  
    96  	// List of currently supported flags for io_uring_enter(2).
    97  	const supportedFlags = linux.IORING_ENTER_GETEVENTS
    98  
    99  	// Since we don't implement everything, we fail explicitly on flags that are unimplemented.
   100  	if flags|supportedFlags != supportedFlags {
   101  		return uintptr(ret), nil, linuxerr.EINVAL
   102  	}
   103  
   104  	// Currently don't support replacing an existing signal mask.
   105  	if sigSet != hostarch.Addr(0) {
   106  		return uintptr(ret), nil, linuxerr.EFAULT
   107  	}
   108  
   109  	// If a user requested to submit zero SQEs, then we don't process any and return right away.
   110  	if toSubmit == 0 {
   111  		return uintptr(ret), nil, nil
   112  	}
   113  
   114  	file := t.GetFile(fd)
   115  	if file == nil {
   116  		return uintptr(ret), nil, linuxerr.EBADF
   117  	}
   118  	defer file.DecRef(t)
   119  	iouringfd, ok := file.Impl().(*iouringfs.FileDescription)
   120  	if !ok {
   121  		return uintptr(ret), nil, linuxerr.EBADF
   122  	}
   123  	ret, err := iouringfd.ProcessSubmissions(t, toSubmit, minComplete, flags)
   124  	if err != nil {
   125  		return uintptr(ret), nil, err
   126  	}
   127  
   128  	return uintptr(ret), nil, nil
   129  }