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  }