1#include <errno.h>
2#include "config.h"
3#if HAVE_SYS_CAPABILITY_H
4#include <linux/types.h>
5#include <sys/capability.h>
6#endif
7#include <sys/prctl.h>
8#include "test.h"
9
10#ifndef SECBIT_KEEP_CAPS
11#define SECBIT_KEEP_CAPS (1<<4)
12#endif
13
14/* Tests:
15	1. drop capabilities at setuid if KEEPCAPS is not set and
16	   new user is nonroot
17	2. keep capabilities if set and new user is nonroot
18	   a. do with prctl(PR_SET_KEEPCAPS)
19	   (call this test 2)
20	   b. do with prctl(PR_SET_SECUREBITS, SECURE_KEEP_CAPS)
21	   (call this test 3)
22   TODO: test that exec clears KEEPCAPS
23   	(just create a simple executable that checks PR_GET_KEEPCAPS
24	 results, and execute that as test 4 after doing PR_SET_KEEPCAPS).
25   TODO: all of the other securebits tests.
26 */
27
28char *TCID = "keepcaps";
29int TST_TOTAL = 1;
30
31#if (HAVE_LINUX_SECUREBITS_H && HAVE_LIBCAP)
32#include <linux/securebits.h>
33
34static int eff_caps_empty(cap_t c)
35{
36	int i, ret, empty = 1;
37	cap_flag_value_t v;
38
39	for (i = 0; i < CAP_LAST_CAP; i++) {
40		ret = cap_get_flag(c, i, CAP_PERMITTED, &v);
41		/*
42		 * If the value of CAP_LAST_CAP in linux/capability.h is greater
43		 * than the value in the capability.h which is used to create
44		 * libcap.so. Then cap_get_flag returns -1, and errno is set to
45		 * EINVAL.
46		 */
47		if (ret == -1) {
48			tst_brkm(TBROK | TERRNO, NULL,
49				"Not expected. Please check arguments.");
50		}
51		if (ret || v)
52			empty = 0;
53	}
54
55	return empty;
56}
57
58static int am_privileged(void)
59{
60	int am_privileged = 1;
61
62	cap_t cap = cap_get_proc();
63	if (eff_caps_empty(cap))
64		am_privileged = 0;
65	cap_free(cap);
66
67	return am_privileged;
68}
69
70#define EXPECT_NOPRIVS 0
71#define EXPECT_PRIVS 1
72static void do_setuid(int expect_privs)
73{
74	int ret;
75	int have_privs;
76
77	ret = setuid(1000);
78	if (ret)
79		tst_brkm(TERRNO | TFAIL, NULL, "setuid failed");
80
81	have_privs = am_privileged();
82	if (have_privs && expect_privs == EXPECT_PRIVS) {
83		tst_resm(TPASS, "kept privs as expected");
84		tst_exit();
85	}
86	if (!have_privs && expect_privs == EXPECT_PRIVS) {
87		tst_brkm(TFAIL, NULL, "expected to keep privs but did not");
88	}
89	if (!have_privs && expect_privs == EXPECT_NOPRIVS) {
90		tst_resm(TPASS, "dropped privs as expected");
91		tst_exit();
92	}
93
94	/* have_privs && EXPECT_NOPRIVS */
95	tst_brkm(TFAIL, NULL, "expected to drop privs but did not");
96}
97
98int main(int argc, char *argv[])
99{
100	int ret, whichtest;
101
102	tst_require_root();
103
104	ret = prctl(PR_GET_KEEPCAPS);
105	if (ret)
106		tst_brkm(TBROK, NULL, "keepcaps was already set?");
107
108	if (argc < 2)
109		tst_brkm(TBROK, NULL, "Usage: %s <tescase_num>", argv[0]);
110
111	whichtest = atoi(argv[1]);
112	if (whichtest < 1 || whichtest > 3)
113		tst_brkm(TFAIL, NULL, "Valid tests are 1-3");
114
115	switch (whichtest) {
116	case 1:
117		do_setuid(EXPECT_NOPRIVS);	/* does not return */
118	case 2:
119		ret = prctl(PR_SET_KEEPCAPS, 1);
120		if (ret == -1) {
121			tst_brkm(TFAIL | TERRNO, NULL,
122				 "PR_SET_KEEPCAPS failed");
123		}
124		ret = prctl(PR_GET_KEEPCAPS);
125		if (!ret) {
126			tst_brkm(TFAIL | TERRNO, NULL,
127				 "PR_SET_KEEPCAPS did not set keepcaps");
128		}
129		do_setuid(EXPECT_PRIVS);	/* does not return */
130	case 3:
131		ret = prctl(PR_GET_SECUREBITS);
132		ret = prctl(PR_SET_SECUREBITS, ret | SECBIT_KEEP_CAPS);
133		if (ret == -1) {
134			tst_brkm(TFAIL | TERRNO, NULL,
135				 "PR_SET_SECUREBITS failed");
136		}
137		ret = prctl(PR_GET_KEEPCAPS);
138		if (!ret) {
139			tst_brkm(TFAIL | TERRNO, NULL,
140				 "PR_SET_SECUREBITS did not set keepcaps");
141		}
142		do_setuid(EXPECT_PRIVS);	/* does not return */
143	default:
144		tst_brkm(TFAIL, NULL, "Valid tests are 1-3");
145	}
146}
147
148#else
149
150int main(void)
151{
152	tst_brkm(TCONF, NULL, "linux/securebits.h or libcap does not exist.");
153}
154
155#endif /* HAVE_LIBCAP */
156