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