package instanceexec import ( "go/ast" "go/build" "go/parser" "go/token" "path" "path/filepath" "runtime" "sort" "strconv" "strings" "testing" ) // Every carlos process inside an instance unit (the probe, the trampoline // and its exit hook, for all four templates) runs under // RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX. A socket of any other // family is refused, so code that asks for one fails on every box: the // probe's net.InterfaceAddrs, which is netlink, kept every box on v0.25.0 // from ever being ready (#126). This walks the platform packages this one // builds from, as linux sees them, and refuses the calls that open one. // Third-party code is outside the walk; at the time of writing its one // such call is google/uuid's net.Interfaces, reached only for v1 and v6 // UUIDs, which nothing here makes. func TestInstanceCodeOpensOnlyTheUnitsAddressFamilies(t *testing.T) { const module = "github.com/carlosframework/platform" root, err := filepath.Abs(filepath.Join("..", "..")) if err != nil { t.Fatal(err) } ctx := build.Default ctx.GOOS, ctx.GOARCH, ctx.CgoEnabled = "linux", runtime.GOARCH, false refused := map[string]map[string]bool{ "net": {"Interfaces": true, "InterfaceAddrs": true, "InterfaceByName": true, "InterfaceByIndex": true}, "syscall": {"NetlinkRIB": true}, "golang.org/x/sys/unix": {}, } allowedAF := map[string]bool{"AF_INET": true, "AF_INET6": true, "AF_UNIX": true, "AF_UNSPEC": true} var found []string seen := map[string]bool{} queue := []string{module + "/internal/instanceexec"} for len(queue) > 0 { ip := queue[0] queue = queue[1:] if seen[ip] { continue } seen[ip] = true dir := filepath.Join(root, strings.TrimPrefix(ip, module)) pkg, err := ctx.ImportDir(dir, 0) if err != nil { t.Fatalf("%s: %v", ip, err) } for _, imp := range pkg.Imports { if strings.HasPrefix(imp, module+"/") { queue = append(queue, imp) } } for _, name := range pkg.GoFiles { file := filepath.Join(dir, name) f, err := parser.ParseFile(token.NewFileSet(), file, nil, parser.SkipObjectResolution) if err != nil { t.Fatal(err) } local := map[string]string{} for _, is := range f.Imports { p, _ := strconv.Unquote(is.Path.Value) n := path.Base(p) if is.Name != nil { n = is.Name.Name } local[n] = p } ast.Inspect(f, func(n ast.Node) bool { sel, ok := n.(*ast.SelectorExpr) if !ok { return true } x, ok := sel.X.(*ast.Ident) if !ok { return true } p := local[x.Name] names, watched := refused[p] if !watched { return true } af := strings.HasPrefix(sel.Sel.Name, "AF_") && !allowedAF[sel.Sel.Name] if names[sel.Sel.Name] || af { found = append(found, strings.TrimPrefix(file, root+string(filepath.Separator))+": "+p+"."+sel.Sel.Name) } return true }) } } sort.Strings(found) for _, f := range found { t.Errorf("%s needs an address family the instance units refuse", f) } if !seen[module+"/internal/instancectl"] { t.Errorf("the walk never reached instancectl: %v", seen) } }