1*2810ac1bSKiyoung Kimpackage cap 2*2810ac1bSKiyoung Kim 3*2810ac1bSKiyoung Kimimport ( 4*2810ac1bSKiyoung Kim "fmt" 5*2810ac1bSKiyoung Kim "testing" 6*2810ac1bSKiyoung Kim) 7*2810ac1bSKiyoung Kim 8*2810ac1bSKiyoung Kimfunc TestAllMask(t *testing.T) { 9*2810ac1bSKiyoung Kim oldMask := maxValues 10*2810ac1bSKiyoung Kim oldWords := words 11*2810ac1bSKiyoung Kim defer func() { 12*2810ac1bSKiyoung Kim maxValues = oldMask 13*2810ac1bSKiyoung Kim words = oldWords 14*2810ac1bSKiyoung Kim }() 15*2810ac1bSKiyoung Kim 16*2810ac1bSKiyoung Kim maxValues = 35 17*2810ac1bSKiyoung Kim words = 3 18*2810ac1bSKiyoung Kim 19*2810ac1bSKiyoung Kim vs := []struct { 20*2810ac1bSKiyoung Kim val Value 21*2810ac1bSKiyoung Kim index uint 22*2810ac1bSKiyoung Kim bit uint32 23*2810ac1bSKiyoung Kim mask uint32 24*2810ac1bSKiyoung Kim }{ 25*2810ac1bSKiyoung Kim {val: CHOWN, index: 0, bit: 0x1, mask: ^uint32(0)}, 26*2810ac1bSKiyoung Kim {val: 38, index: 1, bit: (1 << 6), mask: 0x7}, 27*2810ac1bSKiyoung Kim {val: 34, index: 1, bit: (1 << 2), mask: 0x7}, 28*2810ac1bSKiyoung Kim {val: 65, index: 2, bit: (1 << 1), mask: 0}, 29*2810ac1bSKiyoung Kim } 30*2810ac1bSKiyoung Kim for i, v := range vs { 31*2810ac1bSKiyoung Kim index, bit, err := bitOf(Inheritable, v.val) 32*2810ac1bSKiyoung Kim if err != nil { 33*2810ac1bSKiyoung Kim t.Fatalf("[%d] %v(%d) - not bitOf: %v", i, v.val, v.val, err) 34*2810ac1bSKiyoung Kim } else if index != v.index { 35*2810ac1bSKiyoung Kim t.Errorf("[%d] %v(%d) - index: got=%d want=%d", i, v.val, v.val, index, v.index) 36*2810ac1bSKiyoung Kim } 37*2810ac1bSKiyoung Kim if bit != v.bit { 38*2810ac1bSKiyoung Kim t.Errorf("[%d] %v(%d) - bit: got=%b want=%b", i, v.val, v.val, bit, v.bit) 39*2810ac1bSKiyoung Kim } 40*2810ac1bSKiyoung Kim if mask := allMask(index); mask != v.mask { 41*2810ac1bSKiyoung Kim t.Errorf("[%d] %v(%d) - mask: got=%b want=%b", i, v.val, v.val, mask, v.mask) 42*2810ac1bSKiyoung Kim } 43*2810ac1bSKiyoung Kim } 44*2810ac1bSKiyoung Kim} 45*2810ac1bSKiyoung Kim 46*2810ac1bSKiyoung Kimfunc TestString(t *testing.T) { 47*2810ac1bSKiyoung Kim a := CHOWN 48*2810ac1bSKiyoung Kim if got, want := a.String(), "cap_chown"; got != want { 49*2810ac1bSKiyoung Kim t.Fatalf("pretty basic failure: got=%q, want=%q", got, want) 50*2810ac1bSKiyoung Kim } 51*2810ac1bSKiyoung Kim} 52*2810ac1bSKiyoung Kim 53*2810ac1bSKiyoung Kimfunc TestText(t *testing.T) { 54*2810ac1bSKiyoung Kim vs := []struct { 55*2810ac1bSKiyoung Kim from, to string 56*2810ac1bSKiyoung Kim err error 57*2810ac1bSKiyoung Kim }{ 58*2810ac1bSKiyoung Kim {"", "", ErrBadText}, 59*2810ac1bSKiyoung Kim {"=", "=", nil}, 60*2810ac1bSKiyoung Kim {"= cap_chown+iep cap_chown-i", "cap_chown=ep", nil}, 61*2810ac1bSKiyoung Kim {"= cap_setfcap,cap_chown+iep cap_chown-i", "cap_setfcap=eip cap_chown+ep", nil}, 62*2810ac1bSKiyoung Kim {"cap_setfcap,cap_chown=iep cap_chown-i", "cap_setfcap=eip cap_chown+ep", nil}, 63*2810ac1bSKiyoung Kim {"=i =p", "=p", nil}, 64*2810ac1bSKiyoung Kim {"all+pie", "=eip", nil}, 65*2810ac1bSKiyoung Kim {"all=p+ie-e", "=ip", nil}, 66*2810ac1bSKiyoung Kim } 67*2810ac1bSKiyoung Kim for i, v := range vs { 68*2810ac1bSKiyoung Kim c, err := FromText(v.from) 69*2810ac1bSKiyoung Kim if err != v.err { 70*2810ac1bSKiyoung Kim t.Errorf("[%d] parsing %q failed: got=%v, want=%v", i, v.from, err, v.err) 71*2810ac1bSKiyoung Kim continue 72*2810ac1bSKiyoung Kim } 73*2810ac1bSKiyoung Kim if err != nil { 74*2810ac1bSKiyoung Kim continue 75*2810ac1bSKiyoung Kim } 76*2810ac1bSKiyoung Kim to := c.String() 77*2810ac1bSKiyoung Kim if to != v.to { 78*2810ac1bSKiyoung Kim t.Errorf("[%d] failed to stringify cap: %q -> got=%q, want=%q", i, v.from, to, v.to) 79*2810ac1bSKiyoung Kim } 80*2810ac1bSKiyoung Kim if d, err := FromText(to); err != nil { 81*2810ac1bSKiyoung Kim t.Errorf("[%d] failed to reparse %q: %v", i, to, err) 82*2810ac1bSKiyoung Kim } else if got := d.String(); got != to { 83*2810ac1bSKiyoung Kim t.Errorf("[%d] failed to stringify %q getting %q", i, to, got) 84*2810ac1bSKiyoung Kim } 85*2810ac1bSKiyoung Kim } 86*2810ac1bSKiyoung Kim} 87*2810ac1bSKiyoung Kim 88*2810ac1bSKiyoung Kimfunc same(a, b *Set) error { 89*2810ac1bSKiyoung Kim if (a == nil) != (b == nil) { 90*2810ac1bSKiyoung Kim return fmt.Errorf("nil-ness miscompare: %q vs %v", a, b) 91*2810ac1bSKiyoung Kim } 92*2810ac1bSKiyoung Kim if a == nil { 93*2810ac1bSKiyoung Kim return nil 94*2810ac1bSKiyoung Kim } 95*2810ac1bSKiyoung Kim if a.nsRoot != b.nsRoot { 96*2810ac1bSKiyoung Kim return fmt.Errorf("capabilities differ in nsRoot: a=%d b=%d", a.nsRoot, b.nsRoot) 97*2810ac1bSKiyoung Kim } 98*2810ac1bSKiyoung Kim for i, f := range a.flat { 99*2810ac1bSKiyoung Kim g := b.flat[i] 100*2810ac1bSKiyoung Kim for s := Effective; s <= Inheritable; s++ { 101*2810ac1bSKiyoung Kim if got, want := f[s], g[s]; got != want { 102*2810ac1bSKiyoung Kim return fmt.Errorf("capabilities differ: a[%d].flat[%v]=0x%08x b[%d].flat[%v]=0x%08x", i, s, got, i, s, want) 103*2810ac1bSKiyoung Kim } 104*2810ac1bSKiyoung Kim } 105*2810ac1bSKiyoung Kim } 106*2810ac1bSKiyoung Kim return nil 107*2810ac1bSKiyoung Kim} 108*2810ac1bSKiyoung Kim 109*2810ac1bSKiyoung Kimfunc confirmExpectedExport(t *testing.T, info string, c *Set, size uint) { 110*2810ac1bSKiyoung Kim if ex, err := c.Export(); err != nil { 111*2810ac1bSKiyoung Kim t.Fatalf("[%s] failed to export empty set: %v", info, err) 112*2810ac1bSKiyoung Kim } else if n := 5 + 3*size; uint(len(ex)) != n { 113*2810ac1bSKiyoung Kim t.Fatalf("[%s] wrong length: got=%d [%0x] want=%d", info, len(ex), ex, n) 114*2810ac1bSKiyoung Kim } else if im, err := Import(ex); err != nil { 115*2810ac1bSKiyoung Kim t.Fatalf("[%s] failed to import empty set: %v", info, err) 116*2810ac1bSKiyoung Kim } else if got, want := im.String(), c.String(); got != want { 117*2810ac1bSKiyoung Kim t.Fatalf("[%s] import != export: got=%q want=%q [%02x]", info, got, want, ex) 118*2810ac1bSKiyoung Kim } 119*2810ac1bSKiyoung Kim} 120*2810ac1bSKiyoung Kim 121*2810ac1bSKiyoung Kimfunc TestImportExport(t *testing.T) { 122*2810ac1bSKiyoung Kim wantQ := "=ep cap_chown-e 63+ip" 123*2810ac1bSKiyoung Kim if q, err := FromText(wantQ); err != nil { 124*2810ac1bSKiyoung Kim t.Fatalf("failed to parse %q: %v", wantQ, err) 125*2810ac1bSKiyoung Kim } else if gotQ := q.String(); gotQ != wantQ { 126*2810ac1bSKiyoung Kim t.Fatalf("static test failed %q -> q -> %q", wantQ, gotQ) 127*2810ac1bSKiyoung Kim } 128*2810ac1bSKiyoung Kim 129*2810ac1bSKiyoung Kim // Sanity check empty import/export. 130*2810ac1bSKiyoung Kim c := NewSet() 131*2810ac1bSKiyoung Kim confirmExpectedExport(t, "empty", c, MinExtFlagSize) 132*2810ac1bSKiyoung Kim // Now keep flipping bits on and off and validate that all 133*2810ac1bSKiyoung Kim // forms of import/export work. 134*2810ac1bSKiyoung Kim for i := uint(0); i < 7000; i += 13 { 135*2810ac1bSKiyoung Kim s := Flag(i % 3) 136*2810ac1bSKiyoung Kim v := Value(i % (maxValues + 3)) 137*2810ac1bSKiyoung Kim c.SetFlag(s, i&17 < 8, v) 138*2810ac1bSKiyoung Kim if ex, err := c.Export(); err != nil { 139*2810ac1bSKiyoung Kim t.Fatalf("[%d] failed to export (%q): %v", i, c, err) 140*2810ac1bSKiyoung Kim } else if im, err := Import(ex); err != nil { 141*2810ac1bSKiyoung Kim t.Fatalf("[%d] failed to import (%q) set: %v", i, c, err) 142*2810ac1bSKiyoung Kim } else if got, want := im.String(), c.String(); got != want { 143*2810ac1bSKiyoung Kim t.Fatalf("[%d] import != export: got=%q want=%q [%02x]", i, got, want, ex) 144*2810ac1bSKiyoung Kim } else if parsed, err := FromText(got); err != nil { 145*2810ac1bSKiyoung Kim t.Fatalf("[%d] failed to parse %q: %v", i, got, err) 146*2810ac1bSKiyoung Kim } else if err := same(c, parsed); err != nil { 147*2810ac1bSKiyoung Kim t.Fatalf("[%d] miscompare (%q vs. %q): %v", i, got, parsed, err) 148*2810ac1bSKiyoung Kim } 149*2810ac1bSKiyoung Kim } 150*2810ac1bSKiyoung Kim 151*2810ac1bSKiyoung Kim oMin := MinExtFlagSize 152*2810ac1bSKiyoung Kim for j := uint(0); j < 5; j++ { 153*2810ac1bSKiyoung Kim t.Logf("exporting with min flag size %d", j) 154*2810ac1bSKiyoung Kim MinExtFlagSize = j 155*2810ac1bSKiyoung Kim c = NewSet() 156*2810ac1bSKiyoung Kim for i := uint(0); i < maxValues; i++ { 157*2810ac1bSKiyoung Kim s := Flag(i % 3) 158*2810ac1bSKiyoung Kim v := Value(i) 159*2810ac1bSKiyoung Kim c.SetFlag(s, true, v) 160*2810ac1bSKiyoung Kim size := 1 + i/8 161*2810ac1bSKiyoung Kim if size < MinExtFlagSize { 162*2810ac1bSKiyoung Kim size = MinExtFlagSize 163*2810ac1bSKiyoung Kim } 164*2810ac1bSKiyoung Kim confirmExpectedExport(t, fmt.Sprintf("%d added %d %v %v", j, i, s, v), c, size) 165*2810ac1bSKiyoung Kim } 166*2810ac1bSKiyoung Kim } 167*2810ac1bSKiyoung Kim MinExtFlagSize = oMin 168*2810ac1bSKiyoung Kim} 169*2810ac1bSKiyoung Kim 170*2810ac1bSKiyoung Kimfunc TestIAB(t *testing.T) { 171*2810ac1bSKiyoung Kim vs := []struct { 172*2810ac1bSKiyoung Kim text string 173*2810ac1bSKiyoung Kim bad bool 174*2810ac1bSKiyoung Kim }{ 175*2810ac1bSKiyoung Kim {text: "cup_full", bad: true}, 176*2810ac1bSKiyoung Kim {text: ""}, 177*2810ac1bSKiyoung Kim {text: "!%cap_chown"}, 178*2810ac1bSKiyoung Kim {text: "!cap_chown,^cap_setuid"}, 179*2810ac1bSKiyoung Kim {text: "cap_chown,cap_setuid"}, 180*2810ac1bSKiyoung Kim {text: "^cap_chown,cap_setuid"}, 181*2810ac1bSKiyoung Kim {text: "^cap_chown,!cap_setuid"}, 182*2810ac1bSKiyoung Kim } 183*2810ac1bSKiyoung Kim for i, v := range vs { 184*2810ac1bSKiyoung Kim want := v.text 185*2810ac1bSKiyoung Kim iab, err := IABFromText(want) 186*2810ac1bSKiyoung Kim if err != nil { 187*2810ac1bSKiyoung Kim if v.bad { 188*2810ac1bSKiyoung Kim continue 189*2810ac1bSKiyoung Kim } 190*2810ac1bSKiyoung Kim t.Errorf("[%d] want=%q, got=%q", i, want, iab) 191*2810ac1bSKiyoung Kim continue 192*2810ac1bSKiyoung Kim } 193*2810ac1bSKiyoung Kim if got := iab.String(); got != want { 194*2810ac1bSKiyoung Kim t.Errorf("[%d] got=%q want=%q", i, got, want) 195*2810ac1bSKiyoung Kim } 196*2810ac1bSKiyoung Kim } 197*2810ac1bSKiyoung Kim 198*2810ac1bSKiyoung Kim one, err := GetPID(1) 199*2810ac1bSKiyoung Kim if err != nil { 200*2810ac1bSKiyoung Kim t.Fatalf("failed to get init's capabilities: %v", err) 201*2810ac1bSKiyoung Kim } 202*2810ac1bSKiyoung Kim iab := NewIAB() 203*2810ac1bSKiyoung Kim if err := iab.Fill(Amb, one, Permitted); err != nil { 204*2810ac1bSKiyoung Kim t.Fatalf("failed to fill Amb from Permitted: %v", err) 205*2810ac1bSKiyoung Kim } 206*2810ac1bSKiyoung Kim for i := 0; i < words; i++ { 207*2810ac1bSKiyoung Kim if iab.i[i] != iab.a[i] { 208*2810ac1bSKiyoung Kim t.Errorf("[%d: %q] i=0x%08x != a=0x%08x", i, one, iab.i[i], iab.a[i]) 209*2810ac1bSKiyoung Kim } 210*2810ac1bSKiyoung Kim } 211*2810ac1bSKiyoung Kim one.ClearFlag(Inheritable) 212*2810ac1bSKiyoung Kim iab.Fill(Inh, one, Inheritable) 213*2810ac1bSKiyoung Kim for i := 0; i < words; i++ { 214*2810ac1bSKiyoung Kim if iab.i[i] != iab.a[i] { 215*2810ac1bSKiyoung Kim t.Errorf("[%d: %q] i=0x%08x != a=0x%08x", i, one, iab.i[i], iab.a[i]) 216*2810ac1bSKiyoung Kim } 217*2810ac1bSKiyoung Kim } 218*2810ac1bSKiyoung Kim 219*2810ac1bSKiyoung Kim for n := uint(0); n < 1000; n += 13 { 220*2810ac1bSKiyoung Kim enabled := ((n % 5) & 2) != 0 221*2810ac1bSKiyoung Kim vec := Vector(n % 3) 222*2810ac1bSKiyoung Kim c := Value(n % maxValues) 223*2810ac1bSKiyoung Kim if err := iab.SetVector(vec, enabled, c); err != nil { 224*2810ac1bSKiyoung Kim t.Errorf("[%d] failed to set vec=%v enabled=%v %q in %q", n, vec, enabled, c, iab) 225*2810ac1bSKiyoung Kim continue 226*2810ac1bSKiyoung Kim } 227*2810ac1bSKiyoung Kim replay, err := IABFromText(iab.String()) 228*2810ac1bSKiyoung Kim if err != nil { 229*2810ac1bSKiyoung Kim t.Errorf("failed to replay: %v", err) 230*2810ac1bSKiyoung Kim continue 231*2810ac1bSKiyoung Kim } 232*2810ac1bSKiyoung Kim for i := 0; i < words; i++ { 233*2810ac1bSKiyoung Kim if replay.i[i] != iab.i[i] || replay.a[i] != iab.a[i] || replay.nb[i] != iab.nb[i] { 234*2810ac1bSKiyoung Kim t.Errorf("[%d,%d] got=%q want=%q", n, i, replay, iab) 235*2810ac1bSKiyoung Kim } 236*2810ac1bSKiyoung Kim } 237*2810ac1bSKiyoung Kim } 238*2810ac1bSKiyoung Kim} 239*2810ac1bSKiyoung Kim 240*2810ac1bSKiyoung Kimfunc TestFuncLaunch(t *testing.T) { 241*2810ac1bSKiyoung Kim if _, err := FuncLauncher(func(data interface{}) error { 242*2810ac1bSKiyoung Kim return nil 243*2810ac1bSKiyoung Kim }).Launch(nil); err != nil { 244*2810ac1bSKiyoung Kim t.Fatalf("trivial launcher failed: %v", err) 245*2810ac1bSKiyoung Kim } 246*2810ac1bSKiyoung Kim 247*2810ac1bSKiyoung Kim for i := 0; i < 100; i++ { 248*2810ac1bSKiyoung Kim expect := i & 1 249*2810ac1bSKiyoung Kim before, err := Prctl(prGetKeepCaps) 250*2810ac1bSKiyoung Kim if err != nil { 251*2810ac1bSKiyoung Kim t.Fatalf("failed to get PR_KEEP_CAPS: %v", err) 252*2810ac1bSKiyoung Kim } 253*2810ac1bSKiyoung Kim if before != expect { 254*2810ac1bSKiyoung Kim t.Fatalf("invalid initial state: got=%d want=%d", before, expect) 255*2810ac1bSKiyoung Kim } 256*2810ac1bSKiyoung Kim 257*2810ac1bSKiyoung Kim if _, err := FuncLauncher(func(data interface{}) error { 258*2810ac1bSKiyoung Kim was, ok := data.(int) 259*2810ac1bSKiyoung Kim if !ok { 260*2810ac1bSKiyoung Kim return fmt.Errorf("data was not an int: %v", data) 261*2810ac1bSKiyoung Kim } 262*2810ac1bSKiyoung Kim if _, err := Prctlw(prSetKeepCaps, uintptr(1-was)); err != nil { 263*2810ac1bSKiyoung Kim return err 264*2810ac1bSKiyoung Kim } 265*2810ac1bSKiyoung Kim if v, err := Prctl(prGetKeepCaps); err != nil { 266*2810ac1bSKiyoung Kim return err 267*2810ac1bSKiyoung Kim } else if v == was { 268*2810ac1bSKiyoung Kim return fmt.Errorf("PR_KEEP_CAPS unchanged: got=%d, want=%v", v, 1-was) 269*2810ac1bSKiyoung Kim } 270*2810ac1bSKiyoung Kim // All good. 271*2810ac1bSKiyoung Kim return nil 272*2810ac1bSKiyoung Kim }).Launch(before); err != nil { 273*2810ac1bSKiyoung Kim t.Fatalf("trivial launcher failed: %v", err) 274*2810ac1bSKiyoung Kim } 275*2810ac1bSKiyoung Kim 276*2810ac1bSKiyoung Kim // Now validate that the main process is still OK. 277*2810ac1bSKiyoung Kim if after, err := Prctl(prGetKeepCaps); err != nil { 278*2810ac1bSKiyoung Kim t.Fatalf("failed to get PR_KEEP_CAPS: %v", err) 279*2810ac1bSKiyoung Kim } else if before != after { 280*2810ac1bSKiyoung Kim t.Fatalf("FuncLauncher leaked privileged state: got=%v want=%v", after, before) 281*2810ac1bSKiyoung Kim } 282*2810ac1bSKiyoung Kim 283*2810ac1bSKiyoung Kim // Now force the other way 284*2810ac1bSKiyoung Kim if _, err := Prctlw(prSetKeepCaps, uintptr(1-expect)); err != nil { 285*2810ac1bSKiyoung Kim t.Fatalf("[%d] attempt to flip PR_KEEP_CAPS failed: %v", i, err) 286*2810ac1bSKiyoung Kim } 287*2810ac1bSKiyoung Kim } 288*2810ac1bSKiyoung Kim} 289*2810ac1bSKiyoung Kim 290*2810ac1bSKiyoung Kimfunc TestFill(t *testing.T) { 291*2810ac1bSKiyoung Kim c, err := FromText("cap_setfcap=p") 292*2810ac1bSKiyoung Kim if err != nil { 293*2810ac1bSKiyoung Kim t.Fatalf("failed to parse: %v", err) 294*2810ac1bSKiyoung Kim } 295*2810ac1bSKiyoung Kim c.Fill(Effective, Permitted) 296*2810ac1bSKiyoung Kim c.ClearFlag(Permitted) 297*2810ac1bSKiyoung Kim c.Fill(Inheritable, Effective) 298*2810ac1bSKiyoung Kim c.ClearFlag(Effective) 299*2810ac1bSKiyoung Kim if got, want := c.String(), "cap_setfcap=i"; got != want { 300*2810ac1bSKiyoung Kim t.Errorf("Fill failed: got=%q want=%q", got, want) 301*2810ac1bSKiyoung Kim } 302*2810ac1bSKiyoung Kim} 303