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
28 char *TCID = "keepcaps";
29 int TST_TOTAL = 1;
30
31 #if (HAVE_LINUX_SECUREBITS_H && HAVE_LIBCAP)
32 #include <linux/securebits.h>
33
eff_caps_empty(cap_t c)34 static 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
am_privileged(void)58 static 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
do_setuid(int expect_privs)72 static 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
main(int argc,char * argv[])98 int 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
main(void)150 int main(void)
151 {
152 tst_brkm(TCONF, NULL, "linux/securebits.h or libcap does not exist.");
153 }
154
155 #endif /* HAVE_LIBCAP */
156