xref: /aosp_15_r20/external/libcap-ng/utils/captest.c (revision 8dd5e09d5faf27a871e8654ddaa2d2af7c696578)
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