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