• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * captest.c - A program that demonstrates and outputs capabilities
3  * Copyright (c) 2009 Red Hat Inc., Durham, North Carolina.
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., 675 Mass Ave, Cambridge, MA 02139, USA.
19  *
20  * Authors:
21  *   Steve Grubb <sgrubb@redhat.com>
22  *
23  */
24 #include "config.h"
25 #include <unistd.h>
26 #include <stdio.h>
27 #include <fcntl.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <errno.h>
31 #include <cap-ng.h>
32 #include <sys/prctl.h>
33 #ifdef HAVE_LINUX_SECUREBITS_H
34 #include <linux/securebits.h>
35 #endif
36 
37 /* children can't get caps back */
38 #ifndef SECURE_NOROOT
39 #define SECURE_NOROOT                   0
40 #endif
41 #ifndef SECURE_NOROOT_LOCKED
42 #define SECURE_NOROOT_LOCKED            1  /* make bit-0 immutable */
43 #endif
44 /* Setuid apps run by uid 0 don't get caps back */
45 #ifndef SECURE_NO_SETUID_FIXUP
46 #define SECURE_NO_SETUID_FIXUP          2
47 #endif
48 #ifndef SECURE_NO_SETUID_FIXUP_LOCKED
49 #define SECURE_NO_SETUID_FIXUP_LOCKED   3  /* make bit-2 immutable */
50 #endif
51 
52 static int text = 0, no_child = 0, lock = 0;
53 
report(void)54 static void report(void)
55 {
56 	int rc, escalated = 0, need_comma = 0;
57 	uid_t uid, euid, suid;
58 	gid_t gid, egid, sgid;
59 
60 	// Refresh what we have for capabilities
61 	if (capng_get_caps_process()) {
62 		printf("Error getting capabilities\n");
63 		exit(1);
64 	}
65 
66 	// Check user credentials
67 	getresuid(&uid, &euid, &suid);
68 	getresgid(&gid, &egid, &sgid);
69 	if (no_child) {
70 		if ((uid != euid && uid != 0) ||
71 					capng_have_capability(CAPNG_EFFECTIVE,
72 						 CAP_SETUID)) {
73 			printf("Attempting to regain root...");
74 			setuid(0);
75 			getresuid(&uid, &euid, &suid);
76 			if (uid == 0) {
77 				printf("SUCCESS - PRIVILEGE ESCALATION POSSIBLE\n");
78 				setgid(0);
79 				getresgid(&gid, &egid, &sgid);
80 				escalated = 1;
81 			} else
82 				printf("FAILED\n");
83 		}
84 		printf("Child ");
85 	}
86 	printf("User  credentials uid:%d euid:%d suid:%d\n", uid, euid, suid);
87 	if (no_child)
88 		printf("Child ");
89 	printf("Group credentials gid:%d egid:%d sgid:%d\n", gid, egid, sgid);
90 	if (uid != euid || gid != egid)
91 		printf("Note: app has mismatching credentials!!\n");
92 
93 	// Check capabilities
94 	if (text) {
95 		if (capng_have_capabilities(CAPNG_SELECT_CAPS) == CAPNG_NONE) {
96 			if (no_child)
97 				printf("Child capabilities: none\n");
98 			else
99 				printf("Current capabilities: none\n");
100 		} else {
101 			if (no_child)
102 				printf("Child ");
103 			printf("Effective: ");
104 			capng_print_caps_text(CAPNG_PRINT_STDOUT,
105 					CAPNG_EFFECTIVE);
106 			printf("\n");
107 			if (no_child)
108 				printf("Child ");
109 			printf("Permitted: ");
110 			capng_print_caps_text(CAPNG_PRINT_STDOUT,
111 					CAPNG_PERMITTED);
112 			printf("\n");
113 			if (no_child)
114 				printf("Child ");
115 			printf("Inheritable: ");
116 			capng_print_caps_text(CAPNG_PRINT_STDOUT,
117 					CAPNG_INHERITABLE);
118 			printf("\n");
119 			if (no_child)
120 				printf("Child ");
121 			printf("Bounding Set: ");
122 			capng_print_caps_text(CAPNG_PRINT_STDOUT,
123 					CAPNG_BOUNDING_SET);
124 			printf("\n");
125 		}
126 	} else {
127 		if (capng_have_capabilities(CAPNG_SELECT_CAPS) == CAPNG_NONE) {
128 			if (no_child)
129 				printf("Child capabilities: none\n");
130 			else
131 				printf("Current capabilities: none\n");
132 		} else {
133 			if (no_child)
134 				printf("Child capabilities:\n");
135 			capng_print_caps_numeric(CAPNG_PRINT_STDOUT,
136 					CAPNG_SELECT_BOTH);
137 		}
138 	}
139 
140 	// Now check securebits flags
141 #ifdef PR_SET_SECUREBITS
142 	if (no_child)
143 		printf("Child ");
144 	printf("securebits flags: ");
145 	rc = prctl(PR_GET_SECUREBITS, 1 << SECURE_NOROOT);
146 	if (rc & (1 << SECURE_NOROOT)) {
147 		printf("NOROOT");
148 		need_comma = 1;
149 	}
150 	rc = prctl(PR_GET_SECUREBITS, 1 << SECURE_NOROOT_LOCKED);
151 	if (rc & (1 << SECURE_NOROOT_LOCKED)) {
152 		if (need_comma)
153 			printf(", ");
154 		printf("NOROOT_LOCKED");
155 		need_comma = 1;
156 	}
157 	rc = prctl(PR_GET_SECUREBITS, 1 << SECURE_NO_SETUID_FIXUP);
158 	if (rc & (1 << SECURE_NO_SETUID_FIXUP)) {
159 		if (need_comma)
160 			printf(", ");
161 		printf("NO_SETUID_FIXUP");
162 		need_comma = 1;
163 	}
164 	rc = prctl(PR_GET_SECUREBITS, 1 << SECURE_NO_SETUID_FIXUP_LOCKED);
165 	if (rc & (1 << SECURE_NO_SETUID_FIXUP_LOCKED)) {
166 		if (need_comma)
167 			printf(", ");
168 		printf("NO_SETUID_FIXUP_LOCKED");
169 		need_comma = 1;
170 	}
171 	if (need_comma == 0)
172 		printf("none");
173 	printf("\n");
174 #endif
175 	// Now do child process checks
176 	if (no_child == 0 || escalated) {
177 		printf("Attempting direct access to shadow...");
178 		if (access("/etc/shadow", R_OK) == 0)
179 			printf("SUCCESS\n");
180 		else
181 			printf("FAILED (%s)\n", strerror(errno));
182 	}
183 	if (no_child == 0) {
184 		printf("Attempting to access shadow by child process...");
185 		rc = system("cat /etc/shadow > /dev/null 2>&1");
186 		if (rc == 0)
187 			printf("SUCCESS\n");
188 		else
189 			printf("FAILED\n");
190 		if (text)
191 			system("/usr/bin/captest --no-child --text");
192 		else
193 			system("/usr/bin/captest --no-child");
194 	}
195 }
196 
usage(void)197 static void usage(void)
198 {
199 	printf("usage: captest [ --drop-all | --drop-caps | --id ] [ --lock ] [ --text ]\n");
200 }
201 
main(int argc,char * argv[])202 int main(int argc, char *argv[])
203 {
204 	int which = 0, i;
205 
206 	for (i = 1; i < argc; i++) {
207 		if (strcmp(argv[i], "--text") == 0)
208 			text = 1;
209 		else if (strcmp(argv[i], "--no-child") == 0)
210 			no_child = 1;
211 		else if (strcmp(argv[i], "--lock") == 0)
212 			lock = 1;
213 		else if (strcmp(argv[i], "--drop-all") == 0)
214 			which = 1;
215 		else if (strcmp(argv[i], "--drop-caps") == 0)
216 			which = 2;
217 		else if (strcmp(argv[i], "--id") == 0)
218 			which = 3;
219 		else {
220 			usage();
221 			return 0;
222 		}
223 	}
224 	switch (which)
225 	{
226 		case 1:
227 			capng_clear(CAPNG_SELECT_BOTH);
228 			if (lock)
229 				capng_lock();
230 			capng_apply(CAPNG_SELECT_BOTH);
231 			report();
232 			break;
233 		case 2:
234 			capng_clear(CAPNG_SELECT_CAPS);
235 			if (lock)
236 				capng_lock();
237 			capng_apply(CAPNG_SELECT_CAPS);
238 			report();
239 			break;
240 		case 3: {
241 			int rc;
242 
243 			capng_clear(CAPNG_SELECT_BOTH);
244 			capng_update(CAPNG_ADD, CAPNG_EFFECTIVE|CAPNG_PERMITTED,
245 					CAP_CHOWN);
246 			rc = capng_change_id(99, 99,
247 				CAPNG_DROP_SUPP_GRP | CAPNG_CLEAR_BOUNDING);
248 			if (rc < 0) {
249 				printf("Error changing uid: %d\n", rc);
250 				capng_print_caps_text(CAPNG_PRINT_STDOUT,
251 					CAPNG_EFFECTIVE);
252 				printf("\n");
253 				exit(1);
254 			}
255 			printf("Keeping CAP_CHOWN to show capabilities across uid change.\n");
256 			report();
257 			} break;
258 		case 0:
259 			if (lock)
260 				capng_lock();
261 			report();
262 			break;
263 	}
264 	return 0;
265 }
266 
267