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