//go:build linux && rootrunner package host import ( "context" "encoding/json" "os" "os/exec" "path/filepath" "syscall" "testing" "github.com/carlosframework/platform/internal/hostguard" "github.com/carlosframework/platform/internal/rootstate" ) func TestPlan14UnitBindingRootRunner(t *testing.T) { dir := generationRootRunnerDir(t) b, in, shape := plan14UnitBindingFixture(t, "plan14-binding.service", "", "") config := filepath.Join(dir, "units.json") raw, _ := json.Marshal(struct { Schema int Units []claimUnitShape }{1, []claimUnitShape{shape}}) if err := os.WriteFile(config, raw, 0644); err != nil { t.Fatal(err) } store, err := rootstate.Open(filepath.Join(dir, "bindings"), true, false) if err != nil { t.Fatal(err) } defer store.Close() b.state = store b.canonical = func(ctx context.Context, host string) (claimUnitShape, error) { all, err := readClaimUnitShapes(config) if err != nil { return claimUnitShape{}, err } s, ok := all[host] if !ok { return s, os.ErrNotExist } return s, nil } bound, err := b.establish(t.Context(), in.Host) if err != nil { t.Fatal(err) } row := shape.route() if _, err := b.check(t.Context(), in.Host, &row); err != nil { t.Fatal(err) } child := exec.Command("/bin/sh", "-c", `printf '{}' > "$1"`, "binding-writer", config) child.SysProcAttr = &syscall.SysProcAttr{Credential: &syscall.Credential{Uid: 65534, Gid: 65534}} if err := child.Run(); err == nil { t.Fatal("service credential replaced root config") } if _, err := b.check(t.Context(), in.Host, &row); err != nil { t.Fatal("hostile writer changed binding", err) } if err := os.Chmod(config, 0666); err != nil { t.Fatal(err) } if _, err := b.check(t.Context(), in.Host, &row); err == nil { t.Fatal("service-writable canonical source accepted") } if err := os.Chmod(config, 0644); err != nil { t.Fatal(err) } if err := os.Chown(config, 65534, 65534); err != nil { t.Fatal(err) } if _, err := b.check(t.Context(), in.Host, &row); err == nil { t.Fatal("service-owned canonical source accepted") } if err := os.Chown(config, 0, 0); err != nil { t.Fatal(err) } successor := in successor.Stamp++ b.installation = func(context.Context, string) (hostguard.RootInstallation, error) { return successor, nil } if _, err := b.check(t.Context(), in.Host, &row); err == nil { t.Fatal("successor reused binding") } if err := b.retire(t.Context(), bound, func(claimUnitBinding) error { return nil }); err != nil { t.Fatal(err) } if _, err := b.establish(t.Context(), in.Host); err == nil { t.Fatal("retirement recreated authority") } }