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