aboutsummaryrefslogtreecommitdiffhomepage
path: root/fst
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2025-01-15 09:42:44 +0900
committerOphestra <cat@gensokyo.uk>2025-01-15 09:42:44 +0900
commitdb03565614821695efdb283a81a4733e6d321670 (patch)
treecb0cfea6467d29b80d068d756517de11b4f49e48 /fst
parent7d99e45b88deb3998542270b7f8469de5f25109a (diff)
fst: move sandbox struct to separate file
Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'fst')
-rw-r--r--fst/config.go131
-rw-r--r--fst/sandbox.go135
2 files changed, 135 insertions, 131 deletions
diff --git a/fst/config.go b/fst/config.go
index 8827b291..7075c6a0 100644
--- a/fst/config.go
+++ b/fst/config.go
@@ -1,11 +1,7 @@
package fst
import (
- "errors"
-
"git.gensokyo.uk/security/fortify/dbus"
- "git.gensokyo.uk/security/fortify/helper/bwrap"
- "git.gensokyo.uk/security/fortify/internal/linux"
"git.gensokyo.uk/security/fortify/internal/system"
)
@@ -49,37 +45,6 @@ type ConfinementConfig struct {
Enablements system.Enablements `json:"enablements"`
}
-// SandboxConfig describes resources made available to the sandbox.
-type SandboxConfig struct {
- // unix hostname within sandbox
- Hostname string `json:"hostname,omitempty"`
- // allow userns within sandbox
- UserNS bool `json:"userns,omitempty"`
- // share net namespace
- Net bool `json:"net,omitempty"`
- // share all devices
- Dev bool `json:"dev,omitempty"`
- // do not run in new session
- NoNewSession bool `json:"no_new_session,omitempty"`
- // map target user uid to privileged user uid in the user namespace
- MapRealUID bool `json:"map_real_uid"`
- // direct access to wayland socket
- DirectWayland bool `json:"direct_wayland,omitempty"`
-
- // final environment variables
- Env map[string]string `json:"env"`
- // sandbox host filesystem access
- Filesystem []*FilesystemConfig `json:"filesystem"`
- // symlinks created inside the sandbox
- Link [][2]string `json:"symlink"`
- // read-only /etc directory
- Etc string `json:"etc,omitempty"`
- // automatically set up /etc symlinks
- AutoEtc bool `json:"auto_etc"`
- // paths to override by mounting tmpfs over them
- Override []string `json:"override"`
-}
-
type ExtraPermConfig struct {
Ensure bool `json:"ensure,omitempty"`
Path string `json:"path"`
@@ -121,102 +86,6 @@ type FilesystemConfig struct {
Must bool `json:"require,omitempty"`
}
-// Bwrap returns the address of the corresponding bwrap.Config to s.
-// Note that remaining tmpfs entries must be queued by the caller prior to launch.
-func (s *SandboxConfig) Bwrap(os linux.System) (*bwrap.Config, error) {
- if s == nil {
- return nil, errors.New("nil sandbox config")
- }
-
- var uid int
- if !s.MapRealUID {
- uid = 65534
- } else {
- uid = os.Geteuid()
- }
-
- conf := (&bwrap.Config{
- Net: s.Net,
- UserNS: s.UserNS,
- Hostname: s.Hostname,
- Clearenv: true,
- SetEnv: s.Env,
-
- /* 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 */
- Filesystem: make([]bwrap.FSBuilder, 0, 256),
-
- NewSession: !s.NoNewSession,
- DieWithParent: true,
- AsInit: true,
-
- // initialise map
- Chmod: make(bwrap.ChmodConfig),
- }).
- SetUID(uid).SetGID(uid).
- Procfs("/proc").
- Tmpfs(Tmp, 4*1024)
-
- if !s.Dev {
- conf.DevTmpfs("/dev").Mqueue("/dev/mqueue")
- } else {
- conf.Bind("/dev", "/dev", false, true, true)
- }
-
- if !s.AutoEtc {
- if s.Etc == "" {
- conf.Dir("/etc")
- } else {
- conf.Bind(s.Etc, "/etc")
- }
- }
-
- for _, c := range s.Filesystem {
- if c == nil {
- continue
- }
- src := c.Src
- dest := c.Dst
- if c.Dst == "" {
- dest = c.Src
- }
- conf.Bind(src, dest, !c.Must, c.Write, c.Device)
- }
-
- for _, l := range s.Link {
- conf.Symlink(l[0], l[1])
- }
-
- if s.AutoEtc {
- etc := s.Etc
- if etc == "" {
- etc = "/etc"
- }
- conf.Bind(etc, Tmp+"/etc")
-
- // link host /etc contents to prevent passwd/group from being overwritten
- if d, err := os.ReadDir(etc); err != nil {
- return nil, err
- } else {
- for _, ent := range d {
- name := ent.Name()
- switch name {
- case "passwd":
- case "group":
-
- case "mtab":
- conf.Symlink("/proc/mounts", "/etc/"+name)
- default:
- conf.Symlink(Tmp+"/etc/"+name, "/etc/"+name)
- }
- }
- }
- }
-
- return conf, nil
-}
-
// Template returns a fully populated instance of Config.
func Template() *Config {
return &Config{
diff --git a/fst/sandbox.go b/fst/sandbox.go
new file mode 100644
index 00000000..32508fde
--- /dev/null
+++ b/fst/sandbox.go
@@ -0,0 +1,135 @@
+package fst
+
+import (
+ "errors"
+
+ "git.gensokyo.uk/security/fortify/helper/bwrap"
+ "git.gensokyo.uk/security/fortify/internal/linux"
+)
+
+// SandboxConfig describes resources made available to the sandbox.
+type SandboxConfig struct {
+ // unix hostname within sandbox
+ Hostname string `json:"hostname,omitempty"`
+ // allow userns within sandbox
+ UserNS bool `json:"userns,omitempty"`
+ // share net namespace
+ Net bool `json:"net,omitempty"`
+ // share all devices
+ Dev bool `json:"dev,omitempty"`
+ // do not run in new session
+ NoNewSession bool `json:"no_new_session,omitempty"`
+ // map target user uid to privileged user uid in the user namespace
+ MapRealUID bool `json:"map_real_uid"`
+ // direct access to wayland socket
+ DirectWayland bool `json:"direct_wayland,omitempty"`
+
+ // final environment variables
+ Env map[string]string `json:"env"`
+ // sandbox host filesystem access
+ Filesystem []*FilesystemConfig `json:"filesystem"`
+ // symlinks created inside the sandbox
+ Link [][2]string `json:"symlink"`
+ // read-only /etc directory
+ Etc string `json:"etc,omitempty"`
+ // automatically set up /etc symlinks
+ AutoEtc bool `json:"auto_etc"`
+ // paths to override by mounting tmpfs over them
+ Override []string `json:"override"`
+}
+
+// Bwrap returns the address of the corresponding bwrap.Config to s.
+// Note that remaining tmpfs entries must be queued by the caller prior to launch.
+func (s *SandboxConfig) Bwrap(os linux.System) (*bwrap.Config, error) {
+ if s == nil {
+ return nil, errors.New("nil sandbox config")
+ }
+
+ var uid int
+ if !s.MapRealUID {
+ uid = 65534
+ } else {
+ uid = os.Geteuid()
+ }
+
+ conf := (&bwrap.Config{
+ Net: s.Net,
+ UserNS: s.UserNS,
+ Hostname: s.Hostname,
+ Clearenv: true,
+ SetEnv: s.Env,
+
+ /* 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 */
+ Filesystem: make([]bwrap.FSBuilder, 0, 256),
+
+ NewSession: !s.NoNewSession,
+ DieWithParent: true,
+ AsInit: true,
+
+ // initialise map
+ Chmod: make(bwrap.ChmodConfig),
+ }).
+ SetUID(uid).SetGID(uid).
+ Procfs("/proc").
+ Tmpfs(Tmp, 4*1024)
+
+ if !s.Dev {
+ conf.DevTmpfs("/dev").Mqueue("/dev/mqueue")
+ } else {
+ conf.Bind("/dev", "/dev", false, true, true)
+ }
+
+ if !s.AutoEtc {
+ if s.Etc == "" {
+ conf.Dir("/etc")
+ } else {
+ conf.Bind(s.Etc, "/etc")
+ }
+ }
+
+ for _, c := range s.Filesystem {
+ if c == nil {
+ continue
+ }
+ src := c.Src
+ dest := c.Dst
+ if c.Dst == "" {
+ dest = c.Src
+ }
+ conf.Bind(src, dest, !c.Must, c.Write, c.Device)
+ }
+
+ for _, l := range s.Link {
+ conf.Symlink(l[0], l[1])
+ }
+
+ if s.AutoEtc {
+ etc := s.Etc
+ if etc == "" {
+ etc = "/etc"
+ }
+ conf.Bind(etc, Tmp+"/etc")
+
+ // link host /etc contents to prevent passwd/group from being overwritten
+ if d, err := os.ReadDir(etc); err != nil {
+ return nil, err
+ } else {
+ for _, ent := range d {
+ name := ent.Name()
+ switch name {
+ case "passwd":
+ case "group":
+
+ case "mtab":
+ conf.Symlink("/proc/mounts", "/etc/"+name)
+ default:
+ conf.Symlink(Tmp+"/etc/"+name, "/etc/"+name)
+ }
+ }
+ }
+ }
+
+ return conf, nil
+}