diff --git a/pkg/abi/sentry/BUILD b/pkg/abi/sentry/BUILD new file mode 100644 index 000000000..d0e79fa27 --- /dev/null +++ b/pkg/abi/sentry/BUILD @@ -0,0 +1,15 @@ +load("//tools:defs.bzl", "go_library") + +package( + default_applicable_licenses = ["//:license"], + licenses = ["notice"], +) + +go_library( + name = "sentry", + srcs = [ + "sentry.go", + "syscall.go", + ], + visibility = ["//:sandbox"], +) diff --git a/pkg/abi/sentry/sentry.go b/pkg/abi/sentry/sentry.go new file mode 100644 index 000000000..84f765ed3 --- /dev/null +++ b/pkg/abi/sentry/sentry.go @@ -0,0 +1,16 @@ +// Copyright 2023 The gVisor Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package sentry contains ABI-related constants for the gVisor sentry. +package sentry diff --git a/pkg/abi/sentry/syscall.go b/pkg/abi/sentry/syscall.go new file mode 100644 index 000000000..71391b5d7 --- /dev/null +++ b/pkg/abi/sentry/syscall.go @@ -0,0 +1,20 @@ +// Copyright 2023 The gVisor Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package sentry + +// MaxSyscallNum is the largest-numbered syscall that is supported. +// Having this as a constant allows allocating per-syscall data structures +// that are of fixed size throughout the codebase. +const MaxSyscallNum = 2000 diff --git a/pkg/sentry/kernel/BUILD b/pkg/sentry/kernel/BUILD index 5c627205a..5892f32c5 100644 --- a/pkg/sentry/kernel/BUILD +++ b/pkg/sentry/kernel/BUILD @@ -317,6 +317,7 @@ go_library( "//pkg/abi", "//pkg/abi/linux", "//pkg/abi/linux/errno", + "//pkg/abi/sentry", "//pkg/atomicbitops", "//pkg/bitmap", "//pkg/bits", diff --git a/pkg/sentry/kernel/syscalls.go b/pkg/sentry/kernel/syscalls.go index eb3957c67..7211d7cde 100644 --- a/pkg/sentry/kernel/syscalls.go +++ b/pkg/sentry/kernel/syscalls.go @@ -20,6 +20,7 @@ import ( "google.golang.org/protobuf/proto" "gvisor.dev/gvisor/pkg/abi" + "gvisor.dev/gvisor/pkg/abi/sentry" "gvisor.dev/gvisor/pkg/atomicbitops" "gvisor.dev/gvisor/pkg/bits" "gvisor.dev/gvisor/pkg/hostarch" @@ -30,17 +31,6 @@ import ( "gvisor.dev/gvisor/pkg/sync" ) -const ( - // maxSyscallNum is the highest supported syscall number. - // - // The types below create fast lookup slices for all syscalls. This maximum - // serves as a sanity check that we don't allocate huge slices for a very large - // syscall. This is checked during registration. - // LINT.IfChange - maxSyscallNum = 2000 - // LINT.ThenChange(../seccheck/syscall.go) -) - // outOfRangeSyscallNumber is used to represent a syscall number that is out of the // range [0, maxSyscallNum] in monitoring. var outOfRangeSyscallNumber = []*metric.FieldValue{&metric.FieldValue{"-1"}} @@ -149,7 +139,7 @@ type SyscallFlagsTable struct { // // missing syscalls have the same value in enable as missingEnable to // avoid an extra branch in Word. - enable [maxSyscallNum + 1]atomicbitops.Uint32 + enable [sentry.MaxSyscallNum + 1]atomicbitops.Uint32 // missingEnable contains the enable bits for missing syscalls. missingEnable atomicbitops.Uint32 @@ -173,7 +163,7 @@ func (e *SyscallFlagsTable) init(table map[uintptr]Syscall) { func (e *SyscallFlagsTable) UpdateSecCheck(state *seccheck.State) { e.mu.Lock() defer e.mu.Unlock() - for sysno := uintptr(0); sysno < maxSyscallNum; sysno++ { + for sysno := uintptr(0); sysno <= sentry.MaxSyscallNum; sysno++ { oldFlags := e.enable[sysno].Load() if !bits.IsOn32(oldFlags, syscallPresent) { continue @@ -207,7 +197,7 @@ func (e *SyscallFlagsTable) UpdateSecCheck(state *seccheck.State) { // Word returns the enable bitfield for sysno. func (e *SyscallFlagsTable) Word(sysno uintptr) uint32 { - if sysno <= maxSyscallNum { + if sysno <= sentry.MaxSyscallNum { return e.enable[sysno].Load() } return e.missingEnable.Load() @@ -308,12 +298,12 @@ type SyscallTable struct { // lookup is a fixed-size array that holds the syscalls (indexed by // their numbers). It is used for fast look ups. - lookup [maxSyscallNum + 1]SyscallFn + lookup [sentry.MaxSyscallNum + 1]SyscallFn // pointCallbacks is a fixed-size array that holds SyscallToProto callbacks // (indexed by syscall numbers). It is used for fast lookups when // seccheck.Point is enabled for the syscall. - pointCallbacks [maxSyscallNum + 1]SyscallToProto + pointCallbacks [sentry.MaxSyscallNum + 1]SyscallToProto // Emulate is a collection of instruction addresses to emulate. The // keys are addresses, and the values are system call numbers. @@ -386,7 +376,7 @@ func LookupSyscallTable(os abi.OS, a arch.Arch) (*SyscallTable, bool) { // RegisterSyscallTable registers a new syscall table for use by a Kernel. func RegisterSyscallTable(s *SyscallTable) { - if max := s.MaxSysno(); max > maxSyscallNum { + if max := s.MaxSysno(); max > sentry.MaxSyscallNum { panic(fmt.Sprintf("SyscallTable %+v contains too large syscall number %d", s, max)) } if _, ok := LookupSyscallTable(s.OS, s.Arch); ok { @@ -394,9 +384,9 @@ func RegisterSyscallTable(s *SyscallTable) { } allSyscallTables = append(allSyscallTables, s) unimplementedSyscallCounterInit.Do(func() { - allowedValues := make([]*metric.FieldValue, maxSyscallNum+2) + allowedValues := make([]*metric.FieldValue, sentry.MaxSyscallNum+2) unimplementedSyscallNumbers = make(map[uintptr][]*metric.FieldValue, len(allowedValues)) - for i := uintptr(0); i <= maxSyscallNum; i++ { + for i := uintptr(0); i <= sentry.MaxSyscallNum; i++ { s := &metric.FieldValue{strconv.Itoa(int(i))} allowedValues[i] = s unimplementedSyscallNumbers[i] = []*metric.FieldValue{s} @@ -434,7 +424,7 @@ func (s *SyscallTable) Init() { // Lookup returns the syscall implementation, if one exists. func (s *SyscallTable) Lookup(sysno uintptr) SyscallFn { - if sysno <= maxSyscallNum { + if sysno <= sentry.MaxSyscallNum { return s.lookup[sysno] } return nil @@ -476,7 +466,7 @@ func (s *SyscallTable) mapLookup(sysno uintptr) SyscallFn { // LookupSyscallToProto looks up the SyscallToProto callback for the given // syscall. It may return nil if none is registered. func (s *SyscallTable) LookupSyscallToProto(sysno uintptr) SyscallToProto { - if sysno > maxSyscallNum { + if sysno > sentry.MaxSyscallNum { return nil } return s.pointCallbacks[sysno] diff --git a/pkg/sentry/seccheck/BUILD b/pkg/sentry/seccheck/BUILD index c772c4b0c..e8faf0410 100644 --- a/pkg/sentry/seccheck/BUILD +++ b/pkg/sentry/seccheck/BUILD @@ -29,7 +29,9 @@ go_library( ], visibility = ["//:sandbox"], deps = [ + "//pkg/abi", "//pkg/abi/linux", + "//pkg/abi/sentry", "//pkg/atomicbitops", "//pkg/context", "//pkg/fd", diff --git a/pkg/sentry/seccheck/syscall.go b/pkg/sentry/seccheck/syscall.go index cdfec0b55..e0231df44 100644 --- a/pkg/sentry/seccheck/syscall.go +++ b/pkg/sentry/seccheck/syscall.go @@ -14,6 +14,10 @@ package seccheck +import ( + "gvisor.dev/gvisor/pkg/abi/sentry" +) + // SyscallType is an enum that denotes different types of syscall points. There // are 2 types of syscall point: fully-schematized and raw. Schematizes are // points that have syscall specific format, e.g. open => {path, flags, mode}. @@ -47,9 +51,7 @@ type SyscallFlagListener interface { } const ( - // Copied from kernel.maxSyscallNum to avoid reverse dependency. - syscallsMax = 2000 - syscallPoints = syscallsMax * int(syscallTypesCount) + syscallPoints = (sentry.MaxSyscallNum + 1) * int(syscallTypesCount) ) // Fields that are common for many syscalls. @@ -75,7 +77,7 @@ func GetPointForSyscall(typ SyscallType, sysno uintptr) Point { // SyscallEnabled checks if the corresponding point for the syscall is enabled. func (s *State) SyscallEnabled(typ SyscallType, sysno uintptr) bool { // Prevent overflow. - if sysno >= syscallsMax { + if sysno >= sentry.MaxSyscallNum { return false } return s.Enabled(GetPointForSyscall(typ, sysno))