summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew G. Morgan <morgan@kernel.org>2021-08-28 15:58:16 -0700
committerAndrew G. Morgan <morgan@kernel.org>2021-08-28 16:50:35 -0700
commit61b2fcc4510641ffd691d8e5a82e968b458f0cb9 (patch)
tree8f70e030e250d8c442d4d37d90be19e7acde6de8
parent6c38eb78d96a60a9503dc5c89ade67b65778fed9 (diff)
downloadlibcap2-61b2fcc4510641ffd691d8e5a82e968b458f0cb9.tar.gz
Make sudotest more robust against untestable environments
I'm setting up some testing environments and they are not all created equal. Signed-off-by: Andrew G. Morgan <morgan@kernel.org>
-rw-r--r--doc/capsh.17
-rw-r--r--go/Makefile2
-rw-r--r--go/try-launching.go4
-rw-r--r--libcap/cap_flag.c1
-rw-r--r--progs/capsh.c13
-rwxr-xr-xprogs/quicktest.sh12
-rw-r--r--tests/uns_test.c11
7 files changed, 41 insertions, 9 deletions
diff --git a/doc/capsh.1 b/doc/capsh.1
index e309438..9bed928 100644
--- a/doc/capsh.1
+++ b/doc/capsh.1
@@ -279,6 +279,13 @@ vector has capability
.B xxx
raised.
.TP
+.BI \-\-has\-b= xxx
+Exit with status 1 unless the
+.I bounding
+set vector has capability
+.B xxx
+enabled.
+.TP
.BI \-\-iab= xxx
Attempts to set the IAB tuple of inheritable capability vectors.
The text conventions used for \fIxxx\fP are those of
diff --git a/go/Makefile b/go/Makefile
index ce464d1..854f0e3 100644
--- a/go/Makefile
+++ b/go/Makefile
@@ -110,7 +110,7 @@ endif
# requiring that the hosting kernel supports user namespaces for the
# regular test case.
sudotest: test ../progs/tcapsh-static b210613
- ./gowns --ns -- -c "echo gowns runs with user namespace"
+ ../progs/tcapsh-static --has-b=cap_sys_admin || exit 0 && ./gowns --ns -- -c "echo gowns runs with user namespace"
./try-launching
ifeq ($(CGO_REQUIRED),0)
./try-launching-cgo
diff --git a/go/try-launching.go b/go/try-launching.go
index 9f20e6b..b09b254 100644
--- a/go/try-launching.go
+++ b/go/try-launching.go
@@ -20,6 +20,8 @@ func tryLaunching() {
}
root := cwd[:strings.LastIndex(cwd, "/")]
+ hasSysAdmin, _ := cap.GetBound(cap.SYS_ADMIN)
+
vs := []struct {
args []string
fail bool
@@ -38,7 +40,7 @@ func tryLaunching() {
uid: 123,
gid: 456,
groups: []int{1, 2, 3},
- fail: syscall.Getuid() != 0,
+ fail: syscall.Getuid() != 0 || !hasSysAdmin,
},
{
args: []string{"/ok"},
diff --git a/libcap/cap_flag.c b/libcap/cap_flag.c
index 1f561f7..9df1842 100644
--- a/libcap/cap_flag.c
+++ b/libcap/cap_flag.c
@@ -14,7 +14,6 @@
* returned as the contents of *raised. The capability is from one of
* the sets stored in cap_d as specified by set and value
*/
-
int cap_get_flag(cap_t cap_d, cap_value_t value, cap_flag_t set,
cap_flag_value_t *raised)
{
diff --git a/progs/capsh.c b/progs/capsh.c
index 763c08d..0cf8b1e 100644
--- a/progs/capsh.c
+++ b/progs/capsh.c
@@ -967,6 +967,17 @@ int main(int argc, char *argv[], char *envp[])
fprintf(stderr, "cap[%s] not in ambient vector\n", argv[i]+8);
exit(1);
}
+ } else if (!strncmp("--has-b=", argv[i], 8)) {
+ cap_value_t cap;
+ if (cap_from_name(argv[i]+8, &cap) < 0) {
+ fprintf(stderr, "cap[%s] not recognized by library\n",
+ argv[i] + 8);
+ exit(1);
+ }
+ if (!cap_get_bound(cap)) {
+ fprintf(stderr, "cap[%s] not in bounding vector\n", argv[i]+8);
+ exit(1);
+ }
} else if (!strncmp("--is-uid=", argv[i], 9)) {
unsigned value;
uid_t uid;
@@ -1075,11 +1086,13 @@ int main(int argc, char *argv[], char *envp[])
" --current show current caps and IAB vectors\n"
" --decode=xxx decode a hex string to a list of caps\n"
" --delamb=xxx remove xxx,... capabilities from ambient\n"
+ " --drop=xxx drop xxx,... caps from bounding set\n"
" --explain=xxx explain what capability xxx permits\n"
" --forkfor=<n> fork and make child sleep for <n> sec\n"
" --gid=<n> set gid to <n> (hint: id <username>)\n"
" --groups=g,... set the supplemental groups\n"
" --has-a=xxx exit 1 if capability xxx not ambient\n"
+ " --has-b=xxx exit 1 if capability xxx not dropped\n"
" --has-ambient exit 1 unless ambient vector supported\n"
" --has-i=xxx exit 1 if capability xxx not inheritable\n"
" --has-p=xxx exit 1 if capability xxx not permitted\n"
diff --git a/progs/quicktest.sh b/progs/quicktest.sh
index ba64ab5..ebb7567 100755
--- a/progs/quicktest.sh
+++ b/progs/quicktest.sh
@@ -79,7 +79,7 @@ fail_capsh --mode=NOPRIV --print --mode=PURE1E
fail_capsh --user=nobody --mode=NOPRIV --print -- ./privileged
# simple IAB setting (no ambient) in pure1e mode.
-pass_capsh --mode=PURE1E --iab='!%cap_chown,cap_sys_admin'
+pass_capsh --mode=PURE1E --iab='!%cap_chown,cap_setuid'
# Explore keep_caps support
pass_capsh --keep=0 --keep=1 --keep=0 --keep=1 --print
@@ -94,14 +94,14 @@ pass_capsh --keep=0 --keep=1 --keep=0 --keep=1 --print
# from setuid root to capable luser (as per wireshark/dumpcap 0.99.7)
# This test is subtle. It is testing that a change to self, dropping
# euid=0 back to that of the luser keeps capabilities.
-pass_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"
+pass_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"
# this test is a change of user to a new user, note we need to raise
# the cap_setuid capability (libcap has a function for that) in this case.
-pass_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"
+pass_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"
# This fails, on 2.6.24, but shouldn't
-pass_capsh --uid=1 -- -c "./tcapsh --keep=1 --caps=\"cap_net_raw,cap_net_admin=ip\" --uid=1 --forkfor=10 --caps= --print --killit=9 --print"
+pass_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"
# only continue with these if --secbits is supported
./capsh --secbits=0x2f > /dev/null 2>&1
@@ -214,8 +214,8 @@ EOF
pass_capsh --keep=1 --uid=$nouid --inh=cap_setuid --addamb=cap_setuid -- -c "./privileged --print --uid=1"
# validate IAB setting with an ambient capability
- pass_capsh --iab='!%cap_chown,^cap_setpcap,cap_sys_admin'
- fail_capsh --mode=PURE1E --iab='!%cap_chown,^cap_sys_admin'
+ pass_capsh --iab='!%cap_chown,^cap_setpcap,cap_setuid'
+ fail_capsh --mode=PURE1E --iab='!%cap_chown,^cap_setuid'
fi
/bin/rm -f ./privileged
diff --git a/tests/uns_test.c b/tests/uns_test.c
index a1dbde0..3fe73af 100644
--- a/tests/uns_test.c
+++ b/tests/uns_test.c
@@ -62,6 +62,17 @@ int main(int argc, char **argv)
static const char id_map[] = "0 1 1\n1 2 1\n2 0 1\n3 3 49999997\n";
cap_value_t fscap = CAP_SETFCAP;
cap_t orig = cap_get_proc();
+ cap_flag_value_t present;
+
+ if (cap_get_flag(orig, CAP_SYS_ADMIN, CAP_EFFECTIVE, &present) != 0) {
+ perror("failed to read a capability flag");
+ exit(1);
+ }
+ if (present != CAP_SET) {
+ fprintf(stderr,
+ "environment missing cap_sys_admin - exploit not testable\n");
+ exit(0);
+ }
/* Run with this one lowered */
cap_set_flag(orig, CAP_EFFECTIVE, 1, &fscap, CAP_CLEAR);