• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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