Compare commits
No commits in common. "b8c254f4f957ebf2db67d36e9d963f83b3f0b812" and "ad6d0ee55febef84ab44ab7740267c490f5db7dd" have entirely different histories.
b8c254f4f9
...
ad6d0ee55f
@ -9,14 +9,17 @@ jobs:
|
||||
release:
|
||||
name: Create release
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: write
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
|
||||
- name: Setup go
|
||||
uses: https://github.com/actions/setup-go@v5
|
||||
with:
|
||||
go-version: '>=1.23.0'
|
||||
|
||||
- name: Install Nix
|
||||
uses: cachix/install-nix-action@v30
|
||||
uses: cachix/install-nix-action@08dcb3a5e62fa31e2da3d490afc4176ef55ecd72 # v30
|
||||
with:
|
||||
# explicitly enable sandbox
|
||||
install_options: --daemon
|
||||
@ -33,13 +36,15 @@ jobs:
|
||||
- name: Restore Nix store
|
||||
uses: nix-community/cache-nix-action@v5
|
||||
with:
|
||||
primary-key: build-dist-${{ runner.os }}-${{ hashFiles('**/*.nix') }}
|
||||
restore-prefixes-first-match: build-dist-${{ runner.os }}-
|
||||
primary-key: nix-small-${{ runner.os }}-${{ hashFiles('**/*.nix') }}
|
||||
restore-prefixes-first-match: nix-small-${{ runner.os }}-
|
||||
|
||||
- name: Build for release
|
||||
id: build-test
|
||||
run: nix build --print-out-paths --print-build-logs .#dist
|
||||
|
||||
- name: Release
|
||||
id: use-go-action
|
||||
uses: https://gitea.com/actions/release-action@main
|
||||
with:
|
||||
files: |-
|
||||
|
@ -8,14 +8,12 @@ jobs:
|
||||
test:
|
||||
name: Run NixOS test
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: write
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
|
||||
- name: Install Nix
|
||||
uses: cachix/install-nix-action@v30
|
||||
uses: cachix/install-nix-action@08dcb3a5e62fa31e2da3d490afc4176ef55ecd72 # v30
|
||||
with:
|
||||
# explicitly enable sandbox
|
||||
install_options: --daemon
|
||||
@ -55,14 +53,12 @@ jobs:
|
||||
dist:
|
||||
name: Create distribution
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: write
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
|
||||
- name: Install Nix
|
||||
uses: cachix/install-nix-action@v30
|
||||
uses: cachix/install-nix-action@08dcb3a5e62fa31e2da3d490afc4176ef55ecd72 # v30
|
||||
with:
|
||||
# explicitly enable sandbox
|
||||
install_options: --daemon
|
||||
|
12
flake.lock
generated
12
flake.lock
generated
@ -7,11 +7,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1736373539,
|
||||
"narHash": "sha256-dinzAqCjenWDxuy+MqUQq0I4zUSfaCvN9rzuCmgMZJY=",
|
||||
"lastModified": 1735344290,
|
||||
"narHash": "sha256-oJDtWPH1oJT34RJK1FSWjwX4qcGOBRkcNQPD0EbSfNM=",
|
||||
"owner": "nix-community",
|
||||
"repo": "home-manager",
|
||||
"rev": "bd65bc3cde04c16755955630b344bc9e35272c56",
|
||||
"rev": "613691f285dad87694c2ba1c9e6298d04736292d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@ -23,11 +23,11 @@
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1737672001,
|
||||
"narHash": "sha256-YnHJJ19wqmibLQdUeq9xzE6CjrMA568KN/lFPuSVs4I=",
|
||||
"lastModified": 1735326919,
|
||||
"narHash": "sha256-BZlgs4l9CXAauo78giGCZdazMMk5VZNro7o5SHFUuyE=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "035f8c0853c2977b24ffc4d0a42c74f00b182cd8",
|
||||
"rev": "8f0aa155aa29f7d2b471aa2ffd322745bf2b2036",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -28,7 +28,7 @@ struct f_syscall_act {
|
||||
#define LEN(arr) (sizeof(arr) / sizeof((arr)[0]))
|
||||
|
||||
#define SECCOMP_RULESET_ADD(ruleset) do { \
|
||||
if (opts & F_VERBOSE) F_println("adding seccomp ruleset \"" #ruleset "\""); \
|
||||
F_println("adding seccomp ruleset \"" #ruleset "\""); \
|
||||
for (int i = 0; i < LEN(ruleset); i++) { \
|
||||
assert(ruleset[i].m_errno == EPERM || ruleset[i].m_errno == ENOSYS); \
|
||||
\
|
||||
@ -89,31 +89,6 @@ int32_t f_export_bpf(int fd, uint32_t arch, uint32_t multiarch, f_syscall_opts o
|
||||
{SCMP_SYS(migrate_pages), EPERM},
|
||||
};
|
||||
|
||||
// fortify: project-specific extensions
|
||||
struct f_syscall_act deny_common_ext[] = {
|
||||
// system calls for changing the system clock
|
||||
{SCMP_SYS(adjtimex), EPERM},
|
||||
{SCMP_SYS(clock_adjtime), EPERM},
|
||||
{SCMP_SYS(clock_adjtime64), EPERM},
|
||||
{SCMP_SYS(clock_settime), EPERM},
|
||||
{SCMP_SYS(clock_settime64), EPERM},
|
||||
{SCMP_SYS(settimeofday), EPERM},
|
||||
|
||||
// loading and unloading of kernel modules
|
||||
{SCMP_SYS(delete_module), EPERM},
|
||||
{SCMP_SYS(finit_module), EPERM},
|
||||
{SCMP_SYS(init_module), EPERM},
|
||||
|
||||
// system calls for rebooting and reboot preparation
|
||||
{SCMP_SYS(kexec_file_load), EPERM},
|
||||
{SCMP_SYS(kexec_load), EPERM},
|
||||
{SCMP_SYS(reboot), EPERM},
|
||||
|
||||
// system calls for enabling/disabling swap devices
|
||||
{SCMP_SYS(swapoff), EPERM},
|
||||
{SCMP_SYS(swapon), EPERM},
|
||||
};
|
||||
|
||||
struct f_syscall_act deny_ns[] = {
|
||||
// Don't allow subnamespace setups:
|
||||
{SCMP_SYS(unshare), EPERM},
|
||||
@ -151,34 +126,6 @@ int32_t f_export_bpf(int fd, uint32_t arch, uint32_t multiarch, f_syscall_opts o
|
||||
{SCMP_SYS(mount_setattr), ENOSYS},
|
||||
};
|
||||
|
||||
// fortify: project-specific extensions
|
||||
struct f_syscall_act deny_ns_ext[] = {
|
||||
// changing file ownership
|
||||
{SCMP_SYS(chown), EPERM},
|
||||
{SCMP_SYS(chown32), EPERM},
|
||||
{SCMP_SYS(fchown), EPERM},
|
||||
{SCMP_SYS(fchown32), EPERM},
|
||||
{SCMP_SYS(fchownat), EPERM},
|
||||
{SCMP_SYS(lchown), EPERM},
|
||||
{SCMP_SYS(lchown32), EPERM},
|
||||
|
||||
// system calls for changing user ID and group ID credentials
|
||||
{SCMP_SYS(setgid), EPERM},
|
||||
{SCMP_SYS(setgid32), EPERM},
|
||||
{SCMP_SYS(setgroups), EPERM},
|
||||
{SCMP_SYS(setgroups32), EPERM},
|
||||
{SCMP_SYS(setregid), EPERM},
|
||||
{SCMP_SYS(setregid32), EPERM},
|
||||
{SCMP_SYS(setresgid), EPERM},
|
||||
{SCMP_SYS(setresgid32), EPERM},
|
||||
{SCMP_SYS(setresuid), EPERM},
|
||||
{SCMP_SYS(setresuid32), EPERM},
|
||||
{SCMP_SYS(setreuid), EPERM},
|
||||
{SCMP_SYS(setreuid32), EPERM},
|
||||
{SCMP_SYS(setuid), EPERM},
|
||||
{SCMP_SYS(setuid32), EPERM},
|
||||
};
|
||||
|
||||
struct f_syscall_act deny_tty[] = {
|
||||
// Don't allow faking input to the controlling tty (CVE-2017-5226)
|
||||
{SCMP_SYS(ioctl), EPERM, &SCMP_A1(SCMP_CMP_MASKED_EQ, 0xFFFFFFFFu, (int)TIOCSTI)},
|
||||
@ -198,22 +145,6 @@ int32_t f_export_bpf(int fd, uint32_t arch, uint32_t multiarch, f_syscall_opts o
|
||||
{SCMP_SYS(ptrace), EPERM}
|
||||
};
|
||||
|
||||
struct f_syscall_act deny_emu[] = {
|
||||
// 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.
|
||||
{SCMP_SYS(modify_ldt), EPERM},
|
||||
};
|
||||
|
||||
// fortify: project-specific extensions
|
||||
struct f_syscall_act deny_emu_ext[] = {
|
||||
{SCMP_SYS(subpage_prot), ENOSYS},
|
||||
{SCMP_SYS(switch_endian), ENOSYS},
|
||||
{SCMP_SYS(vm86), ENOSYS},
|
||||
{SCMP_SYS(vm86old), ENOSYS},
|
||||
};
|
||||
|
||||
// Blocklist all but unix, inet, inet6 and netlink
|
||||
struct
|
||||
{
|
||||
@ -268,11 +199,26 @@ int32_t f_export_bpf(int fd, uint32_t arch, uint32_t multiarch, f_syscall_opts o
|
||||
if (opts & F_DENY_NS) SECCOMP_RULESET_ADD(deny_ns);
|
||||
if (opts & F_DENY_TTY) SECCOMP_RULESET_ADD(deny_tty);
|
||||
if (opts & F_DENY_DEVEL) SECCOMP_RULESET_ADD(deny_devel);
|
||||
if (!allow_multiarch) SECCOMP_RULESET_ADD(deny_emu);
|
||||
if (opts & F_EXT) {
|
||||
SECCOMP_RULESET_ADD(deny_common_ext);
|
||||
if (opts & F_DENY_NS) SECCOMP_RULESET_ADD(deny_ns_ext);
|
||||
if (!allow_multiarch) SECCOMP_RULESET_ADD(deny_emu_ext);
|
||||
|
||||
if (!allow_multiarch) {
|
||||
F_println("disabling modify_ldt");
|
||||
|
||||
// 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.
|
||||
ret = seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EPERM), SCMP_SYS(modify_ldt), 0);
|
||||
|
||||
// See above for the meaning of EFAULT.
|
||||
if (ret == -EFAULT) {
|
||||
// call fmsg here?
|
||||
res = 4;
|
||||
goto out;
|
||||
} else if (ret < 0) {
|
||||
res = 5;
|
||||
errno = -ret;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
// Socket filtering doesn't work on e.g. i386, so ignore failures here
|
@ -8,15 +8,13 @@
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
F_VERBOSE = 1 << 0,
|
||||
F_EXT = 1 << 1,
|
||||
F_DENY_NS = 1 << 2,
|
||||
F_DENY_TTY = 1 << 3,
|
||||
F_DENY_DEVEL = 1 << 4,
|
||||
F_MULTIARCH = 1 << 5,
|
||||
F_LINUX32 = 1 << 6,
|
||||
F_CAN = 1 << 7,
|
||||
F_BLUETOOTH = 1 << 8,
|
||||
F_DENY_NS = 1 << 0,
|
||||
F_DENY_TTY = 1 << 1,
|
||||
F_DENY_DEVEL = 1 << 2,
|
||||
F_MULTIARCH = 1 << 3,
|
||||
F_LINUX32 = 1 << 4,
|
||||
F_CAN = 1 << 5,
|
||||
F_BLUETOOTH = 1 << 6,
|
||||
} f_syscall_opts;
|
||||
|
||||
extern void F_println(char *v);
|
95
helper/bwrap/seccomp-resolve.go
Normal file
95
helper/bwrap/seccomp-resolve.go
Normal file
@ -0,0 +1,95 @@
|
||||
package bwrap
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"git.gensokyo.uk/security/fortify/internal/fmsg"
|
||||
)
|
||||
|
||||
type SyscallPolicy struct {
|
||||
DenyDevel bool `json:"deny_devel"`
|
||||
Multiarch bool `json:"multiarch"`
|
||||
Linux32 bool `json:"linux32"`
|
||||
Can bool `json:"can"`
|
||||
Bluetooth bool `json:"bluetooth"`
|
||||
}
|
||||
|
||||
type seccompBuilder struct {
|
||||
config *Config
|
||||
}
|
||||
|
||||
func (s *seccompBuilder) Len() int {
|
||||
if s == nil {
|
||||
return 0
|
||||
}
|
||||
return 2
|
||||
}
|
||||
|
||||
func (s *seccompBuilder) Append(args *[]string, extraFiles *[]*os.File) error {
|
||||
if s == nil {
|
||||
return nil
|
||||
}
|
||||
if f, err := s.config.resolveSeccomp(); err != nil {
|
||||
return err
|
||||
} else {
|
||||
extraFile(args, extraFiles, positionalArgs[Seccomp], f)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Config) resolveSeccomp() (*os.File, error) {
|
||||
if c.Syscall == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// resolve seccomp filter opts
|
||||
var (
|
||||
opts syscallOpts
|
||||
optd []string
|
||||
optCond = [...]struct {
|
||||
v bool
|
||||
o syscallOpts
|
||||
d string
|
||||
}{
|
||||
{!c.UserNS, flagDenyNS, "denyns"},
|
||||
{c.NewSession, flagDenyTTY, "denytty"},
|
||||
{c.Syscall.DenyDevel, flagDenyDevel, "denydevel"},
|
||||
{c.Syscall.Multiarch, flagMultiarch, "multiarch"},
|
||||
{c.Syscall.Linux32, flagLinux32, "linux32"},
|
||||
{c.Syscall.Can, flagCan, "can"},
|
||||
{c.Syscall.Bluetooth, flagBluetooth, "bluetooth"},
|
||||
}
|
||||
)
|
||||
if CPrintln != nil {
|
||||
optd = make([]string, 1, len(optCond)+1)
|
||||
optd[0] = "common"
|
||||
}
|
||||
for _, opt := range optCond {
|
||||
if opt.v {
|
||||
opts |= opt.o
|
||||
if fmsg.Verbose() {
|
||||
optd = append(optd, opt.d)
|
||||
}
|
||||
}
|
||||
}
|
||||
if CPrintln != nil {
|
||||
CPrintln(fmt.Sprintf("seccomp flags: %s", optd))
|
||||
}
|
||||
|
||||
// export seccomp filter to tmpfile
|
||||
if f, err := tmpfile(); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return f, exportAndSeek(f, opts)
|
||||
}
|
||||
}
|
||||
|
||||
func exportAndSeek(f *os.File, opts syscallOpts) error {
|
||||
if err := exportFilter(f.Fd(), opts); err != nil {
|
||||
return err
|
||||
}
|
||||
_, err := f.Seek(0, io.SeekStart)
|
||||
return err
|
||||
}
|
@ -1,90 +1,83 @@
|
||||
package bwrap
|
||||
|
||||
/*
|
||||
#cgo linux pkg-config: --static libseccomp
|
||||
|
||||
#include "seccomp-export.h"
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"git.gensokyo.uk/security/fortify/helper/seccomp"
|
||||
"git.gensokyo.uk/security/fortify/internal/fmsg"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
type SyscallPolicy struct {
|
||||
// disable fortify extensions
|
||||
Compat bool `json:"compat"`
|
||||
// deny development syscalls
|
||||
DenyDevel bool `json:"deny_devel"`
|
||||
// deny multiarch/emulation syscalls
|
||||
Multiarch bool `json:"multiarch"`
|
||||
// allow PER_LINUX32
|
||||
Linux32 bool `json:"linux32"`
|
||||
// allow AF_CAN
|
||||
Can bool `json:"can"`
|
||||
// allow AF_BLUETOOTH
|
||||
Bluetooth bool `json:"bluetooth"`
|
||||
var CPrintln func(v ...any)
|
||||
|
||||
var resErr = [...]error{
|
||||
0: nil,
|
||||
1: errors.New("seccomp_init failed"),
|
||||
2: errors.New("seccomp_arch_add failed"),
|
||||
3: errors.New("seccomp_arch_add failed (multiarch)"),
|
||||
4: errors.New("internal libseccomp failure"),
|
||||
5: errors.New("seccomp_rule_add failed"),
|
||||
6: errors.New("seccomp_export_bpf failed"),
|
||||
}
|
||||
|
||||
type seccompBuilder struct {
|
||||
config *Config
|
||||
type (
|
||||
syscallOpts = C.f_syscall_opts
|
||||
)
|
||||
|
||||
const (
|
||||
flagDenyNS syscallOpts = C.F_DENY_NS
|
||||
flagDenyTTY syscallOpts = C.F_DENY_TTY
|
||||
flagDenyDevel syscallOpts = C.F_DENY_DEVEL
|
||||
flagMultiarch syscallOpts = C.F_MULTIARCH
|
||||
flagLinux32 syscallOpts = C.F_LINUX32
|
||||
flagCan syscallOpts = C.F_CAN
|
||||
flagBluetooth syscallOpts = C.F_BLUETOOTH
|
||||
)
|
||||
|
||||
func tmpfile() (*os.File, error) {
|
||||
fd, err := C.f_tmpfile_fd()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return os.NewFile(uintptr(fd), "tmpfile"), err
|
||||
}
|
||||
|
||||
func (s *seccompBuilder) Len() int {
|
||||
if s == nil {
|
||||
return 0
|
||||
}
|
||||
return 2
|
||||
}
|
||||
|
||||
func (s *seccompBuilder) Append(args *[]string, extraFiles *[]*os.File) error {
|
||||
if s == nil {
|
||||
return nil
|
||||
}
|
||||
if f, err := s.config.resolveSeccomp(); err != nil {
|
||||
return err
|
||||
} else {
|
||||
extraFile(args, extraFiles, positionalArgs[Seccomp], f)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Config) resolveSeccomp() (*os.File, error) {
|
||||
if c.Syscall == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// resolve seccomp filter opts
|
||||
func exportFilter(fd uintptr, opts syscallOpts) error {
|
||||
var (
|
||||
opts seccomp.SyscallOpts
|
||||
optd []string
|
||||
optCond = [...]struct {
|
||||
v bool
|
||||
o seccomp.SyscallOpts
|
||||
d string
|
||||
}{
|
||||
{!c.Syscall.Compat, seccomp.FlagExt, "fortify"},
|
||||
{!c.UserNS, seccomp.FlagDenyNS, "denyns"},
|
||||
{c.NewSession, seccomp.FlagDenyTTY, "denytty"},
|
||||
{c.Syscall.DenyDevel, seccomp.FlagDenyDevel, "denydevel"},
|
||||
{c.Syscall.Multiarch, seccomp.FlagMultiarch, "multiarch"},
|
||||
{c.Syscall.Linux32, seccomp.FlagLinux32, "linux32"},
|
||||
{c.Syscall.Can, seccomp.FlagCan, "can"},
|
||||
{c.Syscall.Bluetooth, seccomp.FlagBluetooth, "bluetooth"},
|
||||
}
|
||||
arch C.uint32_t = 0
|
||||
multiarch C.uint32_t = 0
|
||||
)
|
||||
if seccomp.CPrintln != nil {
|
||||
optd = make([]string, 1, len(optCond)+1)
|
||||
optd[0] = "common"
|
||||
}
|
||||
for _, opt := range optCond {
|
||||
if opt.v {
|
||||
opts |= opt.o
|
||||
if fmsg.Verbose() {
|
||||
optd = append(optd, opt.d)
|
||||
}
|
||||
}
|
||||
}
|
||||
if seccomp.CPrintln != nil {
|
||||
seccomp.CPrintln(fmt.Sprintf("seccomp flags: %s", optd))
|
||||
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
|
||||
}
|
||||
|
||||
return seccomp.Export(opts)
|
||||
res, err := C.f_export_bpf(C.int(fd), arch, multiarch, opts)
|
||||
if re := resErr[res]; re != nil {
|
||||
if err == nil {
|
||||
return re
|
||||
}
|
||||
return fmt.Errorf("%s: %v", re.Error(), err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
//export F_println
|
||||
func F_println(v *C.char) {
|
||||
if CPrintln != nil {
|
||||
CPrintln(C.GoString(v))
|
||||
}
|
||||
}
|
||||
|
@ -1,17 +0,0 @@
|
||||
package seccomp
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
func Export(opts SyscallOpts) (f *os.File, err error) {
|
||||
if f, err = tmpfile(); err != nil {
|
||||
return
|
||||
}
|
||||
if err = exportFilter(f.Fd(), opts); err != nil {
|
||||
return
|
||||
}
|
||||
_, err = f.Seek(0, io.SeekStart)
|
||||
return
|
||||
}
|
@ -1,89 +0,0 @@
|
||||
package seccomp
|
||||
|
||||
/*
|
||||
#cgo linux pkg-config: --static libseccomp
|
||||
|
||||
#include "seccomp-export.h"
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
var CPrintln func(v ...any)
|
||||
|
||||
var resErr = [...]error{
|
||||
0: nil,
|
||||
1: errors.New("seccomp_init failed"),
|
||||
2: errors.New("seccomp_arch_add failed"),
|
||||
3: errors.New("seccomp_arch_add failed (multiarch)"),
|
||||
4: errors.New("internal libseccomp failure"),
|
||||
5: errors.New("seccomp_rule_add failed"),
|
||||
6: errors.New("seccomp_export_bpf failed"),
|
||||
}
|
||||
|
||||
type SyscallOpts = C.f_syscall_opts
|
||||
|
||||
const (
|
||||
flagVerbose SyscallOpts = C.F_VERBOSE
|
||||
FlagExt SyscallOpts = C.F_EXT
|
||||
FlagDenyNS SyscallOpts = C.F_DENY_NS
|
||||
FlagDenyTTY SyscallOpts = C.F_DENY_TTY
|
||||
FlagDenyDevel SyscallOpts = C.F_DENY_DEVEL
|
||||
FlagMultiarch SyscallOpts = C.F_MULTIARCH
|
||||
FlagLinux32 SyscallOpts = C.F_LINUX32
|
||||
FlagCan SyscallOpts = C.F_CAN
|
||||
FlagBluetooth SyscallOpts = C.F_BLUETOOTH
|
||||
)
|
||||
|
||||
func tmpfile() (*os.File, error) {
|
||||
fd, err := C.f_tmpfile_fd()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return os.NewFile(uintptr(fd), "tmpfile"), err
|
||||
}
|
||||
|
||||
func exportFilter(fd uintptr, opts SyscallOpts) error {
|
||||
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
|
||||
}
|
||||
|
||||
// this removes repeated transitions between C and Go execution
|
||||
// when producing log output via F_println and CPrintln is nil
|
||||
if CPrintln != nil {
|
||||
opts |= flagVerbose
|
||||
}
|
||||
|
||||
res, err := C.f_export_bpf(C.int(fd), arch, multiarch, opts)
|
||||
if re := resErr[res]; re != nil {
|
||||
if err == nil {
|
||||
return re
|
||||
}
|
||||
return fmt.Errorf("%s: %v", re.Error(), err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
//export F_println
|
||||
func F_println(v *C.char) {
|
||||
if CPrintln != nil {
|
||||
CPrintln(C.GoString(v))
|
||||
}
|
||||
}
|
@ -8,7 +8,7 @@ import (
|
||||
|
||||
"git.gensokyo.uk/security/fortify/fst"
|
||||
"git.gensokyo.uk/security/fortify/helper"
|
||||
"git.gensokyo.uk/security/fortify/helper/seccomp"
|
||||
"git.gensokyo.uk/security/fortify/helper/bwrap"
|
||||
"git.gensokyo.uk/security/fortify/internal"
|
||||
"git.gensokyo.uk/security/fortify/internal/fmsg"
|
||||
"git.gensokyo.uk/security/fortify/internal/proc"
|
||||
@ -128,7 +128,7 @@ func Main() {
|
||||
|
||||
helper.BubblewrapName = payload.Exec[0] // resolved bwrap path by parent
|
||||
if fmsg.Verbose() {
|
||||
seccomp.CPrintln = fmsg.Println
|
||||
bwrap.CPrintln = fmsg.Println
|
||||
}
|
||||
if b, err := helper.NewBwrap(
|
||||
conf, innerInit,
|
||||
|
4
main.go
4
main.go
@ -16,7 +16,7 @@ import (
|
||||
|
||||
"git.gensokyo.uk/security/fortify/dbus"
|
||||
"git.gensokyo.uk/security/fortify/fst"
|
||||
"git.gensokyo.uk/security/fortify/helper/seccomp"
|
||||
"git.gensokyo.uk/security/fortify/helper/bwrap"
|
||||
"git.gensokyo.uk/security/fortify/internal"
|
||||
"git.gensokyo.uk/security/fortify/internal/app"
|
||||
"git.gensokyo.uk/security/fortify/internal/fmsg"
|
||||
@ -310,7 +310,7 @@ func runApp(config *fst.Config) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
if fmsg.Verbose() {
|
||||
seccomp.CPrintln = fmsg.Println
|
||||
bwrap.CPrintln = fmsg.Println
|
||||
}
|
||||
|
||||
// handle signals for graceful shutdown
|
||||
|
63
nixos.nix
63
nixos.nix
@ -118,46 +118,47 @@ in
|
||||
env
|
||||
;
|
||||
syscall = {
|
||||
inherit (app) compat multiarch bluetooth;
|
||||
deny_devel = !app.devel;
|
||||
inherit (app) devel multiarch bluetooth;
|
||||
};
|
||||
map_real_uid = app.mapRealUid;
|
||||
no_new_session = app.tty;
|
||||
filesystem =
|
||||
let
|
||||
bind = src: { inherit src; };
|
||||
mustBind = src: {
|
||||
inherit src;
|
||||
require = true;
|
||||
};
|
||||
devBind = src: {
|
||||
inherit src;
|
||||
dev = true;
|
||||
};
|
||||
in
|
||||
[
|
||||
(mustBind "/bin")
|
||||
(mustBind "/usr/bin")
|
||||
(mustBind "/nix/store")
|
||||
(mustBind "/run/current-system")
|
||||
(bind "/sys/block")
|
||||
(bind "/sys/bus")
|
||||
(bind "/sys/class")
|
||||
(bind "/sys/dev")
|
||||
(bind "/sys/devices")
|
||||
{ src = "/bin"; }
|
||||
{ src = "/usr/bin"; }
|
||||
{ src = "/nix/store"; }
|
||||
{ src = "/run/current-system"; }
|
||||
{
|
||||
src = "/sys/block";
|
||||
require = false;
|
||||
}
|
||||
{
|
||||
src = "/sys/bus";
|
||||
require = false;
|
||||
}
|
||||
{
|
||||
src = "/sys/class";
|
||||
require = false;
|
||||
}
|
||||
{
|
||||
src = "/sys/dev";
|
||||
require = false;
|
||||
}
|
||||
{
|
||||
src = "/sys/devices";
|
||||
require = false;
|
||||
}
|
||||
]
|
||||
++ optionals app.nix [
|
||||
(mustBind "/nix/var")
|
||||
(bind "/var/db/nix-channels")
|
||||
{ src = "/nix/var"; }
|
||||
{ src = "/var/db/nix-channels"; }
|
||||
]
|
||||
++ optionals (if app.gpu != null then app.gpu else app.capability.wayland || app.capability.x11) [
|
||||
(bind "/run/opengl-driver")
|
||||
(devBind "/dev/dri")
|
||||
(devBind "/dev/nvidiactl")
|
||||
(devBind "/dev/nvidia-modeset")
|
||||
(devBind "/dev/nvidia-uvm")
|
||||
(devBind "/dev/nvidia-uvm-tools")
|
||||
(devBind "/dev/nvidia0")
|
||||
{ src = "/run/opengl-driver"; }
|
||||
{
|
||||
src = "/dev/dri";
|
||||
dev = true;
|
||||
}
|
||||
]
|
||||
++ app.extraPaths;
|
||||
auto_etc = true;
|
||||
|
26
options.md
26
options.md
@ -36,7 +36,7 @@ package
|
||||
|
||||
|
||||
*Default:*
|
||||
` <derivation fortify-0.2.12> `
|
||||
` <derivation fortify-0.2.11> `
|
||||
|
||||
|
||||
|
||||
@ -198,30 +198,6 @@ null or string
|
||||
|
||||
|
||||
|
||||
## environment\.fortify\.apps\.\*\.compat
|
||||
|
||||
|
||||
|
||||
Whether to enable disable syscall filter extensions\.
|
||||
|
||||
|
||||
|
||||
*Type:*
|
||||
boolean
|
||||
|
||||
|
||||
|
||||
*Default:*
|
||||
` false `
|
||||
|
||||
|
||||
|
||||
*Example:*
|
||||
` true `
|
||||
|
||||
|
||||
|
||||
|
||||
## environment\.fortify\.apps\.\*\.dbus\.session
|
||||
|
||||
|
||||
|
@ -151,7 +151,6 @@ in
|
||||
default = true;
|
||||
};
|
||||
|
||||
compat = mkEnableOption "disable syscall filter extensions";
|
||||
devel = mkEnableOption "development kernel APIs";
|
||||
multiarch = mkEnableOption "multiarch kernel support";
|
||||
bluetooth = mkEnableOption "AF_BLUETOOTH socket operations";
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
buildGoModule rec {
|
||||
pname = "fortify";
|
||||
version = "0.2.12";
|
||||
version = "0.2.11";
|
||||
|
||||
src = builtins.path {
|
||||
name = "fortify-src";
|
||||
@ -63,7 +63,7 @@ buildGoModule rec {
|
||||
makeBinaryWrapper
|
||||
];
|
||||
|
||||
preBuild = ''
|
||||
preConfigure = ''
|
||||
HOME=$(mktemp -d) go generate ./...
|
||||
'';
|
||||
|
||||
|
10
test.nix
10
test.nix
@ -80,7 +80,6 @@ nixosTest {
|
||||
|
||||
mkdir -p ~/.config/sway
|
||||
sed s/Mod4/Mod1/ /etc/sway/config > ~/.config/sway/config
|
||||
echo 'output * bg ${pkgs.nixos-artwork.wallpapers.simple-light-gray.gnomeFilePath} fill' >> ~/.config/sway/config
|
||||
|
||||
sway --validate
|
||||
systemd-cat --identifier=sway sway && touch /tmp/sway-exit-ok
|
||||
@ -238,8 +237,8 @@ nixosTest {
|
||||
machine.succeed("rm -rf /tmp/src && cp -a '${self.packages.${system}.fortify.src}' /tmp/src")
|
||||
machine.succeed("fortify-fhs -c '(cd /tmp/src && go generate ./... && go test ./... && touch /tmp/success-gotest)' &> /tmp/gotest &")
|
||||
|
||||
# To check fortify's version:
|
||||
print(machine.succeed("sudo -u alice -i fortify version"))
|
||||
# To check sway's version:
|
||||
print(machine.succeed("sway --version"))
|
||||
|
||||
# Wait for Sway to complete startup:
|
||||
machine.wait_for_file("/run/user/1000/wayland-1")
|
||||
@ -255,11 +254,6 @@ nixosTest {
|
||||
print(machine.succeed("sudo -u alice -i fortify -v run -a 0 touch /tmp/success-bare"))
|
||||
machine.wait_for_file("/tmp/fortify.1000/tmpdir/0/success-bare")
|
||||
|
||||
# Verify silent output permissive defaults:
|
||||
output = machine.succeed("sudo -u alice -i fortify run -a 0 true &>/dev/stdout")
|
||||
if output != "":
|
||||
raise Exception(f"unexpected output\n{output}")
|
||||
|
||||
# Start fortify permissive defaults within Wayland session:
|
||||
fortify('-v run --wayland --dbus notify-send -a "NixOS Tests" "Test notification" "Notification from within sandbox." && touch /tmp/dbus-done')
|
||||
machine.wait_for_file("/tmp/dbus-done")
|
||||
|
Loading…
Reference in New Issue
Block a user