gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/test/secbench/secbenchdef/special_unsafe.go (about) 1 // Copyright 2023 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 secbenchdef 16 17 import ( 18 "runtime" 19 "unsafe" 20 21 "golang.org/x/sys/unix" 22 "gvisor.dev/gvisor/pkg/abi/linux" 23 ) 24 25 // SpecialSyscall are syscalls which need special handling. 26 // This can be syscalls where the arguments must be valid references to user 27 // memory. 28 type SpecialSyscall string 29 30 const ( 31 // NanosleepZero calls nanosleep(2) to sleep for zero nanoseconds. 32 NanosleepZero = SpecialSyscall("NanosleepZero") 33 // PPollNonExistent calls ppoll(2) with a non-existent FD and a tiny timeout. 34 PPollNonExistent = SpecialSyscall("PPollNonExistent") 35 // RTSigreturn calls a system call that stands in the place of `rt_sigreturn(2)`. 36 RTSigreturn = SpecialSyscall("RTSigreturn") 37 ) 38 39 // Sys returns the Syscall struct for this special syscall. 40 func (s SpecialSyscall) Sys() Syscall { 41 return Syscall{Special: s} 42 } 43 44 // Seq returns a one-item slice of the Syscall struct for this special syscall. 45 func (s SpecialSyscall) Seq() []Syscall { 46 return []Syscall{s.Sys()} 47 } 48 49 // zeroNanoseconds is a timespec that represents zero nanoseconds. 50 var zeroNanosecond = &linux.Timespec{} 51 52 // oneNanosecond is a timespec that represents a single nanosecond. 53 var oneNanosecond = &linux.Timespec{Nsec: 1} 54 55 // ppollNonExistent is a PollFD struct with a non-existent FD and no events. 56 var ppollNonExistent = &linux.PollFD{FD: int32(NonExistentFD)} 57 58 // args returns the syscall number and arguments to call, 59 // along with an array of references that must be kept alive if the syscall 60 // arguments should refer to valid user memory. 61 func (s SpecialSyscall) args() (sysno uintptr, args [6]uintptr, refs [6]any) { 62 switch s { 63 case NanosleepZero: 64 refs[0] = zeroNanosecond 65 args[0] = uintptr(unsafe.Pointer(zeroNanosecond)) 66 return unix.SYS_NANOSLEEP, args, refs 67 case PPollNonExistent: 68 refs[0] = ppollNonExistent 69 args[0] = uintptr(unsafe.Pointer(ppollNonExistent)) 70 args[1] = 1 71 refs[2] = oneNanosecond 72 args[2] = uintptr(unsafe.Pointer(oneNanosecond)) 73 return unix.SYS_PPOLL, args, refs 74 case RTSigreturn: 75 // We use `request_key(2)` as a stand-in for `rt_sigreturn(2)`. 76 return unix.SYS_REQUEST_KEY, args, refs 77 default: 78 panic("invalid special syscall") 79 } 80 } 81 82 // Data returns the seccomp data for this syscall. 83 func (s SpecialSyscall) Data(arch uint32) *linux.SeccompData { 84 sysno, args, _ := s.args() 85 return &linux.SeccompData{ 86 Nr: int32(sysno), 87 Arch: arch, 88 Args: [6]uint64{ 89 uint64(args[0]), 90 uint64(args[1]), 91 uint64(args[2]), 92 uint64(args[3]), 93 uint64(args[4]), 94 uint64(args[5]), 95 }, 96 } 97 } 98 99 // Call calls this syscall. 100 func (s SpecialSyscall) Call() (r1 uintptr, r2 uintptr, err error) { 101 sysno, args, refs := s.args() 102 r1, r2, err = unix.Syscall6(sysno, args[0], args[1], args[2], args[3], args[4], args[5]) 103 runtime.KeepAlive(refs) 104 return r1, r2, err 105 }