| #include <errno.h> |
| #include "config.h" |
| #if HAVE_SYS_CAPABILITY_H |
| #include <linux/types.h> |
| #include <sys/capability.h> |
| #endif |
| #include <sys/prctl.h> |
| #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 <linux/securebits.h> |
| |
| 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(NULL); |
| |
| ret = prctl(PR_GET_KEEPCAPS); |
| if (ret) |
| tst_brkm(TBROK, NULL, "keepcaps was already set?"); |
| |
| if (argc < 2) |
| tst_brkm(TBROK, NULL, "Usage: %s <tescase_num>", 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 */ |