1 // SPDX-License-Identifier: BSD-3-Clause
2 /*
3 * Simple tool to set SECBIT_EXEC_RESTRICT_FILE, SECBIT_EXEC_DENY_INTERACTIVE,
4 * before executing a command.
5 *
6 * Copyright © 2024 Microsoft Corporation
7 */
8
9 #define _GNU_SOURCE
10 #define __SANE_USERSPACE_TYPES__
11 #include <errno.h>
12 #include <linux/prctl.h>
13 #include <linux/securebits.h>
14 #include <stdbool.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <sys/prctl.h>
19 #include <unistd.h>
20
print_usage(const char * argv0)21 static void print_usage(const char *argv0)
22 {
23 fprintf(stderr, "usage: %s -f|-i -- <cmd> [args]...\n\n", argv0);
24 fprintf(stderr, "Execute a command with\n");
25 fprintf(stderr, "- SECBIT_EXEC_RESTRICT_FILE set: -f\n");
26 fprintf(stderr, "- SECBIT_EXEC_DENY_INTERACTIVE set: -i\n");
27 }
28
main(const int argc,char * const argv[],char * const * const envp)29 int main(const int argc, char *const argv[], char *const *const envp)
30 {
31 const char *cmd_path;
32 char *const *cmd_argv;
33 int opt, secbits_cur, secbits_new;
34 bool has_policy = false;
35
36 secbits_cur = prctl(PR_GET_SECUREBITS);
37 if (secbits_cur == -1) {
38 /*
39 * This should never happen, except with a buggy seccomp
40 * filter.
41 */
42 perror("ERROR: Failed to get securebits");
43 return 1;
44 }
45
46 secbits_new = secbits_cur;
47 while ((opt = getopt(argc, argv, "fi")) != -1) {
48 switch (opt) {
49 case 'f':
50 secbits_new |= SECBIT_EXEC_RESTRICT_FILE |
51 SECBIT_EXEC_RESTRICT_FILE_LOCKED;
52 has_policy = true;
53 break;
54 case 'i':
55 secbits_new |= SECBIT_EXEC_DENY_INTERACTIVE |
56 SECBIT_EXEC_DENY_INTERACTIVE_LOCKED;
57 has_policy = true;
58 break;
59 default:
60 print_usage(argv[0]);
61 return 1;
62 }
63 }
64
65 if (!argv[optind] || !has_policy) {
66 print_usage(argv[0]);
67 return 1;
68 }
69
70 if (secbits_cur != secbits_new &&
71 prctl(PR_SET_SECUREBITS, secbits_new)) {
72 perror("Failed to set secure bit(s).");
73 fprintf(stderr,
74 "Hint: The running kernel may not support this feature.\n");
75 return 1;
76 }
77
78 cmd_path = argv[optind];
79 cmd_argv = argv + optind;
80 fprintf(stderr, "Executing command...\n");
81 execvpe(cmd_path, cmd_argv, envp);
82 fprintf(stderr, "Failed to execute \"%s\": %s\n", cmd_path,
83 strerror(errno));
84 return 1;
85 }
86