aboutsummaryrefslogtreecommitdiffhomepage
path: root/fst/sandbox.go
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2025-04-12 13:56:41 +0900
committerOphestra <cat@gensokyo.uk>2025-04-12 13:56:41 +0900
commit6309469e933a31a300fbf16d8e77f48dcee402d3 (patch)
tree8f8a72ee02b3ca15b104a6e55c9379e20f8d7e8a /fst/sandbox.go
parent0d7c1a9a4356614f035225aeb24e66421879a99b (diff)
app/instance: wrap internal implementation
This reduces the scope of the fst package, which was growing questionably large. Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'fst/sandbox.go')
-rw-r--r--fst/sandbox.go192
1 files changed, 0 insertions, 192 deletions
diff --git a/fst/sandbox.go b/fst/sandbox.go
index 194fcb76..c4936a2e 100644
--- a/fst/sandbox.go
+++ b/fst/sandbox.go
@@ -1,16 +1,6 @@
package fst
import (
- "errors"
- "fmt"
- "io/fs"
- "maps"
- "path"
- "slices"
- "syscall"
-
- "git.gensokyo.uk/security/fortify/dbus"
- "git.gensokyo.uk/security/fortify/sandbox"
"git.gensokyo.uk/security/fortify/sandbox/seccomp"
)
@@ -57,18 +47,6 @@ type (
Cover []string `json:"cover"`
}
- // SandboxSys encapsulates system functions used during [sandbox.Container] initialisation.
- SandboxSys interface {
- Getuid() int
- Getgid() int
- Paths() Paths
- ReadDir(name string) ([]fs.DirEntry, error)
- EvalSymlinks(path string) (string, error)
-
- Println(v ...any)
- Printf(format string, v ...any)
- }
-
// FilesystemConfig is a representation of [sandbox.BindMount].
FilesystemConfig struct {
// mount point in container, same as src if empty
@@ -83,173 +61,3 @@ type (
Must bool `json:"require,omitempty"`
}
)
-
-// ToContainer initialises [sandbox.Params] via [SandboxConfig].
-// Note that remaining container setup must be queued by the [App] implementation.
-func (s *SandboxConfig) ToContainer(sys SandboxSys, uid, gid *int) (*sandbox.Params, map[string]string, error) {
- if s == nil {
- return nil, nil, syscall.EBADE
- }
-
- container := &sandbox.Params{
- Hostname: s.Hostname,
- Ops: new(sandbox.Ops),
- Seccomp: s.Seccomp,
- }
-
- if s.Multiarch {
- container.Seccomp |= seccomp.FilterMultiarch
- }
-
- /* this is only 4 KiB of memory on a 64-bit system,
- permissive defaults on NixOS results in around 100 entries
- so this capacity should eliminate copies for most setups */
- *container.Ops = slices.Grow(*container.Ops, 1<<8)
-
- if s.Devel {
- container.Flags |= sandbox.FAllowDevel
- }
- if s.Userns {
- container.Flags |= sandbox.FAllowUserns
- }
- if s.Net {
- container.Flags |= sandbox.FAllowNet
- }
- if s.Tty {
- container.Flags |= sandbox.FAllowTTY
- }
-
- if s.MapRealUID {
- /* some programs fail to connect to dbus session running as a different uid
- so this workaround is introduced to map priv-side caller uid in container */
- container.Uid = sys.Getuid()
- *uid = container.Uid
- container.Gid = sys.Getgid()
- *gid = container.Gid
- } else {
- *uid = sandbox.OverflowUid()
- *gid = sandbox.OverflowGid()
- }
-
- container.
- Proc("/proc").
- Tmpfs(Tmp, 1<<12, 0755)
-
- if !s.Device {
- container.Dev("/dev").Mqueue("/dev/mqueue")
- } else {
- container.Bind("/dev", "/dev", sandbox.BindWritable|sandbox.BindDevice)
- }
-
- /* retrieve paths and hide them if they're made available in the sandbox;
- this feature tries to improve user experience of permissive defaults, and
- to warn about issues in custom configuration; it is NOT a security feature
- and should not be treated as such, ALWAYS be careful with what you bind */
- var hidePaths []string
- sc := sys.Paths()
- hidePaths = append(hidePaths, sc.RuntimePath, sc.SharePath)
- _, systemBusAddr := dbus.Address()
- if entries, err := dbus.Parse([]byte(systemBusAddr)); err != nil {
- return nil, nil, err
- } else {
- // there is usually only one, do not preallocate
- for _, entry := range entries {
- if entry.Method != "unix" {
- continue
- }
- for _, pair := range entry.Values {
- if pair[0] == "path" {
- if path.IsAbs(pair[1]) {
- // get parent dir of socket
- dir := path.Dir(pair[1])
- if dir == "." || dir == "/" {
- sys.Printf("dbus socket %q is in an unusual location", pair[1])
- }
- hidePaths = append(hidePaths, dir)
- } else {
- sys.Printf("dbus socket %q is not absolute", pair[1])
- }
- }
- }
- }
- }
- hidePathMatch := make([]bool, len(hidePaths))
- for i := range hidePaths {
- if err := evalSymlinks(sys, &hidePaths[i]); err != nil {
- return nil, nil, err
- }
- }
-
- for _, c := range s.Filesystem {
- if c == nil {
- continue
- }
-
- if !path.IsAbs(c.Src) {
- return nil, nil, fmt.Errorf("src path %q is not absolute", c.Src)
- }
-
- dest := c.Dst
- if c.Dst == "" {
- dest = c.Src
- } else if !path.IsAbs(dest) {
- return nil, nil, fmt.Errorf("dst path %q is not absolute", dest)
- }
-
- srcH := c.Src
- if err := evalSymlinks(sys, &srcH); err != nil {
- return nil, nil, err
- }
-
- for i := range hidePaths {
- // skip matched entries
- if hidePathMatch[i] {
- continue
- }
-
- if ok, err := deepContainsH(srcH, hidePaths[i]); err != nil {
- return nil, nil, err
- } else if ok {
- hidePathMatch[i] = true
- sys.Printf("hiding paths from %q", c.Src)
- }
- }
-
- var flags int
- if c.Write {
- flags |= sandbox.BindWritable
- }
- if c.Device {
- flags |= sandbox.BindDevice | sandbox.BindWritable
- }
- if !c.Must {
- flags |= sandbox.BindOptional
- }
- container.Bind(c.Src, dest, flags)
- }
-
- // cover matched paths
- for i, ok := range hidePathMatch {
- if ok {
- container.Tmpfs(hidePaths[i], 1<<13, 0755)
- }
- }
-
- for _, l := range s.Link {
- container.Link(l[0], l[1])
- }
-
- return container, maps.Clone(s.Env), nil
-}
-
-func evalSymlinks(sys SandboxSys, v *string) error {
- if p, err := sys.EvalSymlinks(*v); err != nil {
- if !errors.Is(err, fs.ErrNotExist) {
- return err
- }
- sys.Printf("path %q does not yet exist", *v)
- } else {
- *v = p
- }
- return nil
-}