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