blob: 1c3d477abebcdad5ec02f8adf8ed9ed2d624f055 [file] [log] [blame]
Andrew G. Morgane20eb692020-02-23 15:50:51 -08001// Program try-launching validates the cap.Launch feature.
2package main
3
4import (
5 "fmt"
6 "log"
7 "strings"
8 "syscall"
9
Andrew G. Morganb0d13e82020-07-03 10:47:42 -070010 "kernel.org/pub/linux/libs/security/libcap/cap"
Andrew G. Morgane20eb692020-02-23 15:50:51 -080011)
12
13// tryLaunching attempts to launch a bunch of programs in parallel. It
14// first tries some unprivileged launches, and then (if privileged)
15// tries some more ambitious ones.
16func tryLaunching() {
17 cwd, err := syscall.Getwd()
18 if err != nil {
19 log.Fatalf("no working directory: %v", err)
20 }
21 root := cwd[:strings.LastIndex(cwd, "/")]
22
23 vs := []struct {
24 args []string
25 fail bool
26 callbackFn func(*syscall.ProcAttr, interface{}) error
27 chroot string
28 iab string
29 uid int
30 gid int
31 groups []int
32 }{
33 {args: []string{root + "/go/ok"}},
34 {
35 args: []string{root + "/progs/capsh", "--dropped=cap_chown", "--is-uid=123", "--is-gid=456", "--has-a=cap_setuid"},
36 iab: "!cap_chown,^cap_setuid,cap_sys_admin",
37 uid: 123,
38 gid: 456,
39 groups: []int{1, 2, 3},
40 fail: syscall.Getuid() != 0,
41 },
42 {
43 args: []string{"/ok"},
44 chroot: root + "/go",
45 fail: syscall.Getuid() != 0,
46 },
47 }
48
49 ps := make([]int, len(vs))
50 ws := make([]syscall.WaitStatus, len(vs))
51
52 for i, v := range vs {
53 e := cap.NewLauncher(v.args[0], v.args, nil)
54 e.Callback(v.callbackFn)
55 if v.chroot != "" {
56 e.SetChroot(v.chroot)
57 }
58 if v.uid != 0 {
59 e.SetUID(v.uid)
60 }
61 if v.gid != 0 {
62 e.SetGroups(v.gid, v.groups)
63 }
64 if v.iab != "" {
65 if iab, err := cap.IABFromText(v.iab); err != nil {
66 log.Fatalf("failed to parse iab=%q: %v", v.iab, err)
67 } else {
68 e.SetIAB(iab)
69 }
70 }
71 if ps[i], err = e.Launch(nil); err != nil {
72 if v.fail {
73 continue
74 }
75 log.Fatalf("[%d] launch %q failed: %v", i, v.args, err)
76 }
77 }
78
79 for i, p := range ps {
80 if p == -1 {
81 continue
82 }
83 if pr, err := syscall.Wait4(p, &ws[i], 0, nil); err != nil {
84 log.Fatalf("wait4 <%d> failed: %v", p, err)
85 } else if p != pr {
86 log.Fatalf("wait4 <%d> returned <%d> instead", p, pr)
87 } else if ws[i] != 0 {
88 if vs[i].fail {
89 continue
90 }
91 log.Fatalf("wait4 <%d> status was %d", p, ws[i])
92 }
93 }
94}
95
96func main() {
97 if cap.LaunchSupported {
98 // The Go runtime had some OS threading bugs that
99 // prevented Launch from working. Specifically, the
100 // launch OS thread would get reused.
101 tryLaunching()
102 }
103 fmt.Println("PASSED")
104}