app: separate appSeal finalise method
All checks were successful
Test / Create distribution (push) Successful in 25s
Test / Run NixOS test (push) Successful in 3m27s

Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
Ophestra 2025-02-19 12:33:51 +09:00
parent dfd9467523
commit 2978a6f046
Signed by: cat
SSH Key Fingerprint: SHA256:gQ67O0enBZ7UdZypgtspB2FDM1g3GVw8nX0XSdcFw8Q
3 changed files with 32 additions and 29 deletions

View File

@ -6,6 +6,7 @@ import (
"git.gensokyo.uk/security/fortify/fst" "git.gensokyo.uk/security/fortify/fst"
"git.gensokyo.uk/security/fortify/internal/app/shim" "git.gensokyo.uk/security/fortify/internal/app/shim"
"git.gensokyo.uk/security/fortify/internal/fmsg"
"git.gensokyo.uk/security/fortify/internal/sys" "git.gensokyo.uk/security/fortify/internal/sys"
) )
@ -55,3 +56,23 @@ func (a *app) String() string {
return fmt.Sprintf("(unsealed app %s)", a.id) return fmt.Sprintf("(unsealed app %s)", a.id)
} }
func (a *app) Seal(config *fst.Config) (err error) {
a.mu.Lock()
defer a.mu.Unlock()
if a.appSeal != nil {
panic("app sealed twice")
}
if config == nil {
return fmsg.WrapError(ErrConfig,
"attempted to seal app with nil config")
}
seal := new(appSeal)
err = seal.finalise(a.sys, config, a.id.String())
if err == nil {
a.appSeal = seal
}
return
}

View File

@ -18,6 +18,7 @@ import (
"git.gensokyo.uk/security/fortify/internal" "git.gensokyo.uk/security/fortify/internal"
"git.gensokyo.uk/security/fortify/internal/fmsg" "git.gensokyo.uk/security/fortify/internal/fmsg"
"git.gensokyo.uk/security/fortify/internal/state" "git.gensokyo.uk/security/fortify/internal/state"
"git.gensokyo.uk/security/fortify/internal/sys"
"git.gensokyo.uk/security/fortify/system" "git.gensokyo.uk/security/fortify/system"
) )
@ -112,23 +113,7 @@ type sealedExtraPerm struct {
ensure bool ensure bool
} }
// Seal seals the app launch context func (seal *appSeal) finalise(sys sys.State, config *fst.Config, id string) error {
func (a *app) Seal(config *fst.Config) error {
a.mu.Lock()
defer a.mu.Unlock()
if a.appSeal != nil {
panic("app sealed twice")
}
if config == nil {
return fmsg.WrapError(ErrConfig,
"attempted to seal app with nil config")
}
// create seal
seal := new(appSeal)
// encode initial configuration for state tracking // encode initial configuration for state tracking
ct := new(bytes.Buffer) ct := new(bytes.Buffer)
if err := gob.NewEncoder(ct).Encode(config); err != nil { if err := gob.NewEncoder(ct).Encode(config); err != nil {
@ -137,11 +122,10 @@ func (a *app) Seal(config *fst.Config) error {
} }
seal.ct = ct seal.ct = ct
// fetch system constants seal.Paths = sys.Paths()
seal.Paths = a.sys.Paths()
// pass through config values // pass through config values
seal.id = a.id.String() seal.id = id
seal.appID = config.ID seal.appID = config.ID
seal.command = config.Command seal.command = config.Command
@ -151,7 +135,7 @@ func (a *app) Seal(config *fst.Config) error {
if config.Confinement.Sandbox != nil && config.Confinement.Sandbox.MapRealUID { if config.Confinement.Sandbox != nil && config.Confinement.Sandbox.MapRealUID {
// some programs fail to connect to dbus session running as a different uid, so a // some programs fail to connect to dbus session running as a different uid, so a
// separate workaround is introduced to map priv-side caller uid in namespace // separate workaround is introduced to map priv-side caller uid in namespace
mapuid = a.sys.Geteuid() mapuid = sys.Geteuid()
} }
seal.mapuid = newInt(mapuid) seal.mapuid = newInt(mapuid)
seal.innerRuntimeDir = path.Join("/run/user", seal.mapuid.String()) seal.innerRuntimeDir = path.Join("/run/user", seal.mapuid.String())
@ -184,7 +168,7 @@ func (a *app) Seal(config *fst.Config) error {
} }
// invoke fsu for full uid // invoke fsu for full uid
if u, err := a.sys.Uid(seal.user.aid.unwrap()); err != nil { if u, err := sys.Uid(seal.user.aid.unwrap()); err != nil {
return err return err
} else { } else {
seal.user.uid = newInt(u) seal.user.uid = newInt(u)
@ -193,7 +177,7 @@ func (a *app) Seal(config *fst.Config) error {
// resolve supplementary group ids from names // resolve supplementary group ids from names
seal.user.supp = make([]string, len(config.Confinement.Groups)) seal.user.supp = make([]string, len(config.Confinement.Groups))
for i, name := range config.Confinement.Groups { for i, name := range config.Confinement.Groups {
if g, err := a.sys.LookupGroup(name); err != nil { if g, err := sys.LookupGroup(name); err != nil {
return fmsg.WrapError(err, return fmsg.WrapError(err,
fmt.Sprintf("unknown group %q", name)) fmt.Sprintf("unknown group %q", name))
} else { } else {
@ -236,7 +220,7 @@ func (a *app) Seal(config *fst.Config) error {
AutoEtc: true, AutoEtc: true,
} }
// bind entries in / // bind entries in /
if d, err := a.sys.ReadDir("/"); err != nil { if d, err := sys.ReadDir("/"); err != nil {
return err return err
} else { } else {
b := make([]*fst.FilesystemConfig, 0, len(d)) b := make([]*fst.FilesystemConfig, 0, len(d))
@ -258,7 +242,7 @@ func (a *app) Seal(config *fst.Config) error {
// hide nscd from sandbox if present // hide nscd from sandbox if present
nscd := "/var/run/nscd" nscd := "/var/run/nscd"
if _, err := a.sys.Stat(nscd); !errors.Is(err, fs.ErrNotExist) { if _, err := sys.Stat(nscd); !errors.Is(err, fs.ErrNotExist) {
conf.Override = append(conf.Override, nscd) conf.Override = append(conf.Override, nscd)
} }
// bind GPU stuff // bind GPU stuff
@ -271,7 +255,7 @@ func (a *app) Seal(config *fst.Config) error {
config.Confinement.Sandbox = conf config.Confinement.Sandbox = conf
} }
seal.directWayland = config.Confinement.Sandbox.DirectWayland seal.directWayland = config.Confinement.Sandbox.DirectWayland
if b, err := config.Confinement.Sandbox.Bwrap(a.sys); err != nil { if b, err := config.Confinement.Sandbox.Bwrap(sys); err != nil {
return err return err
} else { } else {
seal.container = b seal.container = b
@ -297,7 +281,7 @@ func (a *app) Seal(config *fst.Config) error {
seal.Enablements = config.Confinement.Enablements seal.Enablements = config.Confinement.Enablements
// this method calls all share methods in sequence // this method calls all share methods in sequence
if err := seal.setupShares([2]*dbus.Config{config.Confinement.SessionBus, config.Confinement.SystemBus}, a.sys); err != nil { if err := seal.setupShares([2]*dbus.Config{config.Confinement.SessionBus, config.Confinement.SystemBus}, sys); err != nil {
return err return err
} }
@ -305,7 +289,5 @@ func (a *app) Seal(config *fst.Config) error {
fmsg.Verbosef("created application seal for uid %s (%s) groups: %v, command: %s", fmsg.Verbosef("created application seal for uid %s (%s) groups: %v, command: %s",
seal.user.uid, seal.user.username, config.Confinement.Groups, config.Command) seal.user.uid, seal.user.username, config.Confinement.Groups, config.Command)
// seal app and release lock
a.appSeal = seal
return nil return nil
} }