//go:build linux package console import ( "fmt" "os" "strings" "testing" "time" ) func plan9Fix2Boot(t *testing.T) string { t.Helper() raw, err := os.ReadFile("/proc/sys/kernel/random/boot_id") if err != nil { t.Fatal(err) } return strings.TrimSpace(string(raw)) } func TestPlan9Fix4ContainerProcfsDoesNotProveLegacyPIDAbsent(t *testing.T) { boot := plan9Fix2Boot(t) const ns = "4026532999" priorNamespace := hostReportPIDNamespace t.Cleanup(func() { hostReportPIDNamespace = priorNamespace }) hostReportPIDNamespace = func() (string, error) { return ns, nil } // A container with its own procfs sees itself and its init in the same // namespace, while a still-live host PID is absent from both procfs and // kill(0). That agreement is not evidence of the initial namespace. plan9Fix2RootNamespace(t, ns, nil) prior := hostReportProcReadFile t.Cleanup(func() { hostReportProcReadFile = prior }) hostReportProcReadFile = func(path string) ([]byte, error) { if path == "/proc/999999999/stat" { return nil, os.ErrNotExist } return prior(path) } now := time.Now() if err := hostReportCollision(plan9Report(boot+":999999999", now), plan9Report(hostReportProcessID(boot), now), now); err == nil { t.Fatal("container procfs allowed takeover of a live host's legacy report") } } func plan9Fix2RootNamespace(t *testing.T, ns string, err error) { t.Helper() prior := hostReportRootPIDNamespace t.Cleanup(func() { hostReportRootPIDNamespace = prior }) hostReportRootPIDNamespace = func() (string, error) { return ns, err } } func TestPlan9Fix2LegacyTwoPartIDProvedGoneInHostNamespace(t *testing.T) { boot := plan9Fix2Boot(t) const ns = hostReportInitialPIDNamespace priorNamespace := hostReportPIDNamespace t.Cleanup(func() { hostReportPIDNamespace = priorNamespace }) hostReportPIDNamespace = func() (string, error) { return ns, nil } plan9Fix2RootNamespace(t, ns, nil) if !hostReportProcessGone(boot+":999999999", hostReportProcessID(boot)) { t.Fatal("main's absent boot:pid was not accepted during the roll") } } func TestPlan9Fix2LegacyTwoPartIDNeverProvedOutsideHostNamespace(t *testing.T) { boot := plan9Fix2Boot(t) ns, _ := hostReportPIDNamespace() next := hostReportProcessID(boot) plan9Fix2RootNamespace(t, ns+"0", nil) if hostReportProcessGone(boot+":999999999", next) { t.Fatal("legacy ID proved gone from a namespace that is not init's") } plan9Fix2RootNamespace(t, "", os.ErrPermission) if hostReportProcessGone(boot+":999999999", next) { t.Fatal("legacy ID proved gone with an unreadable init namespace") } } func TestPlan9Fix2LegacyTwoPartIDKeepsLivePIDAndBootChecks(t *testing.T) { boot := plan9Fix2Boot(t) const ns = hostReportInitialPIDNamespace priorNamespace := hostReportPIDNamespace t.Cleanup(func() { hostReportPIDNamespace = priorNamespace }) hostReportPIDNamespace = func() (string, error) { return ns, nil } plan9Fix2RootNamespace(t, ns, nil) next := hostReportProcessID(boot) if hostReportProcessGone(fmt.Sprintf("%s:%d", boot, os.Getpid()), next) { t.Fatal("a live legacy PID was proved gone") } if hostReportProcessGone("other-boot:999999999", hostReportProcessID("other-boot")) { t.Fatal("a legacy ID from another boot was proved gone") } if hostReportProcessGone(boot+":999999999", hostReportProcessID("other-boot")) { t.Fatal("boot mismatch between reports was ignored") } }