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 MODE_PROTMAX, 47 MODE_STACKGAP, 48 #ifdef PROC_KPTI_CTL 49 MODE_KPTI, 50 #endif 51 }; 52 53 static pid_t 54 str2pid(const char *str) 55 { 56 pid_t res; 57 char *tail; 58 59 res = strtol(str, &tail, 0); 60 if (*tail != '\0') { 61 warnx("non-numeric pid"); 62 return (-1); 63 } 64 return (res); 65 } 66 67 #ifdef PROC_KPTI_CTL 68 #define KPTI_USAGE "|kpti" 69 #else 70 #define KPTI_USAGE 71 #endif 72 73 static void __dead2 74 usage(void) 75 { 76 77 fprintf(stderr, "Usage: proccontrol -m (aslr|protmax|trace|trapcap|" 78 "stackgap"KPTI_USAGE") [-q] " 79 "[-s (enable|disable)] [-p pid | command]\n"); 80 exit(1); 81 } 82 83 int 84 main(int argc, char *argv[]) 85 { 86 int arg, ch, error, mode; 87 pid_t pid; 88 bool enable, do_command, query; 89 90 mode = MODE_INVALID; 91 enable = true; 92 pid = -1; 93 query = false; 94 while ((ch = getopt(argc, argv, "m:qs:p:")) != -1) { 95 switch (ch) { 96 case 'm': 97 if (strcmp(optarg, "aslr") == 0) 98 mode = MODE_ASLR; 99 else if (strcmp(optarg, "protmax") == 0) 100 mode = MODE_PROTMAX; 101 else if (strcmp(optarg, "trace") == 0) 102 mode = MODE_TRACE; 103 else if (strcmp(optarg, "trapcap") == 0) 104 mode = MODE_TRAPCAP; 105 else if (strcmp(optarg, "stackgap") == 0) 106 mode = MODE_STACKGAP; 107 #ifdef PROC_KPTI_CTL 108 else if (strcmp(optarg, "kpti") == 0) 109 mode = MODE_KPTI; 110 #endif 111 else 112 usage(); 113 break; 114 case 's': 115 if (strcmp(optarg, "enable") == 0) 116 enable = true; 117 else if (strcmp(optarg, "disable") == 0) 118 enable = false; 119 else 120 usage(); 121 break; 122 case 'p': 123 pid = str2pid(optarg); 124 break; 125 case 'q': 126 query = true; 127 break; 128 case '?': 129 default: 130 usage(); 131 break; 132 } 133 } 134 argc -= optind; 135 argv += optind; 136 do_command = argc != 0; 137 if (do_command) { 138 if (pid != -1 || query) 139 usage(); 140 pid = getpid(); 141 } else if (pid == -1) { 142 pid = getpid(); 143 } 144 145 if (query) { 146 switch (mode) { 147 case MODE_ASLR: 148 error = procctl(P_PID, pid, PROC_ASLR_STATUS, &arg); 149 break; 150 case MODE_TRACE: 151 error = procctl(P_PID, pid, PROC_TRACE_STATUS, &arg); 152 break; 153 case MODE_TRAPCAP: 154 error = procctl(P_PID, pid, PROC_TRAPCAP_STATUS, &arg); 155 break; 156 case MODE_PROTMAX: 157 error = procctl(P_PID, pid, PROC_PROTMAX_STATUS, &arg); 158 break; 159 case MODE_STACKGAP: 160 error = procctl(P_PID, pid, PROC_STACKGAP_STATUS, &arg); 161 break; 162 #ifdef PROC_KPTI_CTL 163 case MODE_KPTI: 164 error = procctl(P_PID, pid, PROC_KPTI_STATUS, &arg); 165 break; 166 #endif 167 default: 168 usage(); 169 break; 170 } 171 if (error != 0) 172 err(1, "procctl status"); 173 switch (mode) { 174 case MODE_ASLR: 175 switch (arg & ~PROC_ASLR_ACTIVE) { 176 case PROC_ASLR_FORCE_ENABLE: 177 printf("force enabled"); 178 break; 179 case PROC_ASLR_FORCE_DISABLE: 180 printf("force disabled"); 181 break; 182 case PROC_ASLR_NOFORCE: 183 printf("not forced"); 184 break; 185 } 186 if ((arg & PROC_ASLR_ACTIVE) != 0) 187 printf(", active\n"); 188 else 189 printf(", not active\n"); 190 break; 191 case MODE_TRACE: 192 if (arg == -1) 193 printf("disabled\n"); 194 else if (arg == 0) 195 printf("enabled, no debugger\n"); 196 else 197 printf("enabled, traced by %d\n", arg); 198 break; 199 case MODE_TRAPCAP: 200 switch (arg) { 201 case PROC_TRAPCAP_CTL_ENABLE: 202 printf("enabled\n"); 203 break; 204 case PROC_TRAPCAP_CTL_DISABLE: 205 printf("disabled\n"); 206 break; 207 } 208 break; 209 case MODE_PROTMAX: 210 switch (arg & ~PROC_PROTMAX_ACTIVE) { 211 case PROC_PROTMAX_FORCE_ENABLE: 212 printf("force enabled"); 213 break; 214 case PROC_PROTMAX_FORCE_DISABLE: 215 printf("force disabled"); 216 break; 217 case PROC_PROTMAX_NOFORCE: 218 printf("not forced"); 219 break; 220 } 221 if ((arg & PROC_PROTMAX_ACTIVE) != 0) 222 printf(", active\n"); 223 else 224 printf(", not active\n"); 225 break; 226 case MODE_STACKGAP: 227 switch (arg & (PROC_STACKGAP_ENABLE | 228 PROC_STACKGAP_DISABLE)) { 229 case PROC_STACKGAP_ENABLE: 230 printf("enabled\n"); 231 break; 232 case PROC_STACKGAP_DISABLE: 233 printf("disabled\n"); 234 break; 235 } 236 switch (arg & (PROC_STACKGAP_ENABLE_EXEC | 237 PROC_STACKGAP_DISABLE_EXEC)) { 238 case PROC_STACKGAP_ENABLE_EXEC: 239 printf("enabled after exec\n"); 240 break; 241 case PROC_STACKGAP_DISABLE_EXEC: 242 printf("disabled after exec\n"); 243 break; 244 } 245 break; 246 #ifdef PROC_KPTI_CTL 247 case MODE_KPTI: 248 switch (arg & ~PROC_KPTI_STATUS_ACTIVE) { 249 case PROC_KPTI_CTL_ENABLE_ON_EXEC: 250 printf("enabled"); 251 break; 252 case PROC_KPTI_CTL_DISABLE_ON_EXEC: 253 printf("disabled"); 254 break; 255 } 256 if ((arg & PROC_KPTI_STATUS_ACTIVE) != 0) 257 printf(", active\n"); 258 else 259 printf(", not active\n"); 260 break; 261 #endif 262 } 263 } else { 264 switch (mode) { 265 case MODE_ASLR: 266 arg = enable ? PROC_ASLR_FORCE_ENABLE : 267 PROC_ASLR_FORCE_DISABLE; 268 error = procctl(P_PID, pid, PROC_ASLR_CTL, &arg); 269 break; 270 case MODE_TRACE: 271 arg = enable ? PROC_TRACE_CTL_ENABLE : 272 PROC_TRACE_CTL_DISABLE; 273 error = procctl(P_PID, pid, PROC_TRACE_CTL, &arg); 274 break; 275 case MODE_TRAPCAP: 276 arg = enable ? PROC_TRAPCAP_CTL_ENABLE : 277 PROC_TRAPCAP_CTL_DISABLE; 278 error = procctl(P_PID, pid, PROC_TRAPCAP_CTL, &arg); 279 break; 280 case MODE_PROTMAX: 281 arg = enable ? PROC_PROTMAX_FORCE_ENABLE : 282 PROC_PROTMAX_FORCE_DISABLE; 283 error = procctl(P_PID, pid, PROC_PROTMAX_CTL, &arg); 284 break; 285 case MODE_STACKGAP: 286 arg = enable ? PROC_STACKGAP_ENABLE_EXEC : 287 (PROC_STACKGAP_DISABLE | 288 PROC_STACKGAP_DISABLE_EXEC); 289 error = procctl(P_PID, pid, PROC_STACKGAP_CTL, &arg); 290 break; 291 #ifdef PROC_KPTI_CTL 292 case MODE_KPTI: 293 arg = enable ? PROC_KPTI_CTL_ENABLE_ON_EXEC : 294 PROC_KPTI_CTL_DISABLE_ON_EXEC; 295 error = procctl(P_PID, pid, PROC_KPTI_CTL, &arg); 296 break; 297 #endif 298 default: 299 usage(); 300 break; 301 } 302 if (error != 0) 303 err(1, "procctl ctl"); 304 if (do_command) { 305 error = execvp(argv[0], argv); 306 err(1, "exec"); 307 } 308 } 309 exit(0); 310 } 311