github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/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/SagerNet/gvisor/pkg/abi/linux"
    31  	"github.com/SagerNet/gvisor/pkg/errors/linuxerr"
    32  	"github.com/SagerNet/gvisor/pkg/sentry/arch"
    33  	"github.com/SagerNet/gvisor/pkg/sentry/kernel"
    34  	"github.com/SagerNet/gvisor/pkg/syserror"
    35  )
    36  
    37  // Supported returns a syscall that is fully supported.
    38  func Supported(name string, fn kernel.SyscallFn) kernel.Syscall {
    39  	return kernel.Syscall{
    40  		Name:         name,
    41  		Fn:           fn,
    42  		SupportLevel: kernel.SupportFull,
    43  		Note:         "Fully Supported.",
    44  	}
    45  }
    46  
    47  // PartiallySupported returns a syscall that has a partial implementation.
    48  func PartiallySupported(name string, fn kernel.SyscallFn, note string, urls []string) kernel.Syscall {
    49  	return kernel.Syscall{
    50  		Name:         name,
    51  		Fn:           fn,
    52  		SupportLevel: kernel.SupportPartial,
    53  		Note:         note,
    54  		URLs:         urls,
    55  	}
    56  }
    57  
    58  // Error returns a syscall handler that will always give the passed error.
    59  func Error(name string, err error, note string, urls []string) kernel.Syscall {
    60  	if note != "" {
    61  		note = note + "; "
    62  	}
    63  	return kernel.Syscall{
    64  		Name: name,
    65  		Fn: func(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
    66  			return 0, nil, err
    67  		},
    68  		SupportLevel: kernel.SupportUnimplemented,
    69  		Note:         fmt.Sprintf("%sReturns %q.", note, err.Error()),
    70  		URLs:         urls,
    71  	}
    72  }
    73  
    74  // ErrorWithEvent gives a syscall function that sends an unimplemented
    75  // syscall event via the event channel and returns the passed error.
    76  func ErrorWithEvent(name string, err error, note string, urls []string) kernel.Syscall {
    77  	if note != "" {
    78  		note = note + "; "
    79  	}
    80  	return kernel.Syscall{
    81  		Name: name,
    82  		Fn: func(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
    83  			t.Kernel().EmitUnimplementedEvent(t)
    84  			return 0, nil, err
    85  		},
    86  		SupportLevel: kernel.SupportUnimplemented,
    87  		Note:         fmt.Sprintf("%sReturns %q.", note, err.Error()),
    88  		URLs:         urls,
    89  	}
    90  }
    91  
    92  // CapError gives a syscall function that checks for capability c.  If the task
    93  // has the capability, it returns ENOSYS, otherwise EPERM. To unprivileged
    94  // tasks, it will seem like there is an implementation.
    95  func CapError(name string, c linux.Capability, note string, urls []string) kernel.Syscall {
    96  	if note != "" {
    97  		note = note + "; "
    98  	}
    99  	return kernel.Syscall{
   100  		Name: name,
   101  		Fn: func(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
   102  			if !t.HasCapability(c) {
   103  				return 0, nil, linuxerr.EPERM
   104  			}
   105  			t.Kernel().EmitUnimplementedEvent(t)
   106  			return 0, nil, syserror.ENOSYS
   107  		},
   108  		SupportLevel: kernel.SupportUnimplemented,
   109  		Note:         fmt.Sprintf("%sReturns %q if the process does not have %s; %q otherwise.", note, linuxerr.EPERM, c.String(), syserror.ENOSYS),
   110  		URLs:         urls,
   111  	}
   112  }