aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2025-01-01 21:34:57 +0900
committerOphestra <cat@gensokyo.uk>2025-01-01 21:34:57 +0900
commit6acd0d4e88af6a80836c5409023bbb6ebc57231f (patch)
treec0b5ab89cb7549e817c5dac9c0894279ac376275
parent35b714231768d11b82e575701ca5c7a081e2c542 (diff)
linux/std: handle fsu exit status 1
Printing "exit status 1" is confusing. This handles the ExitError and returns EACCES instead. Signed-off-by: Ophestra <cat@gensokyo.uk>
-rw-r--r--internal/linux/std.go10
-rw-r--r--main.go9
-rw-r--r--parse.go8
-rw-r--r--print.go4
-rw-r--r--test.nix21
5 files changed, 36 insertions, 16 deletions
diff --git a/internal/linux/std.go b/internal/linux/std.go
index 219997ee..a82fff26 100644
--- a/internal/linux/std.go
+++ b/internal/linux/std.go
@@ -1,6 +1,7 @@
package linux
import (
+ "errors"
"io"
"io/fs"
"os"
@@ -8,6 +9,7 @@ import (
"os/user"
"strconv"
"sync"
+ "syscall"
"git.gensokyo.uk/security/fortify/internal"
"git.gensokyo.uk/security/fortify/internal/fmsg"
@@ -79,9 +81,15 @@ func (s *Std) Uid(aid int) (int, error) {
cmd.Stderr = os.Stderr // pass through fatal messages
cmd.Env = []string{"FORTIFY_APP_ID=" + strconv.Itoa(aid)}
cmd.Dir = "/"
- var p []byte
+ var (
+ p []byte
+ exitError *exec.ExitError
+ )
+
if p, u.err = cmd.Output(); u.err == nil {
u.uid, u.err = strconv.Atoi(string(p))
+ } else if errors.As(u.err, &exitError) && exitError != nil && exitError.ExitCode() == 1 {
+ u.err = syscall.EACCES
}
return u.uid, u.err
}
diff --git a/main.go b/main.go
index 2449b681..e4f2860d 100644
--- a/main.go
+++ b/main.go
@@ -4,6 +4,7 @@ import (
_ "embed"
"flag"
"fmt"
+ "os"
"os/user"
"strconv"
"strings"
@@ -32,7 +33,7 @@ func init() {
flag.BoolVar(&flagJSON, "json", false, "Format output in JSON when applicable")
}
-var os = new(linux.Std)
+var sys linux.System = new(linux.Std)
type gl []string
@@ -64,7 +65,7 @@ func main() {
fmt.Println("Usage:\tfortify [-v] [--json] COMMAND [OPTIONS]")
fmt.Println()
fmt.Println("Commands:")
- w := tabwriter.NewWriter(os.Stdout(), 0, 1, 4, ' ', 0)
+ w := tabwriter.NewWriter(os.Stdout, 0, 1, 4, ' ', 0)
commands := [][2]string{
{"app", "Launch app defined by the specified config file"},
{"run", "Configure and start a permissive default sandbox"},
@@ -206,7 +207,7 @@ func main() {
passwdOnce sync.Once
passwdFunc = func() {
var us string
- if uid, err := os.Uid(aid); err != nil {
+ if uid, err := sys.Uid(aid); err != nil {
fmsg.Fatalf("cannot obtain uid from fsu: %v", err)
} else {
us = strconv.Itoa(uid)
@@ -287,7 +288,7 @@ func main() {
}
func runApp(config *fst.Config) {
- a, err := app.New(os)
+ a, err := app.New(sys)
if err != nil {
fmsg.Fatalf("cannot create app: %s\n", err)
} else if err = a.Seal(config); err != nil {
diff --git a/parse.go b/parse.go
index 8be4a493..85dbfca9 100644
--- a/parse.go
+++ b/parse.go
@@ -4,7 +4,7 @@ import (
"encoding/json"
"errors"
"io"
- direct "os"
+ "os"
"strconv"
"strings"
"syscall"
@@ -38,7 +38,7 @@ func tryPath(name string) (config *fst.Config) {
}()
}
} else {
- r = direct.Stdin
+ r = os.Stdin
}
if err := json.NewDecoder(r).Decode(&config); err != nil {
@@ -61,7 +61,7 @@ func tryFd(name string) io.ReadCloser {
}
fmsg.Fatalf("cannot get fd %d: %v", fd, errno)
}
- return direct.NewFile(fd, strconv.Itoa(v))
+ return os.NewFile(fd, strconv.Itoa(v))
}
}
@@ -85,7 +85,7 @@ func tryShort(name string) (config *fst.Config, instance *state.State) {
if likePrefix && len(name) >= 8 {
fmsg.VPrintln("argument looks like prefix")
- s := state.NewMulti(os.Paths().RunDirPath)
+ s := state.NewMulti(sys.Paths().RunDirPath)
if entries, err := state.Join(s); err != nil {
fmsg.Printf("cannot join store: %v", err)
// drop to fetch from file
diff --git a/print.go b/print.go
index e78861fa..ad230975 100644
--- a/print.go
+++ b/print.go
@@ -20,7 +20,7 @@ func printShowSystem(short bool) {
info := new(fst.Info)
// get fid by querying uid of aid 0
- if uid, err := os.Uid(0); err != nil {
+ if uid, err := sys.Uid(0); err != nil {
fmsg.Fatalf("cannot obtain uid from fsu: %v", err)
} else {
info.User = (uid / 10000) - 100
@@ -194,7 +194,7 @@ func printPs(short bool) {
now := time.Now().UTC()
var entries state.Entries
- s := state.NewMulti(os.Paths().RunDirPath)
+ s := state.NewMulti(sys.Paths().RunDirPath)
if e, err := state.Join(s); err != nil {
fmsg.Fatalf("cannot join store: %v", err)
} else {
diff --git a/test.nix b/test.nix
index c7692ba1..d25a1879 100644
--- a/test.nix
+++ b/test.nix
@@ -19,11 +19,19 @@ nixosTest {
nodes.machine =
{ lib, pkgs, ... }:
{
- users.users.alice = {
- isNormalUser = true;
- description = "Alice Foobar";
- password = "foobar";
- uid = 1000;
+ users.users = {
+ alice = {
+ isNormalUser = true;
+ description = "Alice Foobar";
+ password = "foobar";
+ uid = 1000;
+ };
+ untrusted = {
+ isNormalUser = true;
+ description = "Untrusted user";
+ password = "foobar";
+ uid = 1001;
+ };
};
home-manager.users.alice.home.stateVersion = "24.11";
@@ -198,6 +206,9 @@ nixosTest {
machine.wait_for_file("/run/user/1000/wayland-1")
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"))
+
# Create fortify uid 0 state directory:
machine.succeed("install -dm 0755 -o u0_a0 -g users /var/lib/fortify/u0")