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