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