xref: /linux/samples/check-exec/set-exec.c (revision e814f3fd16acfb7f9966773953de8f740a1e3202)
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 
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 
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