diff options
Diffstat (limited to 'usr.bin/proccontrol/proccontrol.c')
-rw-r--r-- | usr.bin/proccontrol/proccontrol.c | 429 |
1 files changed, 429 insertions, 0 deletions
diff --git a/usr.bin/proccontrol/proccontrol.c b/usr.bin/proccontrol/proccontrol.c new file mode 100644 index 000000000000..3548ca606656 --- /dev/null +++ b/usr.bin/proccontrol/proccontrol.c @@ -0,0 +1,429 @@ +/*- + * Copyright (c) 2016 The FreeBSD Foundation + * + * This software was developed by Konstantin Belousov <kib@FreeBSD.org> + * under sponsorship from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/param.h> +#include <sys/procctl.h> +#include <err.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +enum mode { + MODE_INVALID, + MODE_ASLR, + MODE_TRACE, + MODE_TRAPCAP, + MODE_PROTMAX, + MODE_STACKGAP, + MODE_NO_NEW_PRIVS, + MODE_WXMAP, +#ifdef PROC_KPTI_CTL + MODE_KPTI, +#endif +#ifdef PROC_LA_CTL + MODE_LA57, + MODE_LA48, +#endif + MODE_LOGSIGEXIT, +}; + +static const struct { + enum mode mode; + const char *name; +} modes[] = { + { MODE_ASLR, "aslr" }, + { MODE_TRACE, "trace" }, + { MODE_TRAPCAP, "trapcap" }, + { MODE_PROTMAX, "protmax" }, + { MODE_STACKGAP, "stackgap" }, + { MODE_NO_NEW_PRIVS, "nonewprivs" }, + { MODE_WXMAP, "wxmap" }, +#ifdef PROC_KPTI_CTL + { MODE_KPTI, "kpti" }, +#endif +#ifdef PROC_LA_CTL + { MODE_LA57, "la57" }, + { MODE_LA48, "la48" }, +#endif + { MODE_LOGSIGEXIT, "logsigexit" }, +}; + +static pid_t +str2pid(const char *str) +{ + pid_t res; + char *tail; + + res = strtol(str, &tail, 0); + if (*tail != '\0') { + warnx("non-numeric pid"); + return (-1); + } + return (res); +} + +static void __dead2 +usage(void) +{ + fprintf(stderr, "Usage:\n"); + fprintf(stderr, " proccontrol -m mode -s (enable|disable) " + "(-p pid | command)\n"); + fprintf(stderr, " proccontrol -m mode -q [-p pid]\n"); + fprintf(stderr, "Modes: "); + for (size_t i = 0; i < nitems(modes); i++) + fprintf(stderr, "%s%s", i == 0 ? "" : "|", modes[i].name); + fprintf(stderr, "\n"); + exit(1); +} + +int +main(int argc, char *argv[]) +{ + int arg, ch, error, mode; + pid_t pid; + bool enable, do_command, query; + + mode = MODE_INVALID; + enable = true; + pid = -1; + query = false; + while ((ch = getopt(argc, argv, "m:qs:p:")) != -1) { + switch (ch) { + case 'm': + if (mode != MODE_INVALID) + usage(); + for (size_t i = 0; i < nitems(modes); i++) { + if (strcmp(optarg, modes[i].name) == 0) { + mode = modes[i].mode; + break; + } + } + if (mode == MODE_INVALID) + usage(); + break; + case 's': + if (strcmp(optarg, "enable") == 0) + enable = true; + else if (strcmp(optarg, "disable") == 0) + enable = false; + else + usage(); + break; + case 'p': + pid = str2pid(optarg); + break; + case 'q': + query = true; + break; + case '?': + default: + usage(); + break; + } + } + argc -= optind; + argv += optind; + do_command = argc != 0; + if (do_command) { + if (pid != -1 || query) + usage(); + pid = getpid(); + } else if (pid == -1) { + if (!query) + usage(); + pid = getpid(); + } + + if (query) { + switch (mode) { + case MODE_ASLR: + error = procctl(P_PID, pid, PROC_ASLR_STATUS, &arg); + break; + case MODE_TRACE: + error = procctl(P_PID, pid, PROC_TRACE_STATUS, &arg); + break; + case MODE_TRAPCAP: + error = procctl(P_PID, pid, PROC_TRAPCAP_STATUS, &arg); + break; + case MODE_PROTMAX: + error = procctl(P_PID, pid, PROC_PROTMAX_STATUS, &arg); + break; + case MODE_STACKGAP: + error = procctl(P_PID, pid, PROC_STACKGAP_STATUS, &arg); + break; + case MODE_NO_NEW_PRIVS: + error = procctl(P_PID, pid, PROC_NO_NEW_PRIVS_STATUS, + &arg); + break; + case MODE_WXMAP: + error = procctl(P_PID, pid, PROC_WXMAP_STATUS, &arg); + break; +#ifdef PROC_KPTI_CTL + case MODE_KPTI: + error = procctl(P_PID, pid, PROC_KPTI_STATUS, &arg); + break; +#endif +#ifdef PROC_LA_CTL + case MODE_LA57: + case MODE_LA48: + error = procctl(P_PID, pid, PROC_LA_STATUS, &arg); + break; +#endif + case MODE_LOGSIGEXIT: + error = procctl(P_PID, pid, PROC_LOGSIGEXIT_STATUS, + &arg); + break; + default: + usage(); + break; + } + if (error != 0) + err(1, "procctl status"); + switch (mode) { + case MODE_ASLR: + switch (arg & ~PROC_ASLR_ACTIVE) { + case PROC_ASLR_FORCE_ENABLE: + printf("force enabled"); + break; + case PROC_ASLR_FORCE_DISABLE: + printf("force disabled"); + break; + case PROC_ASLR_NOFORCE: + printf("not forced"); + break; + } + if ((arg & PROC_ASLR_ACTIVE) != 0) + printf(", active\n"); + else + printf(", not active\n"); + break; + case MODE_TRACE: + if (arg == -1) + printf("disabled\n"); + else if (arg == 0) + printf("enabled, no debugger\n"); + else + printf("enabled, traced by %d\n", arg); + break; + case MODE_TRAPCAP: + switch (arg) { + case PROC_TRAPCAP_CTL_ENABLE: + printf("enabled\n"); + break; + case PROC_TRAPCAP_CTL_DISABLE: + printf("disabled\n"); + break; + } + break; + case MODE_PROTMAX: + switch (arg & ~PROC_PROTMAX_ACTIVE) { + case PROC_PROTMAX_FORCE_ENABLE: + printf("force enabled"); + break; + case PROC_PROTMAX_FORCE_DISABLE: + printf("force disabled"); + break; + case PROC_PROTMAX_NOFORCE: + printf("not forced"); + break; + } + if ((arg & PROC_PROTMAX_ACTIVE) != 0) + printf(", active\n"); + else + printf(", not active\n"); + break; + case MODE_STACKGAP: + switch (arg & (PROC_STACKGAP_ENABLE | + PROC_STACKGAP_DISABLE)) { + case PROC_STACKGAP_ENABLE: + printf("enabled\n"); + break; + case PROC_STACKGAP_DISABLE: + printf("disabled\n"); + break; + } + switch (arg & (PROC_STACKGAP_ENABLE_EXEC | + PROC_STACKGAP_DISABLE_EXEC)) { + case PROC_STACKGAP_ENABLE_EXEC: + printf("enabled after exec\n"); + break; + case PROC_STACKGAP_DISABLE_EXEC: + printf("disabled after exec\n"); + break; + } + break; + case MODE_NO_NEW_PRIVS: + switch (arg) { + case PROC_NO_NEW_PRIVS_ENABLE: + printf("enabled\n"); + break; + case PROC_NO_NEW_PRIVS_DISABLE: + printf("disabled\n"); + break; + } + break; + case MODE_WXMAP: + if ((arg & PROC_WX_MAPPINGS_PERMIT) != 0) + printf("enabled"); + else + printf("disabled"); + if ((arg & PROC_WX_MAPPINGS_DISALLOW_EXEC) != 0) + printf(", disabled on exec"); + if ((arg & PROC_WXORX_ENFORCE) != 0) + printf(", wxorx enforced"); + printf("\n"); + break; +#ifdef PROC_KPTI_CTL + case MODE_KPTI: + switch (arg & ~PROC_KPTI_STATUS_ACTIVE) { + case PROC_KPTI_CTL_ENABLE_ON_EXEC: + printf("enabled"); + break; + case PROC_KPTI_CTL_DISABLE_ON_EXEC: + printf("disabled"); + break; + } + if ((arg & PROC_KPTI_STATUS_ACTIVE) != 0) + printf(", active\n"); + else + printf(", not active\n"); + break; +#endif +#ifdef PROC_LA_CTL + case MODE_LA57: + case MODE_LA48: + switch (arg & ~(PROC_LA_STATUS_LA48 | + PROC_LA_STATUS_LA57)) { + case PROC_LA_CTL_LA48_ON_EXEC: + printf("la48 on exec"); + break; + case PROC_LA_CTL_LA57_ON_EXEC: + printf("la57 on exec"); + break; + case PROC_LA_CTL_DEFAULT_ON_EXEC: + printf("default on exec"); + break; + } + if ((arg & PROC_LA_STATUS_LA48) != 0) + printf(", la48 active\n"); + else if ((arg & PROC_LA_STATUS_LA57) != 0) + printf(", la57 active\n"); + break; +#endif + case MODE_LOGSIGEXIT: + switch (arg) { + case PROC_LOGSIGEXIT_CTL_NOFORCE: + printf("not forced\n"); + break; + case PROC_LOGSIGEXIT_CTL_FORCE_ENABLE: + printf("force enabled\n"); + break; + case PROC_LOGSIGEXIT_CTL_FORCE_DISABLE: + printf("force disabled\n"); + break; + } + break; + } + } else { + switch (mode) { + case MODE_ASLR: + arg = enable ? PROC_ASLR_FORCE_ENABLE : + PROC_ASLR_FORCE_DISABLE; + error = procctl(P_PID, pid, PROC_ASLR_CTL, &arg); + break; + case MODE_TRACE: + arg = enable ? PROC_TRACE_CTL_ENABLE : + PROC_TRACE_CTL_DISABLE; + error = procctl(P_PID, pid, PROC_TRACE_CTL, &arg); + break; + case MODE_TRAPCAP: + arg = enable ? PROC_TRAPCAP_CTL_ENABLE : + PROC_TRAPCAP_CTL_DISABLE; + error = procctl(P_PID, pid, PROC_TRAPCAP_CTL, &arg); + break; + case MODE_PROTMAX: + arg = enable ? PROC_PROTMAX_FORCE_ENABLE : + PROC_PROTMAX_FORCE_DISABLE; + error = procctl(P_PID, pid, PROC_PROTMAX_CTL, &arg); + break; + case MODE_STACKGAP: + arg = enable ? PROC_STACKGAP_ENABLE_EXEC : + (PROC_STACKGAP_DISABLE | + PROC_STACKGAP_DISABLE_EXEC); + error = procctl(P_PID, pid, PROC_STACKGAP_CTL, &arg); + break; + case MODE_NO_NEW_PRIVS: + arg = enable ? PROC_NO_NEW_PRIVS_ENABLE : + PROC_NO_NEW_PRIVS_DISABLE; + error = procctl(P_PID, pid, PROC_NO_NEW_PRIVS_CTL, + &arg); + break; + case MODE_WXMAP: + arg = enable ? PROC_WX_MAPPINGS_PERMIT : + PROC_WX_MAPPINGS_DISALLOW_EXEC; + error = procctl(P_PID, pid, PROC_WXMAP_CTL, &arg); + break; +#ifdef PROC_KPTI_CTL + case MODE_KPTI: + arg = enable ? PROC_KPTI_CTL_ENABLE_ON_EXEC : + PROC_KPTI_CTL_DISABLE_ON_EXEC; + error = procctl(P_PID, pid, PROC_KPTI_CTL, &arg); + break; +#endif +#ifdef PROC_LA_CTL + case MODE_LA57: + arg = enable ? PROC_LA_CTL_LA57_ON_EXEC : + PROC_LA_CTL_DEFAULT_ON_EXEC; + error = procctl(P_PID, pid, PROC_LA_CTL, &arg); + break; + case MODE_LA48: + arg = enable ? PROC_LA_CTL_LA48_ON_EXEC : + PROC_LA_CTL_DEFAULT_ON_EXEC; + error = procctl(P_PID, pid, PROC_LA_CTL, &arg); + break; +#endif + case MODE_LOGSIGEXIT: + arg = enable ? PROC_LOGSIGEXIT_CTL_FORCE_ENABLE : + PROC_LOGSIGEXIT_CTL_FORCE_DISABLE; + error = procctl(P_PID, pid, PROC_LOGSIGEXIT_CTL, &arg); + break; + default: + usage(); + break; + } + if (error != 0) + err(1, "procctl ctl"); + if (do_command) { + error = execvp(argv[0], argv); + err(1, "exec"); + } + } + exit(0); +} |