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
48# Make a local non-setuid-0 version of capsh and call it privileged
49cp ./capsh ./privileged && chmod -s ./privileged
50if [ $? -ne 0 ]; then
51    echo "Failed to copy capsh for capability manipulation"
52    exit 1
53fi
54
55# Give it the forced capability it could need
56./setcap all=ep ./privileged
57if [ $? -ne 0 ]; then
58    echo "Failed to set all capabilities on file"
59    exit 1
60fi
61./setcap cap_setuid,cap_setgid=ep ./privileged
62if [ $? -ne 0 ]; then
63    echo "Failed to set limited capabilities on privileged file"
64    exit 1
65fi
66
67# Explore keep_caps support
68pass_capsh --keep=0 --keep=1 --keep=0 --keep=1 --print
69
70rm -f tcapsh
71cp capsh tcapsh
72chown root.root tcapsh
73chmod u+s tcapsh
74ls -l tcapsh
75
76# leverage keep caps maintain capabilities accross a change of uid
77# from setuid root to capable luser (as per wireshark/dumpcap 0.99.7)
78pass_capsh --uid=500 -- -c "./tcapsh --keep=1 --caps=\"cap_net_raw,cap_net_admin=ip\" --uid=500 --caps=\"cap_net_raw,cap_net_admin=pie\" --print"
79
80# This fails, on 2.6.24, but shouldn't
81pass_capsh --uid=500 -- -c "./tcapsh --keep=1 --caps=\"cap_net_raw,cap_net_admin=ip\" --uid=500 --forkfor=10 --caps= --print --killit=9 --print"
82
83# only continue with these if --secbits is supported
84./capsh --secbits=0x2f > /dev/null 2>&1
85if [ $? -ne 0 ]; then
86    echo "unable to test securebits manipulation - assume not supported (PASS)"
87    rm -f tcapsh
88    rm -f privileged
89    exit 0
90fi
91
92# nobody's uid. Static compilation of the capsh binary can disable pwd
93# info discovery.
94nouid=$(/usr/bin/id nobody -u)
95
96pass_capsh --secbits=42 --print
97fail_capsh --secbits=32 --keep=1 --keep=0 --print
98pass_capsh --secbits=10 --keep=0 --keep=1 --print
99fail_capsh --secbits=47 -- -c "./tcapsh --uid=$nouid"
100
101rm -f tcapsh
102
103# Suppress uid=0 privilege
104fail_capsh --secbits=47 --print -- -c "./capsh --uid=$nouid"
105
106# suppress uid=0 privilege and test this privileged
107pass_capsh --secbits=0x2f --print -- -c "./privileged --uid=$nouid"
108
109# observe that the bounding set can be used to suppress this forced capability
110fail_capsh --drop=cap_setuid --secbits=0x2f --print -- -c "./privileged --uid=$nouid"
111
112# change the way the capability is obtained (make it inheritable)
113./setcap cap_setuid,cap_setgid=ei ./privileged
114
115# Note, the bounding set (edited with --drop) only limits p
116# capabilities, not i's.
117pass_capsh --secbits=47 --inh=cap_setuid,cap_setgid --drop=cap_setuid \
118    --uid=500 --print -- -c "./privileged --uid=$nouid"
119
120rm -f ./privileged
121
122# test that we do not support capabilities on setuid shell-scripts
123cat > hack.sh <<EOF
124#!/bin/bash
125/usr/bin/id
126mypid=\$\$
127caps=\$(./getpcaps \$mypid 2>&1 | /usr/bin/cut -d: -f2)
128if [ "\$caps" != " =" ]; then
129  echo "Shell script got [\$caps] - you should upgrade your kernel"
130  exit 1
131else
132  ls -l \$0
133  echo "Good, no capabilities [\$caps] for this setuid-0 shell script"
134fi
135exit 0
136EOF
137chmod +xs hack.sh
138./capsh --uid=500 --inh=none --print -- ./hack.sh
139status=$?
140rm -f ./hack.sh
141if [ $status -ne 0 ]; then
142    echo "shell scripts can have capabilities (bug)"
143    exit 1
144fi
145
146# Max lockdown
147pass_capsh --keep=1 --uid=$nouid --caps=cap_setpcap=ep \
148    --drop=all --secbits=0x2f --caps= --print
149
150# Verify we can chroot
151pass_capsh --chroot=$(/bin/pwd)
152pass_capsh --chroot=$(/bin/pwd) ==
153fail_capsh --chroot=$(/bin/pwd) -- -c "echo oops"
154