xref: /freebsd/usr.bin/proccontrol/proccontrol.c (revision c66ec88fed842fbaad62c30d510644ceb7bd2d71)
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 #ifdef PROC_KPTI_CTL
49 	MODE_KPTI,
50 #endif
51 #ifdef PROC_LA_CTL
52 	MODE_LA57,
53 	MODE_LA48,
54 #endif
55 };
56 
57 static pid_t
58 str2pid(const char *str)
59 {
60 	pid_t res;
61 	char *tail;
62 
63 	res = strtol(str, &tail, 0);
64 	if (*tail != '\0') {
65 		warnx("non-numeric pid");
66 		return (-1);
67 	}
68 	return (res);
69 }
70 
71 #ifdef PROC_KPTI_CTL
72 #define	KPTI_USAGE "|kpti"
73 #else
74 #define	KPTI_USAGE
75 #endif
76 #ifdef PROC_LA_CTL
77 #define	LA_USAGE "|la48|la57"
78 #else
79 #define	LA_USAGE
80 #endif
81 
82 static void __dead2
83 usage(void)
84 {
85 
86 	fprintf(stderr, "Usage: proccontrol -m (aslr|protmax|trace|trapcap|"
87 	    "stackgap"KPTI_USAGE LA_USAGE") [-q] "
88 	    "[-s (enable|disable)] [-p pid | command]\n");
89 	exit(1);
90 }
91 
92 int
93 main(int argc, char *argv[])
94 {
95 	int arg, ch, error, mode;
96 	pid_t pid;
97 	bool enable, do_command, query;
98 
99 	mode = MODE_INVALID;
100 	enable = true;
101 	pid = -1;
102 	query = false;
103 	while ((ch = getopt(argc, argv, "m:qs:p:")) != -1) {
104 		switch (ch) {
105 		case 'm':
106 			if (strcmp(optarg, "aslr") == 0)
107 				mode = MODE_ASLR;
108 			else if (strcmp(optarg, "protmax") == 0)
109 				mode = MODE_PROTMAX;
110 			else if (strcmp(optarg, "trace") == 0)
111 				mode = MODE_TRACE;
112 			else if (strcmp(optarg, "trapcap") == 0)
113 				mode = MODE_TRAPCAP;
114 			else if (strcmp(optarg, "stackgap") == 0)
115 				mode = MODE_STACKGAP;
116 #ifdef PROC_KPTI_CTL
117 			else if (strcmp(optarg, "kpti") == 0)
118 				mode = MODE_KPTI;
119 #endif
120 #ifdef PROC_LA_CTL
121 			else if (strcmp(optarg, "la57") == 0)
122 				mode = MODE_LA57;
123 			else if (strcmp(optarg, "la48") == 0)
124 				mode = MODE_LA48;
125 #endif
126 			else
127 				usage();
128 			break;
129 		case 's':
130 			if (strcmp(optarg, "enable") == 0)
131 				enable = true;
132 			else if (strcmp(optarg, "disable") == 0)
133 				enable = false;
134 			else
135 				usage();
136 			break;
137 		case 'p':
138 			pid = str2pid(optarg);
139 			break;
140 		case 'q':
141 			query = true;
142 			break;
143 		case '?':
144 		default:
145 			usage();
146 			break;
147 		}
148 	}
149 	argc -= optind;
150 	argv += optind;
151 	do_command = argc != 0;
152 	if (do_command) {
153 		if (pid != -1 || query)
154 			usage();
155 		pid = getpid();
156 	} else if (pid == -1) {
157 		pid = getpid();
158 	}
159 
160 	if (query) {
161 		switch (mode) {
162 		case MODE_ASLR:
163 			error = procctl(P_PID, pid, PROC_ASLR_STATUS, &arg);
164 			break;
165 		case MODE_TRACE:
166 			error = procctl(P_PID, pid, PROC_TRACE_STATUS, &arg);
167 			break;
168 		case MODE_TRAPCAP:
169 			error = procctl(P_PID, pid, PROC_TRAPCAP_STATUS, &arg);
170 			break;
171 		case MODE_PROTMAX:
172 			error = procctl(P_PID, pid, PROC_PROTMAX_STATUS, &arg);
173 			break;
174 		case MODE_STACKGAP:
175 			error = procctl(P_PID, pid, PROC_STACKGAP_STATUS, &arg);
176 			break;
177 #ifdef PROC_KPTI_CTL
178 		case MODE_KPTI:
179 			error = procctl(P_PID, pid, PROC_KPTI_STATUS, &arg);
180 			break;
181 #endif
182 #ifdef PROC_LA_CTL
183 		case MODE_LA57:
184 		case MODE_LA48:
185 			error = procctl(P_PID, pid, PROC_LA_STATUS, &arg);
186 			break;
187 #endif
188 		default:
189 			usage();
190 			break;
191 		}
192 		if (error != 0)
193 			err(1, "procctl status");
194 		switch (mode) {
195 		case MODE_ASLR:
196 			switch (arg & ~PROC_ASLR_ACTIVE) {
197 			case PROC_ASLR_FORCE_ENABLE:
198 				printf("force enabled");
199 				break;
200 			case PROC_ASLR_FORCE_DISABLE:
201 				printf("force disabled");
202 				break;
203 			case PROC_ASLR_NOFORCE:
204 				printf("not forced");
205 				break;
206 			}
207 			if ((arg & PROC_ASLR_ACTIVE) != 0)
208 				printf(", active\n");
209 			else
210 				printf(", not active\n");
211 			break;
212 		case MODE_TRACE:
213 			if (arg == -1)
214 				printf("disabled\n");
215 			else if (arg == 0)
216 				printf("enabled, no debugger\n");
217 			else
218 				printf("enabled, traced by %d\n", arg);
219 			break;
220 		case MODE_TRAPCAP:
221 			switch (arg) {
222 			case PROC_TRAPCAP_CTL_ENABLE:
223 				printf("enabled\n");
224 				break;
225 			case PROC_TRAPCAP_CTL_DISABLE:
226 				printf("disabled\n");
227 				break;
228 			}
229 			break;
230 		case MODE_PROTMAX:
231 			switch (arg & ~PROC_PROTMAX_ACTIVE) {
232 			case PROC_PROTMAX_FORCE_ENABLE:
233 				printf("force enabled");
234 				break;
235 			case PROC_PROTMAX_FORCE_DISABLE:
236 				printf("force disabled");
237 				break;
238 			case PROC_PROTMAX_NOFORCE:
239 				printf("not forced");
240 				break;
241 			}
242 			if ((arg & PROC_PROTMAX_ACTIVE) != 0)
243 				printf(", active\n");
244 			else
245 				printf(", not active\n");
246 			break;
247 		case MODE_STACKGAP:
248 			switch (arg & (PROC_STACKGAP_ENABLE |
249 			    PROC_STACKGAP_DISABLE)) {
250 			case PROC_STACKGAP_ENABLE:
251 				printf("enabled\n");
252 				break;
253 			case PROC_STACKGAP_DISABLE:
254 				printf("disabled\n");
255 				break;
256 			}
257 			switch (arg & (PROC_STACKGAP_ENABLE_EXEC |
258 			    PROC_STACKGAP_DISABLE_EXEC)) {
259 			case PROC_STACKGAP_ENABLE_EXEC:
260 				printf("enabled after exec\n");
261 				break;
262 			case PROC_STACKGAP_DISABLE_EXEC:
263 				printf("disabled after exec\n");
264 				break;
265 			}
266 			break;
267 #ifdef PROC_KPTI_CTL
268 		case MODE_KPTI:
269 			switch (arg & ~PROC_KPTI_STATUS_ACTIVE) {
270 			case PROC_KPTI_CTL_ENABLE_ON_EXEC:
271 				printf("enabled");
272 				break;
273 			case PROC_KPTI_CTL_DISABLE_ON_EXEC:
274 				printf("disabled");
275 				break;
276 			}
277 			if ((arg & PROC_KPTI_STATUS_ACTIVE) != 0)
278 				printf(", active\n");
279 			else
280 				printf(", not active\n");
281 			break;
282 #endif
283 #ifdef PROC_LA_CTL
284 		case MODE_LA57:
285 		case MODE_LA48:
286 			switch (arg & ~(PROC_LA_STATUS_LA48 |
287 			    PROC_LA_STATUS_LA57)) {
288 			case PROC_LA_CTL_LA48_ON_EXEC:
289 				printf("la48 on exec");
290 				break;
291 			case PROC_LA_CTL_LA57_ON_EXEC:
292 				printf("la57 on exec");
293 				break;
294 			case PROC_LA_CTL_DEFAULT_ON_EXEC:
295 				printf("default on exec");
296 				break;
297 			}
298 			if ((arg & PROC_LA_STATUS_LA48) != 0)
299 				printf(", la48 active\n");
300 			else if ((arg & PROC_LA_STATUS_LA57) != 0)
301 				printf(", la57 active\n");
302 			break;
303 #endif
304 		}
305 	} else {
306 		switch (mode) {
307 		case MODE_ASLR:
308 			arg = enable ? PROC_ASLR_FORCE_ENABLE :
309 			    PROC_ASLR_FORCE_DISABLE;
310 			error = procctl(P_PID, pid, PROC_ASLR_CTL, &arg);
311 			break;
312 		case MODE_TRACE:
313 			arg = enable ? PROC_TRACE_CTL_ENABLE :
314 			    PROC_TRACE_CTL_DISABLE;
315 			error = procctl(P_PID, pid, PROC_TRACE_CTL, &arg);
316 			break;
317 		case MODE_TRAPCAP:
318 			arg = enable ? PROC_TRAPCAP_CTL_ENABLE :
319 			    PROC_TRAPCAP_CTL_DISABLE;
320 			error = procctl(P_PID, pid, PROC_TRAPCAP_CTL, &arg);
321 			break;
322 		case MODE_PROTMAX:
323 			arg = enable ? PROC_PROTMAX_FORCE_ENABLE :
324 			    PROC_PROTMAX_FORCE_DISABLE;
325 			error = procctl(P_PID, pid, PROC_PROTMAX_CTL, &arg);
326 			break;
327 		case MODE_STACKGAP:
328 			arg = enable ? PROC_STACKGAP_ENABLE_EXEC :
329 			    (PROC_STACKGAP_DISABLE |
330 			    PROC_STACKGAP_DISABLE_EXEC);
331 			error = procctl(P_PID, pid, PROC_STACKGAP_CTL, &arg);
332 			break;
333 #ifdef PROC_KPTI_CTL
334 		case MODE_KPTI:
335 			arg = enable ? PROC_KPTI_CTL_ENABLE_ON_EXEC :
336 			    PROC_KPTI_CTL_DISABLE_ON_EXEC;
337 			error = procctl(P_PID, pid, PROC_KPTI_CTL, &arg);
338 			break;
339 #endif
340 #ifdef PROC_LA_CTL
341 		case MODE_LA57:
342 			arg = enable ? PROC_LA_CTL_LA57_ON_EXEC :
343 			    PROC_LA_CTL_DEFAULT_ON_EXEC;
344 			error = procctl(P_PID, pid, PROC_LA_CTL, &arg);
345 			break;
346 		case MODE_LA48:
347 			arg = enable ? PROC_LA_CTL_LA48_ON_EXEC :
348 			    PROC_LA_CTL_DEFAULT_ON_EXEC;
349 			error = procctl(P_PID, pid, PROC_LA_CTL, &arg);
350 			break;
351 #endif
352 		default:
353 			usage();
354 			break;
355 		}
356 		if (error != 0)
357 			err(1, "procctl ctl");
358 		if (do_command) {
359 			error = execvp(argv[0], argv);
360 			err(1, "exec");
361 		}
362 	}
363 	exit(0);
364 }
365