carlos / platform Public

Clone
git clone https://amadan.net/carlos/platform

Plain git — no account needed to clone.

Download

Download this file

1package instanceexec
2
3import (
4 "go/ast"
5 "go/build"
6 "go/parser"
7 "go/token"
8 "path"
9 "path/filepath"
10 "runtime"
11 "sort"
12 "strconv"
13 "strings"
14 "testing"
15)
16
17// Every carlos process inside an instance unit (the probe, the trampoline
18// and its exit hook, for all four templates) runs under
19// RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX. A socket of any other
20// family is refused, so code that asks for one fails on every box: the
21// probe's net.InterfaceAddrs, which is netlink, kept every box on v0.25.0
22// from ever being ready (#126). This walks the platform packages this one
23// builds from, as linux sees them, and refuses the calls that open one.
24// Third-party code is outside the walk; at the time of writing its one
25// such call is google/uuid's net.Interfaces, reached only for v1 and v6
26// UUIDs, which nothing here makes.
27func TestInstanceCodeOpensOnlyTheUnitsAddressFamilies(t *testing.T) {
28 const module = "github.com/carlosframework/platform"
29 root, err := filepath.Abs(filepath.Join("..", ".."))
30 if err != nil {
31 t.Fatal(err)
32 }
33 ctx := build.Default
34 ctx.GOOS, ctx.GOARCH, ctx.CgoEnabled = "linux", runtime.GOARCH, false
35
36 refused := map[string]map[string]bool{
37 "net": {"Interfaces": true, "InterfaceAddrs": true, "InterfaceByName": true, "InterfaceByIndex": true},
38 "syscall": {"NetlinkRIB": true},
39 "golang.org/x/sys/unix": {},
40 }
41 allowedAF := map[string]bool{"AF_INET": true, "AF_INET6": true, "AF_UNIX": true, "AF_UNSPEC": true}
42
43 var found []string
44 seen := map[string]bool{}
45 queue := []string{module + "/internal/instanceexec"}
46 for len(queue) > 0 {
47 ip := queue[0]
48 queue = queue[1:]
49 if seen[ip] {
50 continue
51 }
52 seen[ip] = true
53 dir := filepath.Join(root, strings.TrimPrefix(ip, module))
54 pkg, err := ctx.ImportDir(dir, 0)
55 if err != nil {
56 t.Fatalf("%s: %v", ip, err)
57 }
58 for _, imp := range pkg.Imports {
59 if strings.HasPrefix(imp, module+"/") {
60 queue = append(queue, imp)
61 }
62 }
63 for _, name := range pkg.GoFiles {
64 file := filepath.Join(dir, name)
65 f, err := parser.ParseFile(token.NewFileSet(), file, nil, parser.SkipObjectResolution)
66 if err != nil {
67 t.Fatal(err)
68 }
69 local := map[string]string{}
70 for _, is := range f.Imports {
71 p, _ := strconv.Unquote(is.Path.Value)
72 n := path.Base(p)
73 if is.Name != nil {
74 n = is.Name.Name
75 }
76 local[n] = p
77 }
78 ast.Inspect(f, func(n ast.Node) bool {
79 sel, ok := n.(*ast.SelectorExpr)
80 if !ok {
81 return true
82 }
83 x, ok := sel.X.(*ast.Ident)
84 if !ok {
85 return true
86 }
87 p := local[x.Name]
88 names, watched := refused[p]
89 if !watched {
90 return true
91 }
92 af := strings.HasPrefix(sel.Sel.Name, "AF_") && !allowedAF[sel.Sel.Name]
93 if names[sel.Sel.Name] || af {
94 found = append(found, strings.TrimPrefix(file, root+string(filepath.Separator))+": "+p+"."+sel.Sel.Name)
95 }
96 return true
97 })
98 }
99 }
100 sort.Strings(found)
101 for _, f := range found {
102 t.Errorf("%s needs an address family the instance units refuse", f)
103 }
104 if !seen[module+"/internal/instancectl"] {
105 t.Errorf("the walk never reached instancectl: %v", seen)
106 }
107}
108