1*2810ac1bSKiyoung Kim// Program compare-cap is a sanity check that Go's cap package is 2*2810ac1bSKiyoung Kim// inter-operable with the C libcap. 3*2810ac1bSKiyoung Kimpackage main 4*2810ac1bSKiyoung Kim 5*2810ac1bSKiyoung Kimimport ( 6*2810ac1bSKiyoung Kim "log" 7*2810ac1bSKiyoung Kim "os" 8*2810ac1bSKiyoung Kim "syscall" 9*2810ac1bSKiyoung Kim "unsafe" 10*2810ac1bSKiyoung Kim 11*2810ac1bSKiyoung Kim "kernel.org/pub/linux/libs/security/libcap/cap" 12*2810ac1bSKiyoung Kim) 13*2810ac1bSKiyoung Kim 14*2810ac1bSKiyoung Kim// #include <stdlib.h> 15*2810ac1bSKiyoung Kim// #include <sys/capability.h> 16*2810ac1bSKiyoung Kim// #cgo CFLAGS: -I../libcap/include 17*2810ac1bSKiyoung Kim// #cgo LDFLAGS: -L../libcap -lcap 18*2810ac1bSKiyoung Kimimport "C" 19*2810ac1bSKiyoung Kim 20*2810ac1bSKiyoung Kim// tryFileCaps attempts to use the cap package to manipulate file 21*2810ac1bSKiyoung Kim// capabilities. No reference to libcap in this function. 22*2810ac1bSKiyoung Kimfunc tryFileCaps() { 23*2810ac1bSKiyoung Kim saved := cap.GetProc() 24*2810ac1bSKiyoung Kim 25*2810ac1bSKiyoung Kim // Capabilities we will place on a file. 26*2810ac1bSKiyoung Kim want := cap.NewSet() 27*2810ac1bSKiyoung Kim if err := want.SetFlag(cap.Permitted, true, cap.SETFCAP, cap.DAC_OVERRIDE); err != nil { 28*2810ac1bSKiyoung Kim log.Fatalf("failed to explore desired file capability: %v", err) 29*2810ac1bSKiyoung Kim } 30*2810ac1bSKiyoung Kim if err := want.SetFlag(cap.Effective, true, cap.SETFCAP, cap.DAC_OVERRIDE); err != nil { 31*2810ac1bSKiyoung Kim log.Fatalf("failed to raise the effective bits: %v", err) 32*2810ac1bSKiyoung Kim } 33*2810ac1bSKiyoung Kim 34*2810ac1bSKiyoung Kim if perm, err := saved.GetFlag(cap.Permitted, cap.SETFCAP); err != nil { 35*2810ac1bSKiyoung Kim log.Fatalf("failed to read capability: %v", err) 36*2810ac1bSKiyoung Kim } else if !perm { 37*2810ac1bSKiyoung Kim log.Printf("skipping file cap tests - insufficient privilege") 38*2810ac1bSKiyoung Kim return 39*2810ac1bSKiyoung Kim } 40*2810ac1bSKiyoung Kim 41*2810ac1bSKiyoung Kim if err := saved.ClearFlag(cap.Effective); err != nil { 42*2810ac1bSKiyoung Kim log.Fatalf("failed to drop effective: %v", err) 43*2810ac1bSKiyoung Kim } 44*2810ac1bSKiyoung Kim if err := saved.SetProc(); err != nil { 45*2810ac1bSKiyoung Kim log.Fatalf("failed to limit capabilities: %v", err) 46*2810ac1bSKiyoung Kim } 47*2810ac1bSKiyoung Kim 48*2810ac1bSKiyoung Kim // Failing attempt to remove capabilities. 49*2810ac1bSKiyoung Kim var empty *cap.Set 50*2810ac1bSKiyoung Kim if err := empty.SetFile(os.Args[0]); err != syscall.EPERM { 51*2810ac1bSKiyoung Kim log.Fatalf("failed to be blocked from removing filecaps: %v", err) 52*2810ac1bSKiyoung Kim } 53*2810ac1bSKiyoung Kim 54*2810ac1bSKiyoung Kim // The privilege we want (in the case we are root, we need the 55*2810ac1bSKiyoung Kim // DAC_OVERRIDE too). 56*2810ac1bSKiyoung Kim working, err := saved.Dup() 57*2810ac1bSKiyoung Kim if err != nil { 58*2810ac1bSKiyoung Kim log.Fatalf("failed to duplicate (%v): %v", saved, err) 59*2810ac1bSKiyoung Kim } 60*2810ac1bSKiyoung Kim if err := working.SetFlag(cap.Effective, true, cap.DAC_OVERRIDE, cap.SETFCAP); err != nil { 61*2810ac1bSKiyoung Kim log.Fatalf("failed to raise effective: %v", err) 62*2810ac1bSKiyoung Kim } 63*2810ac1bSKiyoung Kim 64*2810ac1bSKiyoung Kim // Critical (privilege using) section: 65*2810ac1bSKiyoung Kim if err := working.SetProc(); err != nil { 66*2810ac1bSKiyoung Kim log.Fatalf("failed to enable first effective privilege: %v", err) 67*2810ac1bSKiyoung Kim } 68*2810ac1bSKiyoung Kim // Delete capability 69*2810ac1bSKiyoung Kim if err := empty.SetFile(os.Args[0]); err != nil && err != syscall.ENODATA { 70*2810ac1bSKiyoung Kim log.Fatalf("blocked from removing filecaps: %v", err) 71*2810ac1bSKiyoung Kim } 72*2810ac1bSKiyoung Kim if got, err := cap.GetFile(os.Args[0]); err == nil { 73*2810ac1bSKiyoung Kim log.Fatalf("read deleted file caps: %v", got) 74*2810ac1bSKiyoung Kim } 75*2810ac1bSKiyoung Kim // Create file caps (this use employs the effective bit). 76*2810ac1bSKiyoung Kim if err := want.SetFile(os.Args[0]); err != nil { 77*2810ac1bSKiyoung Kim log.Fatalf("failed to set file capability: %v", err) 78*2810ac1bSKiyoung Kim } 79*2810ac1bSKiyoung Kim if err := saved.SetProc(); err != nil { 80*2810ac1bSKiyoung Kim log.Fatalf("failed to lower effective capability: %v", err) 81*2810ac1bSKiyoung Kim } 82*2810ac1bSKiyoung Kim // End of critical section. 83*2810ac1bSKiyoung Kim 84*2810ac1bSKiyoung Kim if got, err := cap.GetFile(os.Args[0]); err != nil { 85*2810ac1bSKiyoung Kim log.Fatalf("failed to read caps: %v", err) 86*2810ac1bSKiyoung Kim } else if is, was := got.String(), want.String(); is != was { 87*2810ac1bSKiyoung Kim log.Fatalf("read file caps do not match desired: got=%q want=%q", is, was) 88*2810ac1bSKiyoung Kim } 89*2810ac1bSKiyoung Kim 90*2810ac1bSKiyoung Kim // Now, do it all again but this time on an open file. 91*2810ac1bSKiyoung Kim f, err := os.Open(os.Args[0]) 92*2810ac1bSKiyoung Kim if err != nil { 93*2810ac1bSKiyoung Kim log.Fatalf("failed to open %q: %v", os.Args[0], err) 94*2810ac1bSKiyoung Kim } 95*2810ac1bSKiyoung Kim defer f.Close() 96*2810ac1bSKiyoung Kim 97*2810ac1bSKiyoung Kim // Failing attempt to remove capabilities. 98*2810ac1bSKiyoung Kim if err := empty.SetFd(f); err != syscall.EPERM { 99*2810ac1bSKiyoung Kim log.Fatalf("failed to be blocked from fremoving filecaps: %v", err) 100*2810ac1bSKiyoung Kim } 101*2810ac1bSKiyoung Kim 102*2810ac1bSKiyoung Kim // For the next section, we won't set the effective bit on the file. 103*2810ac1bSKiyoung Kim want.ClearFlag(cap.Effective) 104*2810ac1bSKiyoung Kim 105*2810ac1bSKiyoung Kim // Critical (privilege using) section: 106*2810ac1bSKiyoung Kim if err := working.SetProc(); err != nil { 107*2810ac1bSKiyoung Kim log.Fatalf("failed to enable effective privilege: %v", err) 108*2810ac1bSKiyoung Kim } 109*2810ac1bSKiyoung Kim if err := empty.SetFd(f); err != nil && err != syscall.ENODATA { 110*2810ac1bSKiyoung Kim log.Fatalf("blocked from fremoving filecaps: %v", err) 111*2810ac1bSKiyoung Kim } 112*2810ac1bSKiyoung Kim if got, err := cap.GetFd(f); err == nil { 113*2810ac1bSKiyoung Kim log.Fatalf("read fdeleted file caps: %v", got) 114*2810ac1bSKiyoung Kim } 115*2810ac1bSKiyoung Kim // This one does not set the effective bit. 116*2810ac1bSKiyoung Kim if err := want.SetFd(f); err != nil { 117*2810ac1bSKiyoung Kim log.Fatalf("failed to fset file capability: %v", err) 118*2810ac1bSKiyoung Kim } 119*2810ac1bSKiyoung Kim if got, err := cap.GetFd(f); err != nil { 120*2810ac1bSKiyoung Kim log.Fatalf("failed to fread caps: %v", err) 121*2810ac1bSKiyoung Kim } else if is, was := got.String(), want.String(); is != was { 122*2810ac1bSKiyoung Kim log.Fatalf("fread file caps do not match desired: got=%q want=%q", is, was) 123*2810ac1bSKiyoung Kim } 124*2810ac1bSKiyoung Kim if err := empty.SetFd(f); err != nil && err != syscall.ENODATA { 125*2810ac1bSKiyoung Kim log.Fatalf("blocked from cleanup fremoving filecaps: %v", err) 126*2810ac1bSKiyoung Kim } 127*2810ac1bSKiyoung Kim if err := saved.SetProc(); err != nil { 128*2810ac1bSKiyoung Kim log.Fatalf("failed to lower effective capability: %v", err) 129*2810ac1bSKiyoung Kim } 130*2810ac1bSKiyoung Kim // End of critical section. 131*2810ac1bSKiyoung Kim} 132*2810ac1bSKiyoung Kim 133*2810ac1bSKiyoung Kim// tryProcCaps performs a set of convenience functions and compares 134*2810ac1bSKiyoung Kim// the results with those seen by libcap. At the end of this function, 135*2810ac1bSKiyoung Kim// the running process has no privileges at all. So exiting the 136*2810ac1bSKiyoung Kim// program is the only option. 137*2810ac1bSKiyoung Kimfunc tryProcCaps() { 138*2810ac1bSKiyoung Kim c := cap.GetProc() 139*2810ac1bSKiyoung Kim if v, err := c.GetFlag(cap.Permitted, cap.SETPCAP); err != nil { 140*2810ac1bSKiyoung Kim log.Fatalf("failed to read permitted setpcap: %v", err) 141*2810ac1bSKiyoung Kim } else if !v { 142*2810ac1bSKiyoung Kim log.Printf("skipping proc cap tests - insufficient privilege") 143*2810ac1bSKiyoung Kim return 144*2810ac1bSKiyoung Kim } 145*2810ac1bSKiyoung Kim if err := cap.SetUID(99); err != nil { 146*2810ac1bSKiyoung Kim log.Fatalf("failed to set uid=99: %v", err) 147*2810ac1bSKiyoung Kim } 148*2810ac1bSKiyoung Kim if u := syscall.Getuid(); u != 99 { 149*2810ac1bSKiyoung Kim log.Fatal("uid=99 did not take: got=%d", u) 150*2810ac1bSKiyoung Kim } 151*2810ac1bSKiyoung Kim if err := cap.SetGroups(98, 100, 101); err != nil { 152*2810ac1bSKiyoung Kim log.Fatalf("failed to set groups=98 [100, 101]: %v", err) 153*2810ac1bSKiyoung Kim } 154*2810ac1bSKiyoung Kim if g := syscall.Getgid(); g != 98 { 155*2810ac1bSKiyoung Kim log.Fatalf("gid=98 did not take: got=%d", g) 156*2810ac1bSKiyoung Kim } 157*2810ac1bSKiyoung Kim if gs, err := syscall.Getgroups(); err != nil { 158*2810ac1bSKiyoung Kim log.Fatalf("error getting groups: %v", err) 159*2810ac1bSKiyoung Kim } else if len(gs) != 2 || gs[0] != 100 || gs[1] != 101 { 160*2810ac1bSKiyoung Kim log.Fatalf("wrong of groups: got=%v want=[100 l01]", gs) 161*2810ac1bSKiyoung Kim } 162*2810ac1bSKiyoung Kim 163*2810ac1bSKiyoung Kim if mode := cap.GetMode(); mode != cap.ModeHybrid { 164*2810ac1bSKiyoung Kim log.Fatalf("initial mode should be 4 (HYBRID), got: %d (%v)", mode, mode) 165*2810ac1bSKiyoung Kim } 166*2810ac1bSKiyoung Kim 167*2810ac1bSKiyoung Kim // To distinguish PURE1E and PURE1E_INIT we need an inheritable capability set. 168*2810ac1bSKiyoung Kim working := cap.GetProc() 169*2810ac1bSKiyoung Kim if err := working.SetFlag(cap.Inheritable, true, cap.SETPCAP); err != nil { 170*2810ac1bSKiyoung Kim log.Fatalf("unable to raise inheritable bit: %v", err) 171*2810ac1bSKiyoung Kim } 172*2810ac1bSKiyoung Kim if err := working.SetProc(); err != nil { 173*2810ac1bSKiyoung Kim log.Fatalf("failed to add inheritable bit: %v", err) 174*2810ac1bSKiyoung Kim } 175*2810ac1bSKiyoung Kim 176*2810ac1bSKiyoung Kim for i, mode := range []cap.Mode{cap.ModePure1E, cap.ModePure1EInit, cap.ModeNoPriv} { 177*2810ac1bSKiyoung Kim if err := mode.Set(); err != nil { 178*2810ac1bSKiyoung Kim log.Fatalf("[%d] in mode=%v and failed to set mode to %d (%v): %v", i, cap.GetMode(), mode, mode, err) 179*2810ac1bSKiyoung Kim } 180*2810ac1bSKiyoung Kim if got := cap.GetMode(); got != mode { 181*2810ac1bSKiyoung Kim log.Fatalf("[%d] unable to recognise mode %d (%v), got: %d (%v)", i, mode, mode, got, got) 182*2810ac1bSKiyoung Kim } 183*2810ac1bSKiyoung Kim cM := C.cap_get_mode() 184*2810ac1bSKiyoung Kim if mode != cap.Mode(cM) { 185*2810ac1bSKiyoung Kim log.Fatalf("[%d] C and Go disagree on mode: %d vs %d", cM, mode) 186*2810ac1bSKiyoung Kim } 187*2810ac1bSKiyoung Kim } 188*2810ac1bSKiyoung Kim 189*2810ac1bSKiyoung Kim // The current process is now without any access to privilege. 190*2810ac1bSKiyoung Kim} 191*2810ac1bSKiyoung Kim 192*2810ac1bSKiyoung Kimfunc main() { 193*2810ac1bSKiyoung Kim // Use the C libcap to obtain a non-trivial capability in text form (from init). 194*2810ac1bSKiyoung Kim cC := C.cap_get_pid(1) 195*2810ac1bSKiyoung Kim if cC == nil { 196*2810ac1bSKiyoung Kim log.Fatal("basic c caps from init function failure") 197*2810ac1bSKiyoung Kim } 198*2810ac1bSKiyoung Kim defer C.cap_free(unsafe.Pointer(cC)) 199*2810ac1bSKiyoung Kim var tCLen C.ssize_t 200*2810ac1bSKiyoung Kim tC := C.cap_to_text(cC, &tCLen) 201*2810ac1bSKiyoung Kim if tC == nil { 202*2810ac1bSKiyoung Kim log.Fatal("basic c init caps -> text failure") 203*2810ac1bSKiyoung Kim } 204*2810ac1bSKiyoung Kim defer C.cap_free(unsafe.Pointer(tC)) 205*2810ac1bSKiyoung Kim 206*2810ac1bSKiyoung Kim importT := C.GoString(tC) 207*2810ac1bSKiyoung Kim if got, want := len(importT), int(tCLen); got != want { 208*2810ac1bSKiyoung Kim log.Fatalf("C string import failed: got=%d [%q] want=%d", got, importT, want) 209*2810ac1bSKiyoung Kim } 210*2810ac1bSKiyoung Kim 211*2810ac1bSKiyoung Kim // Validate that it can be decoded in Go. 212*2810ac1bSKiyoung Kim cGo, err := cap.FromText(importT) 213*2810ac1bSKiyoung Kim if err != nil { 214*2810ac1bSKiyoung Kim log.Fatalf("go parsing of c text import failed: %v", err) 215*2810ac1bSKiyoung Kim } 216*2810ac1bSKiyoung Kim 217*2810ac1bSKiyoung Kim // Validate that it matches the one directly loaded in Go. 218*2810ac1bSKiyoung Kim c, err := cap.GetPID(1) 219*2810ac1bSKiyoung Kim if err != nil { 220*2810ac1bSKiyoung Kim log.Fatalf("...failed to read init's capabilities:", err) 221*2810ac1bSKiyoung Kim } 222*2810ac1bSKiyoung Kim tGo := c.String() 223*2810ac1bSKiyoung Kim if got, want := tGo, cGo.String(); got != want { 224*2810ac1bSKiyoung Kim log.Fatalf("go text rep does not match c: got=%q, want=%q", got, want) 225*2810ac1bSKiyoung Kim } 226*2810ac1bSKiyoung Kim 227*2810ac1bSKiyoung Kim // Export it in text form again from Go. 228*2810ac1bSKiyoung Kim tForC := C.CString(tGo) 229*2810ac1bSKiyoung Kim defer C.free(unsafe.Pointer(tForC)) 230*2810ac1bSKiyoung Kim 231*2810ac1bSKiyoung Kim // Validate it can be encoded in C. 232*2810ac1bSKiyoung Kim cC2 := C.cap_from_text(tForC) 233*2810ac1bSKiyoung Kim if cC2 == nil { 234*2810ac1bSKiyoung Kim log.Fatal("go text rep not parsable by c") 235*2810ac1bSKiyoung Kim } 236*2810ac1bSKiyoung Kim defer C.cap_free(unsafe.Pointer(cC2)) 237*2810ac1bSKiyoung Kim 238*2810ac1bSKiyoung Kim // Validate that it can be exported in binary form in C 239*2810ac1bSKiyoung Kim const enoughForAnyone = 1000 240*2810ac1bSKiyoung Kim eC := make([]byte, enoughForAnyone) 241*2810ac1bSKiyoung Kim eCLen := C.cap_copy_ext(unsafe.Pointer(&eC[0]), cC2, C.ssize_t(len(eC))) 242*2810ac1bSKiyoung Kim if eCLen < 5 { 243*2810ac1bSKiyoung Kim log.Fatalf("c export yielded bad length: %d", eCLen) 244*2810ac1bSKiyoung Kim } 245*2810ac1bSKiyoung Kim 246*2810ac1bSKiyoung Kim // Validate that it can be imported from binary in Go 247*2810ac1bSKiyoung Kim iGo, err := cap.Import(eC[:eCLen]) 248*2810ac1bSKiyoung Kim if err != nil { 249*2810ac1bSKiyoung Kim log.Fatalf("go import of c binary failed: %v", err) 250*2810ac1bSKiyoung Kim } 251*2810ac1bSKiyoung Kim if got, want := iGo.String(), importT; got != want { 252*2810ac1bSKiyoung Kim log.Fatalf("go import of c binary miscompare: got=%q want=%q", got, want) 253*2810ac1bSKiyoung Kim } 254*2810ac1bSKiyoung Kim 255*2810ac1bSKiyoung Kim // Validate that it can be exported in binary in Go 256*2810ac1bSKiyoung Kim iE, err := iGo.Export() 257*2810ac1bSKiyoung Kim if err != nil { 258*2810ac1bSKiyoung Kim log.Fatalf("go failed to export binary: %v", err) 259*2810ac1bSKiyoung Kim } 260*2810ac1bSKiyoung Kim 261*2810ac1bSKiyoung Kim // Validate that it can be imported in binary in C 262*2810ac1bSKiyoung Kim iC := C.cap_copy_int_check(unsafe.Pointer(&iE[0]), C.ssize_t(len(iE))) 263*2810ac1bSKiyoung Kim if iC == nil { 264*2810ac1bSKiyoung Kim log.Fatal("c failed to import go binary") 265*2810ac1bSKiyoung Kim } 266*2810ac1bSKiyoung Kim defer C.cap_free(unsafe.Pointer(iC)) 267*2810ac1bSKiyoung Kim fC := C.cap_to_text(iC, &tCLen) 268*2810ac1bSKiyoung Kim if fC == nil { 269*2810ac1bSKiyoung Kim log.Fatal("basic c init caps -> text failure") 270*2810ac1bSKiyoung Kim } 271*2810ac1bSKiyoung Kim defer C.cap_free(unsafe.Pointer(fC)) 272*2810ac1bSKiyoung Kim if got, want := C.GoString(fC), importT; got != want { 273*2810ac1bSKiyoung Kim log.Fatalf("c import from go yielded bad caps: got=%q want=%q", got, want) 274*2810ac1bSKiyoung Kim } 275*2810ac1bSKiyoung Kim 276*2810ac1bSKiyoung Kim // Validate that everyone agrees what all is: 277*2810ac1bSKiyoung Kim want := "=ep" 278*2810ac1bSKiyoung Kim all, err := cap.FromText("all=ep") 279*2810ac1bSKiyoung Kim if err != nil { 280*2810ac1bSKiyoung Kim log.Fatalf("unable to parse all=ep: %v", err) 281*2810ac1bSKiyoung Kim } 282*2810ac1bSKiyoung Kim if got := all.String(); got != want { 283*2810ac1bSKiyoung Kim log.Fatalf("all decode failed in Go: got=%q, want=%q", got, want) 284*2810ac1bSKiyoung Kim } 285*2810ac1bSKiyoung Kim 286*2810ac1bSKiyoung Kim // Validate some random values stringify consistently between 287*2810ac1bSKiyoung Kim // libcap.cap_to_text() and (*cap.Set).String(). 288*2810ac1bSKiyoung Kim mb := cap.MaxBits() 289*2810ac1bSKiyoung Kim sample := cap.NewSet() 290*2810ac1bSKiyoung Kim for c := cap.Value(0); c < 7*mb; c += 3 { 291*2810ac1bSKiyoung Kim n := int(c) 292*2810ac1bSKiyoung Kim raise, f := c%mb, cap.Flag(c/mb)%3 293*2810ac1bSKiyoung Kim sample.SetFlag(f, true, raise) 294*2810ac1bSKiyoung Kim if v, err := cap.FromText(sample.String()); err != nil { 295*2810ac1bSKiyoung Kim log.Fatalf("[%d] cap to text for %q not reversible: %v", n, sample, err) 296*2810ac1bSKiyoung Kim } else if cf, err := v.Compare(sample); err != nil { 297*2810ac1bSKiyoung Kim log.Fatalf("[%d] FromText generated bad capability from %q: %v", n, sample, err) 298*2810ac1bSKiyoung Kim } else if cf != 0 { 299*2810ac1bSKiyoung Kim log.Fatalf("[%d] text import got=%q want=%q", n, v, sample) 300*2810ac1bSKiyoung Kim } 301*2810ac1bSKiyoung Kim e, err := sample.Export() 302*2810ac1bSKiyoung Kim if err != nil { 303*2810ac1bSKiyoung Kim log.Fatalf("[%d] failed to export %q: %v", n, sample, err) 304*2810ac1bSKiyoung Kim } 305*2810ac1bSKiyoung Kim i, err := cap.Import(e) 306*2810ac1bSKiyoung Kim if err != nil { 307*2810ac1bSKiyoung Kim log.Fatalf("[%d] failed to import %q: %v", n, sample, err) 308*2810ac1bSKiyoung Kim } 309*2810ac1bSKiyoung Kim if cf, err := i.Compare(sample); err != nil { 310*2810ac1bSKiyoung Kim log.Fatalf("[%d] failed to compare %q vs original:%q", n, i, sample) 311*2810ac1bSKiyoung Kim } else if cf != 0 { 312*2810ac1bSKiyoung Kim log.Fatalf("[%d] import got=%q want=%q", n, i, sample) 313*2810ac1bSKiyoung Kim } 314*2810ac1bSKiyoung Kim // Confirm that importing this portable binary 315*2810ac1bSKiyoung Kim // representation in libcap and converting to text, 316*2810ac1bSKiyoung Kim // generates the same text as Go generates. This was 317*2810ac1bSKiyoung Kim // broken prior to v0.2.41. 318*2810ac1bSKiyoung Kim cCap := C.cap_copy_int(unsafe.Pointer(&e[0])) 319*2810ac1bSKiyoung Kim if cCap == nil { 320*2810ac1bSKiyoung Kim log.Fatalf("[%d] C import failed for %q export", n, sample) 321*2810ac1bSKiyoung Kim } 322*2810ac1bSKiyoung Kim var tCLen C.ssize_t 323*2810ac1bSKiyoung Kim tC := C.cap_to_text(cCap, &tCLen) 324*2810ac1bSKiyoung Kim if tC == nil { 325*2810ac1bSKiyoung Kim log.Fatalf("[%d] basic c init caps -> text failure", n) 326*2810ac1bSKiyoung Kim } 327*2810ac1bSKiyoung Kim C.cap_free(unsafe.Pointer(cCap)) 328*2810ac1bSKiyoung Kim importT := C.GoString(tC) 329*2810ac1bSKiyoung Kim C.cap_free(unsafe.Pointer(tC)) 330*2810ac1bSKiyoung Kim if got, want := len(importT), int(tCLen); got != want { 331*2810ac1bSKiyoung Kim log.Fatalf("[%d] C text generated wrong length: Go=%d, C=%d", n, got, want) 332*2810ac1bSKiyoung Kim } 333*2810ac1bSKiyoung Kim if got, want := importT, sample.String(); got != want { 334*2810ac1bSKiyoung Kim log.Fatalf("[%d] C and Go text rep disparity: C=%q Go=%q", n, got, want) 335*2810ac1bSKiyoung Kim } 336*2810ac1bSKiyoung Kim } 337*2810ac1bSKiyoung Kim 338*2810ac1bSKiyoung Kim iab, err := cap.IABFromText("cap_chown,!cap_setuid,^cap_setgid") 339*2810ac1bSKiyoung Kim if err != nil { 340*2810ac1bSKiyoung Kim log.Fatalf("failed to initialize iab from text: %v", err) 341*2810ac1bSKiyoung Kim } 342*2810ac1bSKiyoung Kim cIAB := C.cap_iab_init() 343*2810ac1bSKiyoung Kim defer C.cap_free(unsafe.Pointer(cIAB)) 344*2810ac1bSKiyoung Kim for c := cap.MaxBits(); c > 0; { 345*2810ac1bSKiyoung Kim c-- 346*2810ac1bSKiyoung Kim if en, err := iab.GetVector(cap.Inh, c); err != nil { 347*2810ac1bSKiyoung Kim log.Fatalf("failed to read iab.i[%v]", c) 348*2810ac1bSKiyoung Kim } else if en { 349*2810ac1bSKiyoung Kim if C.cap_iab_set_vector(cIAB, C.CAP_IAB_INH, C.cap_value_t(int(c)), C.CAP_SET) != 0 { 350*2810ac1bSKiyoung Kim log.Fatalf("failed to set C's AIB.I %v: %v", c) 351*2810ac1bSKiyoung Kim } 352*2810ac1bSKiyoung Kim } 353*2810ac1bSKiyoung Kim if en, err := iab.GetVector(cap.Amb, c); err != nil { 354*2810ac1bSKiyoung Kim log.Fatalf("failed to read iab.a[%v]", c) 355*2810ac1bSKiyoung Kim } else if en { 356*2810ac1bSKiyoung Kim if C.cap_iab_set_vector(cIAB, C.CAP_IAB_AMB, C.cap_value_t(int(c)), C.CAP_SET) != 0 { 357*2810ac1bSKiyoung Kim log.Fatalf("failed to set C's AIB.A %v: %v", c) 358*2810ac1bSKiyoung Kim } 359*2810ac1bSKiyoung Kim } 360*2810ac1bSKiyoung Kim if en, err := iab.GetVector(cap.Bound, c); err != nil { 361*2810ac1bSKiyoung Kim log.Fatalf("failed to read iab.b[%v]", c) 362*2810ac1bSKiyoung Kim } else if en { 363*2810ac1bSKiyoung Kim if C.cap_iab_set_vector(cIAB, C.CAP_IAB_BOUND, C.cap_value_t(int(c)), C.CAP_SET) != 0 { 364*2810ac1bSKiyoung Kim log.Fatalf("failed to set C's AIB.B %v: %v", c) 365*2810ac1bSKiyoung Kim } 366*2810ac1bSKiyoung Kim } 367*2810ac1bSKiyoung Kim } 368*2810ac1bSKiyoung Kim iabC := C.cap_iab_to_text(cIAB) 369*2810ac1bSKiyoung Kim if iabC == nil { 370*2810ac1bSKiyoung Kim log.Fatalf("failed to get text from C for %q", iab) 371*2810ac1bSKiyoung Kim } 372*2810ac1bSKiyoung Kim defer C.cap_free(unsafe.Pointer(iabC)) 373*2810ac1bSKiyoung Kim if got, want := C.GoString(iabC), iab.String(); got != want { 374*2810ac1bSKiyoung Kim log.Fatalf("IAB for Go and C differ: got=%q, want=%q", got, want) 375*2810ac1bSKiyoung Kim } 376*2810ac1bSKiyoung Kim 377*2810ac1bSKiyoung Kim // Next, we attempt to manipulate some file capabilities on 378*2810ac1bSKiyoung Kim // the running program. These are optional, based on whether 379*2810ac1bSKiyoung Kim // the current program is capable enough and do not involve 380*2810ac1bSKiyoung Kim // any cgo calls to libcap. 381*2810ac1bSKiyoung Kim tryFileCaps() 382*2810ac1bSKiyoung Kim 383*2810ac1bSKiyoung Kim // Nothing left to do but exit after this one. 384*2810ac1bSKiyoung Kim tryProcCaps() 385*2810ac1bSKiyoung Kim log.Printf("compare-cap success!") 386*2810ac1bSKiyoung Kim} 387