gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/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 "gvisor.dev/gvisor/pkg/abi/linux" 19 "gvisor.dev/gvisor/pkg/errors/linuxerr" 20 "gvisor.dev/gvisor/pkg/hostarch" 21 "gvisor.dev/gvisor/pkg/sentry/arch" 22 "gvisor.dev/gvisor/pkg/sentry/fsimpl/iouringfs" 23 "gvisor.dev/gvisor/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, ¶ms) 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 }