xref: /aosp_15_r20/external/libcap/progs/quicktest.sh (revision 2810ac1b38eead2603277920c78344c84ddf3aff)
1*2810ac1bSKiyoung Kim#!/bin/bash
2*2810ac1bSKiyoung Kim#
3*2810ac1bSKiyoung Kim# Run through a series of tests to try out the various capability
4*2810ac1bSKiyoung Kim# manipulations possible through exec.
5*2810ac1bSKiyoung Kim#
6*2810ac1bSKiyoung Kim# [Run this as root in a root-enabled process tree.]
7*2810ac1bSKiyoung Kim
8*2810ac1bSKiyoung Kimtry_capsh () {
9*2810ac1bSKiyoung Kim    echo "TEST: ./capsh $*"
10*2810ac1bSKiyoung Kim    ./capsh "$@"
11*2810ac1bSKiyoung Kim    if [ $? -ne 0 ]; then
12*2810ac1bSKiyoung Kim	echo FAILED
13*2810ac1bSKiyoung Kim	return 1
14*2810ac1bSKiyoung Kim    else
15*2810ac1bSKiyoung Kim	echo PASSED
16*2810ac1bSKiyoung Kim	return 0
17*2810ac1bSKiyoung Kim    fi
18*2810ac1bSKiyoung Kim}
19*2810ac1bSKiyoung Kim
20*2810ac1bSKiyoung Kimfail_capsh () {
21*2810ac1bSKiyoung Kim    echo -n "EXPECT FAILURE: "
22*2810ac1bSKiyoung Kim    try_capsh "$@"
23*2810ac1bSKiyoung Kim    if [ $? -eq 1 ]; then
24*2810ac1bSKiyoung Kim	echo "[WHICH MEANS A PASS!]"
25*2810ac1bSKiyoung Kim	return 0
26*2810ac1bSKiyoung Kim    else
27*2810ac1bSKiyoung Kim	echo "Undesired result - aborting"
28*2810ac1bSKiyoung Kim	echo "PROBLEM TEST: $*"
29*2810ac1bSKiyoung Kim	exit 1
30*2810ac1bSKiyoung Kim    fi
31*2810ac1bSKiyoung Kim}
32*2810ac1bSKiyoung Kim
33*2810ac1bSKiyoung Kimpass_capsh () {
34*2810ac1bSKiyoung Kim    echo -n "EXPECT SUCCESS: "
35*2810ac1bSKiyoung Kim    try_capsh "$@"
36*2810ac1bSKiyoung Kim    if [ $? -eq 0 ]; then
37*2810ac1bSKiyoung Kim	return 0
38*2810ac1bSKiyoung Kim    else
39*2810ac1bSKiyoung Kim	echo "Undesired result - aborting"
40*2810ac1bSKiyoung Kim	echo "PROBLEM TEST: $*"
41*2810ac1bSKiyoung Kim	exit 1
42*2810ac1bSKiyoung Kim    fi
43*2810ac1bSKiyoung Kim}
44*2810ac1bSKiyoung Kim
45*2810ac1bSKiyoung Kimpass_capsh --print
46*2810ac1bSKiyoung Kimpass_capsh --current
47*2810ac1bSKiyoung Kim
48*2810ac1bSKiyoung Kim# Validate that PATH expansion works
49*2810ac1bSKiyoung KimPATH=$(/bin/pwd)/junk:$(/bin/pwd) capsh == == == --modes
50*2810ac1bSKiyoung Kimif [ $? -ne 0 ]; then
51*2810ac1bSKiyoung Kim    echo "Failed to execute capsh consecutively for capability manipulation"
52*2810ac1bSKiyoung Kim    exit 1
53*2810ac1bSKiyoung Kimfi
54*2810ac1bSKiyoung Kim
55*2810ac1bSKiyoung Kim# Make a local non-setuid-0 version of capsh and call it privileged
56*2810ac1bSKiyoung Kimcp ./tcapsh-static ./privileged && /bin/chmod -s ./privileged
57*2810ac1bSKiyoung Kimif [ $? -ne 0 ]; then
58*2810ac1bSKiyoung Kim    echo "Failed to copy capsh for capability manipulation"
59*2810ac1bSKiyoung Kim    exit 1
60*2810ac1bSKiyoung Kimfi
61*2810ac1bSKiyoung Kim
62*2810ac1bSKiyoung Kim# Give it the forced capability it could need
63*2810ac1bSKiyoung Kim./setcap all=ep ./privileged
64*2810ac1bSKiyoung Kimif [ $? -ne 0 ]; then
65*2810ac1bSKiyoung Kim    echo "Failed to set all capabilities on file"
66*2810ac1bSKiyoung Kim    exit 1
67*2810ac1bSKiyoung Kimfi
68*2810ac1bSKiyoung Kim./setcap cap_setuid,cap_setgid=ep ./privileged
69*2810ac1bSKiyoung Kimif [ $? -ne 0 ]; then
70*2810ac1bSKiyoung Kim    echo "Failed to set limited capabilities on privileged file"
71*2810ac1bSKiyoung Kim    exit 1
72*2810ac1bSKiyoung Kimfi
73*2810ac1bSKiyoung Kim
74*2810ac1bSKiyoung Kim# validate libcap modes:
75*2810ac1bSKiyoung Kimpass_capsh --inh=cap_chown --mode=PURE1E --print --inmode=PURE1E
76*2810ac1bSKiyoung Kimpass_capsh --mode=NOPRIV --print --inmode=NOPRIV
77*2810ac1bSKiyoung Kimpass_capsh --mode=PURE1E --print --mode=NOPRIV --inmode=NOPRIV
78*2810ac1bSKiyoung Kimfail_capsh --mode=NOPRIV --print --mode=PURE1E
79*2810ac1bSKiyoung Kimfail_capsh --user=nobody --mode=NOPRIV --print -- ./privileged
80*2810ac1bSKiyoung Kim
81*2810ac1bSKiyoung Kim# simple IAB setting (no ambient) in pure1e mode.
82*2810ac1bSKiyoung Kimpass_capsh --mode=PURE1E --iab='!%cap_chown,cap_setuid'
83*2810ac1bSKiyoung Kim
84*2810ac1bSKiyoung Kim# Explore keep_caps support
85*2810ac1bSKiyoung Kimpass_capsh --keep=0 --keep=1 --keep=0 --keep=1 --print
86*2810ac1bSKiyoung Kim
87*2810ac1bSKiyoung Kim/bin/rm -f tcapsh
88*2810ac1bSKiyoung Kim/bin/cp tcapsh-static tcapsh
89*2810ac1bSKiyoung Kim/bin/chown root.root tcapsh
90*2810ac1bSKiyoung Kim/bin/chmod u+s tcapsh
91*2810ac1bSKiyoung Kim/bin/ls -l tcapsh
92*2810ac1bSKiyoung Kim
93*2810ac1bSKiyoung Kim# leverage keep caps to maintain capabilities across a change of euid
94*2810ac1bSKiyoung Kim# from setuid root to capable luser (as per wireshark/dumpcap 0.99.7)
95*2810ac1bSKiyoung Kim# This test is subtle. It is testing that a change to self, dropping
96*2810ac1bSKiyoung Kim# euid=0 back to that of the luser keeps capabilities.
97*2810ac1bSKiyoung Kimpass_capsh --uid=1 -- -c "./tcapsh --keep=1 --caps=\"cap_net_raw,cap_net_bind_service=ip\" --print --uid=1 --print --caps=\"cap_net_raw,cap_net_bind_service=pie\" --print"
98*2810ac1bSKiyoung Kim
99*2810ac1bSKiyoung Kim# this test is a change of user to a new user, note we need to raise
100*2810ac1bSKiyoung Kim# the cap_setuid capability (libcap has a function for that) in this case.
101*2810ac1bSKiyoung Kimpass_capsh --uid=1 -- -c "./tcapsh --caps=\"cap_net_raw,cap_net_bind_service=ip cap_setuid=p\" --print --cap-uid=2 --print --caps=\"cap_net_raw,cap_net_bind_service=pie\" --print"
102*2810ac1bSKiyoung Kim
103*2810ac1bSKiyoung Kim# This fails, on 2.6.24, but shouldn't
104*2810ac1bSKiyoung Kimpass_capsh --uid=1 -- -c "./tcapsh --keep=1 --caps=\"cap_net_raw,cap_net_bind_service=ip\" --uid=1 --forkfor=10 --caps= --print --killit=9 --print"
105*2810ac1bSKiyoung Kim
106*2810ac1bSKiyoung Kim# only continue with these if --secbits is supported
107*2810ac1bSKiyoung Kim./capsh --secbits=0x2f > /dev/null 2>&1
108*2810ac1bSKiyoung Kimif [ $? -ne 0 ]; then
109*2810ac1bSKiyoung Kim    echo "unable to test securebits manipulation - assume not supported (PASS)"
110*2810ac1bSKiyoung Kim    rm -f tcapsh
111*2810ac1bSKiyoung Kim    rm -f privileged
112*2810ac1bSKiyoung Kim    exit 0
113*2810ac1bSKiyoung Kimfi
114*2810ac1bSKiyoung Kim
115*2810ac1bSKiyoung Kim# nobody's uid. Static compilation of the capsh binary can disable pwd
116*2810ac1bSKiyoung Kim# info discovery.
117*2810ac1bSKiyoung Kimnouid=$(/usr/bin/id nobody -u)
118*2810ac1bSKiyoung Kim
119*2810ac1bSKiyoung Kimpass_capsh --secbits=42 --print
120*2810ac1bSKiyoung Kimfail_capsh --secbits=32 --keep=1 --keep=0 --print
121*2810ac1bSKiyoung Kimpass_capsh --secbits=10 --keep=0 --keep=1 --print
122*2810ac1bSKiyoung Kimfail_capsh --secbits=47 -- -c "./tcapsh --uid=$nouid"
123*2810ac1bSKiyoung Kim
124*2810ac1bSKiyoung Kim/bin/rm -f tcapsh
125*2810ac1bSKiyoung Kim
126*2810ac1bSKiyoung Kim# Suppress uid=0 privilege
127*2810ac1bSKiyoung Kimfail_capsh --secbits=47 --print -- -c "./capsh --uid=$nouid"
128*2810ac1bSKiyoung Kim
129*2810ac1bSKiyoung Kim# suppress uid=0 privilege and test this privileged
130*2810ac1bSKiyoung Kimpass_capsh --secbits=0x2f --print -- -c "./privileged --uid=$nouid"
131*2810ac1bSKiyoung Kim
132*2810ac1bSKiyoung Kim# observe that the bounding set can be used to suppress this forced capability
133*2810ac1bSKiyoung Kimfail_capsh --drop=cap_setuid --secbits=0x2f --print -- \
134*2810ac1bSKiyoung Kim	   -c "./privileged --uid=$nouid"
135*2810ac1bSKiyoung Kim
136*2810ac1bSKiyoung Kim# observe that effective cap_setpcap is required to drop bset
137*2810ac1bSKiyoung Kimfail_capsh --caps="=ep cap_setpcap-ep" --drop=cap_setuid --current
138*2810ac1bSKiyoung Kimpass_capsh --strict --caps="cap_setpcap=ep" --drop=cap_setuid --current
139*2810ac1bSKiyoung Kimfail_capsh --strict --caps="cap_setpcap=p" --drop=cap_setuid --current
140*2810ac1bSKiyoung Kimfail_capsh --strict --caps="=ep cap_setpcap-e" --drop=cap_setuid --current
141*2810ac1bSKiyoung Kim
142*2810ac1bSKiyoung Kim# observe that effective cap_setpcap is required to raise non-p bits
143*2810ac1bSKiyoung Kimfail_capsh --strict --caps="cap_setpcap=p" --inh=cap_chown --current
144*2810ac1bSKiyoung Kim# non-strict mode and capsh figures it out
145*2810ac1bSKiyoung Kimpass_capsh --caps="cap_setpcap=p" --inh=cap_chown --current
146*2810ac1bSKiyoung Kim
147*2810ac1bSKiyoung Kim# permitted bits can be raised in inheritable flag without being effective.
148*2810ac1bSKiyoung Kimpass_capsh --strict --caps="cap_chown=p" --inh=cap_chown --current
149*2810ac1bSKiyoung Kim
150*2810ac1bSKiyoung Kim# change the way the capability is obtained (make it inheritable)
151*2810ac1bSKiyoung Kim./setcap cap_setuid,cap_setgid=ei ./privileged
152*2810ac1bSKiyoung Kim
153*2810ac1bSKiyoung Kim# Note, the bounding set (edited with --drop) only limits p
154*2810ac1bSKiyoung Kim# capabilities, not i's.
155*2810ac1bSKiyoung Kimpass_capsh --secbits=47 --inh=cap_setuid,cap_setgid --drop=cap_setuid \
156*2810ac1bSKiyoung Kim    --uid=1 --print -- -c "./privileged --uid=$nouid"
157*2810ac1bSKiyoung Kim
158*2810ac1bSKiyoung Kim# test that we do not support capabilities on setuid shell-scripts
159*2810ac1bSKiyoung Kim/bin/cat > hack.sh <<EOF
160*2810ac1bSKiyoung Kim#!/bin/bash
161*2810ac1bSKiyoung Kim/usr/bin/id
162*2810ac1bSKiyoung Kimmypid=\$\$
163*2810ac1bSKiyoung Kimcaps=\$(./getpcaps \$mypid 2>&1 | /usr/bin/cut -d: -f2)
164*2810ac1bSKiyoung Kimif [ "\$caps" != " =" ]; then
165*2810ac1bSKiyoung Kim  echo "Shell script got [\$caps] - you should upgrade your kernel"
166*2810ac1bSKiyoung Kim  exit 1
167*2810ac1bSKiyoung Kimelse
168*2810ac1bSKiyoung Kim  ls -l \$0
169*2810ac1bSKiyoung Kim  echo "Good, no capabilities [\$caps] for this setuid-0 shell script"
170*2810ac1bSKiyoung Kimfi
171*2810ac1bSKiyoung Kimexit 0
172*2810ac1bSKiyoung KimEOF
173*2810ac1bSKiyoung Kim/bin/chmod +xs hack.sh
174*2810ac1bSKiyoung Kim./capsh --uid=1 --inh=none --print -- ./hack.sh
175*2810ac1bSKiyoung Kimstatus=$?
176*2810ac1bSKiyoung Kim/bin/rm -f ./hack.sh
177*2810ac1bSKiyoung Kimif [ $status -ne 0 ]; then
178*2810ac1bSKiyoung Kim    echo "shell scripts can have capabilities (bug)"
179*2810ac1bSKiyoung Kim    exit 1
180*2810ac1bSKiyoung Kimfi
181*2810ac1bSKiyoung Kim
182*2810ac1bSKiyoung Kim# Max lockdown (ie., pure capability model as POSIX.1e intended).
183*2810ac1bSKiyoung Kimsecbits=0x2f
184*2810ac1bSKiyoung Kimif ./capsh --has-ambient ; then
185*2810ac1bSKiyoung Kim    secbits="0xef --noamb"
186*2810ac1bSKiyoung Kimfi
187*2810ac1bSKiyoung Kimpass_capsh --keep=1 --uid=$nouid --caps=cap_setpcap=ep \
188*2810ac1bSKiyoung Kim	   --drop=all --secbits=$secbits --caps= --print
189*2810ac1bSKiyoung Kim
190*2810ac1bSKiyoung Kim# Verify we can chroot
191*2810ac1bSKiyoung Kimpass_capsh --chroot=$(/bin/pwd)
192*2810ac1bSKiyoung Kimpass_capsh -- -c "./tcapsh-static --chroot=$(/bin/pwd) =="
193*2810ac1bSKiyoung Kimfail_capsh --chroot=$(/bin/pwd) -- -c "echo oops"
194*2810ac1bSKiyoung Kim
195*2810ac1bSKiyoung Kim./capsh --has-ambient
196*2810ac1bSKiyoung Kimif [ $? -eq 0 ]; then
197*2810ac1bSKiyoung Kim    echo "test ambient capabilities"
198*2810ac1bSKiyoung Kim
199*2810ac1bSKiyoung Kim    # Ambient capabilities (any file can inherit capabilities)
200*2810ac1bSKiyoung Kim    pass_capsh --noamb
201*2810ac1bSKiyoung Kim
202*2810ac1bSKiyoung Kim    # test that shell scripts can inherit through ambient capabilities
203*2810ac1bSKiyoung Kim    /bin/cat > hack.sh <<EOF
204*2810ac1bSKiyoung Kim#!/bin/bash
205*2810ac1bSKiyoung Kim/usr/bin/id
206*2810ac1bSKiyoung Kimmypid=\$\$
207*2810ac1bSKiyoung Kimcaps=\$(./getpcaps \$mypid 2>&1 | /usr/bin/cut -d: -f2)
208*2810ac1bSKiyoung Kimif [ "\$caps" != " = cap_setuid+i" ]; then
209*2810ac1bSKiyoung Kim  echo "Shell script got [\$caps]"
210*2810ac1bSKiyoung Kim  exit 0
211*2810ac1bSKiyoung Kimfi
212*2810ac1bSKiyoung Kimls -l \$0
213*2810ac1bSKiyoung Kimecho "no capabilities [\$caps] for this shell script"
214*2810ac1bSKiyoung Kimexit 1
215*2810ac1bSKiyoung KimEOF
216*2810ac1bSKiyoung Kim    /bin/chmod +x hack.sh
217*2810ac1bSKiyoung Kim    pass_capsh --keep=1 --uid=$nouid --inh=cap_setuid --addamb=cap_setuid -- \
218*2810ac1bSKiyoung Kim	       ./hack.sh
219*2810ac1bSKiyoung Kim
220*2810ac1bSKiyoung Kim    /bin/rm -f hack.sh
221*2810ac1bSKiyoung Kim
222*2810ac1bSKiyoung Kim    # Next force the privileged binary to have an empty capability set.
223*2810ac1bSKiyoung Kim    # This is sort of the opposite of privileged - it should ensure that
224*2810ac1bSKiyoung Kim    # the file can never acquire privilege by the ambient method.
225*2810ac1bSKiyoung Kim    ./setcap = ./privileged
226*2810ac1bSKiyoung Kim    fail_capsh --keep=1 --uid=$nouid --inh=cap_setuid --addamb=cap_setuid -- \
227*2810ac1bSKiyoung Kim	       -c "./privileged --print --uid=1"
228*2810ac1bSKiyoung Kim
229*2810ac1bSKiyoung Kim    pass_capsh --keep=1 --uid=$nouid --strict \
230*2810ac1bSKiyoung Kim	       --caps="cap_setuid=p cap_setpcap=ep" \
231*2810ac1bSKiyoung Kim	       --inh=cap_setuid --addamb=cap_setuid --current
232*2810ac1bSKiyoung Kim
233*2810ac1bSKiyoung Kim    # No effective capabilities are needed to raise or lower ambient values.
234*2810ac1bSKiyoung Kim    pass_capsh --keep=1 --uid=$nouid --strict --caps="cap_setuid=p" \
235*2810ac1bSKiyoung Kim	       --inh=cap_setuid --addamb=cap_setuid --current
236*2810ac1bSKiyoung Kim    pass_capsh --keep=1 --uid=$nouid --strict --iab="!^cap_setuid" \
237*2810ac1bSKiyoung Kim	       --caps="cap_setuid=pi" --current --delamb=cap_setuid --current
238*2810ac1bSKiyoung Kim
239*2810ac1bSKiyoung Kim
240*2810ac1bSKiyoung Kim    # finally remove the capability from the privileged binary and try again.
241*2810ac1bSKiyoung Kim    ./setcap -r ./privileged
242*2810ac1bSKiyoung Kim    pass_capsh --keep=1 --uid=$nouid --inh=cap_setuid --addamb=cap_setuid -- \
243*2810ac1bSKiyoung Kim	       -c "./privileged --print --uid=1"
244*2810ac1bSKiyoung Kim
245*2810ac1bSKiyoung Kim    # validate IAB setting with an ambient capability
246*2810ac1bSKiyoung Kim    pass_capsh --iab='!%cap_chown,^cap_setpcap,cap_setuid'
247*2810ac1bSKiyoung Kim    fail_capsh --mode=PURE1E --iab='!%cap_chown,^cap_setuid'
248*2810ac1bSKiyoung Kimfi
249*2810ac1bSKiyoung Kim/bin/rm -f ./privileged
250*2810ac1bSKiyoung Kim
251*2810ac1bSKiyoung Kimecho "testing namespaced file caps"
252*2810ac1bSKiyoung Kim
253*2810ac1bSKiyoung Kim# nsprivileged capsh will have an ns rootid value (this is
254*2810ac1bSKiyoung Kim# the same setup as an earlier test but with a ns file cap).
255*2810ac1bSKiyoung Kimrm -f nsprivileged
256*2810ac1bSKiyoung Kimcp ./tcapsh-static ./nsprivileged && /bin/chmod -s ./nsprivileged
257*2810ac1bSKiyoung Kim./setcap -n 1 all=ep ./nsprivileged
258*2810ac1bSKiyoung Kimif [ $? -eq 0 ]; then
259*2810ac1bSKiyoung Kim    ./getcap -n ./nsprivileged | grep -F "[rootid=1]"
260*2810ac1bSKiyoung Kim    if [ $? -ne 0 ]; then
261*2810ac1bSKiyoung Kim	echo "FAILED setting ns rootid on file"
262*2810ac1bSKiyoung Kim	exit 1
263*2810ac1bSKiyoung Kim    fi
264*2810ac1bSKiyoung Kim    # since this is a ns file cap and not a regular one, it should not
265*2810ac1bSKiyoung Kim    # lead to a privilege escalation outside of the namespace it
266*2810ac1bSKiyoung Kim    # refers to. We suppress uid=0 privilege and confirm this
267*2810ac1bSKiyoung Kim    # nsprivileged binary does not have the power to change uid.
268*2810ac1bSKiyoung Kim    fail_capsh --secbits=$secbits --print -- -c "./nsprivileged --uid=$nouid"
269*2810ac1bSKiyoung Kimelse
270*2810ac1bSKiyoung Kim    echo "ns file caps not supported - skipping test"
271*2810ac1bSKiyoung Kimfi
272*2810ac1bSKiyoung Kimrm -f nsprivileged
273*2810ac1bSKiyoung Kim
274*2810ac1bSKiyoung Kim# If the build tree compiled the Go cap package.
275*2810ac1bSKiyoung Kimif [ -f ../go/compare-cap ]; then
276*2810ac1bSKiyoung Kim    cp ../go/compare-cap .
277*2810ac1bSKiyoung Kim    LD_LIBRARY_PATH=../libcap ./compare-cap
278*2810ac1bSKiyoung Kim    if [ $? -ne 0 ]; then
279*2810ac1bSKiyoung Kim	echo "FAILED to execute go binary"
280*2810ac1bSKiyoung Kim	exit 1
281*2810ac1bSKiyoung Kim    fi
282*2810ac1bSKiyoung Kim    LD_LIBRARY_PATH=../libcap ./compare-cap 2>&1 | \
283*2810ac1bSKiyoung Kim	grep "skipping file cap tests"
284*2810ac1bSKiyoung Kim    if [ $? -eq 0 ]; then
285*2810ac1bSKiyoung Kim	echo "FAILED not engaging file cap tests"
286*2810ac1bSKiyoung Kim	exit 1
287*2810ac1bSKiyoung Kim    fi
288*2810ac1bSKiyoung Kim    echo "PASSED"
289*2810ac1bSKiyoung Kimelse
290*2810ac1bSKiyoung Kim    echo "no Go support compiled, so skipping Go tests"
291*2810ac1bSKiyoung Kimfi
292*2810ac1bSKiyoung Kimrm -f compare-cap
293*2810ac1bSKiyoung Kim
294*2810ac1bSKiyoung Kimecho "attempt to exploit kernel bug"
295*2810ac1bSKiyoung Kim./uns_test
296*2810ac1bSKiyoung Kimif [ $? -ne 0 ]; then
297*2810ac1bSKiyoung Kim    echo "upgrade your kernel"
298*2810ac1bSKiyoung Kim    exit 1
299*2810ac1bSKiyoung Kimfi
300*2810ac1bSKiyoung Kim
301*2810ac1bSKiyoung Kimecho "ALL TESTS PASSED!"
302