Something went wrong. Try again.
Monorepo for Tangled
Something went wrong. Try again.
5.2 kB · 175 lines
Go
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176//go:build linux
package sandbox
import ( "os/exec" "strings" "syscall" "testing")
func TestLandlockBackend_Name(t *testing.T) { if (&LandlockBackend{}).Name() != "landlock" { t.Error("Name should return \"landlock\"") }}
func TestLandlockBackend_WrapMulti_NoPaths(t *testing.T) { sb := &LandlockBackend{selfExe: "/proc/self/exe"} cmd := exec.Command("git", "status")
wrapped, err := sb.WrapMulti(nil, cmd) if err != nil { t.Fatalf("WrapMulti: %v", err) } if wrapped != cmd { t.Error("empty paths should return the original cmd unchanged") }}
func TestLandlockBackend_WrapMulti_ArgsConstruction(t *testing.T) { sb := &LandlockBackend{selfExe: "/path/to/knot"} cmd := exec.Command("git", "upload-pack", "--stateless-rpc", ".") cmd.Env = []string{"GIT_PROTOCOL=version=2"} cmd.Stdin = strings.NewReader("input")
wrapped, err := sb.WrapMulti([]string{"/repos/a", "/repos/b"}, cmd) if err != nil { t.Fatalf("WrapMulti: %v", err) }
// argv[0] is the selfExe if wrapped.Path != "/path/to/knot" { t.Errorf("Path = %q, want %q", wrapped.Path, "/path/to/knot") }
// argv should be: [knot, sandbox-exec, --repo-path=/repos/a, --repo-path=/repos/b, --, <abs-git>, upload-pack, ...] args := wrapped.Args if len(args) < 6 { t.Fatalf("Args too short: %v", args) } if args[0] != "/path/to/knot" { t.Errorf("Args[0] = %q, want %q", args[0], "/path/to/knot") } if args[1] != "sandbox-exec" { t.Errorf("Args[1] = %q, want %q", args[1], "sandbox-exec") } if args[2] != "--repo-path=/repos/a" { t.Errorf("Args[2] = %q, want --repo-path=/repos/a", args[2]) } if args[3] != "--repo-path=/repos/b" { t.Errorf("Args[3] = %q, want --repo-path=/repos/b", args[3]) } if args[4] != "--" { t.Errorf("Args[4] = %q, want --", args[4]) } // args[5] is the resolved absolute git path; just check it ends with /git if !strings.HasSuffix(args[5], "/git") && args[5] != "git" { t.Errorf("Args[5] = %q, want path ending in /git or bare \"git\"", args[5]) } if got := args[len(args)-1]; got != "." { t.Errorf("last arg = %q, want %q", got, ".") }
// Dir should be the first repo path so the kernel chdirs there // after setuid, before execve. if wrapped.Dir != "/repos/a" { t.Errorf("Dir = %q, want %q", wrapped.Dir, "/repos/a") }
// Env propagated if len(wrapped.Env) != 1 || wrapped.Env[0] != "GIT_PROTOCOL=version=2" { t.Errorf("Env = %v, want [GIT_PROTOCOL=version=2]", wrapped.Env) }
// Stdio propagated if wrapped.Stdin != cmd.Stdin { t.Error("Stdin not propagated to wrapped cmd") }}
func TestLandlockBackend_WrapMulti_NoLookupNoCredential(t *testing.T) { sb := &LandlockBackend{selfExe: "/path/to/knot"} // no lookup cmd := exec.Command("git", "status")
wrapped, err := sb.WrapMulti([]string{"/repos/a"}, cmd) if err != nil { t.Fatalf("WrapMulti: %v", err) } if wrapped.SysProcAttr != nil && wrapped.SysProcAttr.Credential != nil { t.Error("no lookup configured; Credential should not be set") }}
func TestLandlockBackend_WrapMulti_LookupSetsCredential(t *testing.T) { // lookup deliberately returns a different gid (the service group) to // confirm that WrapMulti ignores it and uses uid as the primary gid. // see the comment in sandbox_linux.go for why this matters. sb := &LandlockBackend{ selfExe: "/path/to/knot", lookup: func(repoPath string) (uint32, uint32, error) { if repoPath != "/repos/a" { t.Errorf("lookup called with %q, want /repos/a", repoPath) } return 100042, 1234, nil }, } cmd := exec.Command("git", "status")
wrapped, err := sb.WrapMulti([]string{"/repos/a"}, cmd) if err != nil { t.Fatalf("WrapMulti: %v", err) } if wrapped.SysProcAttr == nil || wrapped.SysProcAttr.Credential == nil { t.Fatal("Credential should be set when lookup returns uid > 0") } cred := wrapped.SysProcAttr.Credential if cred.Uid != 100042 { t.Errorf("Credential.Uid = %d, want 100042", cred.Uid) } if cred.Gid != 100042 { t.Errorf("Credential.Gid = %d, want 100042 (must equal Uid, not lookup's gid 1234)", cred.Gid) } if !cred.NoSetGroups { t.Error("NoSetGroups should be true") }}
func TestLandlockBackend_WrapMulti_LookupErrSkipsCredential(t *testing.T) { sb := &LandlockBackend{ selfExe: "/path/to/knot", lookup: func(string) (uint32, uint32, error) { return 0, 0, syscall.ENOENT }, } cmd := exec.Command("git", "status")
wrapped, err := sb.WrapMulti([]string{"/repos/a"}, cmd) if err != nil { t.Fatalf("WrapMulti: %v", err) } if wrapped.SysProcAttr != nil && wrapped.SysProcAttr.Credential != nil { t.Error("lookup errored; Credential should not be set") }}
func TestLandlockBackend_WrapMulti_LookupZeroSkipsCredential(t *testing.T) { // uid == 0 is treated as "don't drop" so we never accidentally drop to // root. Verify Credential isn't set in that case. sb := &LandlockBackend{ selfExe: "/path/to/knot", lookup: func(string) (uint32, uint32, error) { return 0, 0, nil }, } cmd := exec.Command("git", "status")
wrapped, err := sb.WrapMulti([]string{"/repos/a"}, cmd) if err != nil { t.Fatalf("WrapMulti: %v", err) } if wrapped.SysProcAttr != nil && wrapped.SysProcAttr.Credential != nil { t.Error("lookup returned uid=0; Credential should not be set") }}