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