blob: 9f20e6b770a0f4fb81be91b3ab1a4eaff11b15a2 [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
Andrew G. Morganf552b8f2020-12-26 21:42:15 -080031 mode cap.Mode
Andrew G. Morgane20eb692020-02-23 15:50:51 -080032 groups []int
33 }{
34 {args: []string{root + "/go/ok"}},
35 {
Andrew G. Morgan307e7f52020-09-07 12:24:43 -070036 args: []string{root + "/progs/tcapsh-static", "--dropped=cap_chown", "--is-uid=123", "--is-gid=456", "--has-a=cap_setuid"},
Andrew G. Morgane20eb692020-02-23 15:50:51 -080037 iab: "!cap_chown,^cap_setuid,cap_sys_admin",
38 uid: 123,
39 gid: 456,
40 groups: []int{1, 2, 3},
41 fail: syscall.Getuid() != 0,
42 },
43 {
44 args: []string{"/ok"},
45 chroot: root + "/go",
46 fail: syscall.Getuid() != 0,
47 },
Andrew G. Morganf552b8f2020-12-26 21:42:15 -080048 {
49 args: []string{root + "/progs/tcapsh-static", "--inmode=NOPRIV", "--has-no-new-privs"},
50 mode: cap.ModeNoPriv,
51 fail: syscall.Getuid() != 0,
52 },
Andrew G. Morgane20eb692020-02-23 15:50:51 -080053 }
54
55 ps := make([]int, len(vs))
56 ws := make([]syscall.WaitStatus, len(vs))
57
58 for i, v := range vs {
59 e := cap.NewLauncher(v.args[0], v.args, nil)
60 e.Callback(v.callbackFn)
61 if v.chroot != "" {
62 e.SetChroot(v.chroot)
63 }
64 if v.uid != 0 {
65 e.SetUID(v.uid)
66 }
67 if v.gid != 0 {
68 e.SetGroups(v.gid, v.groups)
69 }
Andrew G. Morganf552b8f2020-12-26 21:42:15 -080070 if v.mode != 0 {
71 e.SetMode(v.mode)
72 }
Andrew G. Morgane20eb692020-02-23 15:50:51 -080073 if v.iab != "" {
74 if iab, err := cap.IABFromText(v.iab); err != nil {
75 log.Fatalf("failed to parse iab=%q: %v", v.iab, err)
76 } else {
77 e.SetIAB(iab)
78 }
79 }
Andrew G. Morganf552b8f2020-12-26 21:42:15 -080080 log.Printf("[%d] trying: %q\n", i, v.args)
Andrew G. Morgane20eb692020-02-23 15:50:51 -080081 if ps[i], err = e.Launch(nil); err != nil {
82 if v.fail {
83 continue
84 }
85 log.Fatalf("[%d] launch %q failed: %v", i, v.args, err)
86 }
87 }
88
89 for i, p := range ps {
90 if p == -1 {
91 continue
92 }
93 if pr, err := syscall.Wait4(p, &ws[i], 0, nil); err != nil {
94 log.Fatalf("wait4 <%d> failed: %v", p, err)
95 } else if p != pr {
96 log.Fatalf("wait4 <%d> returned <%d> instead", p, pr)
97 } else if ws[i] != 0 {
98 if vs[i].fail {
99 continue
100 }
101 log.Fatalf("wait4 <%d> status was %d", p, ws[i])
102 }
103 }
104}
105
106func main() {
107 if cap.LaunchSupported {
108 // The Go runtime had some OS threading bugs that
109 // prevented Launch from working. Specifically, the
110 // launch OS thread would get reused.
111 tryLaunching()
112 }
113 fmt.Println("PASSED")
114}