xref: /freebsd/usr.bin/proccontrol/proccontrol.c (revision 9bc300465e48e19d794d88d0c158a2adb92c7197)
1 /*-
2  * Copyright (c) 2016 The FreeBSD Foundation
3  *
4  * This software was developed by Konstantin Belousov <kib@FreeBSD.org>
5  * under sponsorship from the FreeBSD Foundation.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include <sys/cdefs.h>
30 #include <sys/procctl.h>
31 #include <err.h>
32 #include <stdbool.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <unistd.h>
37 
38 enum {
39 	MODE_ASLR,
40 	MODE_INVALID,
41 	MODE_TRACE,
42 	MODE_TRAPCAP,
43 	MODE_PROTMAX,
44 	MODE_STACKGAP,
45 	MODE_NO_NEW_PRIVS,
46 	MODE_WXMAP,
47 #ifdef PROC_KPTI_CTL
48 	MODE_KPTI,
49 #endif
50 #ifdef PROC_LA_CTL
51 	MODE_LA57,
52 	MODE_LA48,
53 #endif
54 };
55 
56 static pid_t
57 str2pid(const char *str)
58 {
59 	pid_t res;
60 	char *tail;
61 
62 	res = strtol(str, &tail, 0);
63 	if (*tail != '\0') {
64 		warnx("non-numeric pid");
65 		return (-1);
66 	}
67 	return (res);
68 }
69 
70 #ifdef PROC_KPTI_CTL
71 #define	KPTI_USAGE "|kpti"
72 #else
73 #define	KPTI_USAGE
74 #endif
75 #ifdef PROC_LA_CTL
76 #define	LA_USAGE "|la48|la57"
77 #else
78 #define	LA_USAGE
79 #endif
80 
81 static void __dead2
82 usage(void)
83 {
84 
85 	fprintf(stderr, "Usage: proccontrol -m (aslr|protmax|trace|trapcap|"
86 	    "stackgap|nonewprivs|wxmap"KPTI_USAGE LA_USAGE") [-q] "
87 	    "[-s (enable|disable)] [-p pid | command]\n");
88 	exit(1);
89 }
90 
91 int
92 main(int argc, char *argv[])
93 {
94 	int arg, ch, error, mode;
95 	pid_t pid;
96 	bool enable, do_command, query;
97 
98 	mode = MODE_INVALID;
99 	enable = true;
100 	pid = -1;
101 	query = false;
102 	while ((ch = getopt(argc, argv, "m:qs:p:")) != -1) {
103 		switch (ch) {
104 		case 'm':
105 			if (strcmp(optarg, "aslr") == 0)
106 				mode = MODE_ASLR;
107 			else if (strcmp(optarg, "protmax") == 0)
108 				mode = MODE_PROTMAX;
109 			else if (strcmp(optarg, "trace") == 0)
110 				mode = MODE_TRACE;
111 			else if (strcmp(optarg, "trapcap") == 0)
112 				mode = MODE_TRAPCAP;
113 			else if (strcmp(optarg, "stackgap") == 0)
114 				mode = MODE_STACKGAP;
115 			else if (strcmp(optarg, "nonewprivs") == 0)
116 				mode = MODE_NO_NEW_PRIVS;
117 			else if (strcmp(optarg, "wxmap") == 0)
118 				mode = MODE_WXMAP;
119 #ifdef PROC_KPTI_CTL
120 			else if (strcmp(optarg, "kpti") == 0)
121 				mode = MODE_KPTI;
122 #endif
123 #ifdef PROC_LA_CTL
124 			else if (strcmp(optarg, "la57") == 0)
125 				mode = MODE_LA57;
126 			else if (strcmp(optarg, "la48") == 0)
127 				mode = MODE_LA48;
128 #endif
129 			else
130 				usage();
131 			break;
132 		case 's':
133 			if (strcmp(optarg, "enable") == 0)
134 				enable = true;
135 			else if (strcmp(optarg, "disable") == 0)
136 				enable = false;
137 			else
138 				usage();
139 			break;
140 		case 'p':
141 			pid = str2pid(optarg);
142 			break;
143 		case 'q':
144 			query = true;
145 			break;
146 		case '?':
147 		default:
148 			usage();
149 			break;
150 		}
151 	}
152 	argc -= optind;
153 	argv += optind;
154 	do_command = argc != 0;
155 	if (do_command) {
156 		if (pid != -1 || query)
157 			usage();
158 		pid = getpid();
159 	} else if (pid == -1) {
160 		pid = getpid();
161 	}
162 
163 	if (query) {
164 		switch (mode) {
165 		case MODE_ASLR:
166 			error = procctl(P_PID, pid, PROC_ASLR_STATUS, &arg);
167 			break;
168 		case MODE_TRACE:
169 			error = procctl(P_PID, pid, PROC_TRACE_STATUS, &arg);
170 			break;
171 		case MODE_TRAPCAP:
172 			error = procctl(P_PID, pid, PROC_TRAPCAP_STATUS, &arg);
173 			break;
174 		case MODE_PROTMAX:
175 			error = procctl(P_PID, pid, PROC_PROTMAX_STATUS, &arg);
176 			break;
177 		case MODE_STACKGAP:
178 			error = procctl(P_PID, pid, PROC_STACKGAP_STATUS, &arg);
179 			break;
180 		case MODE_NO_NEW_PRIVS:
181 			error = procctl(P_PID, pid, PROC_NO_NEW_PRIVS_STATUS,
182 			    &arg);
183 			break;
184 		case MODE_WXMAP:
185 			error = procctl(P_PID, pid, PROC_WXMAP_STATUS, &arg);
186 			break;
187 #ifdef PROC_KPTI_CTL
188 		case MODE_KPTI:
189 			error = procctl(P_PID, pid, PROC_KPTI_STATUS, &arg);
190 			break;
191 #endif
192 #ifdef PROC_LA_CTL
193 		case MODE_LA57:
194 		case MODE_LA48:
195 			error = procctl(P_PID, pid, PROC_LA_STATUS, &arg);
196 			break;
197 #endif
198 		default:
199 			usage();
200 			break;
201 		}
202 		if (error != 0)
203 			err(1, "procctl status");
204 		switch (mode) {
205 		case MODE_ASLR:
206 			switch (arg & ~PROC_ASLR_ACTIVE) {
207 			case PROC_ASLR_FORCE_ENABLE:
208 				printf("force enabled");
209 				break;
210 			case PROC_ASLR_FORCE_DISABLE:
211 				printf("force disabled");
212 				break;
213 			case PROC_ASLR_NOFORCE:
214 				printf("not forced");
215 				break;
216 			}
217 			if ((arg & PROC_ASLR_ACTIVE) != 0)
218 				printf(", active\n");
219 			else
220 				printf(", not active\n");
221 			break;
222 		case MODE_TRACE:
223 			if (arg == -1)
224 				printf("disabled\n");
225 			else if (arg == 0)
226 				printf("enabled, no debugger\n");
227 			else
228 				printf("enabled, traced by %d\n", arg);
229 			break;
230 		case MODE_TRAPCAP:
231 			switch (arg) {
232 			case PROC_TRAPCAP_CTL_ENABLE:
233 				printf("enabled\n");
234 				break;
235 			case PROC_TRAPCAP_CTL_DISABLE:
236 				printf("disabled\n");
237 				break;
238 			}
239 			break;
240 		case MODE_PROTMAX:
241 			switch (arg & ~PROC_PROTMAX_ACTIVE) {
242 			case PROC_PROTMAX_FORCE_ENABLE:
243 				printf("force enabled");
244 				break;
245 			case PROC_PROTMAX_FORCE_DISABLE:
246 				printf("force disabled");
247 				break;
248 			case PROC_PROTMAX_NOFORCE:
249 				printf("not forced");
250 				break;
251 			}
252 			if ((arg & PROC_PROTMAX_ACTIVE) != 0)
253 				printf(", active\n");
254 			else
255 				printf(", not active\n");
256 			break;
257 		case MODE_STACKGAP:
258 			switch (arg & (PROC_STACKGAP_ENABLE |
259 			    PROC_STACKGAP_DISABLE)) {
260 			case PROC_STACKGAP_ENABLE:
261 				printf("enabled\n");
262 				break;
263 			case PROC_STACKGAP_DISABLE:
264 				printf("disabled\n");
265 				break;
266 			}
267 			switch (arg & (PROC_STACKGAP_ENABLE_EXEC |
268 			    PROC_STACKGAP_DISABLE_EXEC)) {
269 			case PROC_STACKGAP_ENABLE_EXEC:
270 				printf("enabled after exec\n");
271 				break;
272 			case PROC_STACKGAP_DISABLE_EXEC:
273 				printf("disabled after exec\n");
274 				break;
275 			}
276 			break;
277 		case MODE_NO_NEW_PRIVS:
278 			switch (arg) {
279 			case PROC_NO_NEW_PRIVS_ENABLE:
280 				printf("enabled\n");
281 				break;
282 			case PROC_NO_NEW_PRIVS_DISABLE:
283 				printf("disabled\n");
284 				break;
285 			}
286 			break;
287 		case MODE_WXMAP:
288 			if ((arg & PROC_WX_MAPPINGS_PERMIT) != 0)
289 				printf("enabled");
290 			else
291 				printf("disabled");
292 			if ((arg & PROC_WX_MAPPINGS_DISALLOW_EXEC) != 0)
293 				printf(", disabled on exec");
294 			if ((arg & PROC_WXORX_ENFORCE) != 0)
295 				printf(", wxorx enforced");
296 			printf("\n");
297 			break;
298 #ifdef PROC_KPTI_CTL
299 		case MODE_KPTI:
300 			switch (arg & ~PROC_KPTI_STATUS_ACTIVE) {
301 			case PROC_KPTI_CTL_ENABLE_ON_EXEC:
302 				printf("enabled");
303 				break;
304 			case PROC_KPTI_CTL_DISABLE_ON_EXEC:
305 				printf("disabled");
306 				break;
307 			}
308 			if ((arg & PROC_KPTI_STATUS_ACTIVE) != 0)
309 				printf(", active\n");
310 			else
311 				printf(", not active\n");
312 			break;
313 #endif
314 #ifdef PROC_LA_CTL
315 		case MODE_LA57:
316 		case MODE_LA48:
317 			switch (arg & ~(PROC_LA_STATUS_LA48 |
318 			    PROC_LA_STATUS_LA57)) {
319 			case PROC_LA_CTL_LA48_ON_EXEC:
320 				printf("la48 on exec");
321 				break;
322 			case PROC_LA_CTL_LA57_ON_EXEC:
323 				printf("la57 on exec");
324 				break;
325 			case PROC_LA_CTL_DEFAULT_ON_EXEC:
326 				printf("default on exec");
327 				break;
328 			}
329 			if ((arg & PROC_LA_STATUS_LA48) != 0)
330 				printf(", la48 active\n");
331 			else if ((arg & PROC_LA_STATUS_LA57) != 0)
332 				printf(", la57 active\n");
333 			break;
334 #endif
335 		}
336 	} else {
337 		switch (mode) {
338 		case MODE_ASLR:
339 			arg = enable ? PROC_ASLR_FORCE_ENABLE :
340 			    PROC_ASLR_FORCE_DISABLE;
341 			error = procctl(P_PID, pid, PROC_ASLR_CTL, &arg);
342 			break;
343 		case MODE_TRACE:
344 			arg = enable ? PROC_TRACE_CTL_ENABLE :
345 			    PROC_TRACE_CTL_DISABLE;
346 			error = procctl(P_PID, pid, PROC_TRACE_CTL, &arg);
347 			break;
348 		case MODE_TRAPCAP:
349 			arg = enable ? PROC_TRAPCAP_CTL_ENABLE :
350 			    PROC_TRAPCAP_CTL_DISABLE;
351 			error = procctl(P_PID, pid, PROC_TRAPCAP_CTL, &arg);
352 			break;
353 		case MODE_PROTMAX:
354 			arg = enable ? PROC_PROTMAX_FORCE_ENABLE :
355 			    PROC_PROTMAX_FORCE_DISABLE;
356 			error = procctl(P_PID, pid, PROC_PROTMAX_CTL, &arg);
357 			break;
358 		case MODE_STACKGAP:
359 			arg = enable ? PROC_STACKGAP_ENABLE_EXEC :
360 			    (PROC_STACKGAP_DISABLE |
361 			    PROC_STACKGAP_DISABLE_EXEC);
362 			error = procctl(P_PID, pid, PROC_STACKGAP_CTL, &arg);
363 			break;
364 		case MODE_NO_NEW_PRIVS:
365 			arg = enable ? PROC_NO_NEW_PRIVS_ENABLE :
366 			    PROC_NO_NEW_PRIVS_DISABLE;
367 			error = procctl(P_PID, pid, PROC_NO_NEW_PRIVS_CTL,
368 			    &arg);
369 			break;
370 		case MODE_WXMAP:
371 			arg = enable ? PROC_WX_MAPPINGS_PERMIT :
372 			    PROC_WX_MAPPINGS_DISALLOW_EXEC;
373 			error = procctl(P_PID, pid, PROC_WXMAP_CTL, &arg);
374 			break;
375 #ifdef PROC_KPTI_CTL
376 		case MODE_KPTI:
377 			arg = enable ? PROC_KPTI_CTL_ENABLE_ON_EXEC :
378 			    PROC_KPTI_CTL_DISABLE_ON_EXEC;
379 			error = procctl(P_PID, pid, PROC_KPTI_CTL, &arg);
380 			break;
381 #endif
382 #ifdef PROC_LA_CTL
383 		case MODE_LA57:
384 			arg = enable ? PROC_LA_CTL_LA57_ON_EXEC :
385 			    PROC_LA_CTL_DEFAULT_ON_EXEC;
386 			error = procctl(P_PID, pid, PROC_LA_CTL, &arg);
387 			break;
388 		case MODE_LA48:
389 			arg = enable ? PROC_LA_CTL_LA48_ON_EXEC :
390 			    PROC_LA_CTL_DEFAULT_ON_EXEC;
391 			error = procctl(P_PID, pid, PROC_LA_CTL, &arg);
392 			break;
393 #endif
394 		default:
395 			usage();
396 			break;
397 		}
398 		if (error != 0)
399 			err(1, "procctl ctl");
400 		if (do_command) {
401 			error = execvp(argv[0], argv);
402 			err(1, "exec");
403 		}
404 	}
405 	exit(0);
406 }
407