aboutsummaryrefslogtreecommitdiffhomepage
path: root/internal
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2025-03-17 02:31:46 +0900
committerOphestra <cat@gensokyo.uk>2025-03-17 02:44:07 +0900
commit9a1f8e129fe0f9919981b8a1d345a9b455bd76de (patch)
treee52f33a3908c256aebb30f059cabd40f371a886f /internal
parentee108603572101ad3c285830e04ee248916b6c5d (diff)
sandbox: wrap fmsg interface
Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'internal')
-rw-r--r--internal/app/init0/main.go5
-rw-r--r--internal/app/seal.go4
-rw-r--r--internal/app/shim/main.go3
-rw-r--r--internal/fmsg/msg.go12
-rw-r--r--internal/output.go4
-rw-r--r--internal/prctl.go25
-rw-r--r--internal/sandbox/container.go18
-rw-r--r--internal/sandbox/container_test.go7
-rw-r--r--internal/sandbox/executable.go (renamed from internal/executable.go)6
-rw-r--r--internal/sandbox/executable_test.go (renamed from internal/executable_test.go)6
-rw-r--r--internal/sandbox/init.go50
-rw-r--r--internal/sandbox/mount.go26
-rw-r--r--internal/sandbox/msg.go43
-rw-r--r--internal/sandbox/output.go19
-rw-r--r--internal/sandbox/path.go4
-rw-r--r--internal/sandbox/sequential.go24
-rw-r--r--internal/sandbox/syscall.go (renamed from internal/file.go)24
-rw-r--r--internal/sys/std.go3
18 files changed, 177 insertions, 106 deletions
diff --git a/internal/app/init0/main.go b/internal/app/init0/main.go
index fe2f9aef..83033134 100644
--- a/internal/app/init0/main.go
+++ b/internal/app/init0/main.go
@@ -12,6 +12,7 @@ import (
"git.gensokyo.uk/security/fortify/helper/proc"
"git.gensokyo.uk/security/fortify/internal"
"git.gensokyo.uk/security/fortify/internal/fmsg"
+ "git.gensokyo.uk/security/fortify/internal/sandbox"
)
const (
@@ -28,7 +29,7 @@ func Main() {
fmsg.Prepare("init0")
// setting this prevents ptrace
- if err := internal.SetDumpable(internal.SUID_DUMP_DISABLE); err != nil {
+ if err := sandbox.SetDumpable(sandbox.SUID_DUMP_DISABLE); err != nil {
log.Fatalf("cannot set SUID_DUMP_DISABLE: %s", err)
}
@@ -64,7 +65,7 @@ func Main() {
}
// die with parent
- if err := internal.SetPdeathsig(syscall.SIGKILL); err != nil {
+ if err := sandbox.SetPdeathsig(syscall.SIGKILL); err != nil {
log.Fatalf("prctl(PR_SET_PDEATHSIG, SIGKILL): %v", err)
}
diff --git a/internal/app/seal.go b/internal/app/seal.go
index 7c4ba4b7..30702124 100644
--- a/internal/app/seal.go
+++ b/internal/app/seal.go
@@ -231,10 +231,6 @@ func (seal *outcome) finalise(sys sys.State, config *fst.Config) error {
sc := sys.Paths()
seal.runDirPath = sc.RunDirPath
seal.sys = system.New(seal.user.uid.unwrap())
- seal.sys.IsVerbose = fmsg.Load
- seal.sys.Verbose = fmsg.Verbose
- seal.sys.Verbosef = fmsg.Verbosef
- seal.sys.WrapErr = fmsg.WrapError
/*
Work directories
diff --git a/internal/app/shim/main.go b/internal/app/shim/main.go
index 64df53d0..effa6b84 100644
--- a/internal/app/shim/main.go
+++ b/internal/app/shim/main.go
@@ -17,6 +17,7 @@ import (
"git.gensokyo.uk/security/fortify/internal"
"git.gensokyo.uk/security/fortify/internal/app/init0"
"git.gensokyo.uk/security/fortify/internal/fmsg"
+ "git.gensokyo.uk/security/fortify/internal/sandbox"
)
// everything beyond this point runs as unconstrained target user
@@ -28,7 +29,7 @@ func Main() {
fmsg.Prepare("shim")
// setting this prevents ptrace
- if err := internal.SetDumpable(internal.SUID_DUMP_DISABLE); err != nil {
+ if err := sandbox.SetDumpable(sandbox.SUID_DUMP_DISABLE); err != nil {
log.Fatalf("cannot set SUID_DUMP_DISABLE: %s", err)
}
diff --git a/internal/fmsg/msg.go b/internal/fmsg/msg.go
new file mode 100644
index 00000000..7ff42b75
--- /dev/null
+++ b/internal/fmsg/msg.go
@@ -0,0 +1,12 @@
+package fmsg
+
+type Output struct{}
+
+func (Output) IsVerbose() bool { return Load() }
+func (Output) Verbose(v ...any) { Verbose(v...) }
+func (Output) Verbosef(format string, v ...any) { Verbosef(format, v...) }
+func (Output) WrapErr(err error, a ...any) error { return WrapError(err, a...) }
+func (Output) PrintBaseErr(err error, fallback string) { PrintBaseError(err, fallback) }
+func (Output) Suspend() { Suspend() }
+func (Output) Resume() bool { return Resume() }
+func (Output) BeforeExit() { BeforeExit() }
diff --git a/internal/output.go b/internal/output.go
index db37f55c..c85f1b51 100644
--- a/internal/output.go
+++ b/internal/output.go
@@ -2,11 +2,15 @@ package internal
import (
"git.gensokyo.uk/security/fortify/internal/fmsg"
+ "git.gensokyo.uk/security/fortify/internal/sandbox"
"git.gensokyo.uk/security/fortify/seccomp"
+ "git.gensokyo.uk/security/fortify/system"
)
func InstallFmsg(verbose bool) {
fmsg.Store(verbose)
+ sandbox.SetOutput(fmsg.Output{})
+ system.SetOutput(fmsg.Output{})
if verbose {
seccomp.SetOutput(fmsg.Verbose)
}
diff --git a/internal/prctl.go b/internal/prctl.go
deleted file mode 100644
index ae8392a6..00000000
--- a/internal/prctl.go
+++ /dev/null
@@ -1,25 +0,0 @@
-package internal
-
-import "syscall"
-
-const (
- SUID_DUMP_DISABLE = iota
- SUID_DUMP_USER
-)
-
-func SetDumpable(dumpable uintptr) error {
- // linux/sched/coredump.h
- if _, _, errno := syscall.RawSyscall(syscall.SYS_PRCTL, syscall.PR_SET_DUMPABLE, dumpable, 0); errno != 0 {
- return errno
- }
-
- return nil
-}
-
-func SetPdeathsig(sig syscall.Signal) error {
- if _, _, errno := syscall.RawSyscall(syscall.SYS_PRCTL, syscall.PR_SET_PDEATHSIG, uintptr(sig), 0); errno != 0 {
- return errno
- }
-
- return nil
-}
diff --git a/internal/sandbox/container.go b/internal/sandbox/container.go
index 2cd64ebf..f243ffd9 100644
--- a/internal/sandbox/container.go
+++ b/internal/sandbox/container.go
@@ -14,8 +14,6 @@ import (
"time"
"git.gensokyo.uk/security/fortify/helper/proc"
- "git.gensokyo.uk/security/fortify/internal"
- "git.gensokyo.uk/security/fortify/internal/fmsg"
"git.gensokyo.uk/security/fortify/seccomp"
)
@@ -139,7 +137,7 @@ func (p *Container) Start() error {
if p.CommandContext != nil {
p.cmd = p.CommandContext(ctx)
} else {
- p.cmd = exec.CommandContext(ctx, internal.MustExecutable())
+ p.cmd = exec.CommandContext(ctx, MustExecutable())
p.cmd.Args = []string{"init"}
}
@@ -166,7 +164,7 @@ func (p *Container) Start() error {
// place setup pipe before user supplied extra files, this is later restored by init
if fd, e, err := proc.Setup(&p.cmd.ExtraFiles); err != nil {
- return fmsg.WrapErrorSuffix(err,
+ return wrapErrSuffix(err,
"cannot create shim setup pipe:")
} else {
p.setup = e
@@ -174,9 +172,9 @@ func (p *Container) Start() error {
}
p.cmd.ExtraFiles = append(p.cmd.ExtraFiles, p.ExtraFiles...)
- fmsg.Verbose("starting container init")
+ msg.Verbose("starting container init")
if err := p.cmd.Start(); err != nil {
- return fmsg.WrapError(err, err.Error())
+ return msg.WrapErr(err, err.Error())
}
return nil
}
@@ -187,7 +185,7 @@ func (p *Container) Serve() error {
}
if p.Path != "" && !path.IsAbs(p.Path) {
- return fmsg.WrapError(syscall.EINVAL,
+ return msg.WrapErr(syscall.EINVAL,
fmt.Sprintf("invalid executable path %q", p.Path))
}
@@ -195,14 +193,14 @@ func (p *Container) Serve() error {
if p.name == "" {
p.Path = os.Getenv("SHELL")
if !path.IsAbs(p.Path) {
- return fmsg.WrapError(syscall.EBADE,
+ return msg.WrapErr(syscall.EBADE,
"no command specified and $SHELL is invalid")
}
p.name = path.Base(p.Path)
} else if path.IsAbs(p.name) {
p.Path = p.name
} else if v, err := exec.LookPath(p.name); err != nil {
- return fmsg.WrapError(err, err.Error())
+ return msg.WrapErr(err, err.Error())
} else {
p.Path = v
}
@@ -216,7 +214,7 @@ func (p *Container) Serve() error {
syscall.Getuid(),
syscall.Getgid(),
len(p.ExtraFiles),
- fmsg.Load(),
+ msg.IsVerbose(),
},
)
}
diff --git a/internal/sandbox/container_test.go b/internal/sandbox/container_test.go
index 1a629d99..55df60b2 100644
--- a/internal/sandbox/container_test.go
+++ b/internal/sandbox/container_test.go
@@ -23,8 +23,10 @@ import (
func TestContainer(t *testing.T) {
{
oldVerbose := fmsg.Load()
- fmsg.Store(true)
+ oldOutput := sandbox.GetOutput()
+ internal.InstallFmsg(true)
t.Cleanup(func() { fmsg.Store(oldVerbose) })
+ t.Cleanup(func() { sandbox.SetOutput(oldOutput) })
}
testCases := []struct {
@@ -146,7 +148,8 @@ func TestHelperInit(t *testing.T) {
if len(os.Args) != 5 || os.Args[4] != "init" {
return
}
- sandbox.Init(internal.Exit)
+ sandbox.SetOutput(fmsg.Output{})
+ sandbox.Init(fmsg.Prepare, internal.InstallFmsg)
}
func TestHelperCheckContainer(t *testing.T) {
diff --git a/internal/executable.go b/internal/sandbox/executable.go
index 381a09b5..5f73d238 100644
--- a/internal/executable.go
+++ b/internal/sandbox/executable.go
@@ -1,11 +1,9 @@
-package internal
+package sandbox
import (
"log"
"os"
"sync"
-
- "git.gensokyo.uk/security/fortify/internal/fmsg"
)
var (
@@ -15,7 +13,7 @@ var (
func copyExecutable() {
if name, err := os.Executable(); err != nil {
- fmsg.BeforeExit()
+ msg.BeforeExit()
log.Fatalf("cannot read executable path: %v", err)
} else {
executable = name
diff --git a/internal/executable_test.go b/internal/sandbox/executable_test.go
index 1fdd40a2..b11908c5 100644
--- a/internal/executable_test.go
+++ b/internal/sandbox/executable_test.go
@@ -1,15 +1,15 @@
-package internal_test
+package sandbox_test
import (
"os"
"testing"
- "git.gensokyo.uk/security/fortify/internal"
+ "git.gensokyo.uk/security/fortify/internal/sandbox"
)
func TestExecutable(t *testing.T) {
for i := 0; i < 16; i++ {
- if got := internal.MustExecutable(); got != os.Args[0] {
+ if got := sandbox.MustExecutable(); got != os.Args[0] {
t.Errorf("MustExecutable: %q, want %q",
got, os.Args[0])
}
diff --git a/internal/sandbox/init.go b/internal/sandbox/init.go
index 85fcb13c..058fe9a2 100644
--- a/internal/sandbox/init.go
+++ b/internal/sandbox/init.go
@@ -14,8 +14,6 @@ import (
"time"
"git.gensokyo.uk/security/fortify/helper/proc"
- "git.gensokyo.uk/security/fortify/internal"
- "git.gensokyo.uk/security/fortify/internal/fmsg"
"git.gensokyo.uk/security/fortify/seccomp"
)
@@ -40,9 +38,9 @@ type initParams struct {
Verbose bool
}
-func Init(exit func(code int)) {
+func Init(prepare func(prefix string), setVerbose func(verbose bool)) {
runtime.LockOSThread()
- fmsg.Prepare("init")
+ prepare("init")
if os.Getpid() != 1 {
log.Fatal("this process must run as pid 1")
@@ -72,14 +70,14 @@ func Init(exit func(code int)) {
log.Fatal("invalid setup parameters")
}
- internal.InstallFmsg(params.Verbose)
- fmsg.Verbose("received setup parameters")
+ setVerbose(params.Verbose)
+ msg.Verbose("received setup parameters")
closeSetup = f
offsetSetup = int(setupFile.Fd() + 1)
}
// write uid/gid map here so parent does not need to set dumpable
- if err := internal.SetDumpable(internal.SUID_DUMP_USER); err != nil {
+ if err := SetDumpable(SUID_DUMP_USER); err != nil {
log.Fatalf("cannot set SUID_DUMP_USER: %s", err)
}
if err := os.WriteFile("/proc/self/uid_map",
@@ -97,7 +95,7 @@ func Init(exit func(code int)) {
0); err != nil {
log.Fatalf("%v", err)
}
- if err := internal.SetDumpable(internal.SUID_DUMP_DISABLE); err != nil {
+ if err := SetDumpable(SUID_DUMP_DISABLE); err != nil {
log.Fatalf("cannot set SUID_DUMP_DISABLE: %s", err)
}
@@ -146,11 +144,12 @@ func Init(exit func(code int)) {
}
for i, op := range *params.Ops {
- fmsg.Verbosef("mounting %s", op)
+ msg.Verbosef("mounting %s", op)
if err := op.apply(&params.InitParams); err != nil {
- fmsg.PrintBaseError(err,
+ msg.PrintBaseErr(err,
fmt.Sprintf("cannot apply op %d:", i))
- exit(1)
+ msg.BeforeExit()
+ os.Exit(1)
}
}
@@ -169,7 +168,7 @@ func Init(exit func(code int)) {
{
var fd int
- if err := internal.IgnoringEINTR(func() (err error) {
+ if err := IgnoringEINTR(func() (err error) {
fd, err = syscall.Open("/", syscall.O_DIRECTORY|syscall.O_RDONLY, 0)
return
}); err != nil {
@@ -234,7 +233,7 @@ func Init(exit func(code int)) {
if err := cmd.Start(); err != nil {
log.Fatalf("%v", err)
}
- fmsg.Suspend()
+ msg.Suspend()
/*
close setup pipe
@@ -295,16 +294,17 @@ func Init(exit func(code int)) {
for {
select {
case s := <-sig:
- if fmsg.Resume() {
- fmsg.Verbosef("terminating on %s after process start", s.String())
+ if msg.Resume() {
+ msg.Verbosef("terminating on %s after process start", s.String())
} else {
- fmsg.Verbosef("terminating on %s", s.String())
+ msg.Verbosef("terminating on %s", s.String())
}
- exit(0)
+ msg.BeforeExit()
+ os.Exit(0)
case w := <-info:
if w.wpid == cmd.Process.Pid {
// initial process exited, output is most likely available again
- fmsg.Resume()
+ msg.Resume()
switch {
case w.wstatus.Exited():
@@ -321,18 +321,22 @@ func Init(exit func(code int)) {
}()
}
case <-done:
- exit(r)
+ msg.BeforeExit()
+ os.Exit(r)
case <-timeout:
log.Println("timeout exceeded waiting for lingering processes")
- exit(r)
+ msg.BeforeExit()
+ os.Exit(r)
}
}
}
// TryArgv0 calls [Init] if the last element of argv0 is "init".
-func TryArgv0() {
+func TryArgv0(v Msg, prepare func(prefix string), setVerbose func(verbose bool)) {
if len(os.Args) > 0 && path.Base(os.Args[0]) == "init" {
- Init(internal.Exit)
- internal.Exit(0)
+ msg = v
+ Init(prepare, setVerbose)
+ msg.BeforeExit()
+ os.Exit(0)
}
}
diff --git a/internal/sandbox/mount.go b/internal/sandbox/mount.go
index eaede7b4..e47e7f5d 100644
--- a/internal/sandbox/mount.go
+++ b/internal/sandbox/mount.go
@@ -6,8 +6,6 @@ import (
"os"
"strings"
"syscall"
-
- "git.gensokyo.uk/security/fortify/internal/fmsg"
)
const (
@@ -30,34 +28,34 @@ func bindMount(src, dest string, flags int) error {
if flags&BindOptional != 0 {
return nil
} else {
- return fmsg.WrapError(err,
+ return msg.WrapErr(err,
fmt.Sprintf("path %q does not exist", src))
}
}
- return fmsg.WrapError(err, err.Error())
+ return msg.WrapErr(err, err.Error())
} else {
source = toHost(rp)
}
} else if flags&BindOptional != 0 {
- return fmsg.WrapError(syscall.EINVAL,
+ return msg.WrapErr(syscall.EINVAL,
"flag source excludes optional")
} else {
source = toHost(src)
}
if fi, err := os.Stat(source); err != nil {
- return fmsg.WrapError(err, err.Error())
+ return msg.WrapErr(err, err.Error())
} else if fi.IsDir() {
if err = os.MkdirAll(target, 0755); err != nil {
- return fmsg.WrapErrorSuffix(err,
+ return wrapErrSuffix(err,
fmt.Sprintf("cannot create directory %q:", dest))
}
} else if err = ensureFile(target, 0444); err != nil {
if errors.Is(err, syscall.EISDIR) {
- return fmsg.WrapError(err,
+ return msg.WrapErr(err,
fmt.Sprintf("path %q is a directory", dest))
}
- return fmsg.WrapErrorSuffix(err,
+ return wrapErrSuffix(err,
fmt.Sprintf("cannot create %q:", dest))
}
@@ -71,14 +69,14 @@ func bindMount(src, dest string, flags int) error {
if flags&BindDevices == 0 {
mf |= syscall.MS_NODEV
}
- if fmsg.Load() {
+ if msg.IsVerbose() {
if strings.TrimPrefix(source, hostPath) == strings.TrimPrefix(target, sysrootPath) {
- fmsg.Verbosef("resolved %q flags %#x", target, mf)
+ msg.Verbosef("resolved %q flags %#x", target, mf)
} else {
- fmsg.Verbosef("resolved %q on %q flags %#x", source, target, mf)
+ msg.Verbosef("resolved %q on %q flags %#x", source, target, mf)
}
}
- return fmsg.WrapErrorSuffix(syscall.Mount(source, target, "", mf, ""),
+ return wrapErrSuffix(syscall.Mount(source, target, "", mf, ""),
fmt.Sprintf("cannot bind %q on %q:", src, dest))
}
@@ -91,7 +89,7 @@ func mountTmpfs(fsname, name string, size int, perm os.FileMode) error {
if size > 0 {
opt += fmt.Sprintf(",size=%d", size)
}
- return fmsg.WrapErrorSuffix(syscall.Mount(fsname, target, "tmpfs",
+ return wrapErrSuffix(syscall.Mount(fsname, target, "tmpfs",
syscall.MS_NOSUID|syscall.MS_NODEV, opt),
fmt.Sprintf("cannot mount tmpfs on %q:", name))
}
diff --git a/internal/sandbox/msg.go b/internal/sandbox/msg.go
new file mode 100644
index 00000000..5ee18509
--- /dev/null
+++ b/internal/sandbox/msg.go
@@ -0,0 +1,43 @@
+package sandbox
+
+import (
+ "log"
+ "sync/atomic"
+)
+
+type Msg interface {
+ IsVerbose() bool
+ Verbose(v ...any)
+ Verbosef(format string, v ...any)
+ WrapErr(err error, a ...any) error
+ PrintBaseErr(err error, fallback string)
+
+ Suspend()
+ Resume() bool
+
+ BeforeExit()
+}
+
+type DefaultMsg struct{ inactive atomic.Bool }
+
+func (msg *DefaultMsg) IsVerbose() bool { return true }
+func (msg *DefaultMsg) Verbose(v ...any) {
+ if !msg.inactive.Load() {
+ log.Println(v...)
+ }
+}
+func (msg *DefaultMsg) Verbosef(format string, v ...any) {
+ if !msg.inactive.Load() {
+ log.Printf(format, v...)
+ }
+}
+
+func (msg *DefaultMsg) WrapErr(err error, a ...any) error {
+ log.Println(a...)
+ return err
+}
+func (msg *DefaultMsg) PrintBaseErr(err error, fallback string) { log.Println(fallback, err) }
+
+func (msg *DefaultMsg) Suspend() { msg.inactive.Store(true) }
+func (msg *DefaultMsg) Resume() bool { return msg.inactive.CompareAndSwap(true, false) }
+func (msg *DefaultMsg) BeforeExit() {}
diff --git a/internal/sandbox/output.go b/internal/sandbox/output.go
new file mode 100644
index 00000000..de4a104a
--- /dev/null
+++ b/internal/sandbox/output.go
@@ -0,0 +1,19 @@
+package sandbox
+
+var msg Msg = new(DefaultMsg)
+
+func GetOutput() Msg { return msg }
+func SetOutput(v Msg) {
+ if v == nil {
+ msg = new(DefaultMsg)
+ } else {
+ msg = v
+ }
+}
+
+func wrapErrSuffix(err error, a ...any) error {
+ if err == nil {
+ return nil
+ }
+ return msg.WrapErr(err, append(a, err)...)
+}
diff --git a/internal/sandbox/path.go b/internal/sandbox/path.go
index 0d49afa0..6c5a6e2c 100644
--- a/internal/sandbox/path.go
+++ b/internal/sandbox/path.go
@@ -7,8 +7,6 @@ import (
"path"
"strings"
"syscall"
-
- "git.gensokyo.uk/security/fortify/internal/fmsg"
)
const (
@@ -43,7 +41,7 @@ func realpathHost(name string) (string, error) {
if !path.IsAbs(rp) {
return name, nil
}
- fmsg.Verbosef("path %q resolves to %q", name, rp)
+ msg.Verbosef("path %q resolves to %q", name, rp)
return rp, nil
}
diff --git a/internal/sandbox/sequential.go b/internal/sandbox/sequential.go
index 93cc74c3..aa4bb18e 100644
--- a/internal/sandbox/sequential.go
+++ b/internal/sandbox/sequential.go
@@ -8,8 +8,6 @@ import (
"path"
"syscall"
"unsafe"
-
- "git.gensokyo.uk/security/fortify/internal/fmsg"
)
func init() { gob.Register(new(BindMount)) }
@@ -23,7 +21,7 @@ type BindMount struct {
func (b *BindMount) apply(*InitParams) error {
if !path.IsAbs(b.Source) || !path.IsAbs(b.Target) {
- return fmsg.WrapError(syscall.EBADE,
+ return msg.WrapErr(syscall.EBADE,
"path is not absolute")
}
return bindMount(b.Source, b.Target, b.Flags)
@@ -50,15 +48,15 @@ type MountProc struct {
func (p *MountProc) apply(*InitParams) error {
if !path.IsAbs(p.Path) {
- return fmsg.WrapError(syscall.EBADE,
+ return msg.WrapErr(syscall.EBADE,
fmt.Sprintf("path %q is not absolute", p.Path))
}
target := toSysroot(p.Path)
if err := os.MkdirAll(target, 0755); err != nil {
- return fmsg.WrapError(err, err.Error())
+ return msg.WrapErr(err, err.Error())
}
- return fmsg.WrapErrorSuffix(syscall.Mount("proc", target, "proc",
+ return wrapErrSuffix(syscall.Mount("proc", target, "proc",
syscall.MS_NOSUID|syscall.MS_NOEXEC|syscall.MS_NODEV, ""),
fmt.Sprintf("cannot mount proc on %q:", p.Path))
}
@@ -72,7 +70,7 @@ type MountDev struct {
func (d *MountDev) apply(params *InitParams) error {
if !path.IsAbs(d.Path) {
- return fmsg.WrapError(syscall.EBADE,
+ return msg.WrapErr(syscall.EBADE,
fmt.Sprintf("path %q is not absolute", d.Path))
}
target := toSysroot(d.Path)
@@ -94,7 +92,7 @@ func (d *MountDev) apply(params *InitParams) error {
"/proc/self/fd/"+string(rune(i+'0')),
path.Join(target, name),
); err != nil {
- return fmsg.WrapError(err, err.Error())
+ return msg.WrapErr(err, err.Error())
}
}
for _, pair := range [][2]string{
@@ -103,21 +101,21 @@ func (d *MountDev) apply(params *InitParams) error {
{"pts/ptmx", "ptmx"},
} {
if err := os.Symlink(pair[0], path.Join(target, pair[1])); err != nil {
- return fmsg.WrapError(err, err.Error())
+ return msg.WrapErr(err, err.Error())
}
}
devPtsPath := path.Join(target, "pts")
for _, name := range []string{path.Join(target, "shm"), devPtsPath} {
if err := os.Mkdir(name, 0755); err != nil {
- return fmsg.WrapError(err, err.Error())
+ return msg.WrapErr(err, err.Error())
}
}
if err := syscall.Mount("devpts", devPtsPath, "devpts",
syscall.MS_NOSUID|syscall.MS_NOEXEC,
"newinstance,ptmxmode=0666,mode=620"); err != nil {
- return fmsg.WrapErrorSuffix(err,
+ return wrapErrSuffix(err,
fmt.Sprintf("cannot mount devpts on %q:", devPtsPath))
}
@@ -164,11 +162,11 @@ type MountTmpfs struct {
func (t *MountTmpfs) apply(*InitParams) error {
if !path.IsAbs(t.Path) {
- return fmsg.WrapError(syscall.EBADE,
+ return msg.WrapErr(syscall.EBADE,
fmt.Sprintf("path %q is not absolute", t.Path))
}
if t.Size < 0 || t.Size > math.MaxUint>>1 {
- return fmsg.WrapError(syscall.EBADE,
+ return msg.WrapErr(syscall.EBADE,
fmt.Sprintf("size %d out of bounds", t.Size))
}
return mountTmpfs("tmpfs", t.Path, t.Size, t.Perm)
diff --git a/internal/file.go b/internal/sandbox/syscall.go
index 153f0f99..a17928f7 100644
--- a/internal/file.go
+++ b/internal/sandbox/syscall.go
@@ -1,7 +1,29 @@
-package internal
+package sandbox
import "syscall"
+const (
+ SUID_DUMP_DISABLE = iota
+ SUID_DUMP_USER
+)
+
+func SetDumpable(dumpable uintptr) error {
+ // linux/sched/coredump.h
+ if _, _, errno := syscall.RawSyscall(syscall.SYS_PRCTL, syscall.PR_SET_DUMPABLE, dumpable, 0); errno != 0 {
+ return errno
+ }
+
+ return nil
+}
+
+func SetPdeathsig(sig syscall.Signal) error {
+ if _, _, errno := syscall.RawSyscall(syscall.SYS_PRCTL, syscall.PR_SET_PDEATHSIG, uintptr(sig), 0); errno != 0 {
+ return errno
+ }
+
+ return nil
+}
+
// IgnoringEINTR makes a function call and repeats it if it returns an
// EINTR error. This appears to be required even though we install all
// signal handlers with SA_RESTART: see #22838, #38033, #38836, #40846.
diff --git a/internal/sys/std.go b/internal/sys/std.go
index d447f586..0145eb23 100644
--- a/internal/sys/std.go
+++ b/internal/sys/std.go
@@ -15,6 +15,7 @@ import (
"git.gensokyo.uk/security/fortify/fst"
"git.gensokyo.uk/security/fortify/internal"
"git.gensokyo.uk/security/fortify/internal/fmsg"
+ "git.gensokyo.uk/security/fortify/internal/sandbox"
)
// Std implements System using the standard library.
@@ -34,7 +35,7 @@ func (s *Std) Geteuid() int { return os.Geteuid(
func (s *Std) LookupEnv(key string) (string, bool) { return os.LookupEnv(key) }
func (s *Std) TempDir() string { return os.TempDir() }
func (s *Std) LookPath(file string) (string, error) { return exec.LookPath(file) }
-func (s *Std) MustExecutable() string { return internal.MustExecutable() }
+func (s *Std) MustExecutable() string { return sandbox.MustExecutable() }
func (s *Std) LookupGroup(name string) (*user.Group, error) { return user.LookupGroup(name) }
func (s *Std) ReadDir(name string) ([]os.DirEntry, error) { return os.ReadDir(name) }
func (s *Std) Stat(name string) (fs.FileInfo, error) { return os.Stat(name) }