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