diff --git a/internal/app/config.go b/internal/app/config.go index eccb592..6a25d83 100644 --- a/internal/app/config.go +++ b/internal/app/config.go @@ -8,11 +8,6 @@ import ( "git.ophivana.moe/security/fortify/internal/system" ) -const ( - mappedID = 65534 - mappedIDString = "65534" -) - // Config is used to seal an *App type Config struct { // D-Bus application ID @@ -54,6 +49,8 @@ type SandboxConfig struct { Net bool `json:"net,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 + UseRealUID bool `json:"use_real_uid"` // mediated access to wayland socket Wayland bool `json:"wayland,omitempty"` @@ -82,11 +79,15 @@ 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() *bwrap.Config { +func (s *SandboxConfig) Bwrap(uid int) *bwrap.Config { if s == nil { return nil } + if !s.UseRealUID { + uid = 65534 + } + conf := (&bwrap.Config{ Net: s.Net, UserNS: s.UserNS, @@ -100,7 +101,7 @@ func (s *SandboxConfig) Bwrap() *bwrap.Config { // initialise map Chmod: make(map[string]os.FileMode), }). - SetUID(mappedID).SetGID(mappedID). + SetUID(uid).SetGID(uid). Procfs("/proc").DevTmpfs("/dev").Mqueue("/dev/mqueue"). Tmpfs("/dev/fortify", 4*1024) diff --git a/internal/app/seal.go b/internal/app/seal.go index 6852ddc..aaf8a2d 100644 --- a/internal/app/seal.go +++ b/internal/app/seal.go @@ -129,6 +129,15 @@ func (a *app) Seal(config *Config) error { // create seal system component seal.sys = new(appSealSys) + // mapped uid + if config.Confinement.Sandbox != nil && config.Confinement.Sandbox.UseRealUID { + seal.sys.mappedID = a.os.Geteuid() + } else { + seal.sys.mappedID = 65534 + } + seal.sys.mappedIDString = strconv.Itoa(seal.sys.mappedID) + seal.sys.runtime = path.Join("/run/user", seal.sys.mappedIDString) + // look up user from system if u, err := a.os.Lookup(config.User); err != nil { if errors.As(err, new(user.UnknownUserError)) { @@ -139,7 +148,6 @@ func (a *app) Seal(config *Config) error { } } else { seal.sys.user = u - seal.sys.runtime = path.Join("/run/user", mappedIDString) } // map sandbox config to bwrap @@ -228,7 +236,7 @@ func (a *app) Seal(config *Config) error { config.Confinement.Sandbox = conf } - seal.sys.bwrap = config.Confinement.Sandbox.Bwrap() + seal.sys.bwrap = config.Confinement.Sandbox.Bwrap(a.os.Geteuid()) seal.sys.override = config.Confinement.Sandbox.Override if seal.sys.bwrap.SetEnv == nil { seal.sys.bwrap.SetEnv = make(map[string]string) diff --git a/internal/app/share.system.go b/internal/app/share.system.go index 26e9b56..08b006c 100644 --- a/internal/app/share.system.go +++ b/internal/app/share.system.go @@ -58,12 +58,12 @@ func (seal *appSeal) sharePasswd(os linux.System) { homeDir = seal.sys.user.HomeDir seal.sys.bwrap.SetEnv["HOME"] = seal.sys.user.HomeDir } - passwd := username + ":x:" + mappedIDString + ":" + mappedIDString + ":Fortify:" + homeDir + ":" + sh + "\n" + passwd := username + ":x:" + seal.sys.mappedIDString + ":" + seal.sys.mappedIDString + ":Fortify:" + homeDir + ":" + sh + "\n" seal.sys.Write(passwdPath, passwd) // write /etc/group groupPath := path.Join(seal.share, "group") - seal.sys.Write(groupPath, "fortify:x:"+mappedIDString+":\n") + seal.sys.Write(groupPath, "fortify:x:"+seal.sys.mappedIDString+":\n") // bind /etc/passwd and /etc/group seal.sys.bwrap.Bind(passwdPath, "/etc/passwd") diff --git a/internal/app/system.go b/internal/app/system.go index 3c17cf4..47bbd7e 100644 --- a/internal/app/system.go +++ b/internal/app/system.go @@ -20,6 +20,11 @@ type appSealSys struct { // target user sealed from config user *user.User + // mapped uid and gid in user namespace + mappedID int + // string representation of mappedID + mappedIDString string + needRevert bool saveState bool *system.I