1 /*
2 * captest.c - A program that demonstrates and outputs capabilities
3 * Copyright (c) 2009, 2013, 2020 Red Hat Inc.
4 * All Rights Reserved.
5 *
6 * This software may be freely redistributed and/or modified under the
7 * terms of the GNU General Public License as published by the Free
8 * Software Foundation; either version 2, or (at your option) any
9 * later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; see the file COPYING. If not, write to the
18 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor
19 * Boston, MA 02110-1335, USA.
20 *
21 * Authors:
22 * Steve Grubb <[email protected]>
23 *
24 */
25 #include "config.h"
26 #include <unistd.h>
27 #include <stdio.h>
28 #include <fcntl.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <errno.h>
32 #include <cap-ng.h>
33 #include <sys/prctl.h>
34 #ifdef HAVE_LINUX_SECUREBITS_H
35 #include <linux/securebits.h>
36 #endif
37
38 /* children can't get caps back */
39 #ifndef SECURE_NOROOT
40 #define SECURE_NOROOT 0
41 #endif
42 #ifndef SECURE_NOROOT_LOCKED
43 #define SECURE_NOROOT_LOCKED 1 /* make bit-0 immutable */
44 #endif
45 /* Setuid apps run by uid 0 don't get caps back */
46 #ifndef SECURE_NO_SETUID_FIXUP
47 #define SECURE_NO_SETUID_FIXUP 2
48 #endif
49 #ifndef SECURE_NO_SETUID_FIXUP_LOCKED
50 #define SECURE_NO_SETUID_FIXUP_LOCKED 3 /* make bit-2 immutable */
51 #endif
52
53 static int text = 0, no_child = 0, lock = 0, ambient = 0;
54
report(void)55 static void report(void)
56 {
57 int rc, escalated = 0, need_comma = 0;
58 uid_t uid, euid, suid;
59 gid_t gid, egid, sgid;
60
61 // Refresh what we have for capabilities
62 if (capng_get_caps_process()) {
63 printf("Error getting capabilities\n");
64 exit(1);
65 }
66
67 // Check user credentials
68 getresuid(&uid, &euid, &suid);
69 getresgid(&gid, &egid, &sgid);
70 if (no_child) {
71 if ((uid != euid && uid != 0) ||
72 capng_have_capability(CAPNG_EFFECTIVE,
73 CAP_SETUID)) {
74 printf("Attempting to regain root...");
75 setuid(0);
76 getresuid(&uid, &euid, &suid);
77 if (uid == 0) {
78 printf("SUCCESS - PRIVILEGE ESCALATION POSSIBLE\n");
79 setgid(0);
80 getresgid(&gid, &egid, &sgid);
81 escalated = 1;
82 } else
83 printf("FAILED\n");
84 }
85 printf("Child ");
86 }
87 printf("User credentials uid:%u euid:%u suid:%u\n", uid, euid, suid);
88 if (no_child)
89 printf("Child ");
90 printf("Group credentials gid:%u egid:%u sgid:%u\n", gid, egid, sgid);
91 if (uid != euid || gid != egid)
92 printf("Note: app has mismatching credentials!!\n");
93
94 // Check capabilities
95 if (text) {
96 if (capng_have_capabilities(CAPNG_SELECT_CAPS) == CAPNG_NONE) {
97 if (no_child)
98 printf("Child capabilities: none\n");
99 else
100 printf("Current capabilities: none\n");
101 } else {
102 if (no_child)
103 printf("Child ");
104 printf("Effective: ");
105 capng_print_caps_text(CAPNG_PRINT_STDOUT,
106 CAPNG_EFFECTIVE);
107 printf("\n");
108 if (no_child)
109 printf("Child ");
110 printf("Permitted: ");
111 capng_print_caps_text(CAPNG_PRINT_STDOUT,
112 CAPNG_PERMITTED);
113 printf("\n");
114 if (no_child)
115 printf("Child ");
116 printf("Inheritable: ");
117 capng_print_caps_text(CAPNG_PRINT_STDOUT,
118 CAPNG_INHERITABLE);
119 printf("\n");
120 if (no_child)
121 printf("Child ");
122 printf("Bounding Set: ");
123 capng_print_caps_text(CAPNG_PRINT_STDOUT,
124 CAPNG_BOUNDING_SET);
125 printf("\n");
126 if (no_child)
127 printf("Child ");
128 printf("Ambient: ");
129 capng_print_caps_text(CAPNG_PRINT_STDOUT,
130 CAPNG_AMBIENT);
131 printf("\n");
132 }
133 } else {
134 if (capng_have_capabilities(CAPNG_SELECT_CAPS) == CAPNG_NONE) {
135 if (no_child)
136 printf("Child capabilities: none\n");
137 else
138 printf("Current capabilities: none\n");
139 } else {
140 if (no_child)
141 printf("Child capabilities:\n");
142 capng_print_caps_numeric(CAPNG_PRINT_STDOUT,
143 CAPNG_SELECT_ALL);
144 }
145 }
146
147 // Now check securebits flags
148 #ifdef PR_SET_SECUREBITS
149 if (no_child)
150 printf("Child ");
151 printf("securebits flags: ");
152 rc = prctl(PR_GET_SECUREBITS, 1 << SECURE_NOROOT);
153 if (rc & (1 << SECURE_NOROOT)) {
154 printf("NOROOT");
155 need_comma = 1;
156 }
157 rc = prctl(PR_GET_SECUREBITS, 1 << SECURE_NOROOT_LOCKED);
158 if (rc & (1 << SECURE_NOROOT_LOCKED)) {
159 if (need_comma)
160 printf(", ");
161 printf("NOROOT_LOCKED");
162 need_comma = 1;
163 }
164 rc = prctl(PR_GET_SECUREBITS, 1 << SECURE_NO_SETUID_FIXUP);
165 if (rc & (1 << SECURE_NO_SETUID_FIXUP)) {
166 if (need_comma)
167 printf(", ");
168 printf("NO_SETUID_FIXUP");
169 need_comma = 1;
170 }
171 rc = prctl(PR_GET_SECUREBITS, 1 << SECURE_NO_SETUID_FIXUP_LOCKED);
172 if (rc & (1 << SECURE_NO_SETUID_FIXUP_LOCKED)) {
173 if (need_comma)
174 printf(", ");
175 printf("NO_SETUID_FIXUP_LOCKED");
176 need_comma = 1;
177 }
178 if (need_comma == 0)
179 printf("none");
180 printf("\n");
181 #endif
182 // Now do child process checks
183 if (no_child == 0 || escalated) {
184 printf("Attempting direct access to shadow...");
185 if (access("/etc/shadow", R_OK) == 0)
186 printf("SUCCESS\n");
187 else
188 printf("FAILED (%s)\n", strerror(errno));
189 }
190 if (no_child == 0) {
191 printf("Attempting to access shadow by child process...");
192 rc = system("cat /etc/shadow > /dev/null 2>&1");
193 if (rc == 0)
194 printf("SUCCESS\n");
195 else
196 printf("FAILED\n");
197 if (text)
198 system("/usr/bin/captest --no-child --text");
199 else
200 system("/usr/bin/captest --no-child");
201 }
202 }
203
usage(void)204 static void usage(void)
205 {
206 printf("usage: captest [ --ambient | --drop-all | --drop-caps | --id | --init-grp ] [ --lock ] [ --text ]\n");
207 }
208
main(int argc,char * argv[])209 int main(int argc, char *argv[])
210 {
211 int which = 0, i;
212
213 for (i = 1; i < argc; i++) {
214 if (strcmp(argv[i], "--text") == 0)
215 text = 1;
216 else if (strcmp(argv[i], "--no-child") == 0)
217 no_child = 1;
218 else if (strcmp(argv[i], "--lock") == 0)
219 lock = 1;
220 else if (strcmp(argv[i], "--drop-all") == 0)
221 which = 1;
222 else if (strcmp(argv[i], "--drop-caps") == 0)
223 which = 2;
224 else if (strcmp(argv[i], "--id") == 0)
225 which = 3;
226 else if (strcmp(argv[i], "--init-grp") == 0)
227 which = 4;
228 else if (strcmp(argv[i], "--ambient") == 0)
229 ambient = 1;
230 else {
231 usage();
232 return 0;
233 }
234 }
235 switch (which)
236 {
237 case 1:
238 capng_clear(CAPNG_SELECT_ALL);
239 if (lock) {
240 if (capng_lock()) {
241 fprintf(stderr, "capng_lock failed\n");
242 return 1;
243 }
244 }
245 if (capng_apply(CAPNG_SELECT_ALL)) {
246 fprintf(stderr, "capng_apply failed\n");
247 return 1;
248 }
249 report();
250 break;
251 case 2:
252 capng_clear(CAPNG_SELECT_CAPS);
253 if (ambient)
254 capng_update(CAPNG_ADD, CAPNG_AMBIENT,
255 CAP_CHOWN);
256 if (lock) {
257 if (capng_lock()) {
258 fprintf(stderr, "capng_lock failed\n");
259 return 1;
260 }
261 }
262 if (ambient) {
263 if (capng_apply(
264 CAPNG_SELECT_CAPS|CAPNG_SELECT_AMBIENT)) {
265 fprintf(stderr, "capng_apply failed\n");
266 return 1;
267 }
268 } else {
269 if (capng_apply(CAPNG_SELECT_CAPS)) {
270 fprintf(stderr, "capng_apply failed\n");
271 return 1;
272 }
273 }
274 report();
275 break;
276 case 3:
277 case 4: {
278 int rc;
279
280 capng_clear(CAPNG_SELECT_BOTH);
281 capng_update(CAPNG_ADD, CAPNG_EFFECTIVE|CAPNG_PERMITTED,
282 CAP_CHOWN);
283 if (ambient)
284 capng_update(CAPNG_ADD,
285 CAPNG_INHERITABLE|CAPNG_AMBIENT,
286 CAP_CHOWN);
287 if (which == 4)
288 rc = capng_change_id(99, 99,
289 CAPNG_INIT_SUPP_GRP | CAPNG_CLEAR_BOUNDING);
290 else
291 rc = capng_change_id(99, 99,
292 CAPNG_DROP_SUPP_GRP | CAPNG_CLEAR_BOUNDING);
293 if (rc < 0) {
294 printf("Error changing uid: %d\n", rc);
295 capng_print_caps_text(CAPNG_PRINT_STDOUT,
296 CAPNG_EFFECTIVE);
297 printf("\n");
298 return 1;
299 }
300 printf("Keeping CAP_CHOWN to show capabilities across uid change.\n");
301 report();
302 } break;
303 case 0:
304 if (lock) {
305 if (capng_lock()) {
306 fprintf(stderr, "capng_lock failed\n");
307 return 1;
308 }
309 }
310 report();
311 break;
312 }
313 return 0;
314 }
315
316