xref: /aosp_15_r20/external/libcap/cap/cap_test.go (revision 2810ac1b38eead2603277920c78344c84ddf3aff)
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