github.com/nicocha30/gvisor-ligolo@v0.0.0-20230726075806-989fa2c0a413/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/nicocha30/gvisor-ligolo/pkg/abi/linux" 31 "github.com/nicocha30/gvisor-ligolo/pkg/errors/linuxerr" 32 "github.com/nicocha30/gvisor-ligolo/pkg/sentry/arch" 33 "github.com/nicocha30/gvisor-ligolo/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 correspoding 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 correspoding 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 }