156 lines
3.5 KiB
C
156 lines
3.5 KiB
C
#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();
|
|
|
|
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 */
|