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