Commit faf2d88e authored by Mickaël Salaün's avatar Mickaël Salaün Committed by Kees Cook
Browse files

samples/check-exec: Add set-exec



Add a simple tool to set SECBIT_EXEC_RESTRICT_FILE or
SECBIT_EXEC_DENY_INTERACTIVE before executing a command.  This is useful
to easily test against enlighten script interpreters.

Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Christian Brauner <brauner@kernel.org>
Cc: Kees Cook <keescook@chromium.org>
Cc: Paul Moore <paul@paul-moore.com>
Cc: Serge Hallyn <serge@hallyn.com>
Signed-off-by: default avatarMickaël Salaün <mic@digikod.net>
Link: https://lore.kernel.org/r/20241212174223.389435-6-mic@digikod.net


Signed-off-by: default avatarKees Cook <kees@kernel.org>
parent 0e7f90f3
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -291,6 +291,13 @@ config SAMPLE_CGROUP
	help
	  Build samples that demonstrate the usage of the cgroup API.

config SAMPLE_CHECK_EXEC
	bool "Exec secure bits examples"
	depends on CC_CAN_LINK && HEADERS_INSTALL
	help
	  Build a tool to easily configure SECBIT_EXEC_RESTRICT_FILE and
	  SECBIT_EXEC_DENY_INTERACTIVE.

source "samples/rust/Kconfig"

endif # SAMPLES
+1 −0
Original line number Diff line number Diff line
@@ -3,6 +3,7 @@

subdir-$(CONFIG_SAMPLE_AUXDISPLAY)	+= auxdisplay
subdir-$(CONFIG_SAMPLE_ANDROID_BINDERFS) += binderfs
subdir-$(CONFIG_SAMPLE_CHECK_EXEC)	+= check-exec
subdir-$(CONFIG_SAMPLE_CGROUP) += cgroup
obj-$(CONFIG_SAMPLE_CONFIGFS)		+= configfs/
obj-$(CONFIG_SAMPLE_CONNECTOR)		+= connector/
+1 −0
Original line number Diff line number Diff line
/set-exec
+14 −0
Original line number Diff line number Diff line
# SPDX-License-Identifier: BSD-3-Clause

userprogs-always-y := \
	set-exec

userccflags += -I usr/include

.PHONY: all clean

all:
	$(MAKE) -C ../.. samples/check-exec/

clean:
	$(MAKE) -C ../.. M=samples/check-exec/ clean
+85 −0
Original line number Diff line number Diff line
// 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;
}