diff --git a/cmd/fpkg/app.go b/cmd/fpkg/app.go index e67ef11..c6ed60e 100644 --- a/cmd/fpkg/app.go +++ b/cmd/fpkg/app.go @@ -111,10 +111,10 @@ func (app *appInfo) toFst(pathSet *appPathSet, argv []string, flagDropShell bool }, } if app.Multiarch { - config.Confinement.Sandbox.Seccomp |= seccomp.FlagMultiarch + config.Confinement.Sandbox.Seccomp |= seccomp.FilterMultiarch } if app.Bluetooth { - config.Confinement.Sandbox.Seccomp |= seccomp.FlagBluetooth + config.Confinement.Sandbox.Seccomp |= seccomp.FilterBluetooth } return config } diff --git a/cmd/fpkg/with.go b/cmd/fpkg/with.go index f9ffe84..92c5ba9 100644 --- a/cmd/fpkg/with.go +++ b/cmd/fpkg/with.go @@ -39,7 +39,7 @@ func withNixDaemon( Hostname: formatHostname(app.Name) + "-" + action, Userns: true, // nix sandbox requires userns Net: net, - Seccomp: seccomp.FlagMultiarch, + Seccomp: seccomp.FilterMultiarch, Tty: dropShell, Filesystem: []*fst.FilesystemConfig{ {Src: pathSet.nixPath, Dst: "/nix", Write: true, Must: true}, @@ -76,7 +76,7 @@ func withCacheDir( Shell: shellPath, Sandbox: &fst.SandboxConfig{ Hostname: formatHostname(app.Name) + "-" + action, - Seccomp: seccomp.FlagMultiarch, + Seccomp: seccomp.FilterMultiarch, Tty: dropShell, Filesystem: []*fst.FilesystemConfig{ {Src: path.Join(workDir, "nix"), Dst: "/nix", Must: true}, diff --git a/dbus/proc.go b/dbus/proc.go index 07e8b78..cd087d5 100644 --- a/dbus/proc.go +++ b/dbus/proc.go @@ -63,7 +63,7 @@ func (p *Proxy) Start(ctx context.Context, output io.Writer, useSandbox bool) er c, toolPath, p.seal, true, argF, func(container *sandbox.Container) { - container.Seccomp |= seccomp.FlagMultiarch + container.Seccomp |= seccomp.FilterMultiarch container.Hostname = "fortify-dbus" container.CommandContext = p.CommandContext if output != nil { diff --git a/fst/config.go b/fst/config.go index 48f74eb..1a989e4 100644 --- a/fst/config.go +++ b/fst/config.go @@ -106,7 +106,7 @@ func Template() *Config { Userns: true, Net: true, Dev: true, - Seccomp: seccomp.FlagMultiarch, + Seccomp: seccomp.FilterMultiarch, Tty: true, Multiarch: true, MapRealUID: true, diff --git a/fst/sandbox.go b/fst/sandbox.go index 8bbc076..716e303 100644 --- a/fst/sandbox.go +++ b/fst/sandbox.go @@ -21,7 +21,7 @@ type ( Hostname string `json:"hostname,omitempty"` // extra seccomp flags - Seccomp seccomp.SyscallOpts `json:"seccomp"` + Seccomp seccomp.FilterOpts `json:"seccomp"` // allow ptrace and friends Devel bool `json:"devel,omitempty"` // allow userns creation in container @@ -98,7 +98,7 @@ func (s *SandboxConfig) ToContainer(sys SandboxSys, uid, gid *int) (*sandbox.Par } if s.Multiarch { - container.Seccomp |= seccomp.FlagMultiarch + container.Seccomp |= seccomp.FilterMultiarch } /* this is only 4 KiB of memory on a 64-bit system, diff --git a/internal/app/shim.go b/internal/app/shim.go index ebc00aa..ea11dcc 100644 --- a/internal/app/shim.go +++ b/internal/app/shim.go @@ -163,9 +163,7 @@ func ShimMain() { fmsg.PrintBaseError(err, "cannot configure container:") } - if err := seccomp.Load(seccomp.FlagExt | - seccomp.FlagDenyNS | seccomp.FlagDenyTTY | seccomp.FlagDenyDevel | - seccomp.FlagMultiarch); err != nil { + if err := seccomp.Load(seccomp.PresetCommon); err != nil { log.Fatalf("cannot load syscall filter: %v", err) } diff --git a/sandbox/container.go b/sandbox/container.go index 7bbdf25..eb8b734 100644 --- a/sandbox/container.go +++ b/sandbox/container.go @@ -27,18 +27,18 @@ const ( FAllowNet ) -func (flags HardeningFlags) seccomp(opts seccomp.SyscallOpts) seccomp.SyscallOpts { +func (flags HardeningFlags) seccomp(opts seccomp.FilterOpts) seccomp.FilterOpts { if flags&FSyscallCompat == 0 { - opts |= seccomp.FlagExt + opts |= seccomp.FilterExt } if flags&FAllowDevel == 0 { - opts |= seccomp.FlagDenyDevel + opts |= seccomp.FilterDenyDevel } if flags&FAllowUserns == 0 { - opts |= seccomp.FlagDenyNS + opts |= seccomp.FilterDenyNS } if flags&FAllowTTY == 0 { - opts |= seccomp.FlagDenyTTY + opts |= seccomp.FilterDenyTTY } return opts } @@ -95,7 +95,7 @@ type ( // Sequential container setup ops. *Ops // Extra seccomp options. - Seccomp seccomp.SyscallOpts + Seccomp seccomp.FilterOpts // Permission bits of newly created parent directories. // The zero value is interpreted as 0755. ParentPerm os.FileMode diff --git a/sandbox/container_test.go b/sandbox/container_test.go index f3d0854..0ba75da 100644 --- a/sandbox/container_test.go +++ b/sandbox/container_test.go @@ -164,7 +164,7 @@ func e(root, target, vfsOptstr, fsType, source, fsOptstr string) *vfs.MountInfoE func TestContainerString(t *testing.T) { container := sandbox.New(context.TODO(), "ldd", "/usr/bin/env") container.Flags |= sandbox.FAllowDevel - container.Seccomp |= seccomp.FlagMultiarch + container.Seccomp |= seccomp.FilterMultiarch want := `argv: ["ldd" "/usr/bin/env"], flags: 0x2, seccomp: 0x2e` if got := container.String(); got != want { t.Errorf("String: %s, want %s", got, want) diff --git a/sandbox/seccomp/api.go b/sandbox/seccomp/api.go index 697b09f..f084a14 100644 --- a/sandbox/seccomp/api.go +++ b/sandbox/seccomp/api.go @@ -8,11 +8,16 @@ import ( "git.gensokyo.uk/security/fortify/helper/proc" ) +const ( + PresetStrict = FilterExt | FilterDenyNS | FilterDenyTTY | FilterDenyDevel + PresetCommon = PresetStrict | FilterMultiarch +) + // New returns an inactive Encoder instance. -func New(opts SyscallOpts) *Encoder { return &Encoder{newExporter(opts)} } +func New(opts FilterOpts) *Encoder { return &Encoder{newExporter(opts)} } // Load loads a filter into the kernel. -func Load(opts SyscallOpts) error { return buildFilter(-1, opts) } +func Load(opts FilterOpts) error { return buildFilter(-1, opts) } /* An Encoder writes a BPF program to an output stream. @@ -42,11 +47,11 @@ func (e *Encoder) Close() error { } // NewFile returns an instance of exporter implementing [proc.File]. -func NewFile(opts SyscallOpts) proc.File { return &File{opts: opts} } +func NewFile(opts FilterOpts) proc.File { return &File{opts: opts} } // File implements [proc.File] and provides access to the read end of exporter pipe. type File struct { - opts SyscallOpts + opts FilterOpts proc.BaseFile } diff --git a/sandbox/seccomp/export.go b/sandbox/seccomp/export.go index 9568423..c0d2803 100644 --- a/sandbox/seccomp/export.go +++ b/sandbox/seccomp/export.go @@ -7,7 +7,7 @@ import ( ) type exporter struct { - opts SyscallOpts + opts FilterOpts r, w *os.File prepareOnce sync.Once @@ -53,6 +53,6 @@ func (e *exporter) closeWrite() error { return e.closeErr } -func newExporter(opts SyscallOpts) *exporter { +func newExporter(opts FilterOpts) *exporter { return &exporter{opts: opts} } diff --git a/sandbox/seccomp/export_test.go b/sandbox/seccomp/export_test.go index 66db3e4..dbe4d74 100644 --- a/sandbox/seccomp/export_test.go +++ b/sandbox/seccomp/export_test.go @@ -14,7 +14,7 @@ import ( func TestExport(t *testing.T) { testCases := []struct { name string - opts seccomp.SyscallOpts + opts seccomp.FilterOpts want []byte wantErr bool }{ @@ -28,7 +28,7 @@ func TestExport(t *testing.T) { 0xa7, 0x9b, 0x07, 0x0e, 0x04, 0xc0, 0xee, 0x9a, 0xcd, 0xf5, 0x8f, 0x55, 0xcf, 0xa8, 0x15, 0xa5, }, false}, - {"base", seccomp.FlagExt, []byte{ + {"base", seccomp.FilterExt, []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, @@ -38,10 +38,10 @@ func TestExport(t *testing.T) { 0x1d, 0xb0, 0x5d, 0x90, 0x99, 0x7c, 0x86, 0x59, 0xb9, 0x58, 0x91, 0x20, 0x6a, 0xc9, 0x95, 0x2d, }, false}, - {"everything", seccomp.FlagExt | - seccomp.FlagDenyNS | seccomp.FlagDenyTTY | seccomp.FlagDenyDevel | - seccomp.FlagMultiarch | seccomp.FlagLinux32 | seccomp.FlagCan | - seccomp.FlagBluetooth, []byte{ + {"everything", seccomp.FilterExt | + seccomp.FilterDenyNS | seccomp.FilterDenyTTY | seccomp.FilterDenyDevel | + seccomp.FilterMultiarch | seccomp.FilterLinux32 | seccomp.FilterCan | + seccomp.FilterBluetooth, []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, @@ -51,8 +51,7 @@ func TestExport(t *testing.T) { 0x4c, 0x02, 0x4e, 0xd4, 0x88, 0x50, 0xbe, 0x69, 0xb6, 0x8a, 0x9a, 0x4c, 0x5f, 0x53, 0xa9, 0xdb, }, false}, - {"strict", seccomp.FlagExt | - seccomp.FlagDenyNS | seccomp.FlagDenyTTY | seccomp.FlagDenyDevel, []byte{ + {"strict", seccomp.PresetStrict, []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, @@ -63,7 +62,7 @@ func TestExport(t *testing.T) { 0x14, 0x89, 0x60, 0xfb, 0xd3, 0x5c, 0xd7, 0x35, }, false}, {"strict compat", 0 | - seccomp.FlagDenyNS | seccomp.FlagDenyTTY | seccomp.FlagDenyDevel, []byte{ + seccomp.FilterDenyNS | seccomp.FilterDenyTTY | seccomp.FilterDenyDevel, []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, @@ -73,7 +72,7 @@ func TestExport(t *testing.T) { 0x80, 0x8b, 0x1a, 0x6f, 0x84, 0xf3, 0x2b, 0xbd, 0xe1, 0xaa, 0x02, 0xae, 0x30, 0xee, 0xdc, 0xfa, }, false}, - {"fortify default", seccomp.FlagExt | seccomp.FlagDenyDevel, []byte{ + {"fortify default", seccomp.FilterExt | seccomp.FilterDenyDevel, []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, @@ -138,10 +137,10 @@ func TestExport(t *testing.T) { func BenchmarkExport(b *testing.B) { buf := make([]byte, 8) for i := 0; i < b.N; i++ { - e := seccomp.New(seccomp.FlagExt | - seccomp.FlagDenyNS | seccomp.FlagDenyTTY | seccomp.FlagDenyDevel | - seccomp.FlagMultiarch | seccomp.FlagLinux32 | seccomp.FlagCan | - seccomp.FlagBluetooth) + e := seccomp.New(seccomp.FilterExt | + seccomp.FilterDenyNS | seccomp.FilterDenyTTY | seccomp.FilterDenyDevel | + seccomp.FilterMultiarch | seccomp.FilterLinux32 | seccomp.FilterCan | + seccomp.FilterBluetooth) if _, err := io.CopyBuffer(io.Discard, e, buf); err != nil { b.Fatalf("cannot export: %v", err) } diff --git a/sandbox/seccomp/seccomp-build.c b/sandbox/seccomp/seccomp-build.c index 9423e78..ee2cc63 100644 --- a/sandbox/seccomp/seccomp-build.c +++ b/sandbox/seccomp/seccomp-build.c @@ -47,7 +47,7 @@ struct f_syscall_act { } \ } while (0) -int32_t f_build_filter(int *ret_p, int fd, uint32_t arch, uint32_t multiarch, f_syscall_opts opts) { +int32_t f_build_filter(int *ret_p, int fd, uint32_t arch, uint32_t multiarch, f_filter_opts opts) { int32_t res = 0; // refer to resErr for meaning int allow_multiarch = opts & F_MULTIARCH; int allowed_personality = PER_LINUX; @@ -209,7 +209,7 @@ int32_t f_build_filter(int *ret_p, int fd, uint32_t arch, uint32_t multiarch, f_ struct { int family; - f_syscall_opts flags_mask; + f_filter_opts flags_mask; } socket_family_allowlist[] = { // NOTE: Keep in numerical order { AF_UNSPEC, 0 }, diff --git a/sandbox/seccomp/seccomp-build.h b/sandbox/seccomp/seccomp-build.h index d6e53fb..0b3a095 100644 --- a/sandbox/seccomp/seccomp-build.h +++ b/sandbox/seccomp/seccomp-build.h @@ -17,7 +17,7 @@ typedef enum { F_LINUX32 = 1 << 6, F_CAN = 1 << 7, F_BLUETOOTH = 1 << 8, -} f_syscall_opts; +} f_filter_opts; extern void f_println(char *v); -int32_t f_build_filter(int *ret_p, int fd, uint32_t arch, uint32_t multiarch, f_syscall_opts opts); \ No newline at end of file +int32_t f_build_filter(int *ret_p, int fd, uint32_t arch, uint32_t multiarch, f_filter_opts opts); \ No newline at end of file diff --git a/sandbox/seccomp/seccomp.go b/sandbox/seccomp/seccomp.go index 228c683..944d542 100644 --- a/sandbox/seccomp/seccomp.go +++ b/sandbox/seccomp/seccomp.go @@ -57,29 +57,29 @@ var resPrefix = [...]string{ 7: "seccomp_load failed", } -type SyscallOpts = C.f_syscall_opts +type FilterOpts = C.f_filter_opts const ( - flagVerbose SyscallOpts = C.F_VERBOSE - // FlagExt are project-specific extensions. - FlagExt SyscallOpts = C.F_EXT - // FlagDenyNS denies namespace setup syscalls. - FlagDenyNS SyscallOpts = C.F_DENY_NS - // FlagDenyTTY denies faking input. - FlagDenyTTY SyscallOpts = C.F_DENY_TTY - // FlagDenyDevel denies development-related syscalls. - FlagDenyDevel SyscallOpts = C.F_DENY_DEVEL - // FlagMultiarch allows multiarch/emulation. - FlagMultiarch SyscallOpts = C.F_MULTIARCH - // FlagLinux32 sets PER_LINUX32. - FlagLinux32 SyscallOpts = C.F_LINUX32 - // FlagCan allows AF_CAN. - FlagCan SyscallOpts = C.F_CAN - // FlagBluetooth allows AF_BLUETOOTH. - FlagBluetooth SyscallOpts = C.F_BLUETOOTH + filterVerbose FilterOpts = C.F_VERBOSE + // FilterExt are project-specific extensions. + FilterExt FilterOpts = C.F_EXT + // FilterDenyNS denies namespace setup syscalls. + FilterDenyNS FilterOpts = C.F_DENY_NS + // FilterDenyTTY denies faking input. + FilterDenyTTY FilterOpts = C.F_DENY_TTY + // FilterDenyDevel denies development-related syscalls. + FilterDenyDevel FilterOpts = C.F_DENY_DEVEL + // FilterMultiarch allows multiarch/emulation. + FilterMultiarch FilterOpts = C.F_MULTIARCH + // FilterLinux32 sets PER_LINUX32. + FilterLinux32 FilterOpts = C.F_LINUX32 + // FilterCan allows AF_CAN. + FilterCan FilterOpts = C.F_CAN + // FilterBluetooth allows AF_BLUETOOTH. + FilterBluetooth FilterOpts = C.F_BLUETOOTH ) -func buildFilter(fd int, opts SyscallOpts) error { +func buildFilter(fd int, opts FilterOpts) error { var ( arch C.uint32_t = 0 multiarch C.uint32_t = 0 @@ -100,7 +100,7 @@ func buildFilter(fd int, opts SyscallOpts) error { // this removes repeated transitions between C and Go execution // when producing log output via F_println and CPrintln is nil if fp := printlnP.Load(); fp != nil { - opts |= flagVerbose + opts |= filterVerbose } var ret C.int