aboutsummaryrefslogtreecommitdiffhomepage
path: root/container/seccomp
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2025-07-03 02:59:43 +0900
committerOphestra <cat@gensokyo.uk>2025-07-03 02:59:43 +0900
commit1b5ecd9eaf3289d164d8ed1bce6013e0e4ef8e86 (patch)
tree047fe5fabdfb37d5c0088f7f572cebc8b13853bb /container/seccomp
parent82561d62b66f17c05604e87f18187bb3a91f00d2 (diff)
container: move out of toplevel
This allows slightly easier use of the vanity url. This also provides some disambiguation between low level containers and hakurei app containers. Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'container/seccomp')
-rw-r--r--container/seccomp/libseccomp-helper.c130
-rw-r--r--container/seccomp/libseccomp-helper.h24
-rw-r--r--container/seccomp/libseccomp.go188
-rw-r--r--container/seccomp/libseccomp_test.go147
-rwxr-xr-xcontainer/seccomp/mksysnum_linux.pl83
-rw-r--r--container/seccomp/presets.go229
-rw-r--r--container/seccomp/presets_clone_backwards2.go7
-rw-r--r--container/seccomp/presets_clone_generic.go6
-rw-r--r--container/seccomp/proc.go78
-rw-r--r--container/seccomp/seccomp.go60
-rw-r--r--container/seccomp/seccomp_test.go65
-rw-r--r--container/seccomp/syscall.go28
-rw-r--r--container/seccomp/syscall_extra_linux_amd64.go54
-rw-r--r--container/seccomp/syscall_linux_amd64.go459
-rw-r--r--container/seccomp/syscall_test.go20
15 files changed, 1578 insertions, 0 deletions
diff --git a/container/seccomp/libseccomp-helper.c b/container/seccomp/libseccomp-helper.c
new file mode 100644
index 00000000..b09c3eb2
--- /dev/null
+++ b/container/seccomp/libseccomp-helper.c
@@ -0,0 +1,130 @@
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE /* CLONE_NEWUSER */
+#endif
+
+#include "libseccomp-helper.h"
+#include <assert.h>
+#include <errno.h>
+#include <sys/socket.h>
+
+#define LEN(arr) (sizeof(arr) / sizeof((arr)[0]))
+
+int32_t hakurei_export_filter(int *ret_p, int fd, uint32_t arch,
+ uint32_t multiarch,
+ struct hakurei_syscall_rule *rules,
+ size_t rules_sz, hakurei_export_flag flags) {
+ int i;
+ int last_allowed_family;
+ int disallowed;
+ struct hakurei_syscall_rule *rule;
+
+ int32_t res = 0; /* refer to resPrefix for message */
+
+ /* Blocklist all but unix, inet, inet6 and netlink */
+ struct {
+ int family;
+ hakurei_export_flag flags_mask;
+ } socket_family_allowlist[] = {
+ /* NOTE: Keep in numerical order */
+ {AF_UNSPEC, 0},
+ {AF_LOCAL, 0},
+ {AF_INET, 0},
+ {AF_INET6, 0},
+ {AF_NETLINK, 0},
+ {AF_CAN, HAKUREI_EXPORT_CAN},
+ {AF_BLUETOOTH, HAKUREI_EXPORT_BLUETOOTH},
+ };
+
+ scmp_filter_ctx ctx = seccomp_init(SCMP_ACT_ALLOW);
+ if (ctx == NULL) {
+ res = 1;
+ goto out;
+ } else
+ errno = 0;
+
+ /* We only really need to handle arches on multiarch systems.
+ * If only one arch is supported the default is fine */
+ if (arch != 0) {
+ /* This *adds* the target arch, instead of replacing the
+ * native one. This is not ideal, because we'd like to only
+ * allow the target arch, but we can't really disallow the
+ * native arch at this point, because then bubblewrap
+ * couldn't continue running. */
+ *ret_p = seccomp_arch_add(ctx, arch);
+ if (*ret_p < 0 && *ret_p != -EEXIST) {
+ res = 2;
+ goto out;
+ }
+
+ if (flags & HAKUREI_EXPORT_MULTIARCH && multiarch != 0) {
+ *ret_p = seccomp_arch_add(ctx, multiarch);
+ if (*ret_p < 0 && *ret_p != -EEXIST) {
+ res = 3;
+ goto out;
+ }
+ }
+ }
+
+ for (i = 0; i < rules_sz; i++) {
+ rule = &rules[i];
+ assert(rule->m_errno == EPERM || rule->m_errno == ENOSYS);
+
+ if (rule->arg)
+ *ret_p = seccomp_rule_add(ctx, SCMP_ACT_ERRNO(rule->m_errno),
+ rule->syscall, 1, *rule->arg);
+ else
+ *ret_p = seccomp_rule_add(ctx, SCMP_ACT_ERRNO(rule->m_errno),
+ rule->syscall, 0);
+
+ if (*ret_p == -EFAULT) {
+ res = 4;
+ goto out;
+ } else if (*ret_p < 0) {
+ res = 5;
+ goto out;
+ }
+ }
+
+ /* Socket filtering doesn't work on e.g. i386, so ignore failures here
+ * However, we need to user seccomp_rule_add_exact to avoid libseccomp doing
+ * something else: https://github.com/seccomp/libseccomp/issues/8 */
+ last_allowed_family = -1;
+ for (i = 0; i < LEN(socket_family_allowlist); i++) {
+ if (socket_family_allowlist[i].flags_mask != 0 &&
+ (socket_family_allowlist[i].flags_mask & flags) !=
+ socket_family_allowlist[i].flags_mask)
+ continue;
+
+ for (disallowed = last_allowed_family + 1;
+ disallowed < socket_family_allowlist[i].family; disallowed++) {
+ /* Blocklist the in-between valid families */
+ seccomp_rule_add_exact(ctx, SCMP_ACT_ERRNO(EAFNOSUPPORT),
+ SCMP_SYS(socket), 1,
+ SCMP_A0(SCMP_CMP_EQ, disallowed));
+ }
+ last_allowed_family = socket_family_allowlist[i].family;
+ }
+ /* Blocklist the rest */
+ seccomp_rule_add_exact(ctx, SCMP_ACT_ERRNO(EAFNOSUPPORT), SCMP_SYS(socket), 1,
+ SCMP_A0(SCMP_CMP_GE, last_allowed_family + 1));
+
+ if (fd < 0) {
+ *ret_p = seccomp_load(ctx);
+ if (*ret_p != 0) {
+ res = 7;
+ goto out;
+ }
+ } else {
+ *ret_p = seccomp_export_bpf(ctx, fd);
+ if (*ret_p != 0) {
+ res = 6;
+ goto out;
+ }
+ }
+
+out:
+ if (ctx)
+ seccomp_release(ctx);
+
+ return res;
+}
diff --git a/container/seccomp/libseccomp-helper.h b/container/seccomp/libseccomp-helper.h
new file mode 100644
index 00000000..330fc99b
--- /dev/null
+++ b/container/seccomp/libseccomp-helper.h
@@ -0,0 +1,24 @@
+#include <seccomp.h>
+#include <stdint.h>
+
+#if (SCMP_VER_MAJOR < 2) || (SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR < 5) || \
+ (SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR == 5 && SCMP_VER_MICRO < 1)
+#error This package requires libseccomp >= v2.5.1
+#endif
+
+typedef enum {
+ HAKUREI_EXPORT_MULTIARCH = 1 << 0,
+ HAKUREI_EXPORT_CAN = 1 << 1,
+ HAKUREI_EXPORT_BLUETOOTH = 1 << 2,
+} hakurei_export_flag;
+
+struct hakurei_syscall_rule {
+ int syscall;
+ int m_errno;
+ struct scmp_arg_cmp *arg;
+};
+
+int32_t hakurei_export_filter(int *ret_p, int fd, uint32_t arch,
+ uint32_t multiarch,
+ struct hakurei_syscall_rule *rules,
+ size_t rules_sz, hakurei_export_flag flags); \ No newline at end of file
diff --git a/container/seccomp/libseccomp.go b/container/seccomp/libseccomp.go
new file mode 100644
index 00000000..a43b8f23
--- /dev/null
+++ b/container/seccomp/libseccomp.go
@@ -0,0 +1,188 @@
+package seccomp
+
+/*
+#cgo linux pkg-config: --static libseccomp
+
+#include <libseccomp-helper.h>
+*/
+import "C"
+import (
+ "errors"
+ "fmt"
+ "runtime"
+ "syscall"
+ "unsafe"
+)
+
+var (
+ ErrInvalidRules = errors.New("invalid native rules slice")
+)
+
+// LibraryError represents a libseccomp error.
+type LibraryError struct {
+ Prefix string
+ Seccomp syscall.Errno
+ Errno error
+}
+
+func (e *LibraryError) Error() string {
+ if e.Seccomp == 0 {
+ if e.Errno == nil {
+ panic("invalid libseccomp error")
+ }
+ return fmt.Sprintf("%s: %s", e.Prefix, e.Errno)
+ }
+ if e.Errno == nil {
+ return fmt.Sprintf("%s: %s", e.Prefix, e.Seccomp)
+ }
+ return fmt.Sprintf("%s: %s (%s)", e.Prefix, e.Seccomp, e.Errno)
+}
+
+func (e *LibraryError) Is(err error) bool {
+ if e == nil {
+ return err == nil
+ }
+ if ef, ok := err.(*LibraryError); ok {
+ return *e == *ef
+ }
+ return (e.Seccomp != 0 && errors.Is(err, e.Seccomp)) ||
+ (e.Errno != nil && errors.Is(err, e.Errno))
+}
+
+type (
+ ScmpSyscall = C.int
+ ScmpErrno = C.int
+)
+
+// A NativeRule specifies an arch-specific action taken by seccomp under certain conditions.
+type NativeRule struct {
+ // Syscall is the arch-dependent syscall number to act against.
+ Syscall ScmpSyscall
+ // Errno is the errno value to return when the condition is satisfied.
+ Errno ScmpErrno
+ // Arg is the optional struct scmp_arg_cmp passed to libseccomp.
+ Arg *ScmpArgCmp
+}
+
+type ExportFlag = C.hakurei_export_flag
+
+const (
+ // AllowMultiarch allows multiarch/emulation.
+ AllowMultiarch ExportFlag = C.HAKUREI_EXPORT_MULTIARCH
+ // AllowCAN allows AF_CAN.
+ AllowCAN ExportFlag = C.HAKUREI_EXPORT_CAN
+ // AllowBluetooth allows AF_BLUETOOTH.
+ AllowBluetooth ExportFlag = C.HAKUREI_EXPORT_BLUETOOTH
+)
+
+var resPrefix = [...]string{
+ 0: "",
+ 1: "seccomp_init failed",
+ 2: "seccomp_arch_add failed",
+ 3: "seccomp_arch_add failed (multiarch)",
+ 4: "internal libseccomp failure",
+ 5: "seccomp_rule_add failed",
+ 6: "seccomp_export_bpf failed",
+ 7: "seccomp_load failed",
+}
+
+// Export streams filter contents to fd, or installs it to the current process if fd < 0.
+func Export(fd int, rules []NativeRule, flags ExportFlag) error {
+ if len(rules) == 0 {
+ return ErrInvalidRules
+ }
+
+ var (
+ arch C.uint32_t = 0
+ multiarch C.uint32_t = 0
+ )
+ switch runtime.GOARCH {
+ case "386":
+ arch = C.SCMP_ARCH_X86
+ case "amd64":
+ arch = C.SCMP_ARCH_X86_64
+ multiarch = C.SCMP_ARCH_X86
+ case "arm":
+ arch = C.SCMP_ARCH_ARM
+ case "arm64":
+ arch = C.SCMP_ARCH_AARCH64
+ multiarch = C.SCMP_ARCH_ARM
+ }
+
+ var ret C.int
+
+ rulesPinner := new(runtime.Pinner)
+ for i := range rules {
+ rule := &rules[i]
+ rulesPinner.Pin(rule)
+ if rule.Arg != nil {
+ rulesPinner.Pin(rule.Arg)
+ }
+ }
+ res, err := C.hakurei_export_filter(
+ &ret, C.int(fd),
+ arch, multiarch,
+ (*C.struct_hakurei_syscall_rule)(unsafe.Pointer(&rules[0])),
+ C.size_t(len(rules)),
+ flags,
+ )
+ rulesPinner.Unpin()
+
+ if prefix := resPrefix[res]; prefix != "" {
+ return &LibraryError{
+ prefix,
+ -syscall.Errno(ret),
+ err,
+ }
+ }
+ return err
+}
+
+// ScmpCompare is the equivalent of scmp_compare;
+// Comparison operators
+type ScmpCompare = C.enum_scmp_compare
+
+const (
+ _SCMP_CMP_MIN = C._SCMP_CMP_MIN
+
+ // not equal
+ SCMP_CMP_NE = C.SCMP_CMP_NE
+ // less than
+ SCMP_CMP_LT = C.SCMP_CMP_LT
+ // less than or equal
+ SCMP_CMP_LE = C.SCMP_CMP_LE
+ // equal
+ SCMP_CMP_EQ = C.SCMP_CMP_EQ
+ // greater than or equal
+ SCMP_CMP_GE = C.SCMP_CMP_GE
+ // greater than
+ SCMP_CMP_GT = C.SCMP_CMP_GT
+ // masked equality
+ SCMP_CMP_MASKED_EQ = C.SCMP_CMP_MASKED_EQ
+
+ _SCMP_CMP_MAX = C._SCMP_CMP_MAX
+)
+
+// ScmpDatum is the equivalent of scmp_datum_t;
+// Argument datum
+type ScmpDatum uint64
+
+// ScmpArgCmp is the equivalent of struct scmp_arg_cmp;
+// Argument / Value comparison definition
+type ScmpArgCmp struct {
+ // argument number, starting at 0
+ Arg C.uint
+ // the comparison op, e.g. SCMP_CMP_*
+ Op ScmpCompare
+
+ DatumA, DatumB ScmpDatum
+}
+
+// only used for testing
+func syscallResolveName(s string) (trap int) {
+ v := C.CString(s)
+ trap = int(C.seccomp_syscall_resolve_name(v))
+ C.free(unsafe.Pointer(v))
+
+ return
+}
diff --git a/container/seccomp/libseccomp_test.go b/container/seccomp/libseccomp_test.go
new file mode 100644
index 00000000..a8bfcbf2
--- /dev/null
+++ b/container/seccomp/libseccomp_test.go
@@ -0,0 +1,147 @@
+package seccomp_test
+
+import (
+ "crypto/sha512"
+ "errors"
+ "io"
+ "slices"
+ "syscall"
+ "testing"
+
+ . "git.gensokyo.uk/security/hakurei/container/seccomp"
+)
+
+func TestExport(t *testing.T) {
+ testCases := []struct {
+ name string
+ presets FilterPreset
+ flags ExportFlag
+ want []byte
+ wantErr bool
+ }{
+ {"compat", 0, 0, []byte{
+ 0x95, 0xec, 0x69, 0xd0, 0x17, 0x73, 0x3e, 0x07,
+ 0x21, 0x60, 0xe0, 0xda, 0x80, 0xfd, 0xeb, 0xec,
+ 0xdf, 0x27, 0xae, 0x81, 0x66, 0xf5, 0xe2, 0xa7,
+ 0x31, 0x27, 0x0c, 0x98, 0xea, 0x2d, 0x29, 0x46,
+ 0xcb, 0x52, 0x31, 0x02, 0x90, 0x63, 0x66, 0x8a,
+ 0xf2, 0x15, 0x87, 0x91, 0x55, 0xda, 0x21, 0xac,
+ 0xa7, 0x9b, 0x07, 0x0e, 0x04, 0xc0, 0xee, 0x9a,
+ 0xcd, 0xf5, 0x8f, 0x55, 0xcf, 0xa8, 0x15, 0xa5,
+ }, false},
+ {"base", PresetExt, 0, []byte{
+ 0xdc, 0x7f, 0x2e, 0x1c, 0x5e, 0x82, 0x9b, 0x79,
+ 0xeb, 0xb7, 0xef, 0xc7, 0x59, 0x15, 0x0f, 0x54,
+ 0xa8, 0x3a, 0x75, 0xc8, 0xdf, 0x6f, 0xee, 0x4d,
+ 0xce, 0x5d, 0xad, 0xc4, 0x73, 0x6c, 0x58, 0x5d,
+ 0x4d, 0xee, 0xbf, 0xeb, 0x3c, 0x79, 0x69, 0xaf,
+ 0x3a, 0x07, 0x7e, 0x90, 0xb7, 0x7b, 0xb4, 0x74,
+ 0x1d, 0xb0, 0x5d, 0x90, 0x99, 0x7c, 0x86, 0x59,
+ 0xb9, 0x58, 0x91, 0x20, 0x6a, 0xc9, 0x95, 0x2d,
+ }, false},
+ {"everything", PresetExt |
+ PresetDenyNS | PresetDenyTTY | PresetDenyDevel |
+ PresetLinux32, AllowMultiarch | AllowCAN |
+ AllowBluetooth, []byte{
+ 0xe9, 0x9d, 0xd3, 0x45, 0xe1, 0x95, 0x41, 0x34,
+ 0x73, 0xd3, 0xcb, 0xee, 0x07, 0xb4, 0xed, 0x57,
+ 0xb9, 0x08, 0xbf, 0xa8, 0x9e, 0xa2, 0x07, 0x2f,
+ 0xe9, 0x34, 0x82, 0x84, 0x7f, 0x50, 0xb5, 0xb7,
+ 0x58, 0xda, 0x17, 0xe7, 0x4c, 0xa2, 0xbb, 0xc0,
+ 0x08, 0x13, 0xde, 0x49, 0xa2, 0xb9, 0xbf, 0x83,
+ 0x4c, 0x02, 0x4e, 0xd4, 0x88, 0x50, 0xbe, 0x69,
+ 0xb6, 0x8a, 0x9a, 0x4c, 0x5f, 0x53, 0xa9, 0xdb,
+ }, false},
+ {"strict", PresetStrict, 0, []byte{
+ 0xe8, 0x80, 0x29, 0x8d, 0xf2, 0xbd, 0x67, 0x51,
+ 0xd0, 0x04, 0x0f, 0xc2, 0x1b, 0xc0, 0xed, 0x4c,
+ 0x00, 0xf9, 0x5d, 0xc0, 0xd7, 0xba, 0x50, 0x6c,
+ 0x24, 0x4d, 0x8b, 0x8c, 0xf6, 0x86, 0x6d, 0xba,
+ 0x8e, 0xf4, 0xa3, 0x32, 0x96, 0xf2, 0x87, 0xb6,
+ 0x6c, 0xcc, 0xc1, 0xd7, 0x8e, 0x97, 0x02, 0x65,
+ 0x97, 0xf8, 0x4c, 0xc7, 0xde, 0xc1, 0x57, 0x3e,
+ 0x14, 0x89, 0x60, 0xfb, 0xd3, 0x5c, 0xd7, 0x35,
+ }, false},
+ {"strict compat", 0 |
+ PresetDenyNS | PresetDenyTTY | PresetDenyDevel, 0, []byte{
+ 0x39, 0x87, 0x1b, 0x93, 0xff, 0xaf, 0xc8, 0xb9,
+ 0x79, 0xfc, 0xed, 0xc0, 0xb0, 0xc3, 0x7b, 0x9e,
+ 0x03, 0x92, 0x2f, 0x5b, 0x02, 0x74, 0x8d, 0xc5,
+ 0xc3, 0xc1, 0x7c, 0x92, 0x52, 0x7f, 0x6e, 0x02,
+ 0x2e, 0xde, 0x1f, 0x48, 0xbf, 0xf5, 0x92, 0x46,
+ 0xea, 0x45, 0x2c, 0x0d, 0x1d, 0xe5, 0x48, 0x27,
+ 0x80, 0x8b, 0x1a, 0x6f, 0x84, 0xf3, 0x2b, 0xbd,
+ 0xe1, 0xaa, 0x02, 0xae, 0x30, 0xee, 0xdc, 0xfa,
+ }, false},
+ {"hakurei default", PresetExt | PresetDenyDevel, 0, []byte{
+ 0xc6, 0x98, 0xb0, 0x81, 0xff, 0x95, 0x7a, 0xfe,
+ 0x17, 0xa6, 0xd9, 0x43, 0x74, 0x53, 0x7d, 0x37,
+ 0xf2, 0xa6, 0x3f, 0x6f, 0x9d, 0xd7, 0x5d, 0xa7,
+ 0x54, 0x65, 0x42, 0x40, 0x7a, 0x9e, 0x32, 0x47,
+ 0x6e, 0xbd, 0xa3, 0x31, 0x2b, 0xa7, 0x78, 0x5d,
+ 0x7f, 0x61, 0x85, 0x42, 0xbc, 0xfa, 0xf2, 0x7c,
+ 0xa2, 0x7d, 0xcc, 0x2d, 0xdd, 0xba, 0x85, 0x20,
+ 0x69, 0xd2, 0x8b, 0xcf, 0xe8, 0xca, 0xd3, 0x9a,
+ }, false},
+ }
+
+ buf := make([]byte, 8)
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ e := New(Preset(tc.presets, tc.flags), tc.flags)
+ digest := sha512.New()
+
+ if _, err := io.CopyBuffer(digest, e, buf); (err != nil) != tc.wantErr {
+ t.Errorf("Exporter: error = %v, wantErr %v", err, tc.wantErr)
+ return
+ }
+ if err := e.Close(); err != nil {
+ t.Errorf("Close: error = %v", err)
+ }
+ if got := digest.Sum(nil); !slices.Equal(got, tc.want) {
+ t.Fatalf("Export() hash = %x, want %x",
+ got, tc.want)
+ return
+ }
+ })
+ }
+
+ t.Run("close without use", func(t *testing.T) {
+ e := New(Preset(0, 0), 0)
+ if err := e.Close(); !errors.Is(err, syscall.EINVAL) {
+ t.Errorf("Close: error = %v", err)
+ return
+ }
+ })
+
+ t.Run("close partial read", func(t *testing.T) {
+ e := New(Preset(0, 0), 0)
+ if _, err := e.Read(nil); err != nil {
+ t.Errorf("Read: error = %v", err)
+ return
+ }
+ // the underlying implementation uses buffered io, so the outcome of this is nondeterministic;
+ // that is not harmful however, so both outcomes are checked for here
+ if err := e.Close(); err != nil &&
+ (!errors.Is(err, syscall.ECANCELED) || !errors.Is(err, syscall.EBADF)) {
+ t.Errorf("Close: error = %v", err)
+ return
+ }
+ })
+}
+
+func BenchmarkExport(b *testing.B) {
+ buf := make([]byte, 8)
+ for i := 0; i < b.N; i++ {
+ e := New(
+ Preset(PresetExt|PresetDenyNS|PresetDenyTTY|PresetDenyDevel|PresetLinux32,
+ AllowMultiarch|AllowCAN|AllowBluetooth),
+ AllowMultiarch|AllowCAN|AllowBluetooth)
+ if _, err := io.CopyBuffer(io.Discard, e, buf); err != nil {
+ b.Fatalf("cannot export: %v", err)
+ }
+ if err := e.Close(); err != nil {
+ b.Fatalf("cannot close exporter: %v", err)
+ }
+ }
+}
diff --git a/container/seccomp/mksysnum_linux.pl b/container/seccomp/mksysnum_linux.pl
new file mode 100755
index 00000000..50b88b62
--- /dev/null
+++ b/container/seccomp/mksysnum_linux.pl
@@ -0,0 +1,83 @@
+#!/usr/bin/env perl
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+use strict;
+
+my $command = "mksysnum_linux.pl ". join(' ', @ARGV);
+
+print <<EOF;
+// $command
+// Code generated by the command above; DO NOT EDIT.
+
+package seccomp
+
+import . "syscall"
+
+var syscallNum = map[string]int{
+EOF
+
+my $offset = 0;
+my $state = -1;
+
+sub fmt {
+ my ($name, $num) = @_;
+ if($num > 999){
+ # ignore deprecated syscalls that are no longer implemented
+ # https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/include/uapi/asm-generic/unistd.h?id=refs/heads/master#n716
+ return;
+ }
+ (my $name_upper = $name) =~ y/a-z/A-Z/;
+ $num = $num + $offset;
+ if($num > 302){ # not wired in Go standard library
+ if($state < 0){
+ print " \"$name\": SYS_$name_upper,\n";
+ }
+ else{
+ print " SYS_$name_upper = $num;\n";
+ }
+ }
+ elsif($state < 0){
+ print " \"$name\": SYS_$name_upper,\n";
+ }
+ else{
+ return;
+ }
+}
+
+GENERATE:
+
+my $prev;
+open(GCC, "gcc -E -dD $ARGV[0] |") || die "can't run gcc";
+while(<GCC>){
+ if(/^#define __NR_Linux\s+([0-9]+)/){
+ # mips/mips64: extract offset
+ $offset = $1;
+ }
+ elsif(/^#define __NR_syscalls\s+/) {
+ # ignore redefinitions of __NR_syscalls
+ }
+ elsif(/^#define __NR_(\w+)\s+([0-9]+)/){
+ $prev = $2;
+ fmt($1, $2);
+ }
+ elsif(/^#define __NR3264_(\w+)\s+([0-9]+)/){
+ $prev = $2;
+ fmt($1, $2);
+ }
+ elsif(/^#define __NR_(\w+)\s+\(\w+\+\s*([0-9]+)\)/){
+ fmt($1, $prev+$2)
+ }
+ elsif(/^#define __NR_(\w+)\s+\(__NR_Linux \+ ([0-9]+)/){
+ fmt($1, $2);
+ }
+}
+
+if($state < 0){
+ $state = $state + 1;
+ print "}\n\nconst (\n";
+ goto GENERATE;
+}
+
+print ")";
diff --git a/container/seccomp/presets.go b/container/seccomp/presets.go
new file mode 100644
index 00000000..4a01d2b0
--- /dev/null
+++ b/container/seccomp/presets.go
@@ -0,0 +1,229 @@
+package seccomp
+
+/* flatpak commit 4c3bf179e2e4a2a298cd1db1d045adaf3f564532 */
+
+import (
+ . "syscall"
+)
+
+type FilterPreset int
+
+const (
+ // PresetExt are project-specific extensions.
+ PresetExt FilterPreset = 1 << iota
+ // PresetDenyNS denies namespace setup syscalls.
+ PresetDenyNS
+ // PresetDenyTTY denies faking input.
+ PresetDenyTTY
+ // PresetDenyDevel denies development-related syscalls.
+ PresetDenyDevel
+ // PresetLinux32 sets PER_LINUX32.
+ PresetLinux32
+)
+
+func Preset(presets FilterPreset, flags ExportFlag) (rules []NativeRule) {
+ allowedPersonality := PER_LINUX
+ if presets&PresetLinux32 != 0 {
+ allowedPersonality = PER_LINUX32
+ }
+ presetDevelFinal := presetDevel(ScmpDatum(allowedPersonality))
+
+ l := len(presetCommon)
+ if presets&PresetDenyNS != 0 {
+ l += len(presetNamespace)
+ }
+ if presets&PresetDenyTTY != 0 {
+ l += len(presetTTY)
+ }
+ if presets&PresetDenyDevel != 0 {
+ l += len(presetDevelFinal)
+ }
+ if flags&AllowMultiarch == 0 {
+ l += len(presetEmu)
+ }
+ if presets&PresetExt != 0 {
+ l += len(presetCommonExt)
+ if presets&PresetDenyNS != 0 {
+ l += len(presetNamespaceExt)
+ }
+ if flags&AllowMultiarch == 0 {
+ l += len(presetEmuExt)
+ }
+ }
+
+ rules = make([]NativeRule, 0, l)
+ rules = append(rules, presetCommon...)
+ if presets&PresetDenyNS != 0 {
+ rules = append(rules, presetNamespace...)
+ }
+ if presets&PresetDenyTTY != 0 {
+ rules = append(rules, presetTTY...)
+ }
+ if presets&PresetDenyDevel != 0 {
+ rules = append(rules, presetDevelFinal...)
+ }
+ if flags&AllowMultiarch == 0 {
+ rules = append(rules, presetEmu...)
+ }
+ if presets&PresetExt != 0 {
+ rules = append(rules, presetCommonExt...)
+ if presets&PresetDenyNS != 0 {
+ rules = append(rules, presetNamespaceExt...)
+ }
+ if flags&AllowMultiarch == 0 {
+ rules = append(rules, presetEmuExt...)
+ }
+ }
+
+ return
+}
+
+var (
+ presetCommon = []NativeRule{
+ /* Block dmesg */
+ {ScmpSyscall(SYS_SYSLOG), ScmpErrno(EPERM), nil},
+ /* Useless old syscall */
+ {ScmpSyscall(SYS_USELIB), ScmpErrno(EPERM), nil},
+ /* Don't allow disabling accounting */
+ {ScmpSyscall(SYS_ACCT), ScmpErrno(EPERM), nil},
+ /* Don't allow reading current quota use */
+ {ScmpSyscall(SYS_QUOTACTL), ScmpErrno(EPERM), nil},
+
+ /* Don't allow access to the kernel keyring */
+ {ScmpSyscall(SYS_ADD_KEY), ScmpErrno(EPERM), nil},
+ {ScmpSyscall(SYS_KEYCTL), ScmpErrno(EPERM), nil},
+ {ScmpSyscall(SYS_REQUEST_KEY), ScmpErrno(EPERM), nil},
+
+ /* Scary VM/NUMA ops */
+ {ScmpSyscall(SYS_MOVE_PAGES), ScmpErrno(EPERM), nil},
+ {ScmpSyscall(SYS_MBIND), ScmpErrno(EPERM), nil},
+ {ScmpSyscall(SYS_GET_MEMPOLICY), ScmpErrno(EPERM), nil},
+ {ScmpSyscall(SYS_SET_MEMPOLICY), ScmpErrno(EPERM), nil},
+ {ScmpSyscall(SYS_MIGRATE_PAGES), ScmpErrno(EPERM), nil},
+ }
+
+ /* hakurei: project-specific extensions */
+ presetCommonExt = []NativeRule{
+ /* system calls for changing the system clock */
+ {ScmpSyscall(SYS_ADJTIMEX), ScmpErrno(EPERM), nil},
+ {ScmpSyscall(SYS_CLOCK_ADJTIME), ScmpErrno(EPERM), nil},
+ {ScmpSyscall(SYS_CLOCK_ADJTIME64), ScmpErrno(EPERM), nil},
+ {ScmpSyscall(SYS_CLOCK_SETTIME), ScmpErrno(EPERM), nil},
+ {ScmpSyscall(SYS_CLOCK_SETTIME64), ScmpErrno(EPERM), nil},
+ {ScmpSyscall(SYS_SETTIMEOFDAY), ScmpErrno(EPERM), nil},
+
+ /* loading and unloading of kernel modules */
+ {ScmpSyscall(SYS_DELETE_MODULE), ScmpErrno(EPERM), nil},
+ {ScmpSyscall(SYS_FINIT_MODULE), ScmpErrno(EPERM), nil},
+ {ScmpSyscall(SYS_INIT_MODULE), ScmpErrno(EPERM), nil},
+
+ /* system calls for rebooting and reboot preparation */
+ {ScmpSyscall(SYS_KEXEC_FILE_LOAD), ScmpErrno(EPERM), nil},
+ {ScmpSyscall(SYS_KEXEC_LOAD), ScmpErrno(EPERM), nil},
+ {ScmpSyscall(SYS_REBOOT), ScmpErrno(EPERM), nil},
+
+ /* system calls for enabling/disabling swap devices */
+ {ScmpSyscall(SYS_SWAPOFF), ScmpErrno(EPERM), nil},
+ {ScmpSyscall(SYS_SWAPON), ScmpErrno(EPERM), nil},
+ }
+
+ presetNamespace = []NativeRule{
+ /* Don't allow subnamespace setups: */
+ {ScmpSyscall(SYS_UNSHARE), ScmpErrno(EPERM), nil},
+ {ScmpSyscall(SYS_SETNS), ScmpErrno(EPERM), nil},
+ {ScmpSyscall(SYS_MOUNT), ScmpErrno(EPERM), nil},
+ {ScmpSyscall(SYS_UMOUNT), ScmpErrno(EPERM), nil},
+ {ScmpSyscall(SYS_UMOUNT2), ScmpErrno(EPERM), nil},
+ {ScmpSyscall(SYS_PIVOT_ROOT), ScmpErrno(EPERM), nil},
+ {ScmpSyscall(SYS_CHROOT), ScmpErrno(EPERM), nil},
+ {ScmpSyscall(SYS_CLONE), ScmpErrno(EPERM),
+ &ScmpArgCmp{cloneArg, SCMP_CMP_MASKED_EQ, CLONE_NEWUSER, CLONE_NEWUSER}},
+
+ /* seccomp can't look into clone3()'s struct clone_args to check whether
+ * the flags are OK, so we have no choice but to block clone3().
+ * Return ENOSYS so user-space will fall back to clone().
+ * (CVE-2021-41133; see also https://github.com/moby/moby/commit/9f6b562d)
+ */
+ {ScmpSyscall(SYS_CLONE3), ScmpErrno(ENOSYS), nil},
+
+ /* New mount manipulation APIs can also change our VFS. There's no
+ * legitimate reason to do these in the sandbox, so block all of them
+ * rather than thinking about which ones might be dangerous.
+ * (CVE-2021-41133) */
+ {ScmpSyscall(SYS_OPEN_TREE), ScmpErrno(ENOSYS), nil},
+ {ScmpSyscall(SYS_MOVE_MOUNT), ScmpErrno(ENOSYS), nil},
+ {ScmpSyscall(SYS_FSOPEN), ScmpErrno(ENOSYS), nil},
+ {ScmpSyscall(SYS_FSCONFIG), ScmpErrno(ENOSYS), nil},
+ {ScmpSyscall(SYS_FSMOUNT), ScmpErrno(ENOSYS), nil},
+ {ScmpSyscall(SYS_FSPICK), ScmpErrno(ENOSYS), nil},
+ {ScmpSyscall(SYS_MOUNT_SETATTR), ScmpErrno(ENOSYS), nil},
+ }
+
+ /* hakurei: project-specific extensions */
+ presetNamespaceExt = []NativeRule{
+ /* changing file ownership */
+ {ScmpSyscall(SYS_CHOWN), ScmpErrno(EPERM), nil},
+ {ScmpSyscall(SYS_CHOWN32), ScmpErrno(EPERM), nil},
+ {ScmpSyscall(SYS_FCHOWN), ScmpErrno(EPERM), nil},
+ {ScmpSyscall(SYS_FCHOWN32), ScmpErrno(EPERM), nil},
+ {ScmpSyscall(SYS_FCHOWNAT), ScmpErrno(EPERM), nil},
+ {ScmpSyscall(SYS_LCHOWN), ScmpErrno(EPERM), nil},
+ {ScmpSyscall(SYS_LCHOWN32), ScmpErrno(EPERM), nil},
+
+ /* system calls for changing user ID and group ID credentials */
+ {ScmpSyscall(SYS_SETGID), ScmpErrno(EPERM), nil},
+ {ScmpSyscall(SYS_SETGID32), ScmpErrno(EPERM), nil},
+ {ScmpSyscall(SYS_SETGROUPS), ScmpErrno(EPERM), nil},
+ {ScmpSyscall(SYS_SETGROUPS32), ScmpErrno(EPERM), nil},
+ {ScmpSyscall(SYS_SETREGID), ScmpErrno(EPERM), nil},
+ {ScmpSyscall(SYS_SETREGID32), ScmpErrno(EPERM), nil},
+ {ScmpSyscall(SYS_SETRESGID), ScmpErrno(EPERM), nil},
+ {ScmpSyscall(SYS_SETRESGID32), ScmpErrno(EPERM), nil},
+ {ScmpSyscall(SYS_SETRESUID), ScmpErrno(EPERM), nil},
+ {ScmpSyscall(SYS_SETRESUID32), ScmpErrno(EPERM), nil},
+ {ScmpSyscall(SYS_SETREUID), ScmpErrno(EPERM), nil},
+ {ScmpSyscall(SYS_SETREUID32), ScmpErrno(EPERM), nil},
+ {ScmpSyscall(SYS_SETUID), ScmpErrno(EPERM), nil},
+ {ScmpSyscall(SYS_SETUID32), ScmpErrno(EPERM), nil},
+ }
+
+ presetTTY = []NativeRule{
+ /* Don't allow faking input to the controlling tty (CVE-2017-5226) */
+ {ScmpSyscall(SYS_IOCTL), ScmpErrno(EPERM),
+ &ScmpArgCmp{1, SCMP_CMP_MASKED_EQ, 0xFFFFFFFF, TIOCSTI}},
+ /* In the unlikely event that the controlling tty is a Linux virtual
+ * console (/dev/tty2 or similar), copy/paste operations have an effect
+ * similar to TIOCSTI (CVE-2023-28100) */
+ {ScmpSyscall(SYS_IOCTL), ScmpErrno(EPERM),
+ &ScmpArgCmp{1, SCMP_CMP_MASKED_EQ, 0xFFFFFFFF, TIOCLINUX}},
+ }
+
+ presetEmu = []NativeRule{
+ /* modify_ldt is a historic source of interesting information leaks,
+ * so it's disabled as a hardening measure.
+ * However, it is required to run old 16-bit applications
+ * as well as some Wine patches, so it's allowed in multiarch. */
+ {ScmpSyscall(SYS_MODIFY_LDT), ScmpErrno(EPERM), nil},
+ }
+
+ /* hakurei: project-specific extensions */
+ presetEmuExt = []NativeRule{
+ {ScmpSyscall(SYS_SUBPAGE_PROT), ScmpErrno(ENOSYS), nil},
+ {ScmpSyscall(SYS_SWITCH_ENDIAN), ScmpErrno(ENOSYS), nil},
+ {ScmpSyscall(SYS_VM86), ScmpErrno(ENOSYS), nil},
+ {ScmpSyscall(SYS_VM86OLD), ScmpErrno(ENOSYS), nil},
+ }
+)
+
+func presetDevel(allowedPersonality ScmpDatum) []NativeRule {
+ return []NativeRule{
+ /* Profiling operations; we expect these to be done by tools from outside
+ * the sandbox. In particular perf has been the source of many CVEs. */
+ {ScmpSyscall(SYS_PERF_EVENT_OPEN), ScmpErrno(EPERM), nil},
+ /* Don't allow you to switch to bsd emulation or whatnot */
+ {ScmpSyscall(SYS_PERSONALITY), ScmpErrno(EPERM),
+ &ScmpArgCmp{0, SCMP_CMP_NE, allowedPersonality, 0}},
+
+ {ScmpSyscall(SYS_PTRACE), ScmpErrno(EPERM), nil},
+ }
+}
diff --git a/container/seccomp/presets_clone_backwards2.go b/container/seccomp/presets_clone_backwards2.go
new file mode 100644
index 00000000..6a7a636e
--- /dev/null
+++ b/container/seccomp/presets_clone_backwards2.go
@@ -0,0 +1,7 @@
+//go:build s390 || s390x
+
+package seccomp
+
+/* Architectures with CONFIG_CLONE_BACKWARDS2: the child stack
+ * and flags arguments are reversed so the flags come second */
+const cloneArg = 1
diff --git a/container/seccomp/presets_clone_generic.go b/container/seccomp/presets_clone_generic.go
new file mode 100644
index 00000000..9d20890e
--- /dev/null
+++ b/container/seccomp/presets_clone_generic.go
@@ -0,0 +1,6 @@
+//go:build !s390 && !s390x
+
+package seccomp
+
+/* Normally the flags come first */
+const cloneArg = 0
diff --git a/container/seccomp/proc.go b/container/seccomp/proc.go
new file mode 100644
index 00000000..e4ce1853
--- /dev/null
+++ b/container/seccomp/proc.go
@@ -0,0 +1,78 @@
+package seccomp
+
+import (
+ "context"
+ "errors"
+ "syscall"
+
+ "git.gensokyo.uk/security/hakurei/helper/proc"
+)
+
+const (
+ PresetStrict = PresetExt | PresetDenyNS | PresetDenyTTY | PresetDenyDevel
+)
+
+// New returns an inactive Encoder instance.
+func New(rules []NativeRule, flags ExportFlag) *Encoder { return &Encoder{newExporter(rules, flags)} }
+
+// Load loads a filter into the kernel.
+func Load(rules []NativeRule, flags ExportFlag) error { return Export(-1, rules, flags) }
+
+/*
+An Encoder writes a BPF program to an output stream.
+
+Methods of Encoder are not safe for concurrent use.
+
+An Encoder must not be copied after first use.
+*/
+type Encoder struct {
+ *exporter
+}
+
+func (e *Encoder) Read(p []byte) (n int, err error) {
+ if err = e.prepare(); err != nil {
+ return
+ }
+ return e.r.Read(p)
+}
+
+func (e *Encoder) Close() error {
+ if e.r == nil {
+ return syscall.EINVAL
+ }
+
+ // this hangs if the cgo thread fails to exit
+ return errors.Join(e.closeWrite(), <-e.exportErr)
+}
+
+// NewFile returns an instance of exporter implementing [proc.File].
+func NewFile(rules []NativeRule, flags ExportFlag) proc.File {
+ return &File{rules: rules, flags: flags}
+}
+
+// File implements [proc.File] and provides access to the read end of exporter pipe.
+type File struct {
+ rules []NativeRule
+ flags ExportFlag
+ proc.BaseFile
+}
+
+func (f *File) ErrCount() int { return 2 }
+func (f *File) Fulfill(ctx context.Context, dispatchErr func(error)) error {
+ e := newExporter(f.rules, f.flags)
+ if err := e.prepare(); err != nil {
+ return err
+ }
+ f.Set(e.r)
+ go func() {
+ select {
+ case err := <-e.exportErr:
+ dispatchErr(nil)
+ dispatchErr(err)
+ case <-ctx.Done():
+ dispatchErr(e.closeWrite())
+ dispatchErr(<-e.exportErr)
+ }
+ }()
+ return nil
+}
diff --git a/container/seccomp/seccomp.go b/container/seccomp/seccomp.go
new file mode 100644
index 00000000..664b31c6
--- /dev/null
+++ b/container/seccomp/seccomp.go
@@ -0,0 +1,60 @@
+// Package seccomp provides high level wrappers around libseccomp.
+package seccomp
+
+import (
+ "os"
+ "runtime"
+ "sync"
+)
+
+type exporter struct {
+ rules []NativeRule
+ flags ExportFlag
+ r, w *os.File
+
+ prepareOnce sync.Once
+ prepareErr error
+ closeOnce sync.Once
+ closeErr error
+ exportErr <-chan error
+}
+
+func (e *exporter) prepare() error {
+ e.prepareOnce.Do(func() {
+ if r, w, err := os.Pipe(); err != nil {
+ e.prepareErr = err
+ return
+ } else {
+ e.r, e.w = r, w
+ }
+
+ ec := make(chan error, 1)
+ go func(fd uintptr) {
+ ec <- Export(int(fd), e.rules, e.flags)
+ close(ec)
+ _ = e.closeWrite()
+ runtime.KeepAlive(e.w)
+ }(e.w.Fd())
+ e.exportErr = ec
+ runtime.SetFinalizer(e, (*exporter).closeWrite)
+ })
+ return e.prepareErr
+}
+
+func (e *exporter) closeWrite() error {
+ e.closeOnce.Do(func() {
+ if e.w == nil {
+ panic("closeWrite called on invalid exporter")
+ }
+ e.closeErr = e.w.Close()
+
+ // no need for a finalizer anymore
+ runtime.SetFinalizer(e, nil)
+ })
+
+ return e.closeErr
+}
+
+func newExporter(rules []NativeRule, flags ExportFlag) *exporter {
+ return &exporter{rules: rules, flags: flags}
+}
diff --git a/container/seccomp/seccomp_test.go b/container/seccomp/seccomp_test.go
new file mode 100644
index 00000000..2b59c9bc
--- /dev/null
+++ b/container/seccomp/seccomp_test.go
@@ -0,0 +1,65 @@
+package seccomp_test
+
+import (
+ "errors"
+ "runtime"
+ "syscall"
+ "testing"
+
+ "git.gensokyo.uk/security/hakurei/container/seccomp"
+)
+
+func TestLibraryError(t *testing.T) {
+ testCases := []struct {
+ name string
+ sample *seccomp.LibraryError
+ want string
+ wantIs bool
+ compare error
+ }{
+ {
+ "full",
+ &seccomp.LibraryError{Prefix: "seccomp_export_bpf failed", Seccomp: syscall.ECANCELED, Errno: syscall.EBADF},
+ "seccomp_export_bpf failed: operation canceled (bad file descriptor)",
+ true,
+ &seccomp.LibraryError{Prefix: "seccomp_export_bpf failed", Seccomp: syscall.ECANCELED, Errno: syscall.EBADF},
+ },
+ {
+ "errno only",
+ &seccomp.LibraryError{Prefix: "seccomp_init failed", Errno: syscall.ENOMEM},
+ "seccomp_init failed: cannot allocate memory",
+ false,
+ nil,
+ },
+ {
+ "seccomp only",
+ &seccomp.LibraryError{Prefix: "internal libseccomp failure", Seccomp: syscall.EFAULT},
+ "internal libseccomp failure: bad address",
+ true,
+ syscall.EFAULT,
+ },
+ }
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ if errors.Is(tc.sample, tc.compare) != tc.wantIs {
+ t.Errorf("errors.Is(%#v, %#v) did not return %v",
+ tc.sample, tc.compare, tc.wantIs)
+ }
+
+ if got := tc.sample.Error(); got != tc.want {
+ t.Errorf("Error: %q, want %q",
+ got, tc.want)
+ }
+ })
+ }
+
+ t.Run("invalid", func(t *testing.T) {
+ wantPanic := "invalid libseccomp error"
+ defer func() {
+ if r := recover(); r != wantPanic {
+ t.Errorf("panic: %q, want %q", r, wantPanic)
+ }
+ }()
+ runtime.KeepAlive(new(seccomp.LibraryError).Error())
+ })
+}
diff --git a/container/seccomp/syscall.go b/container/seccomp/syscall.go
new file mode 100644
index 00000000..36a988aa
--- /dev/null
+++ b/container/seccomp/syscall.go
@@ -0,0 +1,28 @@
+package seccomp
+
+import "iter"
+
+// Syscalls returns an iterator over all wired syscalls.
+func Syscalls() iter.Seq2[string, int] {
+ return func(yield func(string, int) bool) {
+ for name, num := range syscallNum {
+ if !yield(name, num) {
+ return
+ }
+ }
+ for name, num := range syscallNumExtra {
+ if !yield(name, num) {
+ return
+ }
+ }
+ }
+}
+
+// SyscallResolveName resolves a syscall number from its string representation.
+func SyscallResolveName(name string) (num int, ok bool) {
+ if num, ok = syscallNum[name]; ok {
+ return
+ }
+ num, ok = syscallNumExtra[name]
+ return
+}
diff --git a/container/seccomp/syscall_extra_linux_amd64.go b/container/seccomp/syscall_extra_linux_amd64.go
new file mode 100644
index 00000000..4b83a876
--- /dev/null
+++ b/container/seccomp/syscall_extra_linux_amd64.go
@@ -0,0 +1,54 @@
+package seccomp
+
+/*
+#cgo linux pkg-config: --static libseccomp
+
+#include <seccomp.h>
+#include <sys/personality.h>
+*/
+import "C"
+
+const (
+ PER_LINUX = C.PER_LINUX
+ PER_LINUX32 = C.PER_LINUX32
+)
+
+var syscallNumExtra = map[string]int{
+ "umount": SYS_UMOUNT,
+ "subpage_prot": SYS_SUBPAGE_PROT,
+ "switch_endian": SYS_SWITCH_ENDIAN,
+ "vm86": SYS_VM86,
+ "vm86old": SYS_VM86OLD,
+ "clock_adjtime64": SYS_CLOCK_ADJTIME64,
+ "clock_settime64": SYS_CLOCK_SETTIME64,
+ "chown32": SYS_CHOWN32,
+ "fchown32": SYS_FCHOWN32,
+ "lchown32": SYS_LCHOWN32,
+ "setgid32": SYS_SETGID32,
+ "setgroups32": SYS_SETGROUPS32,
+ "setregid32": SYS_SETREGID32,
+ "setresgid32": SYS_SETRESGID32,
+ "setresuid32": SYS_SETRESUID32,
+ "setreuid32": SYS_SETREUID32,
+ "setuid32": SYS_SETUID32,
+}
+
+const (
+ SYS_UMOUNT = C.__SNR_umount
+ SYS_SUBPAGE_PROT = C.__SNR_subpage_prot
+ SYS_SWITCH_ENDIAN = C.__SNR_switch_endian
+ SYS_VM86 = C.__SNR_vm86
+ SYS_VM86OLD = C.__SNR_vm86old
+ SYS_CLOCK_ADJTIME64 = C.__SNR_clock_adjtime64
+ SYS_CLOCK_SETTIME64 = C.__SNR_clock_settime64
+ SYS_CHOWN32 = C.__SNR_chown32
+ SYS_FCHOWN32 = C.__SNR_fchown32
+ SYS_LCHOWN32 = C.__SNR_lchown32
+ SYS_SETGID32 = C.__SNR_setgid32
+ SYS_SETGROUPS32 = C.__SNR_setgroups32
+ SYS_SETREGID32 = C.__SNR_setregid32
+ SYS_SETRESGID32 = C.__SNR_setresgid32
+ SYS_SETRESUID32 = C.__SNR_setresuid32
+ SYS_SETREUID32 = C.__SNR_setreuid32
+ SYS_SETUID32 = C.__SNR_setuid32
+)
diff --git a/container/seccomp/syscall_linux_amd64.go b/container/seccomp/syscall_linux_amd64.go
new file mode 100644
index 00000000..28dbcb47
--- /dev/null
+++ b/container/seccomp/syscall_linux_amd64.go
@@ -0,0 +1,459 @@
+// mksysnum_linux.pl /usr/include/asm/unistd_64.h
+// Code generated by the command above; DO NOT EDIT.
+
+package seccomp
+
+import . "syscall"
+
+var syscallNum = map[string]int{
+ "read": SYS_READ,
+ "write": SYS_WRITE,
+ "open": SYS_OPEN,
+ "close": SYS_CLOSE,
+ "stat": SYS_STAT,
+ "fstat": SYS_FSTAT,
+ "lstat": SYS_LSTAT,
+ "poll": SYS_POLL,
+ "lseek": SYS_LSEEK,
+ "mmap": SYS_MMAP,
+ "mprotect": SYS_MPROTECT,
+ "munmap": SYS_MUNMAP,
+ "brk": SYS_BRK,
+ "rt_sigaction": SYS_RT_SIGACTION,
+ "rt_sigprocmask": SYS_RT_SIGPROCMASK,
+ "rt_sigreturn": SYS_RT_SIGRETURN,
+ "ioctl": SYS_IOCTL,
+ "pread64": SYS_PREAD64,
+ "pwrite64": SYS_PWRITE64,
+ "readv": SYS_READV,
+ "writev": SYS_WRITEV,
+ "access": SYS_ACCESS,
+ "pipe": SYS_PIPE,
+ "select": SYS_SELECT,
+ "sched_yield": SYS_SCHED_YIELD,
+ "mremap": SYS_MREMAP,
+ "msync": SYS_MSYNC,
+ "mincore": SYS_MINCORE,
+ "madvise": SYS_MADVISE,
+ "shmget": SYS_SHMGET,
+ "shmat": SYS_SHMAT,
+ "shmctl": SYS_SHMCTL,
+ "dup": SYS_DUP,
+ "dup2": SYS_DUP2,
+ "pause": SYS_PAUSE,
+ "nanosleep": SYS_NANOSLEEP,
+ "getitimer": SYS_GETITIMER,
+ "alarm": SYS_ALARM,
+ "setitimer": SYS_SETITIMER,
+ "getpid": SYS_GETPID,
+ "sendfile": SYS_SENDFILE,
+ "socket": SYS_SOCKET,
+ "connect": SYS_CONNECT,
+ "accept": SYS_ACCEPT,
+ "sendto": SYS_SENDTO,
+ "recvfrom": SYS_RECVFROM,
+ "sendmsg": SYS_SENDMSG,
+ "recvmsg": SYS_RECVMSG,
+ "shutdown": SYS_SHUTDOWN,
+ "bind": SYS_BIND,
+ "listen": SYS_LISTEN,
+ "getsockname": SYS_GETSOCKNAME,
+ "getpeername": SYS_GETPEERNAME,
+ "socketpair": SYS_SOCKETPAIR,
+ "setsockopt": SYS_SETSOCKOPT,
+ "getsockopt": SYS_GETSOCKOPT,
+ "clone": SYS_CLONE,
+ "fork": SYS_FORK,
+ "vfork": SYS_VFORK,
+ "execve": SYS_EXECVE,
+ "exit": SYS_EXIT,
+ "wait4": SYS_WAIT4,
+ "kill": SYS_KILL,
+ "uname": SYS_UNAME,
+ "semget": SYS_SEMGET,
+ "semop": SYS_SEMOP,
+ "semctl": SYS_SEMCTL,
+ "shmdt": SYS_SHMDT,
+ "msgget": SYS_MSGGET,
+ "msgsnd": SYS_MSGSND,
+ "msgrcv": SYS_MSGRCV,
+ "msgctl": SYS_MSGCTL,
+ "fcntl": SYS_FCNTL,
+ "flock": SYS_FLOCK,
+ "fsync": SYS_FSYNC,
+ "fdatasync": SYS_FDATASYNC,
+ "truncate": SYS_TRUNCATE,
+ "ftruncate": SYS_FTRUNCATE,
+ "getdents": SYS_GETDENTS,
+ "getcwd": SYS_GETCWD,
+ "chdir": SYS_CHDIR,
+ "fchdir": SYS_FCHDIR,
+ "rename": SYS_RENAME,
+ "mkdir": SYS_MKDIR,
+ "rmdir": SYS_RMDIR,
+ "creat": SYS_CREAT,
+ "link": SYS_LINK,
+ "unlink": SYS_UNLINK,
+ "symlink": SYS_SYMLINK,
+ "readlink": SYS_READLINK,
+ "chmod": SYS_CHMOD,
+ "fchmod": SYS_FCHMOD,
+ "chown": SYS_CHOWN,
+ "fchown": SYS_FCHOWN,
+ "lchown": SYS_LCHOWN,
+ "umask": SYS_UMASK,
+ "gettimeofday": SYS_GETTIMEOFDAY,
+ "getrlimit": SYS_GETRLIMIT,
+ "getrusage": SYS_GETRUSAGE,
+ "sysinfo": SYS_SYSINFO,
+ "times": SYS_TIMES,
+ "ptrace": SYS_PTRACE,
+ "getuid": SYS_GETUID,
+ "syslog": SYS_SYSLOG,
+ "getgid": SYS_GETGID,
+ "setuid": SYS_SETUID,
+ "setgid": SYS_SETGID,
+ "geteuid": SYS_GETEUID,
+ "getegid": SYS_GETEGID,
+ "setpgid": SYS_SETPGID,
+ "getppid": SYS_GETPPID,
+ "getpgrp": SYS_GETPGRP,
+ "setsid": SYS_SETSID,
+ "setreuid": SYS_SETREUID,
+ "setregid": SYS_SETREGID,
+ "getgroups": SYS_GETGROUPS,
+ "setgroups": SYS_SETGROUPS,
+ "setresuid": SYS_SETRESUID,
+ "getresuid": SYS_GETRESUID,
+ "setresgid": SYS_SETRESGID,
+ "getresgid": SYS_GETRESGID,
+ "getpgid": SYS_GETPGID,
+ "setfsuid": SYS_SETFSUID,
+ "setfsgid": SYS_SETFSGID,
+ "getsid": SYS_GETSID,
+ "capget": SYS_CAPGET,
+ "capset": SYS_CAPSET,
+ "rt_sigpending": SYS_RT_SIGPENDING,
+ "rt_sigtimedwait": SYS_RT_SIGTIMEDWAIT,
+ "rt_sigqueueinfo": SYS_RT_SIGQUEUEINFO,
+ "rt_sigsuspend": SYS_RT_SIGSUSPEND,
+ "sigaltstack": SYS_SIGALTSTACK,
+ "utime": SYS_UTIME,
+ "mknod": SYS_MKNOD,
+ "uselib": SYS_USELIB,
+ "personality": SYS_PERSONALITY,
+ "ustat": SYS_USTAT,
+ "statfs": SYS_STATFS,
+ "fstatfs": SYS_FSTATFS,
+ "sysfs": SYS_SYSFS,
+ "getpriority": SYS_GETPRIORITY,
+ "setpriority": SYS_SETPRIORITY,
+ "sched_setparam": SYS_SCHED_SETPARAM,
+ "sched_getparam": SYS_SCHED_GETPARAM,
+ "sched_setscheduler": SYS_SCHED_SETSCHEDULER,
+ "sched_getscheduler": SYS_SCHED_GETSCHEDULER,
+ "sched_get_priority_max": SYS_SCHED_GET_PRIORITY_MAX,
+ "sched_get_priority_min": SYS_SCHED_GET_PRIORITY_MIN,
+ "sched_rr_get_interval": SYS_SCHED_RR_GET_INTERVAL,
+ "mlock": SYS_MLOCK,
+ "munlock": SYS_MUNLOCK,
+ "mlockall": SYS_MLOCKALL,
+ "munlockall": SYS_MUNLOCKALL,
+ "vhangup": SYS_VHANGUP,
+ "modify_ldt": SYS_MODIFY_LDT,
+ "pivot_root": SYS_PIVOT_ROOT,
+ "_sysctl": SYS__SYSCTL,
+ "prctl": SYS_PRCTL,
+ "arch_prctl": SYS_ARCH_PRCTL,
+ "adjtimex": SYS_ADJTIMEX,
+ "setrlimit": SYS_SETRLIMIT,
+ "chroot": SYS_CHROOT,
+ "sync": SYS_SYNC,
+ "acct": SYS_ACCT,
+ "settimeofday": SYS_SETTIMEOFDAY,
+ "mount": SYS_MOUNT,
+ "umount2": SYS_UMOUNT2,
+ "swapon": SYS_SWAPON,
+ "swapoff": SYS_SWAPOFF,
+ "reboot": SYS_REBOOT,
+ "sethostname": SYS_SETHOSTNAME,
+ "setdomainname": SYS_SETDOMAINNAME,
+ "iopl": SYS_IOPL,
+ "ioperm": SYS_IOPERM,
+ "create_module": SYS_CREATE_MODULE,
+ "init_module": SYS_INIT_MODULE,
+ "delete_module": SYS_DELETE_MODULE,
+ "get_kernel_syms": SYS_GET_KERNEL_SYMS,
+ "query_module": SYS_QUERY_MODULE,
+ "quotactl": SYS_QUOTACTL,
+ "nfsservctl": SYS_NFSSERVCTL,
+ "getpmsg": SYS_GETPMSG,
+ "putpmsg": SYS_PUTPMSG,
+ "afs_syscall": SYS_AFS_SYSCALL,
+ "tuxcall": SYS_TUXCALL,
+ "security": SYS_SECURITY,
+ "gettid": SYS_GETTID,
+ "readahead": SYS_READAHEAD,
+ "setxattr": SYS_SETXATTR,
+ "lsetxattr": SYS_LSETXATTR,
+ "fsetxattr": SYS_FSETXATTR,
+ "getxattr": SYS_GETXATTR,
+ "lgetxattr": SYS_LGETXATTR,
+ "fgetxattr": SYS_FGETXATTR,
+ "listxattr": SYS_LISTXATTR,
+ "llistxattr": SYS_LLISTXATTR,
+ "flistxattr": SYS_FLISTXATTR,
+ "removexattr": SYS_REMOVEXATTR,
+ "lremovexattr": SYS_LREMOVEXATTR,
+ "fremovexattr": SYS_FREMOVEXATTR,
+ "tkill": SYS_TKILL,
+ "time": SYS_TIME,
+ "futex": SYS_FUTEX,
+ "sched_setaffinity": SYS_SCHED_SETAFFINITY,
+ "sched_getaffinity": SYS_SCHED_GETAFFINITY,
+ "set_thread_area": SYS_SET_THREAD_AREA,
+ "io_setup": SYS_IO_SETUP,
+ "io_destroy": SYS_IO_DESTROY,
+ "io_getevents": SYS_IO_GETEVENTS,
+ "io_submit": SYS_IO_SUBMIT,
+ "io_cancel": SYS_IO_CANCEL,
+ "get_thread_area": SYS_GET_THREAD_AREA,
+ "lookup_dcookie": SYS_LOOKUP_DCOOKIE,
+ "epoll_create": SYS_EPOLL_CREATE,
+ "epoll_ctl_old": SYS_EPOLL_CTL_OLD,
+ "epoll_wait_old": SYS_EPOLL_WAIT_OLD,
+ "remap_file_pages": SYS_REMAP_FILE_PAGES,
+ "getdents64": SYS_GETDENTS64,
+ "set_tid_address": SYS_SET_TID_ADDRESS,
+ "restart_syscall": SYS_RESTART_SYSCALL,
+ "semtimedop": SYS_SEMTIMEDOP,
+ "fadvise64": SYS_FADVISE64,
+ "timer_create": SYS_TIMER_CREATE,
+ "timer_settime": SYS_TIMER_SETTIME,
+ "timer_gettime": SYS_TIMER_GETTIME,
+ "timer_getoverrun": SYS_TIMER_GETOVERRUN,
+ "timer_delete": SYS_TIMER_DELETE,
+ "clock_settime": SYS_CLOCK_SETTIME,
+ "clock_gettime": SYS_CLOCK_GETTIME,
+ "clock_getres": SYS_CLOCK_GETRES,
+ "clock_nanosleep": SYS_CLOCK_NANOSLEEP,
+ "exit_group": SYS_EXIT_GROUP,
+ "epoll_wait": SYS_EPOLL_WAIT,
+ "epoll_ctl": SYS_EPOLL_CTL,
+ "tgkill": SYS_TGKILL,
+ "utimes": SYS_UTIMES,
+ "vserver": SYS_VSERVER,
+ "mbind": SYS_MBIND,
+ "set_mempolicy": SYS_SET_MEMPOLICY,
+ "get_mempolicy": SYS_GET_MEMPOLICY,
+ "mq_open": SYS_MQ_OPEN,
+ "mq_unlink": SYS_MQ_UNLINK,
+ "mq_timedsend": SYS_MQ_TIMEDSEND,
+ "mq_timedreceive": SYS_MQ_TIMEDRECEIVE,
+ "mq_notify": SYS_MQ_NOTIFY,
+ "mq_getsetattr": SYS_MQ_GETSETATTR,
+ "kexec_load": SYS_KEXEC_LOAD,
+ "waitid": SYS_WAITID,
+ "add_key": SYS_ADD_KEY,
+ "request_key": SYS_REQUEST_KEY,
+ "keyctl": SYS_KEYCTL,
+ "ioprio_set": SYS_IOPRIO_SET,
+ "ioprio_get": SYS_IOPRIO_GET,
+ "inotify_init": SYS_INOTIFY_INIT,
+ "inotify_add_watch": SYS_INOTIFY_ADD_WATCH,
+ "inotify_rm_watch": SYS_INOTIFY_RM_WATCH,
+ "migrate_pages": SYS_MIGRATE_PAGES,
+ "openat": SYS_OPENAT,
+ "mkdirat": SYS_MKDIRAT,
+ "mknodat": SYS_MKNODAT,
+ "fchownat": SYS_FCHOWNAT,
+ "futimesat": SYS_FUTIMESAT,
+ "newfstatat": SYS_NEWFSTATAT,
+ "unlinkat": SYS_UNLINKAT,
+ "renameat": SYS_RENAMEAT,
+ "linkat": SYS_LINKAT,
+ "symlinkat": SYS_SYMLINKAT,
+ "readlinkat": SYS_READLINKAT,
+ "fchmodat": SYS_FCHMODAT,
+ "faccessat": SYS_FACCESSAT,
+ "pselect6": SYS_PSELECT6,
+ "ppoll": SYS_PPOLL,
+ "unshare": SYS_UNSHARE,
+ "set_robust_list": SYS_SET_ROBUST_LIST,
+ "get_robust_list": SYS_GET_ROBUST_LIST,
+ "splice": SYS_SPLICE,
+ "tee": SYS_TEE,
+ "sync_file_range": SYS_SYNC_FILE_RANGE,
+ "vmsplice": SYS_VMSPLICE,
+ "move_pages": SYS_MOVE_PAGES,
+ "utimensat": SYS_UTIMENSAT,
+ "epoll_pwait": SYS_EPOLL_PWAIT,
+ "signalfd": SYS_SIGNALFD,
+ "timerfd_create": SYS_TIMERFD_CREATE,
+ "eventfd": SYS_EVENTFD,
+ "fallocate": SYS_FALLOCATE,
+ "timerfd_settime": SYS_TIMERFD_SETTIME,
+ "timerfd_gettime": SYS_TIMERFD_GETTIME,
+ "accept4": SYS_ACCEPT4,
+ "signalfd4": SYS_SIGNALFD4,
+ "eventfd2": SYS_EVENTFD2,
+ "epoll_create1": SYS_EPOLL_CREATE1,
+ "dup3": SYS_DUP3,
+ "pipe2": SYS_PIPE2,
+ "inotify_init1": SYS_INOTIFY_INIT1,
+ "preadv": SYS_PREADV,
+ "pwritev": SYS_PWRITEV,
+ "rt_tgsigqueueinfo": SYS_RT_TGSIGQUEUEINFO,
+ "perf_event_open": SYS_PERF_EVENT_OPEN,
+ "recvmmsg": SYS_RECVMMSG,
+ "fanotify_init": SYS_FANOTIFY_INIT,
+ "fanotify_mark": SYS_FANOTIFY_MARK,
+ "prlimit64": SYS_PRLIMIT64,
+ "name_to_handle_at": SYS_NAME_TO_HANDLE_AT,
+ "open_by_handle_at": SYS_OPEN_BY_HANDLE_AT,
+ "clock_adjtime": SYS_CLOCK_ADJTIME,
+ "syncfs": SYS_SYNCFS,
+ "sendmmsg": SYS_SENDMMSG,
+ "setns": SYS_SETNS,
+ "getcpu": SYS_GETCPU,
+ "process_vm_readv": SYS_PROCESS_VM_READV,
+ "process_vm_writev": SYS_PROCESS_VM_WRITEV,
+ "kcmp": SYS_KCMP,
+ "finit_module": SYS_FINIT_MODULE,
+ "sched_setattr": SYS_SCHED_SETATTR,
+ "sched_getattr": SYS_SCHED_GETATTR,
+ "renameat2": SYS_RENAMEAT2,
+ "seccomp": SYS_SECCOMP,
+ "getrandom": SYS_GETRANDOM,
+ "memfd_create": SYS_MEMFD_CREATE,
+ "kexec_file_load": SYS_KEXEC_FILE_LOAD,
+ "bpf": SYS_BPF,
+ "execveat": SYS_EXECVEAT,
+ "userfaultfd": SYS_USERFAULTFD,
+ "membarrier": SYS_MEMBARRIER,
+ "mlock2": SYS_MLOCK2,
+ "copy_file_range": SYS_COPY_FILE_RANGE,
+ "preadv2": SYS_PREADV2,
+ "pwritev2": SYS_PWRITEV2,
+ "pkey_mprotect": SYS_PKEY_MPROTECT,
+ "pkey_alloc": SYS_PKEY_ALLOC,
+ "pkey_free": SYS_PKEY_FREE,
+ "statx": SYS_STATX,
+ "io_pgetevents": SYS_IO_PGETEVENTS,
+ "rseq": SYS_RSEQ,
+ "uretprobe": SYS_URETPROBE,
+ "pidfd_send_signal": SYS_PIDFD_SEND_SIGNAL,
+ "io_uring_setup": SYS_IO_URING_SETUP,
+ "io_uring_enter": SYS_IO_URING_ENTER,
+ "io_uring_register": SYS_IO_URING_REGISTER,
+ "open_tree": SYS_OPEN_TREE,
+ "move_mount": SYS_MOVE_MOUNT,
+ "fsopen": SYS_FSOPEN,
+ "fsconfig": SYS_FSCONFIG,
+ "fsmount": SYS_FSMOUNT,
+ "fspick": SYS_FSPICK,
+ "pidfd_open": SYS_PIDFD_OPEN,
+ "clone3": SYS_CLONE3,
+ "close_range": SYS_CLOSE_RANGE,
+ "openat2": SYS_OPENAT2,
+ "pidfd_getfd": SYS_PIDFD_GETFD,
+ "faccessat2": SYS_FACCESSAT2,
+ "process_madvise": SYS_PROCESS_MADVISE,
+ "epoll_pwait2": SYS_EPOLL_PWAIT2,
+ "mount_setattr": SYS_MOUNT_SETATTR,
+ "quotactl_fd": SYS_QUOTACTL_FD,
+ "landlock_create_ruleset": SYS_LANDLOCK_CREATE_RULESET,
+ "landlock_add_rule": SYS_LANDLOCK_ADD_RULE,
+ "landlock_restrict_self": SYS_LANDLOCK_RESTRICT_SELF,
+ "memfd_secret": SYS_MEMFD_SECRET,
+ "process_mrelease": SYS_PROCESS_MRELEASE,
+ "futex_waitv": SYS_FUTEX_WAITV,
+ "set_mempolicy_home_node": SYS_SET_MEMPOLICY_HOME_NODE,
+ "cachestat": SYS_CACHESTAT,
+ "fchmodat2": SYS_FCHMODAT2,
+ "map_shadow_stack": SYS_MAP_SHADOW_STACK,
+ "futex_wake": SYS_FUTEX_WAKE,
+ "futex_wait": SYS_FUTEX_WAIT,
+ "futex_requeue": SYS_FUTEX_REQUEUE,
+ "statmount": SYS_STATMOUNT,
+ "listmount": SYS_LISTMOUNT,
+ "lsm_get_self_attr": SYS_LSM_GET_SELF_ATTR,
+ "lsm_set_self_attr": SYS_LSM_SET_SELF_ATTR,
+ "lsm_list_modules": SYS_LSM_LIST_MODULES,
+ "mseal": SYS_MSEAL,
+}
+
+const (
+ SYS_NAME_TO_HANDLE_AT = 303
+ SYS_OPEN_BY_HANDLE_AT = 304
+ SYS_CLOCK_ADJTIME = 305
+ SYS_SYNCFS = 306
+ SYS_SENDMMSG = 307
+ SYS_SETNS = 308
+ SYS_GETCPU = 309
+ SYS_PROCESS_VM_READV = 310
+ SYS_PROCESS_VM_WRITEV = 311
+ SYS_KCMP = 312
+ SYS_FINIT_MODULE = 313
+ SYS_SCHED_SETATTR = 314
+ SYS_SCHED_GETATTR = 315
+ SYS_RENAMEAT2 = 316
+ SYS_SECCOMP = 317
+ SYS_GETRANDOM = 318
+ SYS_MEMFD_CREATE = 319
+ SYS_KEXEC_FILE_LOAD = 320
+ SYS_BPF = 321
+ SYS_EXECVEAT = 322
+ SYS_USERFAULTFD = 323
+ SYS_MEMBARRIER = 324
+ SYS_MLOCK2 = 325
+ SYS_COPY_FILE_RANGE = 326
+ SYS_PREADV2 = 327
+ SYS_PWRITEV2 = 328
+ SYS_PKEY_MPROTECT = 329
+ SYS_PKEY_ALLOC = 330
+ SYS_PKEY_FREE = 331
+ SYS_STATX = 332
+ SYS_IO_PGETEVENTS = 333
+ SYS_RSEQ = 334
+ SYS_URETPROBE = 335
+ SYS_PIDFD_SEND_SIGNAL = 424
+ SYS_IO_URING_SETUP = 425
+ SYS_IO_URING_ENTER = 426
+ SYS_IO_URING_REGISTER = 427
+ SYS_OPEN_TREE = 428
+ SYS_MOVE_MOUNT = 429
+ SYS_FSOPEN = 430
+ SYS_FSCONFIG = 431
+ SYS_FSMOUNT = 432
+ SYS_FSPICK = 433
+ SYS_PIDFD_OPEN = 434
+ SYS_CLONE3 = 435
+ SYS_CLOSE_RANGE = 436
+ SYS_OPENAT2 = 437
+ SYS_PIDFD_GETFD = 438
+ SYS_FACCESSAT2 = 439
+ SYS_PROCESS_MADVISE = 440
+ SYS_EPOLL_PWAIT2 = 441
+ SYS_MOUNT_SETATTR = 442
+ SYS_QUOTACTL_FD = 443
+ SYS_LANDLOCK_CREATE_RULESET = 444
+ SYS_LANDLOCK_ADD_RULE = 445
+ SYS_LANDLOCK_RESTRICT_SELF = 446
+ SYS_MEMFD_SECRET = 447
+ SYS_PROCESS_MRELEASE = 448
+ SYS_FUTEX_WAITV = 449
+ SYS_SET_MEMPOLICY_HOME_NODE = 450
+ SYS_CACHESTAT = 451
+ SYS_FCHMODAT2 = 452
+ SYS_MAP_SHADOW_STACK = 453
+ SYS_FUTEX_WAKE = 454
+ SYS_FUTEX_WAIT = 455
+ SYS_FUTEX_REQUEUE = 456
+ SYS_STATMOUNT = 457
+ SYS_LISTMOUNT = 458
+ SYS_LSM_GET_SELF_ATTR = 459
+ SYS_LSM_SET_SELF_ATTR = 460
+ SYS_LSM_LIST_MODULES = 461
+ SYS_MSEAL = 462
+)
diff --git a/container/seccomp/syscall_test.go b/container/seccomp/syscall_test.go
new file mode 100644
index 00000000..933f060b
--- /dev/null
+++ b/container/seccomp/syscall_test.go
@@ -0,0 +1,20 @@
+package seccomp
+
+import (
+ "testing"
+)
+
+func TestSyscallResolveName(t *testing.T) {
+ for name, want := range Syscalls() {
+ t.Run(name, func(t *testing.T) {
+ if got := syscallResolveName(name); got != want {
+ t.Errorf("syscallResolveName(%q) = %d, want %d",
+ name, got, want)
+ }
+ if got, ok := SyscallResolveName(name); !ok || got != want {
+ t.Errorf("SyscallResolveName(%q) = %d, want %d",
+ name, got, want)
+ }
+ })
+ }
+}