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