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 #include <sys/procctl.h>
32 #include <err.h>
33 #include <stdbool.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <unistd.h>
38
39 enum {
40 MODE_ASLR,
41 MODE_INVALID,
42 MODE_TRACE,
43 MODE_TRAPCAP,
44 MODE_PROTMAX,
45 MODE_STACKGAP,
46 MODE_NO_NEW_PRIVS,
47 MODE_WXMAP,
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
str2pid(const char * str)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
usage(void)83 usage(void)
84 {
85
86 fprintf(stderr, "Usage: proccontrol -m (aslr|protmax|trace|trapcap|"
87 "stackgap|nonewprivs|wxmap"KPTI_USAGE LA_USAGE") [-q] "
88 "[-s (enable|disable)] [-p pid | command]\n");
89 exit(1);
90 }
91
92 int
main(int argc,char * argv[])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 else if (strcmp(optarg, "nonewprivs") == 0)
117 mode = MODE_NO_NEW_PRIVS;
118 else if (strcmp(optarg, "wxmap") == 0)
119 mode = MODE_WXMAP;
120 #ifdef PROC_KPTI_CTL
121 else if (strcmp(optarg, "kpti") == 0)
122 mode = MODE_KPTI;
123 #endif
124 #ifdef PROC_LA_CTL
125 else if (strcmp(optarg, "la57") == 0)
126 mode = MODE_LA57;
127 else if (strcmp(optarg, "la48") == 0)
128 mode = MODE_LA48;
129 #endif
130 else
131 usage();
132 break;
133 case 's':
134 if (strcmp(optarg, "enable") == 0)
135 enable = true;
136 else if (strcmp(optarg, "disable") == 0)
137 enable = false;
138 else
139 usage();
140 break;
141 case 'p':
142 pid = str2pid(optarg);
143 break;
144 case 'q':
145 query = true;
146 break;
147 case '?':
148 default:
149 usage();
150 break;
151 }
152 }
153 argc -= optind;
154 argv += optind;
155 do_command = argc != 0;
156 if (do_command) {
157 if (pid != -1 || query)
158 usage();
159 pid = getpid();
160 } else if (pid == -1) {
161 pid = getpid();
162 }
163
164 if (query) {
165 switch (mode) {
166 case MODE_ASLR:
167 error = procctl(P_PID, pid, PROC_ASLR_STATUS, &arg);
168 break;
169 case MODE_TRACE:
170 error = procctl(P_PID, pid, PROC_TRACE_STATUS, &arg);
171 break;
172 case MODE_TRAPCAP:
173 error = procctl(P_PID, pid, PROC_TRAPCAP_STATUS, &arg);
174 break;
175 case MODE_PROTMAX:
176 error = procctl(P_PID, pid, PROC_PROTMAX_STATUS, &arg);
177 break;
178 case MODE_STACKGAP:
179 error = procctl(P_PID, pid, PROC_STACKGAP_STATUS, &arg);
180 break;
181 case MODE_NO_NEW_PRIVS:
182 error = procctl(P_PID, pid, PROC_NO_NEW_PRIVS_STATUS,
183 &arg);
184 break;
185 case MODE_WXMAP:
186 error = procctl(P_PID, pid, PROC_WXMAP_STATUS, &arg);
187 break;
188 #ifdef PROC_KPTI_CTL
189 case MODE_KPTI:
190 error = procctl(P_PID, pid, PROC_KPTI_STATUS, &arg);
191 break;
192 #endif
193 #ifdef PROC_LA_CTL
194 case MODE_LA57:
195 case MODE_LA48:
196 error = procctl(P_PID, pid, PROC_LA_STATUS, &arg);
197 break;
198 #endif
199 default:
200 usage();
201 break;
202 }
203 if (error != 0)
204 err(1, "procctl status");
205 switch (mode) {
206 case MODE_ASLR:
207 switch (arg & ~PROC_ASLR_ACTIVE) {
208 case PROC_ASLR_FORCE_ENABLE:
209 printf("force enabled");
210 break;
211 case PROC_ASLR_FORCE_DISABLE:
212 printf("force disabled");
213 break;
214 case PROC_ASLR_NOFORCE:
215 printf("not forced");
216 break;
217 }
218 if ((arg & PROC_ASLR_ACTIVE) != 0)
219 printf(", active\n");
220 else
221 printf(", not active\n");
222 break;
223 case MODE_TRACE:
224 if (arg == -1)
225 printf("disabled\n");
226 else if (arg == 0)
227 printf("enabled, no debugger\n");
228 else
229 printf("enabled, traced by %d\n", arg);
230 break;
231 case MODE_TRAPCAP:
232 switch (arg) {
233 case PROC_TRAPCAP_CTL_ENABLE:
234 printf("enabled\n");
235 break;
236 case PROC_TRAPCAP_CTL_DISABLE:
237 printf("disabled\n");
238 break;
239 }
240 break;
241 case MODE_PROTMAX:
242 switch (arg & ~PROC_PROTMAX_ACTIVE) {
243 case PROC_PROTMAX_FORCE_ENABLE:
244 printf("force enabled");
245 break;
246 case PROC_PROTMAX_FORCE_DISABLE:
247 printf("force disabled");
248 break;
249 case PROC_PROTMAX_NOFORCE:
250 printf("not forced");
251 break;
252 }
253 if ((arg & PROC_PROTMAX_ACTIVE) != 0)
254 printf(", active\n");
255 else
256 printf(", not active\n");
257 break;
258 case MODE_STACKGAP:
259 switch (arg & (PROC_STACKGAP_ENABLE |
260 PROC_STACKGAP_DISABLE)) {
261 case PROC_STACKGAP_ENABLE:
262 printf("enabled\n");
263 break;
264 case PROC_STACKGAP_DISABLE:
265 printf("disabled\n");
266 break;
267 }
268 switch (arg & (PROC_STACKGAP_ENABLE_EXEC |
269 PROC_STACKGAP_DISABLE_EXEC)) {
270 case PROC_STACKGAP_ENABLE_EXEC:
271 printf("enabled after exec\n");
272 break;
273 case PROC_STACKGAP_DISABLE_EXEC:
274 printf("disabled after exec\n");
275 break;
276 }
277 break;
278 case MODE_NO_NEW_PRIVS:
279 switch (arg) {
280 case PROC_NO_NEW_PRIVS_ENABLE:
281 printf("enabled\n");
282 break;
283 case PROC_NO_NEW_PRIVS_DISABLE:
284 printf("disabled\n");
285 break;
286 }
287 break;
288 case MODE_WXMAP:
289 if ((arg & PROC_WX_MAPPINGS_PERMIT) != 0)
290 printf("enabled");
291 else
292 printf("disabled");
293 if ((arg & PROC_WX_MAPPINGS_DISALLOW_EXEC) != 0)
294 printf(", disabled on exec");
295 if ((arg & PROC_WXORX_ENFORCE) != 0)
296 printf(", wxorx enforced");
297 printf("\n");
298 break;
299 #ifdef PROC_KPTI_CTL
300 case MODE_KPTI:
301 switch (arg & ~PROC_KPTI_STATUS_ACTIVE) {
302 case PROC_KPTI_CTL_ENABLE_ON_EXEC:
303 printf("enabled");
304 break;
305 case PROC_KPTI_CTL_DISABLE_ON_EXEC:
306 printf("disabled");
307 break;
308 }
309 if ((arg & PROC_KPTI_STATUS_ACTIVE) != 0)
310 printf(", active\n");
311 else
312 printf(", not active\n");
313 break;
314 #endif
315 #ifdef PROC_LA_CTL
316 case MODE_LA57:
317 case MODE_LA48:
318 switch (arg & ~(PROC_LA_STATUS_LA48 |
319 PROC_LA_STATUS_LA57)) {
320 case PROC_LA_CTL_LA48_ON_EXEC:
321 printf("la48 on exec");
322 break;
323 case PROC_LA_CTL_LA57_ON_EXEC:
324 printf("la57 on exec");
325 break;
326 case PROC_LA_CTL_DEFAULT_ON_EXEC:
327 printf("default on exec");
328 break;
329 }
330 if ((arg & PROC_LA_STATUS_LA48) != 0)
331 printf(", la48 active\n");
332 else if ((arg & PROC_LA_STATUS_LA57) != 0)
333 printf(", la57 active\n");
334 break;
335 #endif
336 }
337 } else {
338 switch (mode) {
339 case MODE_ASLR:
340 arg = enable ? PROC_ASLR_FORCE_ENABLE :
341 PROC_ASLR_FORCE_DISABLE;
342 error = procctl(P_PID, pid, PROC_ASLR_CTL, &arg);
343 break;
344 case MODE_TRACE:
345 arg = enable ? PROC_TRACE_CTL_ENABLE :
346 PROC_TRACE_CTL_DISABLE;
347 error = procctl(P_PID, pid, PROC_TRACE_CTL, &arg);
348 break;
349 case MODE_TRAPCAP:
350 arg = enable ? PROC_TRAPCAP_CTL_ENABLE :
351 PROC_TRAPCAP_CTL_DISABLE;
352 error = procctl(P_PID, pid, PROC_TRAPCAP_CTL, &arg);
353 break;
354 case MODE_PROTMAX:
355 arg = enable ? PROC_PROTMAX_FORCE_ENABLE :
356 PROC_PROTMAX_FORCE_DISABLE;
357 error = procctl(P_PID, pid, PROC_PROTMAX_CTL, &arg);
358 break;
359 case MODE_STACKGAP:
360 arg = enable ? PROC_STACKGAP_ENABLE_EXEC :
361 (PROC_STACKGAP_DISABLE |
362 PROC_STACKGAP_DISABLE_EXEC);
363 error = procctl(P_PID, pid, PROC_STACKGAP_CTL, &arg);
364 break;
365 case MODE_NO_NEW_PRIVS:
366 arg = enable ? PROC_NO_NEW_PRIVS_ENABLE :
367 PROC_NO_NEW_PRIVS_DISABLE;
368 error = procctl(P_PID, pid, PROC_NO_NEW_PRIVS_CTL,
369 &arg);
370 break;
371 case MODE_WXMAP:
372 arg = enable ? PROC_WX_MAPPINGS_PERMIT :
373 PROC_WX_MAPPINGS_DISALLOW_EXEC;
374 error = procctl(P_PID, pid, PROC_WXMAP_CTL, &arg);
375 break;
376 #ifdef PROC_KPTI_CTL
377 case MODE_KPTI:
378 arg = enable ? PROC_KPTI_CTL_ENABLE_ON_EXEC :
379 PROC_KPTI_CTL_DISABLE_ON_EXEC;
380 error = procctl(P_PID, pid, PROC_KPTI_CTL, &arg);
381 break;
382 #endif
383 #ifdef PROC_LA_CTL
384 case MODE_LA57:
385 arg = enable ? PROC_LA_CTL_LA57_ON_EXEC :
386 PROC_LA_CTL_DEFAULT_ON_EXEC;
387 error = procctl(P_PID, pid, PROC_LA_CTL, &arg);
388 break;
389 case MODE_LA48:
390 arg = enable ? PROC_LA_CTL_LA48_ON_EXEC :
391 PROC_LA_CTL_DEFAULT_ON_EXEC;
392 error = procctl(P_PID, pid, PROC_LA_CTL, &arg);
393 break;
394 #endif
395 default:
396 usage();
397 break;
398 }
399 if (error != 0)
400 err(1, "procctl ctl");
401 if (do_command) {
402 error = execvp(argv[0], argv);
403 err(1, "exec");
404 }
405 }
406 exit(0);
407 }
408