xref: /freebsd/usr.bin/proccontrol/proccontrol.c (revision 6683132d54bd6d589889e43dabdc53d35e38a028)
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 #ifdef PROC_KPTI_CTL
47 	MODE_KPTI,
48 #endif
49 };
50 
51 static pid_t
52 str2pid(const char *str)
53 {
54 	pid_t res;
55 	char *tail;
56 
57 	res = strtol(str, &tail, 0);
58 	if (*tail != '\0') {
59 		warnx("non-numeric pid");
60 		return (-1);
61 	}
62 	return (res);
63 }
64 
65 #ifdef PROC_KPTI_CTL
66 #define	KPTI_USAGE "|kpti"
67 #else
68 #define	KPTI_USAGE
69 #endif
70 
71 static void __dead2
72 usage(void)
73 {
74 
75 	fprintf(stderr, "Usage: proccontrol -m (aslr|trace|trapcap"
76 	    KPTI_USAGE") [-q] "
77 	    "[-s (enable|disable)] [-p pid | command]\n");
78 	exit(1);
79 }
80 
81 int
82 main(int argc, char *argv[])
83 {
84 	int arg, ch, error, mode;
85 	pid_t pid;
86 	bool enable, do_command, query;
87 
88 	mode = MODE_INVALID;
89 	enable = true;
90 	pid = -1;
91 	query = false;
92 	while ((ch = getopt(argc, argv, "m:qs:p:")) != -1) {
93 		switch (ch) {
94 		case 'm':
95 			if (strcmp(optarg, "aslr") == 0)
96 				mode = MODE_ASLR;
97 			else if (strcmp(optarg, "trace") == 0)
98 				mode = MODE_TRACE;
99 			else if (strcmp(optarg, "trapcap") == 0)
100 				mode = MODE_TRAPCAP;
101 #ifdef PROC_KPTI_CTL
102 			else if (strcmp(optarg, "kpti") == 0)
103 				mode = MODE_KPTI;
104 #endif
105 			else
106 				usage();
107 			break;
108 		case 's':
109 			if (strcmp(optarg, "enable") == 0)
110 				enable = true;
111 			else if (strcmp(optarg, "disable") == 0)
112 				enable = false;
113 			else
114 				usage();
115 			break;
116 		case 'p':
117 			pid = str2pid(optarg);
118 			break;
119 		case 'q':
120 			query = true;
121 			break;
122 		case '?':
123 		default:
124 			usage();
125 			break;
126 		}
127 	}
128 	argc -= optind;
129 	argv += optind;
130 	do_command = argc != 0;
131 	if (do_command) {
132 		if (pid != -1 || query)
133 			usage();
134 		pid = getpid();
135 	} else if (pid == -1) {
136 		pid = getpid();
137 	}
138 
139 	if (query) {
140 		switch (mode) {
141 		case MODE_ASLR:
142 			error = procctl(P_PID, pid, PROC_ASLR_STATUS, &arg);
143 			break;
144 		case MODE_TRACE:
145 			error = procctl(P_PID, pid, PROC_TRACE_STATUS, &arg);
146 			break;
147 		case MODE_TRAPCAP:
148 			error = procctl(P_PID, pid, PROC_TRAPCAP_STATUS, &arg);
149 			break;
150 #ifdef PROC_KPTI_CTL
151 		case MODE_KPTI:
152 			error = procctl(P_PID, pid, PROC_KPTI_STATUS, &arg);
153 			break;
154 #endif
155 		default:
156 			usage();
157 			break;
158 		}
159 		if (error != 0)
160 			err(1, "procctl status");
161 		switch (mode) {
162 		case MODE_ASLR:
163 			switch (arg & ~PROC_ASLR_ACTIVE) {
164 			case PROC_ASLR_FORCE_ENABLE:
165 				printf("force enabled");
166 				break;
167 			case PROC_ASLR_FORCE_DISABLE:
168 				printf("force disabled");
169 				break;
170 			case PROC_ASLR_NOFORCE:
171 				printf("not forced");
172 				break;
173 			}
174 			if ((arg & PROC_ASLR_ACTIVE) != 0)
175 				printf(", active\n");
176 			else
177 				printf(", not active\n");
178 			break;
179 		case MODE_TRACE:
180 			if (arg == -1)
181 				printf("disabled\n");
182 			else if (arg == 0)
183 				printf("enabled, no debugger\n");
184 			else
185 				printf("enabled, traced by %d\n", arg);
186 			break;
187 		case MODE_TRAPCAP:
188 			switch (arg) {
189 			case PROC_TRAPCAP_CTL_ENABLE:
190 				printf("enabled\n");
191 				break;
192 			case PROC_TRAPCAP_CTL_DISABLE:
193 				printf("disabled\n");
194 				break;
195 			}
196 			break;
197 #ifdef PROC_KPTI_CTL
198 		case MODE_KPTI:
199 			switch (arg & ~PROC_KPTI_STATUS_ACTIVE) {
200 			case PROC_KPTI_CTL_ENABLE_ON_EXEC:
201 				printf("enabled");
202 				break;
203 			case PROC_KPTI_CTL_DISABLE_ON_EXEC:
204 				printf("disabled");
205 				break;
206 			}
207 			if ((arg & PROC_KPTI_STATUS_ACTIVE) != 0)
208 				printf(", active\n");
209 			else
210 				printf(", not active\n");
211 			break;
212 #endif
213 		}
214 	} else {
215 		switch (mode) {
216 		case MODE_ASLR:
217 			arg = enable ? PROC_ASLR_FORCE_ENABLE :
218 			    PROC_ASLR_FORCE_DISABLE;
219 			error = procctl(P_PID, pid, PROC_ASLR_CTL, &arg);
220 			break;
221 		case MODE_TRACE:
222 			arg = enable ? PROC_TRACE_CTL_ENABLE :
223 			    PROC_TRACE_CTL_DISABLE;
224 			error = procctl(P_PID, pid, PROC_TRACE_CTL, &arg);
225 			break;
226 		case MODE_TRAPCAP:
227 			arg = enable ? PROC_TRAPCAP_CTL_ENABLE :
228 			    PROC_TRAPCAP_CTL_DISABLE;
229 			error = procctl(P_PID, pid, PROC_TRAPCAP_CTL, &arg);
230 			break;
231 #ifdef PROC_KPTI_CTL
232 		case MODE_KPTI:
233 			arg = enable ? PROC_KPTI_CTL_ENABLE_ON_EXEC :
234 			    PROC_KPTI_CTL_DISABLE_ON_EXEC;
235 			error = procctl(P_PID, pid, PROC_KPTI_CTL, &arg);
236 			break;
237 #endif
238 		default:
239 			usage();
240 			break;
241 		}
242 		if (error != 0)
243 			err(1, "procctl ctl");
244 		if (do_command) {
245 			error = execvp(argv[0], argv);
246 			err(1, "exec");
247 		}
248 	}
249 	exit(0);
250 }
251