github.com/metacubex/gvisor@v0.0.0-20240320004321-933faba989ec/pkg/sentry/syscalls/syscalls.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 syscalls is the interface from the application to the kernel.
    16  // Traditionally, syscalls is the interface that is used by applications to
    17  // request services from the kernel of a operating system. We provide a
    18  // user-mode kernel that needs to handle those requests coming from unmodified
    19  // applications. Therefore, we still use the term "syscalls" to denote this
    20  // interface.
    21  //
    22  // Note that the stubs in this package may merely provide the interface, not
    23  // the actual implementation. It just makes writing syscall stubs
    24  // straightforward.
    25  package syscalls
    26  
    27  import (
    28  	"fmt"
    29  
    30  	"github.com/metacubex/gvisor/pkg/abi/linux"
    31  	"github.com/metacubex/gvisor/pkg/errors/linuxerr"
    32  	"github.com/metacubex/gvisor/pkg/sentry/arch"
    33  	"github.com/metacubex/gvisor/pkg/sentry/kernel"
    34  )
    35  
    36  // Supported returns a syscall that is fully supported.
    37  func Supported(name string, fn kernel.SyscallFn) kernel.Syscall {
    38  	return kernel.Syscall{
    39  		Name:         name,
    40  		Fn:           fn,
    41  		SupportLevel: kernel.SupportFull,
    42  		Note:         "Fully Supported.",
    43  	}
    44  }
    45  
    46  // SupportedPoint returns a syscall that is fully supported with a corresponding
    47  // seccheck.Point.
    48  func SupportedPoint(name string, fn kernel.SyscallFn, cb kernel.SyscallToProto) kernel.Syscall {
    49  	sys := Supported(name, fn)
    50  	sys.PointCallback = cb
    51  	return sys
    52  }
    53  
    54  // PartiallySupported returns a syscall that has a partial implementation.
    55  func PartiallySupported(name string, fn kernel.SyscallFn, note string, urls []string) kernel.Syscall {
    56  	return kernel.Syscall{
    57  		Name:         name,
    58  		Fn:           fn,
    59  		SupportLevel: kernel.SupportPartial,
    60  		Note:         note,
    61  		URLs:         urls,
    62  	}
    63  }
    64  
    65  // PartiallySupportedPoint returns a syscall that has a partial implementation
    66  // with a corresponding seccheck.Point.
    67  func PartiallySupportedPoint(name string, fn kernel.SyscallFn, cb kernel.SyscallToProto, note string, urls []string) kernel.Syscall {
    68  	sys := PartiallySupported(name, fn, note, urls)
    69  	sys.PointCallback = cb
    70  	return sys
    71  }
    72  
    73  // Error returns a syscall handler that will always give the passed error.
    74  func Error(name string, err error, note string, urls []string) kernel.Syscall {
    75  	if note != "" {
    76  		note = note + "; "
    77  	}
    78  	return kernel.Syscall{
    79  		Name: name,
    80  		Fn: func(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
    81  			kernel.IncrementUnimplementedSyscallCounter(sysno)
    82  			return 0, nil, err
    83  		},
    84  		SupportLevel: kernel.SupportUnimplemented,
    85  		Note:         fmt.Sprintf("%sReturns %q.", note, err.Error()),
    86  		URLs:         urls,
    87  	}
    88  }
    89  
    90  // ErrorWithEvent gives a syscall function that sends an unimplemented
    91  // syscall event via the event channel and returns the passed error.
    92  func ErrorWithEvent(name string, err error, note string, urls []string) kernel.Syscall {
    93  	if note != "" {
    94  		note = note + "; "
    95  	}
    96  	return kernel.Syscall{
    97  		Name: name,
    98  		Fn: func(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
    99  			t.Kernel().EmitUnimplementedEvent(t, sysno)
   100  			return 0, nil, err
   101  		},
   102  		SupportLevel: kernel.SupportUnimplemented,
   103  		Note:         fmt.Sprintf("%sReturns %q.", note, err.Error()),
   104  		URLs:         urls,
   105  	}
   106  }
   107  
   108  // CapError gives a syscall function that checks for capability c.  If the task
   109  // has the capability, it returns ENOSYS, otherwise EPERM. To unprivileged
   110  // tasks, it will seem like there is an implementation.
   111  func CapError(name string, c linux.Capability, note string, urls []string) kernel.Syscall {
   112  	if note != "" {
   113  		note = note + "; "
   114  	}
   115  	return kernel.Syscall{
   116  		Name: name,
   117  		Fn: func(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
   118  			if !t.HasCapability(c) {
   119  				return 0, nil, linuxerr.EPERM
   120  			}
   121  			t.Kernel().EmitUnimplementedEvent(t, sysno)
   122  			return 0, nil, linuxerr.ENOSYS
   123  		},
   124  		SupportLevel: kernel.SupportUnimplemented,
   125  		Note:         fmt.Sprintf("%sReturns %q if the process does not have %s; %q otherwise.", note, linuxerr.EPERM, c.String(), linuxerr.ENOSYS),
   126  		URLs:         urls,
   127  	}
   128  }