app: store values with string representation
Improves code readability without changing memory layout. Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
parent
648e1d641a
commit
a748d40745
@ -1,6 +1,7 @@
|
|||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/fst"
|
"git.gensokyo.uk/security/fortify/fst"
|
||||||
@ -10,14 +11,18 @@ import (
|
|||||||
|
|
||||||
func New(os sys.State) (fst.App, error) {
|
func New(os sys.State) (fst.App, error) {
|
||||||
a := new(app)
|
a := new(app)
|
||||||
a.id = new(fst.ID)
|
|
||||||
a.os = os
|
a.os = os
|
||||||
return a, fst.NewAppID(a.id)
|
|
||||||
|
id := new(fst.ID)
|
||||||
|
err := fst.NewAppID(id)
|
||||||
|
a.id = newID(id)
|
||||||
|
|
||||||
|
return a, err
|
||||||
}
|
}
|
||||||
|
|
||||||
type app struct {
|
type app struct {
|
||||||
// application unique identifier
|
// application unique identifier
|
||||||
id *fst.ID
|
id *stringPair[fst.ID]
|
||||||
// operating system interface
|
// operating system interface
|
||||||
os sys.State
|
os sys.State
|
||||||
// shim process manager
|
// shim process manager
|
||||||
@ -28,13 +33,11 @@ type app struct {
|
|||||||
lock sync.RWMutex
|
lock sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *app) ID() fst.ID {
|
func (a *app) ID() fst.ID { return a.id.unwrap() }
|
||||||
return *a.id
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *app) String() string {
|
func (a *app) String() string {
|
||||||
if a == nil {
|
if a == nil {
|
||||||
return "(invalid fortified app)"
|
return "(invalid app)"
|
||||||
}
|
}
|
||||||
|
|
||||||
a.lock.RLock()
|
a.lock.RLock()
|
||||||
@ -45,8 +48,11 @@ func (a *app) String() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if a.seal != nil {
|
if a.seal != nil {
|
||||||
return "(sealed fortified app as uid " + a.seal.sys.user.us + ")"
|
if a.seal.sys.user.uid == nil {
|
||||||
|
return fmt.Sprintf("(sealed app %s with invalid uid)", a.id)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("(sealed app %s as uid %s)", a.id, a.seal.sys.user.uid)
|
||||||
}
|
}
|
||||||
|
|
||||||
return "(unsealed fortified app)"
|
return fmt.Sprintf("(unsealed app %s)", a.id)
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ import (
|
|||||||
|
|
||||||
func NewWithID(id fst.ID, os sys.State) fst.App {
|
func NewWithID(id fst.ID, os sys.State) fst.App {
|
||||||
a := new(app)
|
a := new(app)
|
||||||
a.id = &id
|
a.id = newID(&id)
|
||||||
a.os = os
|
a.os = os
|
||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,6 @@ import (
|
|||||||
"io/fs"
|
"io/fs"
|
||||||
"path"
|
"path"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/acl"
|
"git.gensokyo.uk/security/fortify/acl"
|
||||||
"git.gensokyo.uk/security/fortify/dbus"
|
"git.gensokyo.uk/security/fortify/dbus"
|
||||||
@ -110,14 +109,17 @@ func (a *app) Seal(config *fst.Config) error {
|
|||||||
// create seal system component
|
// create seal system component
|
||||||
seal.sys = new(appSealSys)
|
seal.sys = new(appSealSys)
|
||||||
|
|
||||||
// mapped uid
|
{
|
||||||
if config.Confinement.Sandbox != nil && config.Confinement.Sandbox.MapRealUID {
|
// mapped uid defaults to 65534 to work around file ownership checks due to a bwrap limitation
|
||||||
seal.sys.mappedID = a.os.Geteuid()
|
mapuid := 65534
|
||||||
} else {
|
if config.Confinement.Sandbox != nil && config.Confinement.Sandbox.MapRealUID {
|
||||||
seal.sys.mappedID = 65534
|
// 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
|
||||||
|
mapuid = a.os.Geteuid()
|
||||||
|
}
|
||||||
|
seal.sys.mapuid = newInt(mapuid)
|
||||||
|
seal.sys.runtime = path.Join("/run/user", seal.sys.mapuid.String())
|
||||||
}
|
}
|
||||||
seal.sys.mappedIDString = strconv.Itoa(seal.sys.mappedID)
|
|
||||||
seal.sys.runtime = path.Join("/run/user", seal.sys.mappedIDString)
|
|
||||||
|
|
||||||
// validate uid and set user info
|
// validate uid and set user info
|
||||||
if config.Confinement.AppID < 0 || config.Confinement.AppID > 9999 {
|
if config.Confinement.AppID < 0 || config.Confinement.AppID > 9999 {
|
||||||
@ -125,8 +127,7 @@ func (a *app) Seal(config *fst.Config) error {
|
|||||||
fmt.Sprintf("aid %d out of range", config.Confinement.AppID))
|
fmt.Sprintf("aid %d out of range", config.Confinement.AppID))
|
||||||
}
|
}
|
||||||
seal.sys.user = appUser{
|
seal.sys.user = appUser{
|
||||||
aid: config.Confinement.AppID,
|
aid: newInt(config.Confinement.AppID),
|
||||||
as: strconv.Itoa(config.Confinement.AppID),
|
|
||||||
data: config.Confinement.Outer,
|
data: config.Confinement.Outer,
|
||||||
home: config.Confinement.Inner,
|
home: config.Confinement.Inner,
|
||||||
username: config.Confinement.Username,
|
username: config.Confinement.Username,
|
||||||
@ -147,11 +148,10 @@ func (a *app) Seal(config *fst.Config) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// invoke fsu for full uid
|
// invoke fsu for full uid
|
||||||
if u, err := a.os.Uid(seal.sys.user.aid); err != nil {
|
if u, err := a.os.Uid(seal.sys.user.aid.unwrap()); err != nil {
|
||||||
return err
|
return err
|
||||||
} else {
|
} else {
|
||||||
seal.sys.user.uid = u
|
seal.sys.user.uid = newInt(u)
|
||||||
seal.sys.user.us = strconv.Itoa(u)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// resolve supplementary group ids from names
|
// resolve supplementary group ids from names
|
||||||
@ -251,7 +251,7 @@ func (a *app) Seal(config *fst.Config) error {
|
|||||||
seal.store = state.NewMulti(seal.RunDirPath)
|
seal.store = state.NewMulti(seal.RunDirPath)
|
||||||
|
|
||||||
// initialise system interface with os uid
|
// initialise system interface with os uid
|
||||||
seal.sys.I = system.New(seal.sys.user.uid)
|
seal.sys.I = system.New(seal.sys.user.uid.unwrap())
|
||||||
seal.sys.I.IsVerbose = fmsg.Load
|
seal.sys.I.IsVerbose = fmsg.Load
|
||||||
seal.sys.I.Verbose = fmsg.Verbose
|
seal.sys.I.Verbose = fmsg.Verbose
|
||||||
seal.sys.I.Verbosef = fmsg.Verbosef
|
seal.sys.I.Verbosef = fmsg.Verbosef
|
||||||
@ -267,7 +267,7 @@ func (a *app) Seal(config *fst.Config) error {
|
|||||||
|
|
||||||
// verbose log seal information
|
// verbose log seal information
|
||||||
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.sys.user.us, seal.sys.user.username, config.Confinement.Groups, config.Command)
|
seal.sys.user.uid, seal.sys.user.username, config.Confinement.Groups, config.Command)
|
||||||
|
|
||||||
// seal app and release lock
|
// seal app and release lock
|
||||||
a.seal = seal
|
a.seal = seal
|
||||||
|
@ -68,7 +68,7 @@ func (seal *appSeal) setupShares(bus [2]*dbus.Config, os sys.State) error {
|
|||||||
seal.sys.UpdatePermType(system.User, targetTmpdirParent, acl.Execute)
|
seal.sys.UpdatePermType(system.User, targetTmpdirParent, acl.Execute)
|
||||||
|
|
||||||
// ensure child tmpdir (e.g. `/tmp/fortify.%d/tmpdir/%d`)
|
// ensure child tmpdir (e.g. `/tmp/fortify.%d/tmpdir/%d`)
|
||||||
targetTmpdir := path.Join(targetTmpdirParent, seal.sys.user.as)
|
targetTmpdir := path.Join(targetTmpdirParent, seal.sys.user.aid.String())
|
||||||
seal.sys.Ensure(targetTmpdir, 01700)
|
seal.sys.Ensure(targetTmpdir, 01700)
|
||||||
seal.sys.UpdatePermType(system.User, targetTmpdir, acl.Read, acl.Write, acl.Execute)
|
seal.sys.UpdatePermType(system.User, targetTmpdir, acl.Read, acl.Write, acl.Execute)
|
||||||
seal.sys.bwrap.Bind(targetTmpdir, "/tmp", false, true)
|
seal.sys.bwrap.Bind(targetTmpdir, "/tmp", false, true)
|
||||||
@ -126,9 +126,9 @@ func (seal *appSeal) setupShares(bus [2]*dbus.Config, os sys.State) error {
|
|||||||
|
|
||||||
// generate /etc/passwd and /etc/group
|
// generate /etc/passwd and /etc/group
|
||||||
seal.sys.bwrap.CopyBind("/etc/passwd",
|
seal.sys.bwrap.CopyBind("/etc/passwd",
|
||||||
[]byte(username+":x:"+seal.sys.mappedIDString+":"+seal.sys.mappedIDString+":Fortify:"+homeDir+":"+sh+"\n"))
|
[]byte(username+":x:"+seal.sys.mapuid.String()+":"+seal.sys.mapuid.String()+":Fortify:"+homeDir+":"+sh+"\n"))
|
||||||
seal.sys.bwrap.CopyBind("/etc/group",
|
seal.sys.bwrap.CopyBind("/etc/group",
|
||||||
[]byte("fortify:x:"+seal.sys.mappedIDString+":\n"))
|
[]byte("fortify:x:"+seal.sys.mapuid.String()+":\n"))
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Display servers
|
Display servers
|
||||||
@ -181,7 +181,7 @@ func (seal *appSeal) setupShares(bus [2]*dbus.Config, os sys.State) error {
|
|||||||
return fmsg.WrapError(ErrXDisplay,
|
return fmsg.WrapError(ErrXDisplay,
|
||||||
"DISPLAY is not set")
|
"DISPLAY is not set")
|
||||||
} else {
|
} else {
|
||||||
seal.sys.ChangeHosts("#" + seal.sys.user.us)
|
seal.sys.ChangeHosts("#" + seal.sys.user.uid.String())
|
||||||
seal.sys.bwrap.SetEnv[display] = d
|
seal.sys.bwrap.SetEnv[display] = d
|
||||||
seal.sys.bwrap.Bind("/tmp/.X11-unix", "/tmp/.X11-unix")
|
seal.sys.bwrap.Bind("/tmp/.X11-unix", "/tmp/.X11-unix")
|
||||||
}
|
}
|
||||||
|
@ -57,7 +57,7 @@ func (a *app) Run(ctx context.Context, rs *fst.RunState) error {
|
|||||||
a.shim = new(shim.Shim)
|
a.shim = new(shim.Shim)
|
||||||
waitErr := make(chan error, 1)
|
waitErr := make(chan error, 1)
|
||||||
if startTime, err := a.shim.Start(
|
if startTime, err := a.shim.Start(
|
||||||
a.seal.sys.user.as,
|
a.seal.sys.user.aid.String(),
|
||||||
a.seal.sys.user.supp,
|
a.seal.sys.user.supp,
|
||||||
a.seal.sys.sp,
|
a.seal.sys.sp,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
@ -90,14 +90,14 @@ func (a *app) Run(ctx context.Context, rs *fst.RunState) error {
|
|||||||
|
|
||||||
// shim accepted setup payload, create process state
|
// shim accepted setup payload, create process state
|
||||||
sd := state.State{
|
sd := state.State{
|
||||||
ID: *a.id,
|
ID: a.id.unwrap(),
|
||||||
PID: a.shim.Unwrap().Process.Pid,
|
PID: a.shim.Unwrap().Process.Pid,
|
||||||
Time: *startTime,
|
Time: *startTime,
|
||||||
}
|
}
|
||||||
|
|
||||||
// register process state
|
// register process state
|
||||||
var err0 = new(StateStoreError)
|
var err0 = new(StateStoreError)
|
||||||
err0.Inner, err0.DoErr = a.seal.store.Do(a.seal.sys.user.aid, func(c state.Cursor) {
|
err0.Inner, err0.DoErr = a.seal.store.Do(a.seal.sys.user.aid.unwrap(), func(c state.Cursor) {
|
||||||
err0.InnerErr = c.Save(&sd, a.seal.ct)
|
err0.InnerErr = c.Save(&sd, a.seal.ct)
|
||||||
})
|
})
|
||||||
a.seal.sys.saveState = true
|
a.seal.sys.saveState = true
|
||||||
@ -147,11 +147,11 @@ func (a *app) Run(ctx context.Context, rs *fst.RunState) error {
|
|||||||
|
|
||||||
// update store and revert app setup transaction
|
// update store and revert app setup transaction
|
||||||
e := new(StateStoreError)
|
e := new(StateStoreError)
|
||||||
e.Inner, e.DoErr = a.seal.store.Do(a.seal.sys.user.aid, func(b state.Cursor) {
|
e.Inner, e.DoErr = a.seal.store.Do(a.seal.sys.user.aid.unwrap(), func(b state.Cursor) {
|
||||||
e.InnerErr = func() error {
|
e.InnerErr = func() error {
|
||||||
// destroy defunct state entry
|
// destroy defunct state entry
|
||||||
if cmd := a.shim.Unwrap(); cmd != nil && a.seal.sys.saveState {
|
if cmd := a.shim.Unwrap(); cmd != nil && a.seal.sys.saveState {
|
||||||
if err := b.Destroy(*a.id); err != nil {
|
if err := b.Destroy(a.id.unwrap()); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
19
internal/app/strings.go
Normal file
19
internal/app/strings.go
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package app
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"git.gensokyo.uk/security/fortify/fst"
|
||||||
|
)
|
||||||
|
|
||||||
|
func newInt(v int) *stringPair[int] { return &stringPair[int]{v, strconv.Itoa(v)} }
|
||||||
|
func newID(id *fst.ID) *stringPair[fst.ID] { return &stringPair[fst.ID]{*id, id.String()} }
|
||||||
|
|
||||||
|
// stringPair stores a value and its string representation.
|
||||||
|
type stringPair[T comparable] struct {
|
||||||
|
v T
|
||||||
|
s string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *stringPair[T]) unwrap() T { return s.v }
|
||||||
|
func (s *stringPair[T]) String() string { return s.s }
|
@ -21,9 +21,7 @@ type appSealSys struct {
|
|||||||
user appUser
|
user appUser
|
||||||
|
|
||||||
// mapped uid and gid in user namespace
|
// mapped uid and gid in user namespace
|
||||||
mappedID int
|
mapuid *stringPair[int]
|
||||||
// string representation of mappedID
|
|
||||||
mappedIDString string
|
|
||||||
|
|
||||||
needRevert bool
|
needRevert bool
|
||||||
saveState bool
|
saveState bool
|
||||||
@ -33,19 +31,14 @@ type appSealSys struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type appUser struct {
|
type appUser struct {
|
||||||
// full uid resolved by fsu
|
// application id
|
||||||
uid int
|
aid *stringPair[int]
|
||||||
// string representation of uid
|
// target uid resolved by fid:aid
|
||||||
us string
|
uid *stringPair[int]
|
||||||
|
|
||||||
// supplementary group ids
|
// supplementary group ids
|
||||||
supp []string
|
supp []string
|
||||||
|
|
||||||
// application id
|
|
||||||
aid int
|
|
||||||
// string representation of aid
|
|
||||||
as string
|
|
||||||
|
|
||||||
// home directory host path
|
// home directory host path
|
||||||
data string
|
data string
|
||||||
// app user home directory
|
// app user home directory
|
||||||
|
Loading…
Reference in New Issue
Block a user