| // SPDX-License-Identifier: BSD-3-Clause |
| /* |
| * Simple tool to set SECBIT_EXEC_RESTRICT_FILE, SECBIT_EXEC_DENY_INTERACTIVE, |
| * before executing a command. |
| * |
| * Copyright © 2024 Microsoft Corporation |
| */ |
| |
| #define _GNU_SOURCE |
| #define __SANE_USERSPACE_TYPES__ |
| #include <errno.h> |
| #include <linux/prctl.h> |
| #include <linux/securebits.h> |
| #include <stdbool.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <sys/prctl.h> |
| #include <unistd.h> |
| |
| static void print_usage(const char *argv0) |
| { |
| fprintf(stderr, "usage: %s -f|-i -- <cmd> [args]...\n\n", argv0); |
| fprintf(stderr, "Execute a command with\n"); |
| fprintf(stderr, "- SECBIT_EXEC_RESTRICT_FILE set: -f\n"); |
| fprintf(stderr, "- SECBIT_EXEC_DENY_INTERACTIVE set: -i\n"); |
| } |
| |
| int main(const int argc, char *const argv[], char *const *const envp) |
| { |
| const char *cmd_path; |
| char *const *cmd_argv; |
| int opt, secbits_cur, secbits_new; |
| bool has_policy = false; |
| |
| secbits_cur = prctl(PR_GET_SECUREBITS); |
| if (secbits_cur == -1) { |
| /* |
| * This should never happen, except with a buggy seccomp |
| * filter. |
| */ |
| perror("ERROR: Failed to get securebits"); |
| return 1; |
| } |
| |
| secbits_new = secbits_cur; |
| while ((opt = getopt(argc, argv, "fi")) != -1) { |
| switch (opt) { |
| case 'f': |
| secbits_new |= SECBIT_EXEC_RESTRICT_FILE | |
| SECBIT_EXEC_RESTRICT_FILE_LOCKED; |
| has_policy = true; |
| break; |
| case 'i': |
| secbits_new |= SECBIT_EXEC_DENY_INTERACTIVE | |
| SECBIT_EXEC_DENY_INTERACTIVE_LOCKED; |
| has_policy = true; |
| break; |
| default: |
| print_usage(argv[0]); |
| return 1; |
| } |
| } |
| |
| if (!argv[optind] || !has_policy) { |
| print_usage(argv[0]); |
| return 1; |
| } |
| |
| if (secbits_cur != secbits_new && |
| prctl(PR_SET_SECUREBITS, secbits_new)) { |
| perror("Failed to set secure bit(s)."); |
| fprintf(stderr, |
| "Hint: The running kernel may not support this feature.\n"); |
| return 1; |
| } |
| |
| cmd_path = argv[optind]; |
| cmd_argv = argv + optind; |
| fprintf(stderr, "Executing command...\n"); |
| execvpe(cmd_path, cmd_argv, envp); |
| fprintf(stderr, "Failed to execute \"%s\": %s\n", cmd_path, |
| strerror(errno)); |
| return 1; |
| } |