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