#include #include "config.h" #if HAVE_SYS_CAPABILITY_H #include #include #endif #include #include "test.h" #ifndef SECBIT_KEEP_CAPS #define SECBIT_KEEP_CAPS (1<<4) #endif /* Tests: 1. drop capabilities at setuid if KEEPCAPS is not set and new user is nonroot 2. keep capabilities if set and new user is nonroot a. do with prctl(PR_SET_KEEPCAPS) (call this test 2) b. do with prctl(PR_SET_SECUREBITS, SECURE_KEEP_CAPS) (call this test 3) TODO: test that exec clears KEEPCAPS (just create a simple executable that checks PR_GET_KEEPCAPS results, and execute that as test 4 after doing PR_SET_KEEPCAPS). TODO: all of the other securebits tests. */ char *TCID = "keepcaps"; int TST_TOTAL = 1; #if (HAVE_LINUX_SECUREBITS_H && HAVE_LIBCAP) #include static int eff_caps_empty(cap_t c) { int i, ret, empty = 1; cap_flag_value_t v; for (i = 0; i < CAP_LAST_CAP; i++) { ret = cap_get_flag(c, i, CAP_PERMITTED, &v); /* * If the value of CAP_LAST_CAP in linux/capability.h is greater * than the value in the capability.h which is used to create * libcap.so. Then cap_get_flag returns -1, and errno is set to * EINVAL. */ if (ret == -1) { tst_brkm(TBROK | TERRNO, NULL, "Not expected. Please check arguments."); } if (ret || v) empty = 0; } return empty; } static int am_privileged(void) { int am_privileged = 1; cap_t cap = cap_get_proc(); if (eff_caps_empty(cap)) am_privileged = 0; cap_free(cap); return am_privileged; } #define EXPECT_NOPRIVS 0 #define EXPECT_PRIVS 1 static void do_setuid(int expect_privs) { int ret; int have_privs; ret = setuid(1000); if (ret) tst_brkm(TERRNO | TFAIL, NULL, "setuid failed"); have_privs = am_privileged(); if (have_privs && expect_privs == EXPECT_PRIVS) { tst_resm(TPASS, "kept privs as expected"); tst_exit(); } if (!have_privs && expect_privs == EXPECT_PRIVS) { tst_brkm(TFAIL, NULL, "expected to keep privs but did not"); } if (!have_privs && expect_privs == EXPECT_NOPRIVS) { tst_resm(TPASS, "dropped privs as expected"); tst_exit(); } /* have_privs && EXPECT_NOPRIVS */ tst_brkm(TFAIL, NULL, "expected to drop privs but did not"); } int main(int argc, char *argv[]) { int ret, whichtest; tst_require_root(); ret = prctl(PR_GET_KEEPCAPS); if (ret) tst_brkm(TBROK, NULL, "keepcaps was already set?"); if (argc < 2) tst_brkm(TBROK, NULL, "Usage: %s ", argv[0]); whichtest = atoi(argv[1]); if (whichtest < 1 || whichtest > 3) tst_brkm(TFAIL, NULL, "Valid tests are 1-3"); switch (whichtest) { case 1: do_setuid(EXPECT_NOPRIVS); /* does not return */ case 2: ret = prctl(PR_SET_KEEPCAPS, 1); if (ret == -1) { tst_brkm(TFAIL | TERRNO, NULL, "PR_SET_KEEPCAPS failed"); } ret = prctl(PR_GET_KEEPCAPS); if (!ret) { tst_brkm(TFAIL | TERRNO, NULL, "PR_SET_KEEPCAPS did not set keepcaps"); } do_setuid(EXPECT_PRIVS); /* does not return */ case 3: ret = prctl(PR_GET_SECUREBITS); ret = prctl(PR_SET_SECUREBITS, ret | SECBIT_KEEP_CAPS); if (ret == -1) { tst_brkm(TFAIL | TERRNO, NULL, "PR_SET_SECUREBITS failed"); } ret = prctl(PR_GET_KEEPCAPS); if (!ret) { tst_brkm(TFAIL | TERRNO, NULL, "PR_SET_SECUREBITS did not set keepcaps"); } do_setuid(EXPECT_PRIVS); /* does not return */ default: tst_brkm(TFAIL, NULL, "Valid tests are 1-3"); } } #else int main(void) { tst_brkm(TCONF, NULL, "linux/securebits.h or libcap does not exist."); } #endif /* HAVE_LIBCAP */