diff --git a/internal/app/seal.go b/internal/app/seal.go index 6ad7edb..3ac31c8 100644 --- a/internal/app/seal.go +++ b/internal/app/seal.go @@ -149,8 +149,7 @@ func (a *app) Seal(config *fst.Config) error { // invoke fsu for full uid if u, err := a.os.Uid(seal.sys.user.aid); err != nil { - return fmsg.WrapErrorSuffix(err, - "cannot obtain uid from fsu:") + return err } else { seal.sys.user.uid = u seal.sys.user.us = strconv.Itoa(u) diff --git a/internal/linux/interface.go b/internal/linux/interface.go index cf25ecb..762414c 100644 --- a/internal/linux/interface.go +++ b/internal/linux/interface.go @@ -37,6 +37,7 @@ type System interface { // Paths returns a populated [Paths] struct. Paths() Paths // Uid invokes fsu and returns target uid. + // Any errors returned by Uid is already wrapped [fmsg.BaseError]. Uid(aid int) (int, error) } diff --git a/internal/linux/std.go b/internal/linux/std.go index fceba95..89338f1 100644 --- a/internal/linux/std.go +++ b/internal/linux/std.go @@ -2,6 +2,7 @@ package linux import ( "errors" + "fmt" "io/fs" "log" "os" @@ -56,13 +57,15 @@ func (s *Std) Uid(aid int) (int, error) { }) }) - s.uidMu.RLock() - if u, ok := s.uidCopy[aid]; ok { + { + s.uidMu.RLock() + u, ok := s.uidCopy[aid] s.uidMu.RUnlock() - return u.uid, u.err + if ok { + return u.uid, u.err + } } - s.uidMu.RUnlock() s.uidMu.Lock() defer s.uidMu.Unlock() @@ -91,8 +94,13 @@ func (s *Std) Uid(aid int) (int, error) { if p, u.err = cmd.Output(); u.err == nil { u.uid, u.err = strconv.Atoi(string(p)) + if u.err != nil { + u.err = fmsg.WrapErrorSuffix(u.err, "cannot parse uid from fsu:") + } } else if errors.As(u.err, &exitError) && exitError != nil && exitError.ExitCode() == 1 { - u.err = syscall.EACCES + u.err = fmsg.WrapError(syscall.EACCES, "") // fsu prints to stderr in this case + } else if os.IsNotExist(u.err) { + u.err = fmsg.WrapError(os.ErrNotExist, fmt.Sprintf("the setuid helper is missing: %s", fsu)) } return u.uid, u.err } diff --git a/main.go b/main.go index 14ca352..8aec22d 100644 --- a/main.go +++ b/main.go @@ -228,7 +228,8 @@ func main() { passwdFunc = func() { var us string if uid, err := sys.Uid(aid); err != nil { - log.Fatalf("cannot obtain uid from fsu: %v", err) + fmsg.PrintBaseError(err, "cannot obtain uid from fsu:") + os.Exit(1) } else { us = strconv.Itoa(uid) } diff --git a/print.go b/print.go index 3c0c219..1022ae1 100644 --- a/print.go +++ b/print.go @@ -5,6 +5,7 @@ import ( "fmt" "io" "log" + "os" "slices" "strconv" "strings" @@ -13,6 +14,7 @@ import ( "git.gensokyo.uk/security/fortify/dbus" "git.gensokyo.uk/security/fortify/fst" + "git.gensokyo.uk/security/fortify/internal/fmsg" "git.gensokyo.uk/security/fortify/internal/state" ) @@ -24,7 +26,8 @@ func printShowSystem(output io.Writer, short bool) { // get fid by querying uid of aid 0 if uid, err := sys.Uid(0); err != nil { - log.Fatalf("cannot obtain uid from fsu: %v", err) + fmsg.PrintBaseError(err, "cannot obtain uid from fsu:") + os.Exit(1) } else { info.User = (uid / 10000) - 100 } diff --git a/test.nix b/test.nix index 6fdb249..c85d3c6 100644 --- a/test.nix +++ b/test.nix @@ -18,7 +18,12 @@ nixosTest { skipTypeCheck = true; nodes.machine = - { lib, pkgs, ... }: + { + lib, + pkgs, + config, + ... + }: { users.users = { alice = { @@ -32,6 +37,9 @@ nixosTest { description = "Untrusted user"; password = "foobar"; uid = 1001; + + # For deny unmapped uid test: + packages = [ config.environment.fortify.package ]; }; }; @@ -284,7 +292,16 @@ nixosTest { machine.wait_for_file("/tmp/sway-ipc.sock") # Deny unmapped uid: - print(machine.fail("sudo -u untrusted -i ${self.packages.${system}.fortify}/bin/fortify -v run")) + denyOutput = machine.fail("sudo -u untrusted -i fortify run &>/dev/stdout") + print(denyOutput) + denyOutputVerbose = machine.fail("sudo -u untrusted -i fortify -v run &>/dev/stdout") + print(denyOutputVerbose) + + # Verify PrintBaseError behaviour: + if denyOutput != "fsu: uid 1001 is not in the fsurc file\n": + raise Exception(f"unexpected deny output:\n{denyOutput}") + if denyOutputVerbose != "fsu: uid 1001 is not in the fsurc file\nfortify: *cannot obtain uid from fsu: permission denied\n": + raise Exception(f"unexpected deny verbose output:\n{denyOutputVerbose}") # Start fortify permissive defaults outside Wayland session: print(machine.succeed("sudo -u alice -i fortify -v run -a 0 touch /tmp/success-bare"))