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