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