diff --git a/examples/seccheck/pod_init.json b/examples/seccheck/pod_init.json index 627687458..a08b26c54 100644 --- a/examples/seccheck/pod_init.json +++ b/examples/seccheck/pod_init.json @@ -10,6 +10,36 @@ }, { "name": "sentry/task_exit" + }, + { + "name": "syscall/openat/enter" + }, + { + "name": "syscall/openat/exit" + }, + { + "name": "syscall/read/enter", + "optional_fields": [ + "fd_path" + ], + "context_fields": [ + "time", + "container_id", + "thread_id" + ] + }, + { + "name": "syscall/read/exit" + }, + { + "name": "syscall/sysno/1/enter", + "context_fields": [ + "time", + "container_id" + ] + }, + { + "name": "syscall/sysno/1/exit" } ], "sinks": [ diff --git a/examples/seccheck/server.cc b/examples/seccheck/server.cc index bf1941306..f4a73fada 100644 --- a/examples/seccheck/server.cc +++ b/examples/seccheck/server.cc @@ -31,6 +31,7 @@ #include "absl/strings/string_view.h" #include "pkg/sentry/seccheck/points/container.pb.h" #include "pkg/sentry/seccheck/points/sentry.pb.h" +#include "pkg/sentry/seccheck/points/syscall.pb.h" typedef std::function Callback; @@ -55,6 +56,22 @@ void log(const char* fmt, ...) { } } +template +void unpackSyscall(const google::protobuf::Any& any) { + T evt; + if (!any.UnpackTo(&evt)) { + err(1, "UnpackTo(): %s", any.DebugString().c_str()); + } + auto last_dot = any.type_url().find_last_of('.'); + if (last_dot == std::string::npos) { + err(1, "invalid name: %.*s", static_cast(any.type_url().size()), + any.type_url().data()); + } + auto name = any.type_url().substr(last_dot + 1); + log("%s %.*s %s\n", evt.has_exit() ? "X" : "E", static_cast(name.size()), + name.data(), evt.ShortDebugString().c_str()); +} + template void unpack(const google::protobuf::Any& any) { T evt; @@ -67,6 +84,13 @@ void unpack(const google::protobuf::Any& any) { } std::map dispatchers = { + {"gvisor.syscall.Syscall", unpackSyscall<::gvisor::syscall::Syscall>}, + {"gvisor.syscall.Read", unpackSyscall<::gvisor::syscall::Read>}, + {"gvisor.syscall.Open", unpackSyscall<::gvisor::syscall::Open>}, + {"gvisor.syscall.Connect", unpackSyscall<::gvisor::syscall::Connect>}, + {"gvisor.syscall.Execve", unpackSyscall<::gvisor::syscall::Execve>}, + {"gvisor.syscall.Close", unpackSyscall<::gvisor::syscall::Close>}, + {"gvisor.syscall.Socket", unpackSyscall<::gvisor::syscall::Socket>}, {"gvisor.container.Start", unpack<::gvisor::container::Start>}, {"gvisor.sentry.CloneInfo", unpack<::gvisor::sentry::CloneInfo>}, {"gvisor.sentry.ExecveInfo", unpack<::gvisor::sentry::ExecveInfo>}, diff --git a/pkg/sentry/kernel/syscalls.go b/pkg/sentry/kernel/syscalls.go index 35da667fc..0744c022c 100644 --- a/pkg/sentry/kernel/syscalls.go +++ b/pkg/sentry/kernel/syscalls.go @@ -21,7 +21,6 @@ import ( "gvisor.dev/gvisor/pkg/abi" "gvisor.dev/gvisor/pkg/atomicbitops" "gvisor.dev/gvisor/pkg/bits" - "gvisor.dev/gvisor/pkg/context" "gvisor.dev/gvisor/pkg/hostarch" "gvisor.dev/gvisor/pkg/sentry/arch" "gvisor.dev/gvisor/pkg/sentry/seccheck" @@ -85,6 +84,8 @@ type Syscall struct { URLs []string // PointCallback is an optional callback that converts syscall arguments // to a proto that can be used with seccheck.Checker. + // Callback functions must follow this naming convention: + // PointSyscallNameInCamelCase, e.g. PointReadat, PointRtSigaction. PointCallback SyscallToProto } @@ -398,7 +399,7 @@ func (s *SyscallTable) LookupSyscallToProto(sysno uintptr) SyscallToProto { // SyscallToProto is a callback function that converts generic syscall data to // schematized protobuf for the corresponding syscall. -type SyscallToProto func(context.Context, seccheck.FieldSet, *pb.ContextData, SyscallInfo) proto.Message +type SyscallToProto func(*Task, seccheck.FieldSet, *pb.ContextData, SyscallInfo) proto.Message // SyscallInfo provides generic information about the syscall. type SyscallInfo struct { diff --git a/pkg/sentry/kernel/task_exec.go b/pkg/sentry/kernel/task_exec.go index c91f30597..ca44fbcc3 100644 --- a/pkg/sentry/kernel/task_exec.go +++ b/pkg/sentry/kernel/task_exec.go @@ -313,7 +313,7 @@ func getExecveSeccheckInfo(t *Task, argv, env []string, executable fsbridge.File if executable != nil { info.BinaryPath = pathname if vfs2bridgeFile, ok := executable.(*fsbridge.VFSFile); ok { - if fields.Local.Contains(seccheck.ExecveFieldBinaryInfo) { + if fields.Local.Contains(seccheck.FieldSentryExecveBinaryInfo) { statOpts := vfs.StatOptions{ Mask: linux.STATX_TYPE | linux.STATX_MODE | linux.STATX_UID | linux.STATX_GID, } diff --git a/pkg/sentry/seccheck/BUILD b/pkg/sentry/seccheck/BUILD index 32ef90384..167214e5a 100644 --- a/pkg/sentry/seccheck/BUILD +++ b/pkg/sentry/seccheck/BUILD @@ -19,6 +19,8 @@ go_library( srcs = [ "config.go", "metadata.go", + "metadata_amd64.go", + "metadata_arm64.go", "seccheck.go", "seqatomic_checkerslice_unsafe.go", "syscall.go", diff --git a/pkg/sentry/seccheck/config.go b/pkg/sentry/seccheck/config.go index 72541ef83..3e83afdba 100644 --- a/pkg/sentry/seccheck/config.go +++ b/pkg/sentry/seccheck/config.go @@ -123,7 +123,7 @@ func findSession(name string) (*State, error) { } func findPointDesc(name string) (PointDesc, error) { - if desc, ok := points[name]; ok { + if desc, ok := Points[name]; ok { return desc, nil } return PointDesc{}, fmt.Errorf("point %q not found", name) diff --git a/pkg/sentry/seccheck/metadata.go b/pkg/sentry/seccheck/metadata.go index 261c76e65..57a776074 100644 --- a/pkg/sentry/seccheck/metadata.go +++ b/pkg/sentry/seccheck/metadata.go @@ -17,6 +17,7 @@ package seccheck import ( "fmt" "os" + "path" "gvisor.dev/gvisor/pkg/fd" ) @@ -46,22 +47,25 @@ const ( FieldCtxtTime ) +// Fields for container/start point. const ( - // ContainerStartFieldEnv is an optional field to collect list of environment + // FieldContainerStartEnv is an optional field to collect list of environment // variables set for the container start process. - ContainerStartFieldEnv Field = iota + FieldContainerStartEnv Field = iota ) +// Fields for sentry/execve point. const ( - // ExecveFieldBinaryInfo is an optional field to collect information about the - // binary being executed. - ExecveFieldBinaryInfo Field = iota + // FieldSentryExecveBinaryInfo is an optional field to collect information + // about the binary being executed. + FieldSentryExecveBinaryInfo Field = iota ) -var points = map[string]PointDesc{} +// Points is a map with all the Points registered in the system. +var Points = map[string]PointDesc{} var sinks = map[string]SinkDesc{} -// defaultContextFields are the fields present in most points. +// defaultContextFields are the fields present in most Points. var defaultContextFields = []FieldDesc{ { ID: FieldCtxtTime, @@ -127,7 +131,7 @@ func RegisterSink(sink SinkDesc) { // PointDesc describes a Point that is available to be configured. // Schema for these points are defined in pkg/sentry/seccheck/points/. type PointDesc struct { - // ID is the point unique indentifier. + // ID is the point unique identifier. ID Point // Name is the point unique name. Convention is to use the following format: // namespace/name @@ -153,7 +157,7 @@ type FieldDesc struct { } func registerPoint(pt PointDesc) { - if _, ok := points[pt.Name]; ok { + if _, ok := Points[pt.Name]; ok { panic(fmt.Sprintf("Point %q already registered", pt.Name)) } if err := validateFields(pt.OptionalFields); err != nil { @@ -162,7 +166,7 @@ func registerPoint(pt PointDesc) { if err := validateFields(pt.ContextFields); err != nil { panic(err) } - points[pt.Name] = pt + Points[pt.Name] = pt } func validateFields(fields []FieldDesc) error { @@ -181,7 +185,30 @@ func validateFields(fields []FieldDesc) error { return nil } -// These are all the points available in the system. +func addRawSyscallPoint(sysno uintptr) { + addSyscallPointHelper(SyscallRawEnter, sysno, fmt.Sprintf("sysno/%d", sysno), nil) +} + +func addSyscallPoint(sysno uintptr, name string, optionalFields []FieldDesc) { + addSyscallPointHelper(SyscallEnter, sysno, name, optionalFields) +} + +func addSyscallPointHelper(typ SyscallType, sysno uintptr, name string, optionalFields []FieldDesc) { + registerPoint(PointDesc{ + ID: GetPointForSyscall(typ, sysno), + Name: path.Join("syscall", name, "enter"), + OptionalFields: optionalFields, + ContextFields: defaultContextFields, + }) + registerPoint(PointDesc{ + ID: GetPointForSyscall(typ+1, sysno), + Name: path.Join("syscall", name, "exit"), + OptionalFields: optionalFields, + ContextFields: defaultContextFields, + }) +} + +// These are all the Points available in the system. func init() { // Points from the container namespace. registerPoint(PointDesc{ @@ -189,7 +216,7 @@ func init() { Name: "container/start", OptionalFields: []FieldDesc{ { - ID: ContainerStartFieldEnv, + ID: FieldContainerStartEnv, Name: "env", }, }, @@ -207,7 +234,7 @@ func init() { Name: "sentry/execve", OptionalFields: []FieldDesc{ { - ID: ExecveFieldBinaryInfo, + ID: FieldSentryExecveBinaryInfo, Name: "binary_info", }, }, diff --git a/pkg/sentry/seccheck/metadata_amd64.go b/pkg/sentry/seccheck/metadata_amd64.go new file mode 100644 index 000000000..2fcf23398 --- /dev/null +++ b/pkg/sentry/seccheck/metadata_amd64.go @@ -0,0 +1,74 @@ +// Copyright 2022 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. + +//go:build amd64 +// +build amd64 + +package seccheck + +func init() { + addSyscallPoint(0, "read", []FieldDesc{ + { + ID: FieldSyscallPath, + Name: "fd_path", + }, + }) + addSyscallPoint(2, "open", nil) + addSyscallPoint(3, "close", []FieldDesc{ + { + ID: FieldSyscallPath, + Name: "fd_path", + }, + }) + addSyscallPoint(41, "socket", nil) + addSyscallPoint(42, "connect", []FieldDesc{ + { + ID: FieldSyscallPath, + Name: "fd_path", + }, + }) + addSyscallPoint(59, "execve", []FieldDesc{ + { + ID: FieldSyscallExecveEnvv, + Name: "envv", + }, + }) + addSyscallPoint(85, "creat", []FieldDesc{ + { + ID: FieldSyscallPath, + Name: "fd_path", + }, + }) + addSyscallPoint(257, "openat", []FieldDesc{ + { + ID: FieldSyscallPath, + Name: "fd_path", + }, + }) + addSyscallPoint(322, "execveat", []FieldDesc{ + { + ID: FieldSyscallPath, + Name: "fd_path", + }, + { + ID: FieldSyscallExecveEnvv, + Name: "envv", + }, + }) + + const lastSyscallInTable = 441 + for i := 0; i <= lastSyscallInTable; i++ { + addRawSyscallPoint(uintptr(i)) + } +} diff --git a/pkg/sentry/seccheck/metadata_arm64.go b/pkg/sentry/seccheck/metadata_arm64.go new file mode 100644 index 000000000..1d051840c --- /dev/null +++ b/pkg/sentry/seccheck/metadata_arm64.go @@ -0,0 +1,67 @@ +// Copyright 2022 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. + +//go:build arm64 +// +build arm64 + +package seccheck + +func init() { + addSyscallPoint(63, "read", []FieldDesc{ + { + ID: FieldSyscallPath, + Name: "fd_path", + }, + }) + addSyscallPoint(57, "close", []FieldDesc{ + { + ID: FieldSyscallPath, + Name: "fd_path", + }, + }) + addSyscallPoint(198, "socket", nil) + addSyscallPoint(203, "connect", []FieldDesc{ + { + ID: FieldSyscallPath, + Name: "fd_path", + }, + }) + addSyscallPoint(221, "execve", []FieldDesc{ + { + ID: FieldSyscallExecveEnvv, + Name: "envv", + }, + }) + addSyscallPoint(56, "openat", []FieldDesc{ + { + ID: FieldSyscallPath, + Name: "fd_path", + }, + }) + addSyscallPoint(281, "execveat", []FieldDesc{ + { + ID: FieldSyscallPath, + Name: "fd_path", + }, + { + ID: FieldSyscallExecveEnvv, + Name: "envv", + }, + }) + + const lastSyscallInTable = 441 + for i := 0; i <= lastSyscallInTable; i++ { + addRawSyscallPoint(uintptr(i)) + } +} diff --git a/pkg/sentry/seccheck/metadata_test.go b/pkg/sentry/seccheck/metadata_test.go index 5aa0e8d06..7dafe471b 100644 --- a/pkg/sentry/seccheck/metadata_test.go +++ b/pkg/sentry/seccheck/metadata_test.go @@ -35,7 +35,7 @@ func TestSinkRegistration(t *testing.T) { func TestPointRegistration(t *testing.T) { point := PointDesc{Name: "test"} registerPoint(point) - if _, ok := points["test"]; !ok { + if _, ok := Points["test"]; !ok { t.Errorf("point registration failed") } diff --git a/pkg/sentry/seccheck/points/syscall.proto b/pkg/sentry/seccheck/points/syscall.proto index 1931d94e8..656ab1fee 100644 --- a/pkg/sentry/seccheck/points/syscall.proto +++ b/pkg/sentry/seccheck/points/syscall.proto @@ -34,3 +34,62 @@ message Syscall { uint64 arg5 = 9; uint64 arg6 = 10; } + +message Open { + gvisor.common.ContextData context_data = 1; + Exit exit = 2; + uint64 sysno = 3; + int64 fd = 4; + string fd_path = 5; + string pathname = 6; + uint32 flags = 7; + uint32 mode = 8; +} + +message Close { + gvisor.common.ContextData context_data = 1; + Exit exit = 2; + uint64 sysno = 3; + int64 fd = 4; + string fd_path = 5; +} + +message Read { + gvisor.common.ContextData context_data = 1; + Exit exit = 2; + uint64 sysno = 3; + int64 fd = 4; + string fd_path = 5; + uint64 count = 6; + bytes data = 7; +} + +message Connect { + gvisor.common.ContextData context_data = 1; + Exit exit = 2; + uint64 sysno = 3; + int64 fd = 4; + string fd_path = 5; + bytes address = 6; +} + +message Execve { + gvisor.common.ContextData context_data = 1; + Exit exit = 2; + uint64 sysno = 3; + int64 fd = 4; + string fd_path = 5; + string pathname = 6; + repeated string argv = 7; + repeated string envv = 8; + uint32 flags = 9; +} + +message Socket { + gvisor.common.ContextData context_data = 1; + Exit exit = 2; + uint64 sysno = 3; + int32 domain = 4; + int32 type = 5; + int32 protocol = 6; +} \ No newline at end of file diff --git a/pkg/sentry/seccheck/syscall.go b/pkg/sentry/seccheck/syscall.go index 66ae3f3e2..43d0cce84 100644 --- a/pkg/sentry/seccheck/syscall.go +++ b/pkg/sentry/seccheck/syscall.go @@ -41,6 +41,21 @@ const ( syscallPoints = syscallsMax * int(syscallTypesCount) ) +// Fields that are common for many syscalls. +const ( + // FieldSyscallPath is an optional field to collect path from an FD. Given + // that many syscalls operate on FDs, this const is used across syscalls. + FieldSyscallPath Field = iota +) + +// Fields for execve*(2) syscalls. +const ( + // FieldSyscallExecveEnvv is an optional field to collect list of environment + // variables. Start after FieldSyscallPath because execveat(2) can collect + // path from FD. + FieldSyscallExecveEnvv = FieldSyscallPath + 1 +) + // GetPointForSyscall translates the syscall number to the corresponding Point. func GetPointForSyscall(typ SyscallType, sysno uintptr) Point { return Point(sysno)*Point(syscallTypesCount) + Point(typ) + pointLengthBeforeSyscalls diff --git a/pkg/sentry/syscalls/linux/BUILD b/pkg/sentry/syscalls/linux/BUILD index 394396cde..29f7b4cc6 100644 --- a/pkg/sentry/syscalls/linux/BUILD +++ b/pkg/sentry/syscalls/linux/BUILD @@ -1,4 +1,4 @@ -load("//tools:defs.bzl", "go_library") +load("//tools:defs.bzl", "go_library", "go_test") package(licenses = ["notice"]) @@ -8,6 +8,7 @@ go_library( "error.go", "flags.go", "linux64.go", + "points.go", "sigset.go", "sys_aio.go", "sys_capability.go", @@ -96,6 +97,8 @@ go_library( "//pkg/sentry/loader", "//pkg/sentry/memmap", "//pkg/sentry/mm", + "//pkg/sentry/seccheck", + "//pkg/sentry/seccheck/points:points_go_proto", "//pkg/sentry/socket", "//pkg/sentry/socket/control", "//pkg/sentry/socket/unix/transport", @@ -106,6 +109,19 @@ go_library( "//pkg/syserr", "//pkg/usermem", "//pkg/waiter", + "@org_golang_google_protobuf//proto:go_default_library", "@org_golang_x_sys//unix:go_default_library", ], ) + +go_test( + name = "linux_test", + size = "small", + srcs = [ + "linux64_amd64_test.go", + "linux64_arm64_test.go", + "linux64_test.go", + ], + library = ":linux", + deps = ["//pkg/sentry/seccheck"], +) diff --git a/pkg/sentry/syscalls/linux/linux64.go b/pkg/sentry/syscalls/linux/linux64.go index dbc483008..9f410eeda 100644 --- a/pkg/sentry/syscalls/linux/linux64.go +++ b/pkg/sentry/syscalls/linux/linux64.go @@ -52,9 +52,9 @@ var AMD64 = &kernel.SyscallTable{ }, AuditNumber: linux.AUDIT_ARCH_X86_64, Table: map[uintptr]kernel.Syscall{ - 0: syscalls.Supported("read", Read), + 0: syscalls.SupportedPoint("read", Read, PointRead), 1: syscalls.Supported("write", Write), - 2: syscalls.PartiallySupported("open", Open, "Options O_DIRECT, O_NOATIME, O_PATH, O_TMPFILE, O_SYNC are not supported.", nil), + 2: syscalls.PartiallySupportedPoint("open", Open, PointOpen, "Options O_DIRECT, O_NOATIME, O_PATH, O_TMPFILE, O_SYNC are not supported.", nil), 3: syscalls.Supported("close", Close), 4: syscalls.Supported("stat", Stat), 5: syscalls.Supported("fstat", Fstat), @@ -94,7 +94,7 @@ var AMD64 = &kernel.SyscallTable{ 39: syscalls.Supported("getpid", Getpid), 40: syscalls.Supported("sendfile", Sendfile), 41: syscalls.PartiallySupported("socket", Socket, "Limited support for AF_NETLINK, NETLINK_ROUTE sockets. Limited support for SOCK_RAW.", nil), - 42: syscalls.Supported("connect", Connect), + 42: syscalls.SupportedPoint("connect", Connect, PointConnect), 43: syscalls.Supported("accept", Accept), 44: syscalls.Supported("sendto", SendTo), 45: syscalls.Supported("recvfrom", RecvFrom), @@ -111,7 +111,7 @@ var AMD64 = &kernel.SyscallTable{ 56: syscalls.PartiallySupported("clone", Clone, "Mount namespace (CLONE_NEWNS) not supported. Options CLONE_PARENT, CLONE_SYSVSEM not supported.", nil), 57: syscalls.Supported("fork", Fork), 58: syscalls.Supported("vfork", Vfork), - 59: syscalls.Supported("execve", Execve), + 59: syscalls.SupportedPoint("execve", Execve, PointExecve), 60: syscalls.Supported("exit", Exit), 61: syscalls.Supported("wait4", Wait4), 62: syscalls.Supported("kill", Kill), @@ -309,7 +309,7 @@ var AMD64 = &kernel.SyscallTable{ 254: syscalls.PartiallySupported("inotify_add_watch", InotifyAddWatch, "Inotify events are only available inside the sandbox. Hard links are treated as different watch targets in gofer fs.", nil), 255: syscalls.PartiallySupported("inotify_rm_watch", InotifyRmWatch, "Inotify events are only available inside the sandbox. Hard links are treated as different watch targets in gofer fs.", nil), 256: syscalls.CapError("migrate_pages", linux.CAP_SYS_NICE, "", nil), - 257: syscalls.Supported("openat", Openat), + 257: syscalls.SupportedPoint("openat", Openat, PointOpenat), 258: syscalls.Supported("mkdirat", Mkdirat), 259: syscalls.Supported("mknodat", Mknodat), 260: syscalls.Supported("fchownat", Fchownat), @@ -374,7 +374,7 @@ var AMD64 = &kernel.SyscallTable{ 319: syscalls.Supported("memfd_create", MemfdCreate), 320: syscalls.CapError("kexec_file_load", linux.CAP_SYS_BOOT, "", nil), 321: syscalls.CapError("bpf", linux.CAP_SYS_ADMIN, "", nil), - 322: syscalls.Supported("execveat", Execveat), + 322: syscalls.SupportedPoint("execveat", Execveat, PointExecveat), 323: syscalls.ErrorWithEvent("userfaultfd", linuxerr.ENOSYS, "", []string{"gvisor.dev/issue/266"}), // TODO(b/118906345) 324: syscalls.PartiallySupported("membarrier", Membarrier, "Not supported on all platforms.", nil), 325: syscalls.PartiallySupported("mlock2", Mlock2, "Stub implementation. The sandbox lacks appropriate permissions.", nil), @@ -486,14 +486,14 @@ var ARM64 = &kernel.SyscallTable{ 53: syscalls.Supported("fchmodat", Fchmodat), 54: syscalls.Supported("fchownat", Fchownat), 55: syscalls.Supported("fchown", Fchown), - 56: syscalls.Supported("openat", Openat), + 56: syscalls.SupportedPoint("openat", Openat, PointOpenat), 57: syscalls.Supported("close", Close), 58: syscalls.CapError("vhangup", linux.CAP_SYS_TTY_CONFIG, "", nil), 59: syscalls.Supported("pipe2", Pipe2), 60: syscalls.CapError("quotactl", linux.CAP_SYS_ADMIN, "", nil), // requires cap_sys_admin for most operations 61: syscalls.Supported("getdents64", Getdents64), 62: syscalls.Supported("lseek", Lseek), - 63: syscalls.Supported("read", Read), + 63: syscalls.SupportedPoint("read", Read, PointRead), 64: syscalls.Supported("write", Write), 65: syscalls.Supported("readv", Readv), 66: syscalls.Supported("writev", Writev), @@ -633,7 +633,7 @@ var ARM64 = &kernel.SyscallTable{ 200: syscalls.PartiallySupported("bind", Bind, "Autobind for abstract Unix sockets is not supported.", nil), 201: syscalls.Supported("listen", Listen), 202: syscalls.Supported("accept", Accept), - 203: syscalls.Supported("connect", Connect), + 203: syscalls.SupportedPoint("connect", Connect, PointConnect), 204: syscalls.Supported("getsockname", GetSockName), 205: syscalls.Supported("getpeername", GetPeerName), 206: syscalls.Supported("sendto", SendTo), @@ -651,7 +651,7 @@ var ARM64 = &kernel.SyscallTable{ 218: syscalls.Error("request_key", linuxerr.EACCES, "Not available to user.", nil), 219: syscalls.Error("keyctl", linuxerr.EACCES, "Not available to user.", nil), 220: syscalls.PartiallySupported("clone", Clone, "Mount namespace (CLONE_NEWNS) not supported. Options CLONE_PARENT, CLONE_SYSVSEM not supported.", nil), - 221: syscalls.Supported("execve", Execve), + 221: syscalls.SupportedPoint("execve", Execve, PointExecve), 222: syscalls.PartiallySupported("mmap", Mmap, "Generally supported with exceptions. Options MAP_FIXED_NOREPLACE, MAP_SHARED_VALIDATE, MAP_SYNC MAP_GROWSDOWN, MAP_HUGETLB are not supported.", nil), 223: syscalls.PartiallySupported("fadvise64", Fadvise64, "Not all options are supported.", nil), 224: syscalls.CapError("swapon", linux.CAP_SYS_ADMIN, "", nil), @@ -695,7 +695,7 @@ var ARM64 = &kernel.SyscallTable{ 278: syscalls.Supported("getrandom", GetRandom), 279: syscalls.Supported("memfd_create", MemfdCreate), 280: syscalls.CapError("bpf", linux.CAP_SYS_ADMIN, "", nil), - 281: syscalls.Supported("execveat", Execveat), + 281: syscalls.SupportedPoint("execveat", Execveat, PointExecveat), 282: syscalls.ErrorWithEvent("userfaultfd", linuxerr.ENOSYS, "", []string{"gvisor.dev/issue/266"}), // TODO(b/118906345) 283: syscalls.PartiallySupported("membarrier", Membarrier, "Not supported on all platforms.", nil), 284: syscalls.PartiallySupported("mlock2", Mlock2, "Stub implementation. The sandbox lacks appropriate permissions.", nil), diff --git a/pkg/sentry/syscalls/linux/linux64_amd64_test.go b/pkg/sentry/syscalls/linux/linux64_amd64_test.go new file mode 100644 index 000000000..e6538fbdd --- /dev/null +++ b/pkg/sentry/syscalls/linux/linux64_amd64_test.go @@ -0,0 +1,20 @@ +// Copyright 2022 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. + +//go:build amd64 +// +build amd64 + +package linux + +var archToTest = AMD64 diff --git a/pkg/sentry/syscalls/linux/linux64_arm64_test.go b/pkg/sentry/syscalls/linux/linux64_arm64_test.go new file mode 100644 index 000000000..fa9d8833d --- /dev/null +++ b/pkg/sentry/syscalls/linux/linux64_arm64_test.go @@ -0,0 +1,20 @@ +// Copyright 2022 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. + +//go:build arm64 +// +build arm64 + +package linux + +var archToTest = ARM64 diff --git a/pkg/sentry/syscalls/linux/linux64_test.go b/pkg/sentry/syscalls/linux/linux64_test.go new file mode 100644 index 000000000..ff6eceab9 --- /dev/null +++ b/pkg/sentry/syscalls/linux/linux64_test.go @@ -0,0 +1,102 @@ +// Copyright 2022 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 linux + +import ( + "fmt" + "reflect" + "runtime" + "strings" + "testing" + "unicode" + + "gvisor.dev/gvisor/pkg/sentry/seccheck" +) + +func findPoint(name string) (seccheck.PointDesc, bool) { + for _, pt := range seccheck.Points { + if pt.Name == name { + return pt, true + } + } + return seccheck.PointDesc{}, false +} + +// TestSeccheckMax catches cases that a new syscall was added but seccheck raw +// syscall numbers (e.g. syscall/sysno/123) have not been updated. +func TestSeccheckMax(t *testing.T) { + max := uintptr(0) + for sysno := range archToTest.Table { + if sysno > max { + max = sysno + } + } + + want := fmt.Sprintf("syscall/sysno/%d/enter", max) + if _, ok := findPoint(want); !ok { + t.Errorf("seccheck.PointDesc for syscall %d not found. Update pkg/sentry/seccheck/metadata_amd64.go", max) + } +} + +// TestSeccheckSyscalls verifies that all syscalls registered with a point +// callback have the corresponding seccheck metadata created. +func TestSeccheckSyscalls(t *testing.T) { + for sysno, syscall := range archToTest.Table { + if syscall.PointCallback == nil { + continue + } + + // For every syscall with a PointCallback, there must be a corresponding + // seccheck.PointDesc created. + funcName := runtime.FuncForPC(reflect.ValueOf(syscall.PointCallback).Pointer()).Name() + if idx := strings.LastIndex(funcName, "."); idx > -1 { + funcName = funcName[idx+1:] + } + t.Run(funcName, func(t *testing.T) { + if !strings.HasPrefix(funcName, "Point") { + t.Errorf("PointCallback function name must start with Point: %q", funcName) + } + funcName = strings.TrimPrefix(funcName, "Point") + if len(funcName) == 0 { + t.Errorf("PointCallback function name invalid: %q", funcName) + } + + pointName := strings.ToLower(string(funcName[0])) + for _, c := range funcName[1:] { + if unicode.IsUpper(c) { + pointName += "_" + } + pointName += string(unicode.ToLower(c)) + } + + for _, flavor := range []struct { + suffix string + typ seccheck.SyscallType + }{ + {suffix: "enter", typ: seccheck.SyscallEnter}, + {suffix: "exit", typ: seccheck.SyscallExit}, + } { + fullName := fmt.Sprintf("syscall/%s/%s", pointName, flavor.suffix) + pt, ok := findPoint(fullName) + if !ok { + t.Fatalf("seccheck.PointDesc %q not found.", fullName) + } + if want := seccheck.GetPointForSyscall(flavor.typ, sysno); want != pt.ID { + t.Errorf("seccheck.Point for syscall %q is wrong, want: %v, got: %v", pointName, want, pt.ID) + } + } + }) + } +} diff --git a/pkg/sentry/syscalls/linux/points.go b/pkg/sentry/syscalls/linux/points.go new file mode 100644 index 000000000..a13e44753 --- /dev/null +++ b/pkg/sentry/syscalls/linux/points.go @@ -0,0 +1,263 @@ +// Copyright 2022 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 linux + +import ( + "fmt" + + "google.golang.org/protobuf/proto" + "gvisor.dev/gvisor/pkg/abi/linux" + "gvisor.dev/gvisor/pkg/sentry/kernel" + "gvisor.dev/gvisor/pkg/sentry/seccheck" + pb "gvisor.dev/gvisor/pkg/sentry/seccheck/points/points_go_proto" +) + +func newExitMaybe(info kernel.SyscallInfo) *pb.Exit { + if !info.Exit { + return nil + } + return &pb.Exit{ + Result: int64(info.Rval), + Errorno: int64(info.Errno), + } +} + +func getFilePath(t *kernel.Task, fd int32) string { + fdt := t.FDTable() + if fdt == nil { + return "[err: no FD table]" + } + file, _ := fdt.GetVFS2(fd) + if file == nil { + return "[err: requires VFS2]" + } + defer file.DecRef(t) + + root := t.MountNamespaceVFS2().Root() + path, err := t.Kernel().VFS().PathnameWithDeleted(t, root, file.VirtualDentry()) + if err != nil { + return fmt.Sprintf("[err: %v]", err) + } + return path +} + +// PointOpen converts open(2) syscall to proto. +func PointOpen(t *kernel.Task, _ seccheck.FieldSet, cxtData *pb.ContextData, info kernel.SyscallInfo) proto.Message { + p := &pb.Open{ + ContextData: cxtData, + Sysno: uint64(info.Sysno), + Fd: linux.AT_FDCWD, + Flags: info.Args[1].Uint(), + Mode: uint32(info.Args[2].ModeT()), + } + addr := info.Args[0].Pointer() + if addr > 0 { + path, err := t.CopyInString(addr, linux.PATH_MAX) + if err == nil { + p.Pathname = path + } + } + p.Exit = newExitMaybe(info) + return p +} + +// PointOpenat converts openat(2) syscall to proto. +func PointOpenat(t *kernel.Task, fields seccheck.FieldSet, cxtData *pb.ContextData, info kernel.SyscallInfo) proto.Message { + p := &pb.Open{ + ContextData: cxtData, + Sysno: uint64(info.Sysno), + Fd: int64(info.Args[0].Int()), + Flags: info.Args[2].Uint(), + } + + addr := info.Args[1].Pointer() + if addr > 0 { + path, err := t.CopyInString(addr, linux.PATH_MAX) + if err == nil { + p.Pathname = path + } + } + if p.Flags&linux.O_CREAT != 0 { + p.Mode = uint32(info.Args[3].ModeT()) + } + + if fields.Local.Contains(seccheck.FieldSyscallPath) { + p.FdPath = getFilePath(t, int32(p.Fd)) + } + + p.Exit = newExitMaybe(info) + + return p +} + +// PointCreat converts creat(2) syscall to proto. +func PointCreat(t *kernel.Task, fields seccheck.FieldSet, cxtData *pb.ContextData, info kernel.SyscallInfo) proto.Message { + p := &pb.Open{ + ContextData: cxtData, + Sysno: uint64(info.Sysno), + Fd: linux.AT_FDCWD, + Flags: linux.O_WRONLY | linux.O_CREAT | linux.O_TRUNC, + Mode: uint32(info.Args[1].ModeT()), + } + + addr := info.Args[0].Pointer() + if addr > 0 { + path, err := t.CopyInString(addr, linux.PATH_MAX) + if err == nil { + p.Pathname = path + } + } + + if fields.Local.Contains(seccheck.FieldSyscallPath) { + p.FdPath = getFilePath(t, int32(p.Fd)) + } + + p.Exit = newExitMaybe(info) + + return p +} + +// PointClose converts close(2) syscall to proto. +func PointClose(t *kernel.Task, fields seccheck.FieldSet, cxtData *pb.ContextData, info kernel.SyscallInfo) proto.Message { + p := &pb.Close{ + ContextData: cxtData, + Sysno: uint64(info.Sysno), + Fd: int64(info.Args[0].Int()), + } + + if fields.Local.Contains(seccheck.FieldSyscallPath) { + p.FdPath = getFilePath(t, int32(p.Fd)) + } + + p.Exit = newExitMaybe(info) + return p +} + +// PointRead converts read(2) syscall to proto. +func PointRead(t *kernel.Task, fields seccheck.FieldSet, cxtData *pb.ContextData, info kernel.SyscallInfo) proto.Message { + p := &pb.Read{ + ContextData: cxtData, + Sysno: uint64(info.Sysno), + Fd: int64(info.Args[0].Int()), + Count: uint64(info.Args[2].SizeT()), + } + if fields.Local.Contains(seccheck.FieldSyscallPath) { + p.FdPath = getFilePath(t, int32(p.Fd)) + } + + p.Exit = newExitMaybe(info) + + return p +} + +// PointSocket converts socket(2) syscall to proto. +func PointSocket(_ *kernel.Task, _ seccheck.FieldSet, cxtData *pb.ContextData, info kernel.SyscallInfo) proto.Message { + p := &pb.Socket{ + ContextData: cxtData, + Sysno: uint64(info.Sysno), + Domain: info.Args[0].Int(), + Type: info.Args[1].Int(), + Protocol: info.Args[2].Int(), + } + + p.Exit = newExitMaybe(info) + + return p +} + +// PointConnect converts connect(2) syscall to proto. +func PointConnect(t *kernel.Task, fields seccheck.FieldSet, cxtData *pb.ContextData, info kernel.SyscallInfo) proto.Message { + p := &pb.Connect{ + ContextData: cxtData, + Sysno: uint64(info.Sysno), + Fd: int64(info.Args[0].Int()), + } + + addr := info.Args[1].Pointer() + addrlen := info.Args[2].Uint() + if addr > 0 { + p.Address = make([]byte, addrlen) + _, _ = t.CopyInBytes(addr, p.Address) + } + + if fields.Local.Contains(seccheck.FieldSyscallPath) { + p.FdPath = getFilePath(t, int32(p.Fd)) + } + + p.Exit = newExitMaybe(info) + + return p +} + +// PointExecve converts execve(2) syscall to proto. +func PointExecve(t *kernel.Task, fields seccheck.FieldSet, cxtData *pb.ContextData, info kernel.SyscallInfo) proto.Message { + p := &pb.Execve{ + ContextData: cxtData, + Sysno: uint64(info.Sysno), + } + if pathname, err := t.CopyInString(info.Args[0].Pointer(), linux.PATH_MAX); err == nil { + p.Pathname = pathname + } + if argvAddr := info.Args[1].Pointer(); argvAddr != 0 { + if argv, err := t.CopyInVector(argvAddr, ExecMaxElemSize, ExecMaxTotalSize); err == nil { + p.Argv = argv + } + } + + if fields.Local.Contains(seccheck.FieldSyscallExecveEnvv) { + if envvAddr := info.Args[2].Pointer(); envvAddr != 0 { + if envv, err := t.CopyInVector(envvAddr, ExecMaxElemSize, ExecMaxTotalSize); err == nil { + p.Envv = envv + } + } + } + + p.Exit = newExitMaybe(info) + + return p +} + +// PointExecveat converts execveat(2) syscall to proto. +func PointExecveat(t *kernel.Task, fields seccheck.FieldSet, cxtData *pb.ContextData, info kernel.SyscallInfo) proto.Message { + p := &pb.Execve{ + ContextData: cxtData, + Sysno: uint64(info.Sysno), + Fd: int64(info.Args[0].Int()), + Flags: info.Args[4].Uint(), + } + if pathname, err := t.CopyInString(info.Args[1].Pointer(), linux.PATH_MAX); err == nil { + p.Pathname = pathname + } + if argvAddr := info.Args[2].Pointer(); argvAddr != 0 { + if argv, err := t.CopyInVector(argvAddr, ExecMaxElemSize, ExecMaxTotalSize); err == nil { + p.Argv = argv + } + } + + if fields.Local.Contains(seccheck.FieldSyscallExecveEnvv) { + if envvAddr := info.Args[3].Pointer(); envvAddr != 0 { + if envv, err := t.CopyInVector(envvAddr, ExecMaxElemSize, ExecMaxTotalSize); err == nil { + p.Envv = envv + } + } + } + if fields.Local.Contains(seccheck.FieldSyscallPath) { + p.FdPath = getFilePath(t, int32(p.Fd)) + } + + p.Exit = newExitMaybe(info) + + return p +} diff --git a/pkg/sentry/syscalls/linux/vfs2/vfs2.go b/pkg/sentry/syscalls/linux/vfs2/vfs2.go index 8d20b7f64..9c22a0e7a 100644 --- a/pkg/sentry/syscalls/linux/vfs2/vfs2.go +++ b/pkg/sentry/syscalls/linux/vfs2/vfs2.go @@ -24,10 +24,10 @@ import ( func Override() { // Override AMD64. s := linux.AMD64 - s.Table[0] = syscalls.Supported("read", Read) + s.Table[0] = syscalls.SupportedPoint("read", Read, linux.PointRead) s.Table[1] = syscalls.Supported("write", Write) - s.Table[2] = syscalls.Supported("open", Open) - s.Table[3] = syscalls.Supported("close", Close) + s.Table[2] = syscalls.SupportedPoint("open", Open, linux.PointOpen) + s.Table[3] = syscalls.SupportedPoint("close", Close, linux.PointClose) s.Table[4] = syscalls.Supported("stat", Stat) s.Table[5] = syscalls.Supported("fstat", Fstat) s.Table[6] = syscalls.Supported("lstat", Lstat) @@ -45,8 +45,8 @@ func Override() { s.Table[32] = syscalls.Supported("dup", Dup) s.Table[33] = syscalls.Supported("dup2", Dup2) s.Table[40] = syscalls.Supported("sendfile", Sendfile) - s.Table[41] = syscalls.Supported("socket", Socket) - s.Table[42] = syscalls.Supported("connect", Connect) + s.Table[41] = syscalls.SupportedPoint("socket", Socket, linux.PointSocket) + s.Table[42] = syscalls.SupportedPoint("connect", Connect, linux.PointConnect) s.Table[43] = syscalls.Supported("accept", Accept) s.Table[44] = syscalls.Supported("sendto", SendTo) s.Table[45] = syscalls.Supported("recvfrom", RecvFrom) @@ -60,7 +60,7 @@ func Override() { s.Table[53] = syscalls.Supported("socketpair", SocketPair) s.Table[54] = syscalls.Supported("setsockopt", SetSockOpt) s.Table[55] = syscalls.Supported("getsockopt", GetSockOpt) - s.Table[59] = syscalls.Supported("execve", Execve) + s.Table[59] = syscalls.SupportedPoint("execve", Execve, linux.PointExecve) s.Table[72] = syscalls.Supported("fcntl", Fcntl) s.Table[73] = syscalls.Supported("flock", Flock) s.Table[74] = syscalls.Supported("fsync", Fsync) @@ -74,7 +74,7 @@ func Override() { s.Table[82] = syscalls.Supported("rename", Rename) s.Table[83] = syscalls.Supported("mkdir", Mkdir) s.Table[84] = syscalls.Supported("rmdir", Rmdir) - s.Table[85] = syscalls.Supported("creat", Creat) + s.Table[85] = syscalls.SupportedPoint("creat", Creat, linux.PointCreat) s.Table[86] = syscalls.Supported("link", Link) s.Table[87] = syscalls.Supported("unlink", Unlink) s.Table[88] = syscalls.Supported("symlink", Symlink) @@ -118,7 +118,7 @@ func Override() { s.Table[253] = syscalls.PartiallySupported("inotify_init", InotifyInit, "inotify events are only available inside the sandbox.", nil) s.Table[254] = syscalls.PartiallySupported("inotify_add_watch", InotifyAddWatch, "inotify events are only available inside the sandbox.", nil) s.Table[255] = syscalls.PartiallySupported("inotify_rm_watch", InotifyRmWatch, "inotify events are only available inside the sandbox.", nil) - s.Table[257] = syscalls.Supported("openat", Openat) + s.Table[257] = syscalls.SupportedPoint("openat", Openat, linux.PointOpenat) s.Table[258] = syscalls.Supported("mkdirat", Mkdirat) s.Table[259] = syscalls.Supported("mknodat", Mknodat) s.Table[260] = syscalls.Supported("fchownat", Fchownat) @@ -158,7 +158,7 @@ func Override() { s.Table[307] = syscalls.Supported("sendmmsg", SendMMsg) s.Table[316] = syscalls.Supported("renameat2", Renameat2) s.Table[319] = syscalls.Supported("memfd_create", MemfdCreate) - s.Table[322] = syscalls.Supported("execveat", Execveat) + s.Table[322] = syscalls.SupportedPoint("execveat", Execveat, linux.PointExecveat) s.Table[327] = syscalls.Supported("preadv2", Preadv2) s.Table[328] = syscalls.Supported("pwritev2", Pwritev2) s.Table[332] = syscalls.Supported("statx", Statx) @@ -217,12 +217,12 @@ func Override() { s.Table[53] = syscalls.Supported("fchmodat", Fchmodat) s.Table[54] = syscalls.Supported("fchownat", Fchownat) s.Table[55] = syscalls.Supported("fchown", Fchown) - s.Table[56] = syscalls.Supported("openat", Openat) - s.Table[57] = syscalls.Supported("close", Close) + s.Table[56] = syscalls.SupportedPoint("openat", Openat, linux.PointOpenat) + s.Table[57] = syscalls.SupportedPoint("close", Close, linux.PointClose) s.Table[59] = syscalls.Supported("pipe2", Pipe2) s.Table[61] = syscalls.Supported("getdents64", Getdents64) s.Table[62] = syscalls.Supported("lseek", Lseek) - s.Table[63] = syscalls.Supported("read", Read) + s.Table[63] = syscalls.SupportedPoint("read", Read, linux.PointRead) s.Table[64] = syscalls.Supported("write", Write) s.Table[65] = syscalls.Supported("readv", Readv) s.Table[66] = syscalls.Supported("writev", Writev) @@ -249,12 +249,12 @@ func Override() { s.Table[88] = syscalls.Supported("utimensat", Utimensat) s.Table[180] = syscalls.Supported("mq_open", MqOpen) s.Table[181] = syscalls.Supported("mq_unlink", MqUnlink) - s.Table[198] = syscalls.Supported("socket", Socket) + s.Table[198] = syscalls.SupportedPoint("socket", Socket, linux.PointSocket) s.Table[199] = syscalls.Supported("socketpair", SocketPair) s.Table[200] = syscalls.Supported("bind", Bind) s.Table[201] = syscalls.Supported("listen", Listen) s.Table[202] = syscalls.Supported("accept", Accept) - s.Table[203] = syscalls.Supported("connect", Connect) + s.Table[203] = syscalls.SupportedPoint("connect", Connect, linux.PointConnect) s.Table[204] = syscalls.Supported("getsockname", GetSockName) s.Table[205] = syscalls.Supported("getpeername", GetPeerName) s.Table[206] = syscalls.Supported("sendto", SendTo) @@ -265,7 +265,7 @@ func Override() { s.Table[211] = syscalls.Supported("sendmsg", SendMsg) s.Table[212] = syscalls.Supported("recvmsg", RecvMsg) s.Table[213] = syscalls.Supported("readahead", Readahead) - s.Table[221] = syscalls.Supported("execve", Execve) + s.Table[221] = syscalls.SupportedPoint("execve", Execve, linux.PointExecve) s.Table[222] = syscalls.Supported("mmap", Mmap) s.Table[223] = syscalls.PartiallySupported("fadvise64", Fadvise64, "Not all options are supported.", nil) s.Table[242] = syscalls.Supported("accept4", Accept4) @@ -274,7 +274,7 @@ func Override() { s.Table[269] = syscalls.Supported("sendmmsg", SendMMsg) s.Table[276] = syscalls.Supported("renameat2", Renameat2) s.Table[279] = syscalls.Supported("memfd_create", MemfdCreate) - s.Table[281] = syscalls.Supported("execveat", Execveat) + s.Table[281] = syscalls.SupportedPoint("execveat", Execveat, linux.PointExecveat) s.Table[286] = syscalls.Supported("preadv2", Preadv2) s.Table[287] = syscalls.Supported("pwritev2", Pwritev2) s.Table[291] = syscalls.Supported("statx", Statx) diff --git a/pkg/sentry/syscalls/syscalls.go b/pkg/sentry/syscalls/syscalls.go index cfcc21271..cd60f7eed 100644 --- a/pkg/sentry/syscalls/syscalls.go +++ b/pkg/sentry/syscalls/syscalls.go @@ -43,6 +43,14 @@ func Supported(name string, fn kernel.SyscallFn) kernel.Syscall { } } +// SupportedPoint returns a syscall that is fully supported with a correspoding +// seccheck.Point. +func SupportedPoint(name string, fn kernel.SyscallFn, cb kernel.SyscallToProto) kernel.Syscall { + sys := Supported(name, fn) + sys.PointCallback = cb + return sys +} + // PartiallySupported returns a syscall that has a partial implementation. func PartiallySupported(name string, fn kernel.SyscallFn, note string, urls []string) kernel.Syscall { return kernel.Syscall{ @@ -54,6 +62,14 @@ func PartiallySupported(name string, fn kernel.SyscallFn, note string, urls []st } } +// PartiallySupportedPoint returns a syscall that has a partial implementation +// with a correspoding seccheck.Point. +func PartiallySupportedPoint(name string, fn kernel.SyscallFn, cb kernel.SyscallToProto, note string, urls []string) kernel.Syscall { + sys := PartiallySupported(name, fn, note, urls) + sys.PointCallback = cb + return sys +} + // Error returns a syscall handler that will always give the passed error. func Error(name string, err error, note string, urls []string) kernel.Syscall { if note != "" { diff --git a/runsc/boot/loader.go b/runsc/boot/loader.go index 9f9160ab0..12bf778e4 100644 --- a/runsc/boot/loader.go +++ b/runsc/boot/loader.go @@ -656,7 +656,7 @@ func (l *Loader) run() error { Terminal: l.root.spec.Process.Terminal, } fields := seccheck.Global.GetFieldSet(seccheck.PointContainerStart) - if fields.Local.Contains(seccheck.ContainerStartFieldEnv) { + if fields.Local.Contains(seccheck.FieldContainerStartEnv) { evt.Env = l.root.spec.Process.Env } if !fields.Context.Empty() { @@ -804,7 +804,7 @@ func (l *Loader) startSubcontainer(spec *specs.Spec, conf *config.Config, cid st Terminal: spec.Process.Terminal, } fields := seccheck.Global.GetFieldSet(seccheck.PointContainerStart) - if fields.Local.Contains(seccheck.ContainerStartFieldEnv) { + if fields.Local.Contains(seccheck.FieldContainerStartEnv) { evt.Env = spec.Process.Env } if !fields.Context.Empty() {