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