From: Petr Tesarik <[email protected]>
Introduce SandBox Mode (SBM) core infrastructure and make the feature
configurable at build time with CONFIG_SANDBOX_MODE.
Provide an API to execute a function in a sandbox. This target function
runs in an address space that is similar to but distinct from the caller's
address space. This is why the target function cannot be called directly.
Instead, it is called via sbm_exec(), which takes the target function as a
parameter and executes it inside the sandbox.
All target functions take one void parameter and return an integer which
can be interpreted as error status (zero is success, negative is error).
Store sandbox parameters and state in struct sbm, and define these
operations on it:
* sbm_init() - set up a sandbox
* sbm_destroy() - clean up sandbox resources
* sbm_error() - query error status
* sbm_exec() - execute code in sandbox
Allow to defer error checking until after the last operation. When a SBM
operation fails, set an error value in struct sbm and make it stick, that
is fail all subsequent operations and return this error instead. The error
value can be explicitly retrieved with sbm_error(), but simple use cases
can get by with the return value of sbm_exec() alone.
Also declare these arch hooks:
* arch_sbm_init() - arch-specific setup
* arch_sbm_destroy() - arch-specific cleanup
* arch_sbm_exec() - arch-specific code execution
These hooks are required to provide strong isolation. The availability of
arch hooks is indicated by CONFIG_HAVE_ARCH_SBM. Initially, no architecture
provides SBM arch hooks, falling back to a trivial no-op implementation.
Signed-off-by: Petr Tesarik <[email protected]>
---
include/linux/sbm.h | 154 ++++++++++++++++++++++++++++++++++++++++++++
init/Kconfig | 2 +
kernel/Kconfig.sbm | 31 +++++++++
kernel/Makefile | 1 +
kernel/sbm.c | 45 +++++++++++++
5 files changed, 233 insertions(+)
create mode 100644 include/linux/sbm.h
create mode 100644 kernel/Kconfig.sbm
create mode 100644 kernel/sbm.c
diff --git a/include/linux/sbm.h b/include/linux/sbm.h
new file mode 100644
index 000000000000..8e0c63fb9fb2
--- /dev/null
+++ b/include/linux/sbm.h
@@ -0,0 +1,154 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2023-2024 Huawei Technologies Duesseldorf GmbH
+ *
+ * Author: Petr Tesarik <[email protected]>
+ *
+ * SandBox Mode (SBM) public API declarations.
+ */
+#ifndef __LINUX_SBM_H
+#define __LINUX_SBM_H
+
+/**
+ * struct sbm - SandBox Mode instance.
+ * @error: Error code. Initialized to zero by sbm_init() and updated when
+ * a SBM operation fails.
+ * @private: Arch-specific private data.
+ */
+struct sbm {
+#ifdef CONFIG_SANDBOX_MODE
+ int error;
+ void *private;
+#endif
+};
+
+/**
+ * typedef sbm_func - Sandbox mode function pointer.
+ * @data: Arbitrary data passed via sbm_exec().
+ *
+ * Return: Zero on success, negative on error.
+ */
+typedef int (*sbm_func)(void *data);
+
+#ifdef CONFIG_SANDBOX_MODE
+
+/**
+ * sbm_init() - Initialize a SandBox Mode instance.
+ * @sbm: SBM instance.
+ *
+ * Initialize a SBM instance structure.
+ *
+ * Return: Zero on success, negative on error.
+ */
+int sbm_init(struct sbm *sbm);
+
+/**
+ * sbm_destroy() - Clean up a SandBox Mode instance.
+ * @sbm: SBM instance to be cleaned up.
+ */
+void sbm_destroy(struct sbm *sbm);
+
+/**
+ * sbm_error() - Get SBM error status.
+ * @sbm: SBM instance.
+ *
+ * Get the SBM error code. This can be used to distinguish between
+ * errors returned by the target function and errors from setting
+ * up the sandbox environment.
+ */
+static inline int sbm_error(const struct sbm *sbm)
+{
+ return sbm->error;
+}
+
+/**
+ * sbm_exec() - Execute function in a sandbox.
+ * @sbm: SBM instance.
+ * @func: Function to be called.
+ * @data: Argument for @func.
+ *
+ * Execute @func in a fully prepared SBM instance.
+ *
+ * Return: Return value of @func on success, or a negative error code.
+ */
+int sbm_exec(struct sbm *sbm, sbm_func func, void *data);
+
+#ifdef CONFIG_HAVE_ARCH_SBM
+
+/**
+ * arch_sbm_init() - Arch hook to initialize a SBM instance.
+ * @sbm: Instance to be initialized.
+ *
+ * Perform any arch-specific initialization. This hook is called by sbm_init()
+ * immediately after zeroing out @sbm.
+ *
+ * Return: Zero on success, negative error code on failure.
+ */
+int arch_sbm_init(struct sbm *sbm);
+
+/**
+ * arch_sbm_destroy() - Arch hook to clean up a SBM instance.
+ * @sbm: Instance to be cleaned up.
+ *
+ * Perform any arch-specific cleanup. This hook is called by sbm_destroy() as
+ * the very last operation on @sbm.
+ */
+void arch_sbm_destroy(struct sbm *sbm);
+
+/**
+ * arch_sbm_exec() - Arch hook to execute code in a sandbox.
+ * @sbm: SBM instance.
+ * @func: Function to be executed in a sandbox.
+ * @data: Argument passed to @func.
+ *
+ * Execute @func in a fully prepared SBM instance. If sandbox mode
+ * cannot be set up or is aborted, set &sbm->error to a negative error
+ * value. This error is then returned by sbm_exec(), overriding the
+ * return value of arch_sbm_exec().
+ *
+ * Return: Return value of @func.
+ */
+int arch_sbm_exec(struct sbm *sbm, sbm_func func, void *data);
+
+#else /* !CONFIG_HAVE_ARCH_SBM */
+
+static inline int arch_sbm_init(struct sbm *sbm)
+{
+ return 0;
+}
+
+static inline void arch_sbm_destroy(struct sbm *sbm)
+{
+}
+
+static inline int arch_sbm_exec(struct sbm *sbm, sbm_func func, void *data)
+{
+ return func(data);
+}
+
+#endif /* CONFIG_HAVE_ARCH_SBM */
+
+#else /* !CONFIG_SANDBOX_MODE */
+
+static inline int sbm_init(struct sbm *sbm)
+{
+ return 0;
+}
+
+static inline void sbm_destroy(struct sbm *sbm)
+{
+}
+
+static inline int sbm_error(const struct sbm *sbm)
+{
+ return 0;
+}
+
+static inline int sbm_exec(struct sbm *sbm, sbm_func func, void *data)
+{
+ return func(data);
+}
+
+#endif /* CONFIG_SANDBOX_MODE */
+
+#endif /* __LINUX_SBM_H */
diff --git a/init/Kconfig b/init/Kconfig
index 8d4e836e1b6b..253ac8c45527 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -1932,6 +1932,8 @@ config TRACEPOINTS
source "kernel/Kconfig.kexec"
+source "kernel/Kconfig.sbm"
+
endmenu # General setup
source "arch/Kconfig"
diff --git a/kernel/Kconfig.sbm b/kernel/Kconfig.sbm
new file mode 100644
index 000000000000..64d683cefd4d
--- /dev/null
+++ b/kernel/Kconfig.sbm
@@ -0,0 +1,31 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Copyright (C) 2023-2024 Huawei Technologies Duesseldorf GmbH
+#
+# Author: Petr Tesarik <[email protected]>
+#
+# SandBox Mode (SBM) config options.
+#
+
+config HAVE_ARCH_SBM
+ def_bool n
+
+config SANDBOX_MODE
+ bool "SandBox Mode (SBM)"
+ default n
+ help
+ SandBox Mode provides kernel API to run native kernel functions in a
+ sandbox, preventing out-of-bounds memory accesses. On targets which
+ implement SBM arch hooks, the isolation is strong, preventing all
+ memory accesses outside the sandbox; after a protection violation,
+ the affected kernel thread can continue running. On all other
+ targets, the isolation is weak, preventing only buffer overflows
+ within a guard page; after a violation, the kernel thread usually
+ terminates.
+
+ This is an opt-in self-defense mechanism, i.e. kernel source code
+ must be modified to run in SandBox Mode. For such code, there is
+ some run-time overhead (CPU time, memory) associated with entering
+ and leaving the sandbox.
+
+ If unsure, say N.
diff --git a/kernel/Makefile b/kernel/Makefile
index ce105a5558fc..ecc4bfd6213f 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -115,6 +115,7 @@ obj-$(CONFIG_HAVE_STATIC_CALL) += static_call.o
obj-$(CONFIG_HAVE_STATIC_CALL_INLINE) += static_call_inline.o
obj-$(CONFIG_CFI_CLANG) += cfi.o
obj-$(CONFIG_NUMA) += numa.o
+obj-$(CONFIG_SANDBOX_MODE) += sbm.o
obj-$(CONFIG_PERF_EVENTS) += events/
diff --git a/kernel/sbm.c b/kernel/sbm.c
new file mode 100644
index 000000000000..9a5b89a71a23
--- /dev/null
+++ b/kernel/sbm.c
@@ -0,0 +1,45 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023-2024 Huawei Technologies Duesseldorf GmbH
+ *
+ * Author: Petr Tesarik <[email protected]>
+ *
+ * SandBox Mode (SBM) public API and generic functions.
+ */
+
+#include <linux/export.h>
+#include <linux/sbm.h>
+#include <linux/string.h>
+
+int sbm_init(struct sbm *sbm)
+{
+ memset(sbm, 0, sizeof(*sbm));
+
+ sbm->error = arch_sbm_init(sbm);
+ if (sbm->error)
+ return sbm->error;
+
+ return 0;
+}
+EXPORT_SYMBOL(sbm_init);
+
+void sbm_destroy(struct sbm *sbm)
+{
+ arch_sbm_destroy(sbm);
+}
+EXPORT_SYMBOL(sbm_destroy);
+
+int sbm_exec(struct sbm *sbm, sbm_func func, void *args)
+{
+ int ret;
+
+ if (sbm->error)
+ return sbm->error;
+
+ ret = arch_sbm_exec(sbm, func, args);
+ if (sbm->error)
+ return sbm->error;
+
+ return ret;
+}
+EXPORT_SYMBOL(sbm_exec);
--
2.34.1