aboutsummaryrefslogtreecommitdiffhomepage
path: root/internal/app
diff options
context:
space:
mode:
authorOphestra Umiker <cat@ophivana.moe>2024-11-04 22:18:05 +0900
committerOphestra Umiker <cat@ophivana.moe>2024-11-04 22:18:05 +0900
commitfc25ac2523c512c67d73db5bbbd47224dc0b2001 (patch)
tree5995444ddebfdc66d0f65370ca63a542e19444d0 /internal/app
parentd909b1190ac0e9a357998dd800405bc9bc41f49c (diff)
app: separate auto etc from permissive defaults
Populating /etc with symlinks is quite useful even outside the permissive defaults usage pattern. Signed-off-by: Ophestra Umiker <cat@ophivana.moe>
Diffstat (limited to 'internal/app')
-rw-r--r--internal/app/app_nixos_test.go4
-rw-r--r--internal/app/config.go55
-rw-r--r--internal/app/seal.go35
3 files changed, 54 insertions, 40 deletions
diff --git a/internal/app/app_nixos_test.go b/internal/app/app_nixos_test.go
index 68cb5fcc..c5a31a65 100644
--- a/internal/app/app_nixos_test.go
+++ b/internal/app/app_nixos_test.go
@@ -58,7 +58,6 @@ var testCasesNixos = []sealTestCase{
Tmpfs("/dev/fortify", 4096).
Bind("/bin", "/bin", false, true).
Bind("/boot", "/boot", false, true).
- Bind("/etc", "/dev/fortify/etc").
Bind("/home", "/home", false, true).
Bind("/lib", "/lib", false, true).
Bind("/lib64", "/lib64", false, true).
@@ -102,6 +101,7 @@ var testCasesNixos = []sealTestCase{
Bind("/run/wrappers", "/run/wrappers", false, true).
Bind("/run/zed.pid", "/run/zed.pid", false, true).
Bind("/run/zed.state", "/run/zed.state", false, true).
+ Bind("/etc", "/dev/fortify/etc").
Symlink("/dev/fortify/etc/alsa", "/etc/alsa").
Symlink("/dev/fortify/etc/bashrc", "/etc/bashrc").
Symlink("/dev/fortify/etc/binfmt.d", "/etc/binfmt.d").
@@ -308,7 +308,6 @@ var testCasesNixos = []sealTestCase{
Tmpfs("/dev/fortify", 4096).
Bind("/bin", "/bin", false, true).
Bind("/boot", "/boot", false, true).
- Bind("/etc", "/dev/fortify/etc").
Bind("/home", "/home", false, true).
Bind("/lib", "/lib", false, true).
Bind("/lib64", "/lib64", false, true).
@@ -353,6 +352,7 @@ var testCasesNixos = []sealTestCase{
Bind("/run/zed.pid", "/run/zed.pid", false, true).
Bind("/run/zed.state", "/run/zed.state", false, true).
Bind("/dev/dri", "/dev/dri", true, true, true).
+ Bind("/etc", "/dev/fortify/etc").
Symlink("/dev/fortify/etc/alsa", "/etc/alsa").
Symlink("/dev/fortify/etc/bashrc", "/etc/bashrc").
Symlink("/dev/fortify/etc/binfmt.d", "/etc/binfmt.d").
diff --git a/internal/app/config.go b/internal/app/config.go
index da3f5168..cea50609 100644
--- a/internal/app/config.go
+++ b/internal/app/config.go
@@ -1,10 +1,11 @@
package app
import (
- "os"
+ "errors"
"git.ophivana.moe/security/fortify/dbus"
"git.ophivana.moe/security/fortify/helper/bwrap"
+ "git.ophivana.moe/security/fortify/internal/linux"
"git.ophivana.moe/security/fortify/internal/system"
)
@@ -60,6 +61,8 @@ type SandboxConfig struct {
Filesystem []*FilesystemConfig `json:"filesystem"`
// symlinks created inside the sandbox
Link [][2]string `json:"symlink"`
+ // automatically set up /etc symlinks
+ AutoEtc bool `json:"auto_etc"`
// paths to override by mounting tmpfs over them
Override []string `json:"override"`
}
@@ -79,13 +82,16 @@ type FilesystemConfig struct {
// 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(uid int) *bwrap.Config {
+func (s *SandboxConfig) Bwrap(os linux.System) (*bwrap.Config, error) {
if s == nil {
- return nil
+ return nil, errors.New("nil sandbox config")
}
+ var uid int
if !s.UseRealUID {
uid = 65534
+ } else {
+ uid = os.Geteuid()
}
conf := (&bwrap.Config{
@@ -99,12 +105,16 @@ func (s *SandboxConfig) Bwrap(uid int) *bwrap.Config {
AsInit: true,
// initialise map
- Chmod: make(map[string]os.FileMode),
+ Chmod: make(bwrap.ChmodConfig),
}).
SetUID(uid).SetGID(uid).
Procfs("/proc").DevTmpfs("/dev").Mqueue("/dev/mqueue").
Tmpfs("/dev/fortify", 4*1024)
+ if !s.AutoEtc {
+ conf.Dir("/etc")
+ }
+
for _, c := range s.Filesystem {
if c == nil {
continue
@@ -121,7 +131,29 @@ func (s *SandboxConfig) Bwrap(uid int) *bwrap.Config {
conf.Symlink(l[0], l[1])
}
- return conf
+ if s.AutoEtc {
+ conf.Bind("/etc", "/dev/fortify/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("/dev/fortify/etc/"+name, "/etc/"+name)
+ }
+ }
+ }
+ }
+
+ return conf, nil
}
// Template returns a fully populated instance of Config.
@@ -153,12 +185,15 @@ func Template() *Config {
"GOOGLE_DEFAULT_CLIENT_SECRET": "OTJgUOQcT7lO7GsGZq2G4IlT",
},
Filesystem: []*FilesystemConfig{
- {Src: "/nix"},
- {Src: "/storage/emulated/0", Write: true, Must: true},
- {Src: "/data/user/0", Dst: "/data/data", Write: true, Must: true},
- {Src: "/var/tmp", Write: true},
+ {Src: "/nix/store"},
+ {Src: "/run/current-system"},
+ {Src: "/run/opengl-driver"},
+ {Src: "/var/db/nix-channels"},
+ {Src: "/home/chronos", Write: true, Must: true},
+ {Src: "/dev/dri", Device: true},
},
- Link: [][2]string{{"/dev/fortify/etc", "/etc"}},
+ Link: [][2]string{{"/run/user/65534", "/run/user/150"}},
+ AutoEtc: true,
Override: []string{"/var/run/nscd"},
},
SystemBus: &dbus.Config{
diff --git a/internal/app/seal.go b/internal/app/seal.go
index aaf8a2d6..0b60920f 100644
--- a/internal/app/seal.go
+++ b/internal/app/seal.go
@@ -159,6 +159,7 @@ func (a *app) Seal(config *Config) error {
UserNS: true,
Net: true,
NoNewSession: true,
+ AutoEtc: true,
}
// bind entries in /
if d, err := a.os.ReadDir("/"); err != nil {
@@ -173,9 +174,8 @@ func (a *app) Seal(config *Config) error {
case "/run":
case "/tmp":
case "/mnt":
-
case "/etc":
- b = append(b, &FilesystemConfig{Src: p, Dst: "/dev/fortify/etc", Write: false, Must: true})
+
default:
b = append(b, &FilesystemConfig{Src: p, Write: true, Must: true})
}
@@ -208,35 +208,14 @@ func (a *app) Seal(config *Config) error {
if config.Confinement.Enablements.Has(system.EX11) || config.Confinement.Enablements.Has(system.EWayland) {
conf.Filesystem = append(conf.Filesystem, &FilesystemConfig{Src: "/dev/dri", Device: true})
}
- // link host /etc to prevent passwd/group from being overwritten
- if d, err := a.os.ReadDir("/etc"); err != nil {
- return err
- } else {
- b := make([][2]string, 0, len(d))
- for _, ent := range d {
- name := ent.Name()
- switch name {
- case "passwd":
- case "group":
-
- case "mtab":
- b = append(b, [2]string{
- "/proc/mounts",
- "/etc/" + name,
- })
- default:
- b = append(b, [2]string{
- "/dev/fortify/etc/" + name,
- "/etc/" + name,
- })
- }
- }
- conf.Link = append(conf.Link, b...)
- }
config.Confinement.Sandbox = conf
}
- seal.sys.bwrap = config.Confinement.Sandbox.Bwrap(a.os.Geteuid())
+ if b, err := config.Confinement.Sandbox.Bwrap(a.os); err != nil {
+ return err
+ } else {
+ seal.sys.bwrap = b
+ }
seal.sys.override = config.Confinement.Sandbox.Override
if seal.sys.bwrap.SetEnv == nil {
seal.sys.bwrap.SetEnv = make(map[string]string)