* [PATCH v2 00/24] Add security policy support
@ 2025-09-17 13:53 Sascha Hauer
2025-09-17 13:53 ` [PATCH v2 01/24] kconfig: allow setting CONFIG_ from the outside Sascha Hauer
` (25 more replies)
0 siblings, 26 replies; 31+ messages in thread
From: Sascha Hauer @ 2025-09-17 13:53 UTC (permalink / raw)
To: BAREBOX; +Cc: Ahmad Fatoum, Ahmad Fatoum
Security policies are a mechanism for barebox to prevent, when so
desired, security relevant code from being executed.
Security policies are controlled via a second Kconfig menu structure
(called Sconfig) which collects security relevant options.
While the normal Kconfig menu structure is about feature support
enabled at compile time, a security policy determines whether a
feature is allowed or prohibited at runtime with an explicit focus
on security.
Except for a security policy's name, all security options are
boolean and control whether a built-in feature is allowed:
config FASTBOOT_CMD_BASE
bool
prompt "Allow fastboot flash/erase commands"
depends on $(kconfig-enabled,FASTBOOT_BASE)
help
This option enables the fastboot "flash" and "erase" commands.
The depends directive ensures the option is hidden when Fastboot support
isn't compiled in anyway. Otherwise, enabling the option should permit
normal operation as if the security policy support was disabled.
Disabling the option, will have the relevant functions return early,
often with a permission denied error.
Checking the state of a security config option is done with the
IS_ALLOWED macro. The macro evaluates to true if the option is
defined and enabled in the active security policy and false otherwise.
A partial manipulation of the active security policy is not desirable
as it makes security posture at runtime harder to reason about.
It's expected that boards will define a fixed set of policies,
e.g. devel, factory, lockdown and then consult eFuses or JSON web tokens
to determine which policy is to be applied.
Some precautions have been made to make sure the security policies have
been reviewed and changes to the security options do not go through
unnoticed during barebox updates: Automatic config updates are
prohibited, so if new options are not present or the other way round,
the build will just fail. The user is expected to run e.g.
make security_olddefconfig to explicitly sync the configuration and
commit the changes.
Changes in v2:
- drop security policies for each filesystem. This needs to be reworked.
A filesystem can safely be mounted when the source is trusted (i.e.
the fs image is compiled into barebox, or is authorized using upcoming
dm-verity support) no matter which filesystem type is mounted.
Therefore just add a policy which selects between "all fs allowed" and
"no fs allowed except ramfs".
- fix adding policy-y to non leaf directories
- remove policy-list files before recreating them to avoid stale entries
- Drop $(ARCH) string from .sconfig files
- bail out with a user friendly message when make security_* is invoked
with security policies being disabled in the config
- document that policies should always go from restrictive to relaxed,
not the other way round
- Link to v1: https://lore.barebox.org/20250820-security-policies-v1-0-76fde70fdbd8@pengutronix.de
Changes in v1:
- Link to RFC:
https://lore.kernel.org/all/20250814130702.4039241-1-a.fatoum@pengutronix.de/
- Add more actual security policies
- Fix some typos in Documentation
- Catch invalid policy names in sconfig command
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
Ahmad Fatoum (16):
kconfig: allow setting CONFIG_ from the outside
scripts: include scripts/include for all host tools
kbuild: implement loopable loop_cmd
Add security policy support
kbuild: allow security config use without source tree modification
defaultenv: update PS1 according to security policy
security: policy: support externally provided configs
docs: security-policies: add documentation
commands: go: add security config option
console: ratp: add security config option
bootm: support calling bootm_optional_signed_images at any time
bootm: make unsigned image support runtime configurable
ARM: configs: add virt32_secure_defconfig
boards: qemu-virt: add security policies
boards: qemu-virt: allow setting policy from command line
test: py: add basic security policy test
Sascha Hauer (8):
commands: implement sconfig command
usbserial: add inline wrappers
security: usbgadget: add usbgadget security policy
security: fastboot: add security policy for fastboot oem
security: shell: add policy for executing the shell
security: add security policy for loading barebox environment
security: add filesystem security policies
security: console: add security policy for console input
.gitignore | 4 +
Documentation/devel/devel.rst | 1 +
Documentation/devel/security-policies.rst | 96 ++++
Documentation/user/defaultenv-2.rst | 2 +
Documentation/user/security-policies.rst | 131 +++++
Documentation/user/user-manual.rst | 1 +
Makefile | 95 +++-
Sconfig | 11 +
arch/arm/configs/virt32_secure_defconfig | 302 ++++++++++++
commands/Kconfig | 23 +
commands/Makefile | 1 +
commands/Sconfig | 12 +
commands/go.c | 4 +
commands/sconfig.c | 227 +++++++++
common/Kconfig | 5 +
common/Sconfig | 63 +++
common/boards/qemu-virt/Makefile | 5 +-
common/boards/qemu-virt/board.c | 11 +
common/boards/qemu-virt/commandline.c | 74 +++
common/boards/qemu-virt/commandline.h | 9 +
common/boards/qemu-virt/qemu-virt-factory.sconfig | 36 ++
common/boards/qemu-virt/qemu-virt-lockdown.sconfig | 35 ++
common/bootm.c | 58 ++-
common/console.c | 11 +-
common/console_ctrlc.c | 4 +
common/console_simple.c | 7 +
common/environment.c | 6 +
common/fastboot.c | 6 +
common/hush.c | 13 +
common/parser.c | 7 +
common/ratp/ratp.c | 17 +
common/usbgadget.c | 26 +
defaultenv/Makefile | 1 +
.../defaultenv-2-security-policy/bin/ps1-policy | 20 +
.../defaultenv-2-security-policy/init/ps1-policy | 1 +
.../init/source-colors | 1 +
defaultenv/defaultenv.c | 2 +
drivers/usb/gadget/Sconfig | 11 +
drivers/usb/gadget/composite.c | 4 +
drivers/usb/gadget/legacy/serial.c | 4 +
fs/Sconfig | 5 +
fs/fs.c | 4 +
include/linux/usb/usbserial.h | 11 +
include/security/config.h | 76 +++
include/security/defs.h | 22 +
include/security/policy.h | 54 +++
scripts/Kbuild.include | 41 ++
scripts/Makefile | 1 -
scripts/Makefile.build | 18 +-
scripts/Makefile.lib | 47 ++
scripts/Makefile.policy | 38 ++
scripts/Sconfig.include | 6 +
scripts/basic/.gitignore | 1 +
scripts/basic/Makefile | 4 +-
scripts/basic/sconfigpost.c | 540 +++++++++++++++++++++
scripts/include/list.h | 7 +
scripts/kconfig/Makefile | 3 +
scripts/kconfig/list.h | 132 -----
security/Kconfig | 2 +
security/Kconfig.policy | 104 ++++
security/Makefile | 39 ++
security/Sconfig | 34 ++
security/policy.c | 239 +++++++++
security/qemu-virt-devel.sconfig | 36 ++
security/qemu-virt-tamper.sconfig | 35 ++
security/sconfig_names.c | 18 +
test/arm/virt32_secure_defconfig.yaml | 22 +
test/py/test_policies.py | 48 ++
68 files changed, 2778 insertions(+), 156 deletions(-)
---
base-commit: f3be3a8e9ae884bdfb116238e9049b1eb2759810
change-id: 20250820-security-policies-43f73477d321
Best regards,
--
Sascha Hauer <s.hauer@pengutronix.de>
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH v2 01/24] kconfig: allow setting CONFIG_ from the outside
2025-09-17 13:53 [PATCH v2 00/24] Add security policy support Sascha Hauer
@ 2025-09-17 13:53 ` Sascha Hauer
2025-09-17 13:53 ` [PATCH v2 02/24] scripts: include scripts/include for all host tools Sascha Hauer
` (24 subsequent siblings)
25 siblings, 0 replies; 31+ messages in thread
From: Sascha Hauer @ 2025-09-17 13:53 UTC (permalink / raw)
To: BAREBOX; +Cc: Ahmad Fatoum
From: Ahmad Fatoum <a.fatoum@pengutronix.de>
Regular config options apply build-wide. Security config options will
be enabled depending on the policy that's currently active.
To allow using an SCONFIG_ prefix for the latter, introduce
KCONFIG_CONFIG_ to affect this.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
scripts/kconfig/Makefile | 3 +++
1 file changed, 3 insertions(+)
diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile
index 5a215880b2688c2ffadd3248410ee29cf19c510c..c4dbdf9abfc7262ec75163a11be432dedbaedfeb 100644
--- a/scripts/kconfig/Makefile
+++ b/scripts/kconfig/Makefile
@@ -29,6 +29,9 @@ KCONFIG_DEFCONFIG_LIST += arch/$(SRCARCH)/configs/$(KBUILD_DEFCONFIG)
# We need this, in case the user has it in its environment
unexport CONFIG_
+ifdef KCONFIG_CONFIG_
+export CONFIG_=$(KCONFIG_CONFIG_)
+endif
config-prog := conf
menuconfig-prog := mconf
--
2.47.3
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH v2 02/24] scripts: include scripts/include for all host tools
2025-09-17 13:53 [PATCH v2 00/24] Add security policy support Sascha Hauer
2025-09-17 13:53 ` [PATCH v2 01/24] kconfig: allow setting CONFIG_ from the outside Sascha Hauer
@ 2025-09-17 13:53 ` Sascha Hauer
2025-09-17 13:53 ` [PATCH v2 03/24] kbuild: implement loopable loop_cmd Sascha Hauer
` (23 subsequent siblings)
25 siblings, 0 replies; 31+ messages in thread
From: Sascha Hauer @ 2025-09-17 13:53 UTC (permalink / raw)
To: BAREBOX; +Cc: Ahmad Fatoum
From: Ahmad Fatoum <a.fatoum@pengutronix.de>
We already have one implementation of list.h, so we do not need to
replicate it of Kconfig specially. Make use of scripts/include for all
host tools to align us with what Linux is doing.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
Makefile | 6 ++-
scripts/Makefile | 1 -
scripts/basic/Makefile | 2 -
scripts/include/list.h | 7 +++
scripts/kconfig/list.h | 132 -------------------------------------------------
5 files changed, 11 insertions(+), 137 deletions(-)
diff --git a/Makefile b/Makefile
index 169b750fe15199913e3169529cdbfa3d47febf69..19d860db1208c9e3a1ac196dcf1cfad38379288a 100644
--- a/Makefile
+++ b/Makefile
@@ -410,8 +410,10 @@ KBUILD_USERHOSTCFLAGS := -Wall -Wmissing-prototypes -Wstrict-prototypes \
KBUILD_USERCFLAGS := $(KBUILD_USERHOSTCFLAGS) $(USERCFLAGS)
KBUILD_USERLDFLAGS := $(USERLDFLAGS)
-KBUILD_HOSTCFLAGS := $(KBUILD_USERHOSTCFLAGS) $(HOST_LFS_CFLAGS) $(HOSTCFLAGS)
-KBUILD_HOSTCXXFLAGS := -Wall -O2 $(HOST_LFS_CFLAGS) $(HOSTCXXFLAGS)
+KBUILD_HOSTCFLAGS := $(KBUILD_USERHOSTCFLAGS) $(HOST_LFS_CFLAGS) \
+ $(HOSTCFLAGS) -I $(srctree)/scripts/include
+KBUILD_HOSTCXXFLAGS := -Wall -O2 $(HOST_LFS_CFLAGS) $(HOSTCXXFLAGS) \
+ -I $(srctree)/scripts/include
KBUILD_HOSTLDFLAGS := $(HOST_LFS_LDFLAGS) $(HOSTLDFLAGS)
KBUILD_HOSTLDLIBS := $(HOST_LFS_LIBS) $(HOSTLDLIBS)
diff --git a/scripts/Makefile b/scripts/Makefile
index 85e0815445537fee8593515f6b892ed761154ed2..7d6bc5a8ab9798dfaf6583d5d09ae63aa98f43ac 100644
--- a/scripts/Makefile
+++ b/scripts/Makefile
@@ -29,7 +29,6 @@ hostprogs-always-$(CONFIG_RISCV) += prelink-riscv
hostprogs-always-$(CONFIG_RK_IMAGE) += rkimage
HOSTCFLAGS_rkimage.o = `$(PKG_CONFIG) --cflags openssl`
HOSTLDLIBS_rkimage = `$(PKG_CONFIG) --libs openssl`
-KBUILD_HOSTCFLAGS += -I$(srctree)/scripts/include/
HOSTCFLAGS_mxsimage.o = `$(PKG_CONFIG) --cflags openssl`
HOSTLDLIBS_mxsimage = `$(PKG_CONFIG) --libs openssl`
HOSTCFLAGS_omap3-usb-loader.o = `$(PKG_CONFIG) --cflags libusb-1.0`
diff --git a/scripts/basic/Makefile b/scripts/basic/Makefile
index e48754e29924117ec6b2f159cfdf8e76ef77fa29..eeb6a38c5551516bc3b1539e5f236ff952fea394 100644
--- a/scripts/basic/Makefile
+++ b/scripts/basic/Makefile
@@ -3,5 +3,3 @@
# fixdep: used to generate dependency information during build process
hostprogs-always-y += fixdep
-
-KBUILD_HOSTCFLAGS += -I$(srctree)/scripts/include/
diff --git a/scripts/include/list.h b/scripts/include/list.h
new file mode 100644
index 0000000000000000000000000000000000000000..ced30b635f95c7bbf2e123ddeb1a093099ce9650
--- /dev/null
+++ b/scripts/include/list.h
@@ -0,0 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef LIST_H
+#define LIST_H
+
+#include "linux/list.h"
+
+#endif
diff --git a/scripts/kconfig/list.h b/scripts/kconfig/list.h
deleted file mode 100644
index 45cb237ab7ef7a9f17779647220da6a30afd06fc..0000000000000000000000000000000000000000
--- a/scripts/kconfig/list.h
+++ /dev/null
@@ -1,132 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef LIST_H
-#define LIST_H
-
-/*
- * Copied from include/linux/...
- */
-
-#undef offsetof
-#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
-
-/**
- * container_of - cast a member of a structure out to the containing structure
- * @ptr: the pointer to the member.
- * @type: the type of the container struct this is embedded in.
- * @member: the name of the member within the struct.
- *
- */
-#define container_of(ptr, type, member) ({ \
- const typeof( ((type *)0)->member ) *__mptr = (ptr); \
- (type *)( (char *)__mptr - offsetof(type,member) );})
-
-
-struct list_head {
- struct list_head *next, *prev;
-};
-
-
-#define LIST_HEAD_INIT(name) { &(name), &(name) }
-
-#define LIST_HEAD(name) \
- struct list_head name = LIST_HEAD_INIT(name)
-
-/**
- * list_entry - get the struct for this entry
- * @ptr: the &struct list_head pointer.
- * @type: the type of the struct this is embedded in.
- * @member: the name of the list_head within the struct.
- */
-#define list_entry(ptr, type, member) \
- container_of(ptr, type, member)
-
-/**
- * list_for_each_entry - iterate over list of given type
- * @pos: the type * to use as a loop cursor.
- * @head: the head for your list.
- * @member: the name of the list_head within the struct.
- */
-#define list_for_each_entry(pos, head, member) \
- for (pos = list_entry((head)->next, typeof(*pos), member); \
- &pos->member != (head); \
- pos = list_entry(pos->member.next, typeof(*pos), member))
-
-/**
- * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
- * @pos: the type * to use as a loop cursor.
- * @n: another type * to use as temporary storage
- * @head: the head for your list.
- * @member: the name of the list_head within the struct.
- */
-#define list_for_each_entry_safe(pos, n, head, member) \
- for (pos = list_entry((head)->next, typeof(*pos), member), \
- n = list_entry(pos->member.next, typeof(*pos), member); \
- &pos->member != (head); \
- pos = n, n = list_entry(n->member.next, typeof(*n), member))
-
-/**
- * list_empty - tests whether a list is empty
- * @head: the list to test.
- */
-static inline int list_empty(const struct list_head *head)
-{
- return head->next == head;
-}
-
-/*
- * Insert a new entry between two known consecutive entries.
- *
- * This is only for internal list manipulation where we know
- * the prev/next entries already!
- */
-static inline void __list_add(struct list_head *_new,
- struct list_head *prev,
- struct list_head *next)
-{
- next->prev = _new;
- _new->next = next;
- _new->prev = prev;
- prev->next = _new;
-}
-
-/**
- * list_add_tail - add a new entry
- * @new: new entry to be added
- * @head: list head to add it before
- *
- * Insert a new entry before the specified head.
- * This is useful for implementing queues.
- */
-static inline void list_add_tail(struct list_head *_new, struct list_head *head)
-{
- __list_add(_new, head->prev, head);
-}
-
-/*
- * Delete a list entry by making the prev/next entries
- * point to each other.
- *
- * This is only for internal list manipulation where we know
- * the prev/next entries already!
- */
-static inline void __list_del(struct list_head *prev, struct list_head *next)
-{
- next->prev = prev;
- prev->next = next;
-}
-
-#define LIST_POISON1 ((void *) 0x00100100)
-#define LIST_POISON2 ((void *) 0x00200200)
-/**
- * list_del - deletes entry from list.
- * @entry: the element to delete from the list.
- * Note: list_empty() on entry does not return true after this, the entry is
- * in an undefined state.
- */
-static inline void list_del(struct list_head *entry)
-{
- __list_del(entry->prev, entry->next);
- entry->next = (struct list_head*)LIST_POISON1;
- entry->prev = (struct list_head*)LIST_POISON2;
-}
-#endif
--
2.47.3
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH v2 03/24] kbuild: implement loopable loop_cmd
2025-09-17 13:53 [PATCH v2 00/24] Add security policy support Sascha Hauer
2025-09-17 13:53 ` [PATCH v2 01/24] kconfig: allow setting CONFIG_ from the outside Sascha Hauer
2025-09-17 13:53 ` [PATCH v2 02/24] scripts: include scripts/include for all host tools Sascha Hauer
@ 2025-09-17 13:53 ` Sascha Hauer
2025-09-17 13:53 ` [PATCH v2 04/24] Add security policy support Sascha Hauer
` (22 subsequent siblings)
25 siblings, 0 replies; 31+ messages in thread
From: Sascha Hauer @ 2025-09-17 13:53 UTC (permalink / raw)
To: BAREBOX; +Cc: Ahmad Fatoum
From: Ahmad Fatoum <a.fatoum@pengutronix.de>
The normal cmd can not be used in foreach, because it's prefixed by @.
Add an optional loopable variant as well as a noop_cmd that's suitable
for use in nesten $(call ...) invocations that would otherwise lead to
Make aborting due to perceived cycles in log_print.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
scripts/Kbuild.include | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include
index e905b54663713beae56b46e4c91079fab9d06c66..a23d27cba315f51082fcf38d6b3e011a541fabd1 100644
--- a/scripts/Kbuild.include
+++ b/scripts/Kbuild.include
@@ -158,6 +158,12 @@ delete-on-interrupt = \
# print and execute commands
cmd = @$(if $(cmd_$(1)),set -e; $($(quiet)log_print) $(delete-on-interrupt) $(cmd_$(1)),:)
+# The normal 'cmd' above is not *loopable*
+loop_cmd = $(if $(cmd_$(1)),set -e; $($(quiet)log_print) $(cmd_$(1)),:) || exit;
+
+# Like loop_cmd, but without printing
+noop_cmd = $(if $(cmd_$(1)),$(cmd_$(1)),:)
+
###
# if_changed - execute command if any prerequisite is newer than
# target, or command line has changed
--
2.47.3
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH v2 04/24] Add security policy support
2025-09-17 13:53 [PATCH v2 00/24] Add security policy support Sascha Hauer
` (2 preceding siblings ...)
2025-09-17 13:53 ` [PATCH v2 03/24] kbuild: implement loopable loop_cmd Sascha Hauer
@ 2025-09-17 13:53 ` Sascha Hauer
2025-09-22 16:14 ` Ahmad Fatoum
2025-09-17 13:53 ` [PATCH v2 05/24] kbuild: allow security config use without source tree modification Sascha Hauer
` (21 subsequent siblings)
25 siblings, 1 reply; 31+ messages in thread
From: Sascha Hauer @ 2025-09-17 13:53 UTC (permalink / raw)
To: BAREBOX; +Cc: Ahmad Fatoum, Ahmad Fatoum
From: Ahmad Fatoum <a.fatoum@barebox.org>
Security policies are a mechanism for barebox to prevent, when so
desired, security relevant code from being executed.
Security policies are controlled via a second Kconfig menu structure
(called Sconfig) which collects security relevant options.
While the normal Kconfig menu structure is about feature support
enabled at compile time, a security policy determines whether a
feature is allowed or prohibited at runtime with an explicit focus
on security.
Except for a security policy's name, all security options are
boolean and control whether a built-in feature is allowed:
config FASTBOOT_CMD_BASE
bool
prompt "Allow fastboot flash/erase commands"
depends on $(kconfig-enabled,FASTBOOT_BASE)
help
This option enables the fastboot "flash" and "erase" commands.
The depends directive ensures the option is hidden when Fastboot support
isn't compiled in anyway. Otherwise, enabling the option should permit
normal operation as if the security policy support was disabled.
Disabling the option, will have the relevant functions return early,
often with a permission denied error.
Checking the state of a security config option is done with the
IS_ALLOWED macro. The macro evaluates to true if the option is
defined and enabled in the active security policy and false otherwise.
A partial manipulation of the active security policy is not desirable
as it makes security posture at runtime harder to reason about.
It's expected that boards will define a fixed set of policies,
e.g. devel, factory, lockdown and then consult eFuses or JSON web tokens
to determine which policy is to be applied.
Some precautions have been made to make sure the security policies have
been reviewed and changes to the security options do not go through
unnoticed during barebox updates: Automatic config updates are
prohibited, so if new options are not present or the other way round,
the build will just fail. The user is expected to run e.g.
make security_olddefconfig to explicitly sync the configuration and
commit the changes.
Co-developed-by: Sascha Hauer <s.hauer@pengutronix.de>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
.gitignore | 4 +
Makefile | 85 ++++++-
Sconfig | 7 +
include/security/config.h | 76 +++++++
include/security/defs.h | 22 ++
include/security/policy.h | 50 ++++
scripts/Kbuild.include | 35 +++
scripts/Makefile.build | 18 +-
scripts/Makefile.lib | 47 ++++
scripts/Makefile.policy | 34 +++
scripts/Sconfig.include | 6 +
scripts/basic/.gitignore | 1 +
scripts/basic/Makefile | 2 +
scripts/basic/sconfigpost.c | 540 ++++++++++++++++++++++++++++++++++++++++++++
security/Kconfig | 2 +
security/Kconfig.policy | 89 ++++++++
security/Makefile | 2 +
security/Sconfig | 34 +++
security/policy.c | 236 +++++++++++++++++++
security/sconfig_names.c | 18 ++
20 files changed, 1302 insertions(+), 6 deletions(-)
diff --git a/.gitignore b/.gitignore
index c37188a9f31519863dd121f31676c1c1b03ca253..98bb4dac891272cfa26a4a3d880fe13ece1a9be1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -30,6 +30,9 @@
*.patch
*.pyc
*.s
+*.sconfig.c
+*.sconfig.old
+*.sconfig.tmp
*.so
*.so.dbg
*.symtypes
@@ -37,6 +40,7 @@
binary.0
Module.symvers
dtbs-list
+policy-list
*.dtb
*.dtb.*
*.dtbo
diff --git a/Makefile b/Makefile
index 19d860db1208c9e3a1ac196dcf1cfad38379288a..5f1e6ab21ce0ca8f612e129aacffd45123421498 100644
--- a/Makefile
+++ b/Makefile
@@ -278,7 +278,7 @@ ifneq ($(KBUILD_EXTMOD),)
endif
ifeq ($(KBUILD_EXTMOD),)
- ifneq ($(filter config %config,$(MAKECMDGOALS)),)
+ ifneq ($(filter config %config,$(filter-out security_%config,$(MAKECMDGOALS))),)
config-build := 1
ifneq ($(words $(MAKECMDGOALS)),1)
mixed-build := 1
@@ -450,6 +450,7 @@ AWK = awk
GENKSYMS = scripts/genksyms/genksyms
DEPMOD = /sbin/depmod
KALLSYMS = scripts/kallsyms
+SCONFIGPOST = scripts/basic/sconfigpost
PERL = perl
PYTHON3 = python3
CHECK = sparse
@@ -524,7 +525,7 @@ LDFLAGS_elf += $(LDFLAGS_common) --nmagic -s
export ARCH SRCARCH CONFIG_SHELL BASH HOSTCC KBUILD_HOSTCFLAGS CROSS_COMPILE LD CC CXX
export CPP AR NM STRIP OBJCOPY OBJDUMP MAKE AWK GENKSYMS PERL PYTHON3 UTS_MACHINE
export LEX YACC PROFDATA COV GENHTML
-export HOSTCXX CHECK CHECKFLAGS MKIMAGE
+export HOSTCXX CHECK CHECKFLAGS MKIMAGE SCONFIGPOST
export KGZIP KBZIP2 KLZOP LZMA LZ4 XZ
export KBUILD_HOSTCXXFLAGS KBUILD_HOSTLDFLAGS KBUILD_HOSTLDLIBS LDFLAGS_MODULE
export KBUILD_USERCFLAGS KBUILD_USERLDFLAGS
@@ -601,6 +602,8 @@ ifdef config-build
# *config targets only - make sure prerequisites are updated, and descend
# in scripts/kconfig to make the *config target
+# KCONFIG_CONFIG_ORIG is only set for policy kconfig processing
+ifndef KCONFIG_CONFIG_ORIG
include $(srctree)/scripts/Makefile.defconf
# Read arch specific Makefile to set KBUILD_DEFCONFIG as needed.
@@ -608,6 +611,7 @@ include $(srctree)/scripts/Makefile.defconf
# used for 'make defconfig'
include $(srctree)/arch/$(SRCARCH)/Makefile
export KBUILD_DEFCONFIG CC_VERSION_TEXT
+endif
config: outputmakefile scripts_basic FORCE
$(Q)$(MAKE) $(build)=scripts/kconfig KCONFIG_DEFCONFIG_LIST= $@
@@ -1081,6 +1085,7 @@ $(sort $(BAREBOX_OBJS)) $(BAREBOX_LDS) $(BAREBOX_PBL_OBJS): $(barebox-dirs) ;
PHONY += $(barebox-dirs)
$(barebox-dirs): prepare scripts
+ @find $@ -name policy-list | xargs rm -f
$(Q)$(MAKE) $(build)=$@
# Store (new) KERNELRELASE string in include/config/kernel.release
@@ -1172,6 +1177,73 @@ include/generated/version.h: FORCE
include/generated/utsrelease.h: include/config/kernel.release FORCE
$(call filechk,utsrelease.h)
+# ---------------------------------------------------------------------------
+# Security policies
+
+ifdef CONFIG_SECURITY_POLICY
+
+.security_config: $(KCONFIG_CONFIG) FORCE
+ +$(call cmd,sconfig,allyesconfig,$@.tmp,$@)
+ $(Q)if [ ! -r $@ ] || ! cmp -s $@.tmp $@; then \
+ mv -f $@.tmp $@; \
+ else \
+ rm -f $@.tmp; \
+ fi
+
+targets += .security_config
+targets += include/generated/security_autoconf.h
+targets += include/generated/sconfig_names.h
+
+KPOLICY = $(shell find $(objtree)/ -name policy-list -exec cat {} \;)
+KPOLICY.tmp = $(addsuffix .tmp,$(KPOLICY))
+
+PHONY += collect-policies
+collect-policies: KBUILD_MODULES :=
+collect-policies: KBUILD_BUILTIN :=
+collect-policies: $(barebox-dirs) FORCE
+
+PHONY += security_listconfigs
+security_listconfigs: collect-policies FORCE
+ @echo policies:
+ @$(foreach p, $(KPOLICY), echo $p ;)
+
+PHONY += security_checkconfigs
+security_checkconfigs: collect-policies $(KPOLICY.tmp) FORCE
+ +$(Q)$(foreach p, $(KPOLICY), \
+ $(call loop_cmd,security_checkconfig,$p.tmp))
+
+security_%config: collect-policies $(KPOLICY.tmp) FORCE
+ +$(Q)$(foreach p, $(KPOLICY), $(call loop_cmd,sconfig, \
+ $(@:security_%=%),$p.tmp))
+ +$(Q)$(foreach p, $(KPOLICY), \
+ cp 2>/dev/null $p.tmp $(call resolve-srctree,$p) || true;)
+
+quiet_cmd_sconfigpost = SCONFPP $@
+ cmd_sconfigpost = $(SCONFIGPOST) $2 -D $(depfile) -o $@ $<
+
+include/generated/security_autoconf.h: .security_config scripts_basic FORCE
+ $(call if_changed_dep,sconfigpost,-e)
+
+include/generated/sconfig_names.h: .security_config scripts_basic FORCE
+ $(call if_changed_dep,sconfigpost,-s)
+
+archprepare: include/generated/security_autoconf.h include/generated/sconfig_names.h
+
+else
+
+PHONY += security_%configs security_%config security_disabled
+security_disabled: FORCE
+ @echo "Security policies are disabled. Set CONFIG_SECURITY_POLICY to enable them"
+ @false
+
+security_%configs: security_disabled FORCE
+ @false
+
+security_%config: security_disabled FORCE
+ @false
+
+endif
+
# ---------------------------------------------------------------------------
# Devicetree files
@@ -1295,8 +1367,8 @@ CLEAN_FILES += scripts/bareboxenv-target scripts/kernel-install-target \
# Directories & files removed with 'make mrproper'
MRPROPER_DIRS += include/config usr/include include/generated Documentation/commands
-MRPROPER_FILES += .config .config.old .version .old_version \
- include/config.h \
+MRPROPER_FILES += .config .config.old .security_config .version .old_version \
+ include/config.h *.sconfig.old \
Module.symvers tags TAGS cscope*
# clean - Delete most, but leave enough to build external modules
@@ -1317,7 +1389,8 @@ clean: archclean $(clean-dirs)
\( -name '*.[oas]' -o -name '*.ko' -o -name '.*.cmd' \
-o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \
-o -name '*lex.c' -o -name '.tab.[ch]' \
- -o -name 'dtbs-list' \
+ -o -name 'dtbs-list' -o -name 'policy-list' \
+ -o -name '*.sconfig.tmp' -o -name '*.sconfig.[co]' \
-o -name '*.symtypes' -o -name '*.bbenv.*' -o -name "*.bbenv" \) \
-type f -print | xargs rm -f
@@ -1481,6 +1554,8 @@ target-dir = $(dir $@)
$(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@)
%.symtypes: %.c prepare scripts FORCE
$(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@)
+%.sconfig.tmp: %.sconfig prepare scripts FORCE
+ $(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@)
# Modules
%/: prepare scripts FORCE
diff --git a/Sconfig b/Sconfig
new file mode 100644
index 0000000000000000000000000000000000000000..6cfd8c8677a655c1b238dadc22aa6d40b161596d
--- /dev/null
+++ b/Sconfig
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+mainmenu "Barebox Security Configuration"
+
+source "scripts/Sconfig.include"
+
+source "security/Sconfig"
diff --git a/include/security/config.h b/include/security/config.h
new file mode 100644
index 0000000000000000000000000000000000000000..b37ef4272c94d955b2d59c4331194c4d02ca27d1
--- /dev/null
+++ b/include/security/config.h
@@ -0,0 +1,76 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __BAREBOX_SECURITY_CONFIG_H
+#define __BAREBOX_SECURITY_CONFIG_H
+
+/*
+ * Security policies is an access control mechanism to control when
+ * security-sensitive code is allowed to run.
+ *
+ * This header is included by security-sensitive code to consult
+ * the policy and enforce it.
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <notifier.h>
+#include <security/defs.h>
+
+extern const char *sconfig_names[SCONFIG_NUM];
+
+int sconfig_lookup(const char *name);
+
+extern struct notifier_head sconfig_notifier_list;
+
+bool is_allowed(const struct security_policy *policy, unsigned option);
+
+#define IF_ALLOWABLE(opt, then, else) \
+ ({ __if_defined(opt##_DEFINED, then, else); })
+
+#ifdef CONFIG_SECURITY_POLICY
+#define IS_ALLOWED(opt) IF_ALLOWABLE(opt, is_allowed(NULL, (opt)), 0)
+#define ALLOWABLE_VALUE(opt) IF_ALLOWABLE(opt, opt, -1)
+#else
+#define IS_ALLOWED(opt) 1
+#define ALLOWABLE_VALUE(opt) (-1)
+#endif
+
+static inline int sconfig_register_handler(struct notifier_block *nb,
+ int (*cb)(struct notifier_block *,
+ unsigned long, void *))
+{
+ if (!IS_ENABLED(CONFIG_SECURITY_POLICY))
+ return -ENOSYS;
+
+ nb->notifier_call = cb;
+ return notifier_chain_register(&sconfig_notifier_list, nb);
+}
+
+static inline int sconfig_unregister_handler(struct notifier_block *nb)
+{
+ if (!IS_ENABLED(CONFIG_SECURITY_POLICY))
+ return -ENOSYS;
+ return notifier_chain_unregister(&sconfig_notifier_list, nb);
+}
+
+struct sconfig_notifier_block;
+typedef void (*sconfig_notifier_callback_t)(struct sconfig_notifier_block *,
+ enum security_config_option,
+ bool val);
+
+struct sconfig_notifier_block {
+ struct notifier_block nb;
+ enum security_config_option opt;
+ sconfig_notifier_callback_t cb_filtered;
+};
+
+int __sconfig_register_handler_filtered(struct sconfig_notifier_block *nb,
+ sconfig_notifier_callback_t cb,
+ enum security_config_option);
+
+#define sconfig_register_handler_filtered(nb, cb, opt) ({ \
+ int __sopt = ALLOWABLE_VALUE(opt); \
+ __sopt != -1 ? __sconfig_register_handler_filtered((nb), (cb), __sopt) \
+ : -ENOSYS; \
+})
+
+#endif /* __BAREBOX_SECURITY_CONFIG_H */
diff --git a/include/security/defs.h b/include/security/defs.h
new file mode 100644
index 0000000000000000000000000000000000000000..5b478039ad9425f4d3635d34ac22b6ef67912a70
--- /dev/null
+++ b/include/security/defs.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __BAREBOX_SECURITY_DEFS_H
+#define __BAREBOX_SECURITY_DEFS_H
+
+#include <linux/types.h>
+
+#ifdef CONFIG_SECURITY_POLICY
+# include <generated/security_autoconf.h>
+#else
+#define SCONFIG_NUM 0
+enum security_config_option { SCONFIG__DUMMY__ };
+#endif
+
+extern const char *sconfig_names[SCONFIG_NUM];
+
+struct security_policy {
+ const char *name;
+ bool chained;
+ unsigned char policy[SCONFIG_NUM];
+};
+
+#endif
diff --git a/include/security/policy.h b/include/security/policy.h
new file mode 100644
index 0000000000000000000000000000000000000000..6f270793bc80b03966c1b47fe9c44c9bfb9263a5
--- /dev/null
+++ b/include/security/policy.h
@@ -0,0 +1,50 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __BAREBOX_SECURITY_POLICY_H
+#define __BAREBOX_SECURITY_POLICY_H
+
+/*
+ * Security policies is an access control mechanism to control when
+ * security-sensitive code is allowed to run.
+ *
+ * This header is included by board code that registers and
+ * selects (activates) these security policies.
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <notifier.h>
+#include <security/defs.h>
+
+/*
+ * It's recommended to use the following names for the
+ * "standard" policies
+ */
+#define POLICY_DEVEL "devel"
+#define POLICY_FACTORY "factory"
+#define POLICY_LOCKDOWN "lockdown"
+#define POLICY_TAMPER "tamper"
+#define POLICY_FIELD_RETURN "return"
+
+extern const struct security_policy *active_policy;
+
+const struct security_policy *security_policy_get(const char *name);
+
+int security_policy_activate(const struct security_policy *policy);
+int security_policy_select(const char *name);
+void security_policy_list(void);
+
+#ifdef CONFIG_SECURITY_POLICY
+int __security_policy_register(const struct security_policy policy[]);
+#else
+static inline int __security_policy_register(const struct security_policy policy[])
+{
+ return -ENOSYS;
+}
+#endif
+
+#define security_policy_add(name) ({ \
+ extern const struct security_policy __policy_##name[]; \
+ __security_policy_register(__policy_##name); \
+})
+
+#endif /* __BAREBOX_SECURITY_POLICY_H */
diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include
index a23d27cba315f51082fcf38d6b3e011a541fabd1..b4c3f92af2ffd74c06217b234a9cfc8dd3d9516a 100644
--- a/scripts/Kbuild.include
+++ b/scripts/Kbuild.include
@@ -225,6 +225,14 @@ cmd_and_fixdep = \
# and if so will execute $(rule_foo).
if_changed_rule = $(if $(if-changed-cond),$(rule_$(1)),@:)
+# Same as newer-prereqs, but allows to exclude specified extra dependencies
+newer_prereqs_except = $(filter-out $(PHONY) $(1),$?)
+
+# Same as if_changed, but allows to exclude specified extra dependencies
+if_changed_except = $(if $(call newer_prereqs_except,$(2))$(cmd-check), \
+ $(cmd); \
+ printf '%s\n' 'savedcmd_$@ := $(make-cmd)' > $(dot-target).cmd, @:)
+
###
# why - tell why a target got built
# enabled by make V=2
@@ -282,3 +290,30 @@ ifneq ($(and $(filter notintermediate, $(.FEATURES)),$(filter-out 4.4,$(MAKE_VER
else
.SECONDARY:
endif
+
+###############################################################################
+## barebox specifics
+###############################################################################
+
+# File resolution
+# ===========================================================================
+
+# turn an absolute path relative if it's beneath the specified directory
+strip-path = $(patsubst $(2)/%,%,$(1))
+strip-srctree = $(call strip-path,$(1),$(srctree))
+strip-objtree = $(call strip-path,$(1),$(objtree))
+
+# turn a relative path absolute if it exists by prefixing it with the
+# specified directory
+resolve-path = $(strip $(if $(1), $(if $(filter /%,$(1)), $(1), \
+ $(if $(wildcard $(2)/$(1)), $(2)/$(1), $(1) ) ), $(1) ))
+resolve-srctree = $(call resolve-path,$(1),$(srctree))
+resolve-objtree = $(call resolve-path,$(1),$(objtree))
+
+# resolve a relative path first beneath srctree if it exists there
+# and otherwise beneath objtree
+resolve-external = $(call resolve-objtree,$(call resolve-srctree,$(1)))
+
+# Read file in filechk
+# ===========================================================================
+filechk_cat = cat $<
diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index fed8c247f9dc6fb49cb34bbba4bfd2a0904e2336..f7900875f0c8b9cec819f0c7c69a5246004f5006 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -15,6 +15,7 @@ obj-m :=
lib-y :=
lib-m :=
pbl-y :=
+policy-y :=
always :=
always-y :=
always-m :=
@@ -60,6 +61,12 @@ ifneq ($(dtb-y)$(dtb-)$(filter %.dtb %.dtb.o %.dtbo.o,$(targets)),)
include $(srctree)/scripts/Makefile.dtbs
endif
+ifdef CONFIG_SECURITY_POLICY
+ifneq ($(policy-y)$(policy-)$(filter %.sconfig %.sconfig.tmp %.sconfig.c %.sconfig.o,$(targets)),)
+include $(srctree)/scripts/Makefile.policy
+endif
+endif
+
ifndef obj
$(warning kbuild: Makefile.build is included improperly)
endif
@@ -73,6 +80,13 @@ cmd_gen_order = { $(foreach m, $(real-prereqs), \
$(if $(filter %/$(notdir $@), $m), cat $m, echo $m);) :; } \
> $@
+# This is a list of source files from the current Makefile and its
+# sub-directories. The timestamp should be updated when any of the member files.
+
+cmd_gen_order_src = { $(foreach m, $(patsubst $(srctree)/%,%,$(real-prereqs)), \
+ $(if $(filter %/$(notdir $@), $m), cat $m, echo $m);) :; } \
+ > $@
+
ifneq ($(strip $(lib-y) $(lib-m) $(lib-n) $(lib-)),)
lib-target := $(obj)/lib.a
endif
@@ -278,12 +292,14 @@ intermediate_targets = $(foreach sfx, $(2), \
# %.dtb.pbl.o <- %.dtb.S <- %.dtb <- %.dts (Barebox only)
# %.lex.o <- %.lex.c <- %.l
# %.tab.o <- %.tab.[ch] <- %.y
+# %.sconfig.o <- %.sconfig.c <- %.sconfig.tmp <- %.sconfig
targets += $(call intermediate_targets, .asn1.o, .asn1.c .asn1.h) \
$(call intermediate_targets, .dtb.o, .dtb.S .dtb.z .dtb) \
$(call intermediate_targets, .dtbo.o, .dtbo.S .dtbo.z .dtbo) \
$(call intermediate_targets, .dtb.pbl.o, .dtb.S .dtb.z .dtb) \
$(call intermediate_targets, .lex.o, .lex.c) \
- $(call intermediate_targets, .tab.o, .tab.c .tab.h)
+ $(call intermediate_targets, .tab.o, .tab.c .tab.h) \
+ $(call intermediate_targets, .sconfig.o, .sconfig.c .sconfig.tmp)
# Descending
# ---------------------------------------------------------------------------
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
index 2128361b3ae327082c278ff9b7ec055d07849810..e05fef843c5fe6049fc94e5eaa59eb9e5e40e030 100644
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -85,6 +85,13 @@ extra-y += $(patsubst %,%.bbenv$(DEFAULT_COMPRESSION_SUFFIX),$(bbenv-y))
extra-y += $(patsubst %,%.bbenv$(DEFAULT_COMPRESSION_SUFFIX).S,$(bbenv-y))
extra-y += $(patsubst %,%.bbenv$(DEFAULT_COMPRESSION_SUFFIX).o,$(bbenv-y))
+ifdef CONFIG_SECURITY_POLICY
+obj-y += $(addsuffix .o, $(policy-y))
+extra- += $(patsubst %,%.c,$(policy-))
+extra-m += $(patsubst %,%.c,$(policy-m))
+extra-y += $(patsubst %,%.c,$(policy-y))
+endif
+
# Replace multi-part objects by their individual parts,
# including built-in.a from subdirectories
real-obj-y := $(foreach m, $(obj-y), $(if $(strip $($(m:.o=-objs)) $($(m:.o=-y)) $($(m:.o=-))),$($(m:.o=-objs)) $($(m:.o=-y)),$(m)))
@@ -640,3 +647,43 @@ cmd_public_keys = \
%: %.base64
$(call cmd,b64dec)
+
+# Security Policy Handling
+# ---------------------------------------------------------------------------
+
+# Process security Kconfig file
+# TODO: set KCONFIG_WARN_UNKNOWN_SYMBOLS & KCONFIG_WERROR once supported
+quiet_cmd_sconfig = SCONFIG $(notdir $(or $(4),$(3)))
+ cmd_sconfig = \
+ KBUILD_KCONFIG=Sconfig \
+ KCONFIG_CONFIG_ORIG=$(KCONFIG_CONFIG) \
+ KCONFIG_CONFIG=$(3) \
+ KCONFIG_CONFIG_=SCONFIG_ \
+ KBUILD_DEFCONFIG=allnoconfig \
+ KCONFIG_NOSILENTUPDATE=1 \
+ KCONFIG_AUTOCONFIG=/dev/null \
+ KCONFIG_AUTOHEADER=/dev/null \
+ $(MAKE) -f $(srctree)/Makefile $(2) quiet=silent_
+
+# Check that a policy is up to date
+# NOTE: With KCONFIG_NOSILENTUPDATE=1, a simpler implementation is
+# possible: $(cmd_sconfig) syncconfig $(2), but it has the downside
+# of a worse error message, so we don't do that here
+quiet_cmd_security_checkconfig = SCONFIG $(notdir $(2))
+ cmd_security_checkconfig = \
+ trap "rm -f $(2).tmp $(2).tmp.old" EXIT; \
+ cp $(2) $(2).tmp ; \
+ $(call noop_cmd,sconfig,olddefconfig,$(2).tmp,$(2)) ; \
+ if ! cmp -s $(2).tmp $(2); then \
+ echo >&2 '***'; \
+ echo >&2 '*** Security policy' \
+ $(notdir $(2)) \
+ 'was not up to date.'; \
+ echo >&2 '***'; \
+ echo >&2 '*** Please run "make security_olddefconfig" or'; \
+ echo >&2 '*** another configurator and commit the results to'; \
+ echo >&2 '*** '$(2); \
+ echo >&2 '***'; \
+ $(if $(Q),,diff -u $(2) $(2).tmp >&2;) \
+ exit 1; \
+ fi ; rm -f $(2).tmp $(2).tmp.old
diff --git a/scripts/Makefile.policy b/scripts/Makefile.policy
new file mode 100644
index 0000000000000000000000000000000000000000..a84e85e73d68f2740c3b02899200a7285e6f58d1
--- /dev/null
+++ b/scripts/Makefile.policy
@@ -0,0 +1,34 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+real-policy-y := $(addprefix $(obj)/, $(policy-y))
+
+targets += $(addsuffix .tmp, $(real-policy-y))
+
+# policy-list
+# ---------------------------------------------------------------------------
+
+ifneq ($(policy-y)$(policy-),)
+always-y += $(obj)/policy-list
+
+$(obj)/policy-list: $(real-policy-y) FORCE
+ $(call if_changed,gen_order_src)
+endif
+
+# sconfigpost (.sconfig -> .sconfig.c -> .sconfig.o)
+# ---------------------------------------------------------------------------
+
+$(obj)/%.sconfig.tmp: $(src)/%.sconfig FORCE
+ $(call filechk,cat)
+
+quiet_cmd_sconfigpost_c = SCONFPP $@
+ cmd_sconfigpost_c = $(SCONFIGPOST) -o $@ -D$(depfile) $(2)
+
+$(obj)/%.sconfig.c: quiet_cmd_sconfig :=
+$(obj)/%.sconfig.c: $(obj)/%.sconfig.tmp FORCE
+ +$(Q)$(call noop_cmd,security_checkconfig,$<)
+ $(call if_changed_dep,sconfigpost_c,$<)
+
+# targets
+# ---------------------------------------------------------------------------
+
+targets += $(always-y)
diff --git a/scripts/Sconfig.include b/scripts/Sconfig.include
new file mode 100644
index 0000000000000000000000000000000000000000..3f5e4c652d97c62926c7dffbf9340bf753f4ea1c
--- /dev/null
+++ b/scripts/Sconfig.include
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+source "scripts/Kconfig.include"
+
+kconfig-state = $(shell,CONFIG_=CONFIG_ $(srctree)/scripts/config --file "$(KCONFIG_CONFIG_ORIG)" -s "$(1)")
+kconfig-enabled = $(shell,echo $(kconfig-state,$(1)))
diff --git a/scripts/basic/.gitignore b/scripts/basic/.gitignore
index 961c91c8a884614a852e620346b6346ecbd4b1a1..660035252b31cf7e1bf6b19a83ff79c6f000d2d4 100644
--- a/scripts/basic/.gitignore
+++ b/scripts/basic/.gitignore
@@ -1,2 +1,3 @@
# SPDX-License-Identifier: GPL-2.0-only
/fixdep
+/sconfigpost
diff --git a/scripts/basic/Makefile b/scripts/basic/Makefile
index eeb6a38c5551516bc3b1539e5f236ff952fea394..cd4d9f321d63d9af7cbea49b51531cd413c44156 100644
--- a/scripts/basic/Makefile
+++ b/scripts/basic/Makefile
@@ -1,5 +1,7 @@
# SPDX-License-Identifier: GPL-2.0-only
#
# fixdep: used to generate dependency information during build process
+# sconfigpost: used to postprocess security configs
hostprogs-always-y += fixdep
+hostprogs-always-y += sconfigpost
diff --git a/scripts/basic/sconfigpost.c b/scripts/basic/sconfigpost.c
new file mode 100644
index 0000000000000000000000000000000000000000..171eb8f43e586c7c2da28bf2254a014c479852e4
--- /dev/null
+++ b/scripts/basic/sconfigpost.c
@@ -0,0 +1,540 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Postprocess Sconfig files
+
+#include <getopt.h>
+#include <stdbool.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <utime.h>
+
+static void usage(int exitcode);
+
+static const char *argv0;
+static char *symbol_name = "untitled";
+static const char *policy_name = "untitled";
+
+#define MAX(x, y) ((x) > (y) ? (x) : (y))
+
+enum print { PRINT_ARRAY, PRINT_ENUM, PRINT_DEFINES, PRINT_STRINGS };
+
+#define panic(fmt, ...) do { \
+ fprintf(stderr, "%s: " fmt, argv0, ##__VA_ARGS__); \
+ exit(6); \
+} while (0)
+
+#define xasprintf(args...) ({ \
+ char *_buf; \
+ if (asprintf(&_buf, args) < 0) \
+ panic("asprintf: %m\n"); \
+ _buf; \
+})
+
+#define xstrdup(args...) nonnull(strdup(args))
+#define xmalloc(args...) nonnull(malloc(args))
+#define xrealloc(args...) nonnull(realloc(args))
+
+#ifdef DEBUG
+#define debug(args...) fprintf(stderr, args)
+#else
+#define debug(args...) (void)0
+#endif
+
+static inline size_t str_has_prefix(const char *str, const char *prefix)
+{
+ size_t len = strlen(prefix);
+ return strncmp(str, prefix, len) == 0 ? len : 0;
+}
+
+static void *nonnull(void *ptr)
+{
+ if (!ptr)
+ exit(2);
+ return ptr;
+}
+
+static FILE *xfopen(const char *path, const char *mode)
+{
+ FILE *fp;
+
+ fp = fopen(path, mode);
+ if (!fp)
+ panic("failed to open \"%s\" with mode '%s': %m\n",
+ path, mode);
+
+ return fp;
+}
+
+static void print_global_header(FILE *out, enum print print)
+{
+ switch (print) {
+ case PRINT_ARRAY:
+ fprintf(out, "#include <security/defs.h>\n");
+ fprintf(out, "const struct security_policy __policy_%s[] = {\n", symbol_name);
+ break;
+ case PRINT_STRINGS:
+ fprintf(out, "#include <security/defs.h>\n");
+ break;
+ default:
+ break;
+ }
+}
+
+static void print_header(FILE *out, enum print print, bool is_last)
+{
+ switch (print) {
+ case PRINT_ARRAY:
+ fprintf(out, "{\n");
+ fprintf(out, "\t.name = \"%s\",\n", policy_name);
+ fprintf(out, "\t.chained = %d,\n", is_last ? 0 : 1);
+ fprintf(out, "\t.policy = {\n");
+ break;
+ case PRINT_ENUM:
+ fprintf(out, "enum security_config_option {\n");
+ break;
+ case PRINT_STRINGS:
+ fprintf(out, "const char *sconfig_names[SCONFIG_NUM] = {\n");
+ break;
+ default:
+ break;
+ }
+}
+
+static void print_elem(FILE *out, enum print print,
+ const char *config, bool enable, int i)
+{
+ switch (print) {
+ case PRINT_DEFINES:
+ fprintf(out, "#define %-40s %u\n", config, i);
+ break;
+ case PRINT_ARRAY:
+ fprintf(out, "\t[%-40s] = %s,\n", config,
+ enable ? "1" : "0");
+ break;
+ case PRINT_ENUM:
+ fprintf(out, "\t%s = %i,\n", config, i);
+ break;
+ case PRINT_STRINGS:
+ fprintf(out, "\t[%s] = \"%s\",\n", config, config);
+ break;
+ }
+}
+
+static void print_footer(FILE *out, enum print print, bool is_last, int i)
+{
+ switch (print) {
+ case PRINT_DEFINES:
+ return;
+ case PRINT_ENUM:
+ fprintf(out, "\tSCONFIG_NUM = %i\n};\n", i);
+ break;
+ case PRINT_ARRAY:
+ if (is_last)
+ fprintf(out, "\t}}\n");
+ else
+ fprintf(out, "\t}},\n");
+ break;
+ case PRINT_STRINGS:
+ fprintf(out, "};\n");
+ break;
+ }
+}
+
+static void print_global_footer(FILE *out, enum print print)
+{
+ switch (print) {
+ case PRINT_ARRAY:
+ fprintf(out, "};\n");
+ break;
+ default:
+ break;
+ }
+}
+
+static const char *nextline(char **line, FILE *in)
+{
+ size_t len = 0;
+ ssize_t nread;
+
+ do {
+ nread = getline(line, &len, in);
+ if (nread < 0)
+ return NULL;
+ } while (!nread);
+
+ if (nread > 256)
+ panic("line \"%s\" exceeds maximum length of 256\n", *line);
+
+ if ((*line)[nread - 1] == '\n')
+ (*line)[nread - 1] = '\0';
+
+ return *line;
+}
+
+#define CONFIG_VAL_SKIP (void *)1
+
+static const char *parse_config_val(char *line, bool *enable)
+{
+ static char config[256];
+ static char name[256];
+ char end[2];
+ int val_offset;
+ int ret;
+
+ if ((ret = sscanf(line, "# %255[A-Za-z0-9_] is not se%1[t]",
+ config, end)) == 2) {
+ if (str_has_prefix(config, "SCONFIG_POLICY_"))
+ return CONFIG_VAL_SKIP;
+ if (enable)
+ *enable = false;
+ } else if ((ret = sscanf(line, "SCONFIG_POLICY_%255[A-Za-z0-9_]=%255s",
+ config, name)) == 2) {
+ if (!strcmp(config, "NAME")) {
+ policy_name = name + 1;
+ *strchrnul(policy_name, '"') = '\0';
+ }
+ return CONFIG_VAL_SKIP;
+ } else if ((ret = sscanf(line, "%255[A-Za-z0-9_]=%n", config,
+ &val_offset)) == 1) {
+ if (strcmp(&line[val_offset], "y"))
+ panic("\"%s\": bool data type expected\n", line);
+
+ if (enable)
+ *enable = true;
+ } else {
+ return NULL;
+ }
+
+ return config;
+}
+
+static void strsanitize(char *str)
+{
+ size_t i;
+
+ while ((i = strcspn(str, "-."))) {
+ switch (str[i]) {
+ case '-':
+ str[i] = '_';
+ break;
+ case '.':
+ str[i] = '\0';
+ /* fallthrough */
+ case '\0':
+ return;
+ }
+
+ str += i + 1;
+ }
+}
+
+static int parse_ext(const struct dirent *dir)
+{
+ const char *ext;
+
+ if (!dir || dir->d_type == DT_DIR)
+ return 0;
+
+ ext = strrchr(dir->d_name, '.');
+ if (!ext || ext == dir->d_name)
+ return 0;
+
+ return strcmp(ext, ".sconfig") == 0;
+}
+
+static time_t newest_mtime;
+
+static void stat_inputfile(const char *path, struct stat *st)
+{
+ if (stat(path, st))
+ panic("Input file '%s' doesn't exist: %m\n", path);
+
+ if (!S_ISDIR(st->st_mode))
+ newest_mtime = MAX(newest_mtime, st->st_mtime);
+}
+
+static char **collect_input(int argc, char *argv[])
+{
+ char **buf;
+ int i = 0;
+
+ argc++;
+ buf = xmalloc(argc * sizeof(*buf));
+
+ for (char **arg = argv; *arg; arg++) {
+ char **newbuf;
+ struct stat st;
+ struct dirent **namelist;
+ int n;
+
+ stat_inputfile(*arg, &st);
+
+ if (!S_ISDIR(st.st_mode)) {
+ buf[i++] = *arg;
+ continue;
+ }
+
+ n = scandir(*arg, &namelist, parse_ext, alphasort);
+ if (n < 0)
+ panic("scandir: %m\n");
+
+ argc += n;
+
+ newbuf = xrealloc(buf, argc * sizeof(*newbuf));
+ buf = newbuf;
+
+ for (int j = 0; j < n; j++) {
+ buf[i + j] = xasprintf("%s/%s", *arg, namelist[j]->d_name);
+ free(namelist[j]);
+
+ /* update newest_times */
+ stat_inputfile(buf[i + j], &st);
+ }
+
+ free(namelist);
+ i += n;
+ }
+
+ buf[i] = NULL;
+ return buf;
+}
+
+static long fsize(FILE *fp)
+{
+ long size;
+
+ fseek(fp, 0, SEEK_END);
+
+ size = ftell(fp);
+ if (size < 0)
+ panic("ftell: %m\n");
+
+ fseek(fp, 0, SEEK_SET);
+
+ return size;
+}
+
+static bool fidentical(FILE *fp1, FILE *fp2)
+{
+ int ch1, ch2;
+ if (fsize(fp1) != fsize(fp2)) {
+ debug("file size mismatch\n");
+ return false;
+ }
+
+ do {
+ ch1 = getc(fp1);
+ ch2 = getc(fp2);
+ if (ch1 != ch2)
+ return false;
+ } while (ch1 != EOF && ch2 != EOF);
+
+ return true;
+}
+
+static char *make_tmp_path(const char *path, FILE **fp)
+{
+
+ const char *filename, *slash;
+ char *tmpfilepath;
+
+ slash = strrchr(path, '/');
+ filename = slash ? slash + 1 : path;
+
+ if (slash)
+ tmpfilepath = xasprintf("%.*s/.%s.tmp", (int)(slash - path), path,
+ filename);
+ else
+ tmpfilepath = xasprintf(".%s.tmp", filename);
+
+ *fp = xfopen(tmpfilepath, "w+");
+
+ return tmpfilepath;
+}
+
+static void append_dependency(FILE *depfile, const char *path)
+{
+ char *abspath;
+
+ if (!depfile)
+ return;
+
+ if (!path) {
+ fprintf(depfile, "\n");
+ return;
+ }
+
+ abspath = nonnull(realpath(path, NULL));
+
+ fprintf(depfile, "\t%s \\\n", abspath);
+
+ free(abspath);
+}
+
+int main(int argc, char *argv[])
+{
+ const char *outfilepath = NULL;
+ char *tmpfilepath = NULL;
+ char **infilepaths;
+ enum print print = PRINT_ARRAY;
+ FILE *in = stdin, *out = stdout, *out_final = NULL, *depfile = NULL;
+ char *line = NULL;
+ int opt;
+
+ argv0 = argv[0];
+
+ while ((opt = getopt(argc, argv, "esdD:o:h")) > 0) {
+ switch (opt) {
+ case 'e':
+ print = PRINT_ENUM;
+ break;
+ case 's':
+ print = PRINT_STRINGS;
+ break;
+ case 'd':
+ print = PRINT_DEFINES;
+ break;
+ case 'D':
+ depfile = xfopen(optarg, "w");
+ break;
+ case 'o':
+ outfilepath = optarg;
+ break;
+ case 'h':
+ usage(0);
+ break;
+ default:
+ usage(1);
+ break;
+ }
+ }
+
+ if (depfile && !outfilepath)
+ panic("can't generate depfile without -o argument\n");
+
+ if (argc - optind > 1 && print != PRINT_ARRAY)
+ panic("processing multiple files at once only possible for array mode\n");
+
+ if (argc == optind && depfile)
+ panic("can't generate depfile while reading stdin\n");
+
+ if (outfilepath) {
+ out_final = fopen(outfilepath, "r+");
+ if (out_final) {
+ tmpfilepath = make_tmp_path(outfilepath, &out);
+ } else if (outfilepath) {
+ out = xfopen(outfilepath, "w");
+ }
+
+ symbol_name = xasprintf("%s", basename(outfilepath));
+ strsanitize(symbol_name);
+ }
+
+ infilepaths = collect_input(argc - optind, &argv[optind]);
+
+ print_global_header(out, print);
+
+ if (depfile)
+ fprintf(depfile, "%s: \\\n", outfilepath);
+
+ for (char **infilepath = infilepaths; *infilepath; infilepath++) {
+ bool is_last = infilepath[1] == NULL;
+ bool hdr_printed = false;
+ const char *comment_prefix = "";
+ int option_idx = 0;
+
+ in = xfopen(*infilepath, "r");
+
+ while (nextline(&line, in)) {
+ const char *config;
+ bool enable;
+
+ config = parse_config_val(line, &enable);
+ if (config == CONFIG_VAL_SKIP)
+ continue;
+ if (!config) {
+ if (line[0] == '#')
+ fprintf(out, "%s// %s\n", comment_prefix, line + 1);
+
+ continue;
+ }
+
+ if (!hdr_printed) {
+ print_header(out, print, is_last);
+ if (print != PRINT_DEFINES)
+ comment_prefix = "\t";
+ hdr_printed = true;
+ }
+
+ print_elem(out, print, config, enable, option_idx++);
+ }
+
+ print_footer(out, print, is_last, option_idx);
+ fputs("\n", out);
+
+ if (print != PRINT_ARRAY) {
+ rewind(in);
+
+ while (nextline(&line, in)) {
+ const char *config = parse_config_val(line, NULL);
+ if (config && config != CONFIG_VAL_SKIP)
+ fprintf(out, "#define\t%s_DEFINED 1\n", config);
+ }
+ }
+
+ free(line);
+ fclose(in);
+
+ append_dependency(depfile, *infilepath);
+ }
+
+ print_global_footer(out, print);
+
+ fflush(out);
+
+ if (out_final) {
+ if (fidentical(out, out_final)) {
+ struct stat st;
+
+ debug("removing %s\n", tmpfilepath);
+ remove(tmpfilepath);
+
+ if (stat(outfilepath, &st))
+ panic("Output file '%s' doesn't exist?? %m\n", outfilepath);
+ if (st.st_mtime <= newest_mtime)
+ utime(outfilepath, NULL);
+ } else {
+ debug("renaming %s to %s\n", tmpfilepath, outfilepath);
+ rename(tmpfilepath, outfilepath);
+ }
+ }
+
+ append_dependency(depfile, "include/generated/autoconf.h");
+ if (print == PRINT_ARRAY || print == PRINT_STRINGS)
+ append_dependency(depfile, "include/generated/security_autoconf.h");
+ append_dependency(depfile, NULL);
+
+ return 0;
+}
+
+static void usage(int exitcode)
+{
+ FILE *fp = exitcode ? stderr : stdout;
+
+ fprintf(fp,
+ "usage: %s [-o FILE] [-d DEPFILE] [-edph] [config]\n"
+ "This script postprocess a barebox Sconfig (Security config)\n"
+ "in the Kconfig .config format for further use inside barebox.\n"
+ "If no positional argument is specified, the script operates on stdin\n"
+ "Options:\n"
+ " -e Output policy as C enumeration\n"
+ " -s Output policy option names as C array of strings\n"
+ " -d Output policy as C preprocessor defines\n"
+ " -D <depfile> Write depedencies into <depfile>\n"
+ " -o <outfile> Write output into <outfile> instead of stdout\n"
+ " -h This help text\n", argv0);
+
+ exit(exitcode);
+}
diff --git a/security/Kconfig b/security/Kconfig
index 530589383a45931c156cf2c645afcc00539dc0c5..7ac92e4af7606b9e070162a633277c599a348f0a 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -17,6 +17,8 @@ config INSECURE
- changes the default of global.env.autoprobe to 1
+source "security/Kconfig.policy"
+
config PASSWORD
bool
prompt "Password Framework"
diff --git a/security/Kconfig.policy b/security/Kconfig.policy
new file mode 100644
index 0000000000000000000000000000000000000000..9ea52e91dad3f2c97768fc804203ddc0cad36f79
--- /dev/null
+++ b/security/Kconfig.policy
@@ -0,0 +1,89 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# barebox Security Policy Support
+
+menuconfig SECURITY_POLICY
+ bool "Security Policy Support"
+ help
+ A Security policy is a collection of security configuration options
+ that can be activated together at runtime.
+ Together, the describe a security state that barebox should operate in.
+
+ Policies can be registered by board code or supplied by
+ an external build system. The policy name must be unique across
+ all registered policies.
+
+ Policies are selected by name and only one can be active at a given time.
+ barebox does not mandate any specific behavior for a policy according
+ to its name. Boards have full freedom to name policies and configure the
+ options as they deem appropriate.
+
+ However, we recommend using established terms to make it easier to reason
+ about the different security states:
+
+ devel Security policy should permit everything for
+ development purposes.
+
+ factory System is in a secure boot mode, but policy allows
+ interactive use for factory bring up purposes.
+ Board code usually enforces via eFuse that factory
+ mode can not be re-selected once deselected.
+
+ lockdown Factory bring up is done and device is ready for use
+ in the field with barebox as part of the secure boot
+ chain. This policy usually disallows booting unsigned
+ images
+
+ tamper Tampering attempt was detected. The security policy would
+ take steps to protect secrets (up to bricking the device).
+
+ return For use in field-return devices, the policy should
+ take steps to unlock the device for analysis purposes.
+ Board code should make sure to delete secret and
+ confidential data before activating this policy.
+
+if SECURITY_POLICY
+
+config SECURITY_POLICY_INIT
+ string
+ prompt "Initial security policy"
+ help
+ The policy named here will be automatically selected the first
+ time a security policy is to be consulted.
+ It's recommended to use a restrictive policy here and remove
+ the restrictions if needed instead of the other way round.
+
+config SECURITY_POLICY_DEFAULT_PERMISSIVE
+ bool "Be permissive on missing security policy"
+ select HAS_INSECURE_DEFAULTS
+ help
+ In absence of a selected security policy, by enabling this option
+ everything is allowed. A warning will be printed the first time a
+ security policy would need to be consulted.
+
+ With this option disabled everything is forbidden until a security
+ policy is selected.
+
+ This is a development aid and unsuitable for use in the field:
+ A security policy should always be selected, either early on by
+ board code or via CONFIG_SECURITY_POLICY_INIT.
+
+config SECURITY_POLICY_PATH
+ string
+ depends on SECURITY_POLICY
+ prompt "Paths to additional security policies"
+ help
+ Space separated list of security policies that should be
+ compiled into barebox and registered. This option currently
+ requires each security policy to match security/*.sconfig, i.e.
+ be directly located in the security/ directory of the source
+ source tree and have the .sconfig extension.
+ If left empty, only security policies explicitly provided
+ and registered by board code will be available.
+
+ Absolute paths are disallowed.
+
+config SECURITY_POLICY_NAMES
+ bool
+
+endif
diff --git a/security/Makefile b/security/Makefile
index de9778620d282c7f541eb22341d5c02c2dcc44d6..16b328266a1b35861ee263e8026fc8ebd704aedb 100644
--- a/security/Makefile
+++ b/security/Makefile
@@ -1,5 +1,7 @@
# SPDX-License-Identifier: GPL-2.0-only
+obj-$(CONFIG_SECURITY_POLICY) += policy.o
+obj-$(CONFIG_SECURITY_POLICY_NAMES) += sconfig_names.o
obj-$(CONFIG_CRYPTO_KEYSTORE) += keystore.o
obj-$(CONFIG_JWT) += jwt.o
obj-pbl-$(CONFIG_HAVE_OPTEE) += optee.o
diff --git a/security/Sconfig b/security/Sconfig
new file mode 100644
index 0000000000000000000000000000000000000000..e57daf5b055232535df81c34dc2f27e5cc01038e
--- /dev/null
+++ b/security/Sconfig
@@ -0,0 +1,34 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+# Note: Symbols starting with POLICY_ are reserved and handled specially
+config POLICY_NAME
+ string "Policy name"
+ help
+ Policies are selected by name and only one can be active at a given time.
+ barebox does not mandate any specific behavior for a policy according
+ to its name. Boards have full freedom to name policies and configure the
+ options as they deem appropriate.
+
+ However, we recommend using established terms to make it easier to reason
+ about the different security states:
+
+ devel Security policy should permit everything for
+ development purposes.
+
+ factory System is in a secure boot mode, but policy allows
+ interactive use for factory bring up purposes.
+ Board code usually enforces via eFuse that factory
+ mode can not be re-selected once deselected.
+
+ lockdown Factory bring up is done and device is ready for use
+ in the field with barebox as part of the secure boot
+ chain. This policy usually disallows booting unsigned
+ images
+
+ tamper Tampering attempt was detected. The security policy would
+ take steps to protect secrets (up to bricking the device).
+
+ return For use in field-return devices, the policy should
+ take steps to unlock the device for analysis purposes.
+ Board code should make sure to delete secret and
+ confidential data before activating this policy.
diff --git a/security/policy.c b/security/policy.c
new file mode 100644
index 0000000000000000000000000000000000000000..0984bb6555cc2417ace290af8db7b6a5b6da0d86
--- /dev/null
+++ b/security/policy.c
@@ -0,0 +1,236 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#define pr_fmt(fmt) "policy: " fmt
+
+#include <init.h>
+#include <linux/printk.h>
+#include <linux/bitmap.h>
+#include <param.h>
+#include <device.h>
+#include <stdio.h>
+
+#include <security/policy.h>
+#include <security/config.h>
+
+static const char *sconfig_name(unsigned option)
+{
+ static char name[sizeof("4294967295")];
+
+ if (IS_ENABLED(CONFIG_SECURITY_POLICY_NAMES))
+ return sconfig_names[option];
+
+ snprintf(name, sizeof(name), "%u", option);
+ return name;
+}
+
+#define policy_debug(policy, opt, fmt, ...) \
+ pr_debug("(%s) %s: " fmt, \
+ (policy) ? (policy)->name : "default", \
+ sconfig_name(opt), ##__VA_ARGS__)
+
+#ifdef CONFIG_SECURITY_POLICY_DEFAULT_PERMISSIVE
+#define policy_err pr_err
+#define policy_warn_once pr_warn_once
+#define policy_WARN WARN
+#else
+#define policy_err(fmt, ...) panic(pr_fmt(fmt), ##__VA_ARGS__)
+#define policy_warn_once(fmt, ...) panic(pr_fmt(fmt), ##__VA_ARGS__)
+#define policy_WARN BUG
+#endif
+
+struct policy_list_entry {
+ const struct security_policy *policy;
+ struct list_head list;
+};
+
+const struct security_policy *active_policy;
+
+static LIST_HEAD(policy_list);
+NOTIFIER_HEAD(sconfig_notifier_list);
+
+static bool __is_allowed(const struct security_policy *policy, unsigned option)
+{
+ if (!policy)
+ return true;
+
+ return policy->policy[option];
+}
+
+bool is_allowed(const struct security_policy *policy, unsigned option)
+{
+ policy = policy ?: active_policy;
+
+ if (WARN(option > SCONFIG_NUM))
+ return false;
+
+ if (!policy && *CONFIG_SECURITY_POLICY_INIT) {
+ security_policy_select(CONFIG_SECURITY_POLICY_INIT);
+ policy = active_policy;
+ }
+
+ if (policy) {
+ bool allow = __is_allowed(policy, option);
+
+ policy_debug(policy, option, "%s for %pS\n",
+ allow ? "allowed" : "denied", (void *)_RET_IP_);
+
+ return allow;
+ }
+
+ if (IS_ENABLED(CONFIG_SECURITY_POLICY_DEFAULT_PERMISSIVE))
+ pr_warn_once("option %s checked before security policy was set!\n",
+ sconfig_name(option));
+ else
+ return false;
+
+ return true;
+}
+
+int security_policy_activate(const struct security_policy *policy)
+{
+ const struct security_policy *old_policy = active_policy;
+
+ if (policy == old_policy)
+ return 0;
+
+ active_policy = policy;
+
+ for (int i = 0; i < SCONFIG_NUM; i++) {
+ if (__is_allowed(policy, i) == __is_allowed(old_policy, i))
+ continue;
+
+ notifier_call_chain(&sconfig_notifier_list, i, NULL);
+ }
+
+ return 0;
+}
+
+const struct security_policy *security_policy_get(const char *name)
+{
+ const struct policy_list_entry *entry;
+
+ list_for_each_entry(entry, &policy_list, list) {
+ if (!strcmp(name, entry->policy->name))
+ return entry->policy;
+ }
+
+ return NULL;
+}
+
+int security_policy_select(const char *name)
+{
+ const struct security_policy *policy;
+
+ policy = security_policy_get(name);
+ if (!policy) {
+ policy_err("Policy '%s' not found!\n", name);
+ return -ENOENT;
+ }
+
+ return security_policy_activate(policy);
+}
+
+int __security_policy_register(const struct security_policy policy[])
+{
+ int ret = 0;
+
+ do {
+ struct policy_list_entry *entry;
+
+ if (security_policy_get(policy->name)) {
+ policy_err("policy '%s' already registered\n", policy->name);
+ ret = -EBUSY;
+ continue;
+ }
+
+ entry = xzalloc(sizeof(*entry));
+ entry->policy = policy;
+ list_add_tail(&entry->list, &policy_list);
+ } while ((policy++)->chained);
+
+ return ret;
+}
+
+#ifdef CONFIG_CMD_SCONFIG
+void security_policy_unregister_one(const struct security_policy *policy)
+{
+ struct policy_list_entry *entry;
+
+ if (!policy)
+ return;
+
+ list_for_each_entry(entry, &policy_list, list) {
+ if (entry->policy == policy) {
+ list_del(&entry->list);
+ return;
+ }
+ }
+}
+#endif
+
+void security_policy_list(void)
+{
+ const struct policy_list_entry *entry;
+
+ list_for_each_entry(entry, &policy_list, list) {
+ printf("%s\n", entry->policy->name);
+ }
+}
+
+static int sconfig_handler_filtered(struct notifier_block *nb,
+ unsigned long opt, void *data)
+{
+ struct sconfig_notifier_block *snb
+ = container_of(nb, struct sconfig_notifier_block, nb);
+ bool allow;
+
+ if (snb->opt != opt)
+ return NOTIFY_DONE;
+
+ allow = is_allowed(NULL, opt);
+
+ policy_debug(active_policy, opt, "calling %pS to %s\n",
+ snb->cb_filtered, allow ? "allow" : "deny");
+
+ snb->cb_filtered(snb, opt, is_allowed(NULL, opt));
+ return NOTIFY_OK;
+}
+
+int __sconfig_register_handler_filtered(struct sconfig_notifier_block *snb,
+ sconfig_notifier_callback_t cb,
+ enum security_config_option opt)
+{
+ snb->cb_filtered = cb;
+ snb->opt = opt;
+ return sconfig_register_handler(&snb->nb, sconfig_handler_filtered);
+}
+
+struct device security_device = {
+ .name = "security",
+ .id = DEVICE_ID_SINGLE,
+};
+
+static char *policy_name = "";
+
+static int security_policy_get_name(struct param_d *param, void *priv)
+{
+ if (!active_policy) {
+ policy_name = "";
+ return 0;
+ }
+
+ free_const(policy_name);
+ policy_name = strdup(active_policy->name);
+ return 0;
+}
+
+static int security_init(void)
+{
+ register_device(&security_device);
+
+ dev_add_param_string(&security_device, "policy", param_set_readonly,
+ security_policy_get_name, &policy_name, NULL);
+
+ return 0;
+}
+pure_initcall(security_init);
diff --git a/security/sconfig_names.c b/security/sconfig_names.c
new file mode 100644
index 0000000000000000000000000000000000000000..c830c4eb389202403e049db6a71b70f0f18b76f5
--- /dev/null
+++ b/security/sconfig_names.c
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <security/config.h>
+#include <string.h>
+#include <errno.h>
+#include <linux/kernel.h>
+
+#include <generated/sconfig_names.h>
+
+int sconfig_lookup(const char *name)
+{
+ for (int i = 0; i < ARRAY_SIZE(sconfig_names); i++) {
+ if (!strcmp(name, sconfig_names[i]))
+ return i;
+ }
+
+ return -ENOENT;
+}
--
2.47.3
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH v2 05/24] kbuild: allow security config use without source tree modification
2025-09-17 13:53 [PATCH v2 00/24] Add security policy support Sascha Hauer
` (3 preceding siblings ...)
2025-09-17 13:53 ` [PATCH v2 04/24] Add security policy support Sascha Hauer
@ 2025-09-17 13:53 ` Sascha Hauer
2025-09-17 13:53 ` [PATCH v2 06/24] defaultenv: update PS1 according to security policy Sascha Hauer
` (20 subsequent siblings)
25 siblings, 0 replies; 31+ messages in thread
From: Sascha Hauer @ 2025-09-17 13:53 UTC (permalink / raw)
To: BAREBOX; +Cc: Ahmad Fatoum
From: Ahmad Fatoum <a.fatoum@pengutronix.de>
A key aspect of security policies is the enforcement of a policy to be
complete with no implicit defaults. To make this easier to use, the
security_*config targets directly manipulate the specified KPOLICY or
all known policies if none were specified.
This is at odds with build systems that assume an immutable source tree
and prefer that changes to files within purview of the build system are
only done explicitly by the user. For that purpose, add an optional
KPOLICY_TMPUPDATE, which works as follows:
- When set, only the tmp file in the build tree is updated, but not the
original
- The tmp file is always what's used in the build
- Once unset, the tmp file will always be overwritten by the original
on next build
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
Makefile | 4 +++-
scripts/Makefile.policy | 4 ++++
2 files changed, 7 insertions(+), 1 deletion(-)
diff --git a/Makefile b/Makefile
index 5f1e6ab21ce0ca8f612e129aacffd45123421498..760ac28e8ff8989d18ed517aa07524209014884d 100644
--- a/Makefile
+++ b/Makefile
@@ -100,7 +100,7 @@ ifeq ($(silence),s)
quiet=silent_
endif
-export quiet Q KBUILD_VERBOSE
+export quiet Q KBUILD_VERBOSE KPOLICY_TMPUPDATE
# Kbuild will save output files in the current working directory.
# This does not need to match to the root of the kernel source tree.
@@ -1215,8 +1215,10 @@ security_checkconfigs: collect-policies $(KPOLICY.tmp) FORCE
security_%config: collect-policies $(KPOLICY.tmp) FORCE
+$(Q)$(foreach p, $(KPOLICY), $(call loop_cmd,sconfig, \
$(@:security_%=%),$p.tmp))
+ifeq ($(KPOLICY_TMPUPDATE),)
+$(Q)$(foreach p, $(KPOLICY), \
cp 2>/dev/null $p.tmp $(call resolve-srctree,$p) || true;)
+endif
quiet_cmd_sconfigpost = SCONFPP $@
cmd_sconfigpost = $(SCONFIGPOST) $2 -D $(depfile) -o $@ $<
diff --git a/scripts/Makefile.policy b/scripts/Makefile.policy
index a84e85e73d68f2740c3b02899200a7285e6f58d1..e517feb56ef09464310b014014aa95e012b0b376 100644
--- a/scripts/Makefile.policy
+++ b/scripts/Makefile.policy
@@ -18,7 +18,11 @@ endif
# ---------------------------------------------------------------------------
$(obj)/%.sconfig.tmp: $(src)/%.sconfig FORCE
+ifeq ($(KPOLICY_TMPUPDATE),)
$(call filechk,cat)
+else
+ $(call if_changed,shipped)
+endif
quiet_cmd_sconfigpost_c = SCONFPP $@
cmd_sconfigpost_c = $(SCONFIGPOST) -o $@ -D$(depfile) $(2)
--
2.47.3
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH v2 06/24] defaultenv: update PS1 according to security policy
2025-09-17 13:53 [PATCH v2 00/24] Add security policy support Sascha Hauer
` (4 preceding siblings ...)
2025-09-17 13:53 ` [PATCH v2 05/24] kbuild: allow security config use without source tree modification Sascha Hauer
@ 2025-09-17 13:53 ` Sascha Hauer
2025-09-17 13:53 ` [PATCH v2 07/24] security: policy: support externally provided configs Sascha Hauer
` (19 subsequent siblings)
25 siblings, 0 replies; 31+ messages in thread
From: Sascha Hauer @ 2025-09-17 13:53 UTC (permalink / raw)
To: BAREBOX; +Cc: Ahmad Fatoum, Ahmad Fatoum
From: Ahmad Fatoum <a.fatoum@barebox.org>
This nifty optional feature makes it easy to see what security policy
is currently active.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
Documentation/user/defaultenv-2.rst | 2 ++
common/Kconfig | 5 +++++
defaultenv/Makefile | 1 +
.../defaultenv-2-security-policy/bin/ps1-policy | 20 ++++++++++++++++++++
.../defaultenv-2-security-policy/init/ps1-policy | 1 +
.../defaultenv-2-security-policy/init/source-colors | 1 +
defaultenv/defaultenv.c | 2 ++
7 files changed, 32 insertions(+)
diff --git a/Documentation/user/defaultenv-2.rst b/Documentation/user/defaultenv-2.rst
index a01a70fa9310be88c8666c40bcc3def33c48ac21..3715fd770d9d89d52172bcc1e7564d871977aa30 100644
--- a/Documentation/user/defaultenv-2.rst
+++ b/Documentation/user/defaultenv-2.rst
@@ -23,6 +23,7 @@ The default environment is composed from different directories during compilatio
defaultenv/defaultenv-2-dfu -> overlay for DFU
defaultenv/defaultenv-2-reboot-mode -> overlay for reboot modes
defaultenv/defaultenv-2-menu -> overlay for menus
+ defaultenv/defaultenv-2-security-policy -> overlay for security policy
arch/$ARCH/boards/<board>/defaultenv-<board> -> board specific overlay
$(CONFIG_DEFAULT_ENVIRONMENT_PATH) -> config specific overlay
@@ -43,6 +44,7 @@ and their respective included directories in ``defaultenv/Makefile``:
bbenv-$(CONFIG_DEFAULT_ENVIRONMENT_GENERIC_NEW_MENU) += defaultenv-2-menu
bbenv-$(CONFIG_DEFAULT_ENVIRONMENT_GENERIC_NEW_DFU) += defaultenv-2-dfu
bbenv-$(CONFIG_DEFAULT_ENVIRONMENT_GENERIC_NEW_REBOOT_MODE) += defaultenv-2-reboot-mode
+ bbenv-$(CONFIG_DEFAULT_ENVIRONMENT_GENERIC_NEW_SECURITY_POLICY) += defaultenv-2-security-policy
bbenv-$(CONFIG_DEFAULT_ENVIRONMENT_GENERIC) += defaultenv-1
/env/bin/init
diff --git a/common/Kconfig b/common/Kconfig
index eb2fb1da1e0919b6e7d5e868c48ad2e195cd8aa8..d923d4c4b6283878e487232a5b43487e3f2d9a4a 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -1068,6 +1068,11 @@ config DEFAULT_ENVIRONMENT_GENERIC_NEW_REBOOT_MODE
depends on DEFAULT_ENVIRONMENT_GENERIC_NEW
depends on REBOOT_MODE
+config DEFAULT_ENVIRONMENT_GENERIC_NEW_SECURITY_POLICY
+ bool "Update PS1 according to active security policy"
+ depends on DEFAULT_ENVIRONMENT_GENERIC_NEW
+ depends on SECURITY_POLICY
+
config DEFAULT_ENVIRONMENT_GENERIC_NEW_IKCONFIG
bool "Ship .config as /env/data/config"
depends on DEFAULT_ENVIRONMENT_GENERIC_NEW
diff --git a/defaultenv/Makefile b/defaultenv/Makefile
index 1eaca9f41087fdb893575db1ab2bf1f267185435..ab88ed739305d4157d6ec124b5330f002c577340 100644
--- a/defaultenv/Makefile
+++ b/defaultenv/Makefile
@@ -4,6 +4,7 @@ bbenv-$(CONFIG_DEFAULT_ENVIRONMENT_GENERIC_NEW) += defaultenv-2-base
bbenv-$(CONFIG_DEFAULT_ENVIRONMENT_GENERIC_NEW_MENU) += defaultenv-2-menu
bbenv-$(CONFIG_DEFAULT_ENVIRONMENT_GENERIC_NEW_DFU) += defaultenv-2-dfu
bbenv-$(CONFIG_DEFAULT_ENVIRONMENT_GENERIC_NEW_REBOOT_MODE) += defaultenv-2-reboot-mode
+bbenv-$(CONFIG_DEFAULT_ENVIRONMENT_GENERIC_NEW_SECURITY_POLICY) += defaultenv-2-security-policy
bbenv-$(CONFIG_DEFAULT_ENVIRONMENT_GENERIC) += defaultenv-1
obj-$(CONFIG_DEFAULT_ENVIRONMENT) += defaultenv.o
extra-y += barebox_default_env barebox_default_env.h barebox_default_env$(DEFAULT_COMPRESSION_SUFFIX) barebox_zero_env
diff --git a/defaultenv/defaultenv-2-security-policy/bin/ps1-policy b/defaultenv/defaultenv-2-security-policy/bin/ps1-policy
new file mode 100755
index 0000000000000000000000000000000000000000..5c8b26415d77062495471aa89f7e1b403165d9cf
--- /dev/null
+++ b/defaultenv/defaultenv-2-security-policy/bin/ps1-policy
@@ -0,0 +1,20 @@
+if [ -n "$security.policy" ]; then
+ if [ "$security.policy" = "devel" ]; then
+ PS1_policy_color="$YELLOW"
+ elif [ "$security.policy" = "factory" ]; then
+ PS1_policy_color="$PINK"
+ elif [ "$security.policy" = "lockdown" ]; then
+ PS1_policy_color="$RED"
+ elif [ "$security.policy" = "tamper" ]; then
+ PS1_policy_color="$RED_INV"
+ elif [ "$security.policy" = "return" ]; then
+ PS1_policy_color="$PINK_INV"
+ elif [[ "$security.policy" = "debug*" ]]; then
+ PS1_policy_color="$CYAN"
+ else
+ PS1_policy_color="$NC"
+ fi
+
+ . /env/init/ps1
+ export PS1="(${PS1_policy_color}${security.policy}${NC}) $PS1"
+fi
diff --git a/defaultenv/defaultenv-2-security-policy/init/ps1-policy b/defaultenv/defaultenv-2-security-policy/init/ps1-policy
new file mode 100644
index 0000000000000000000000000000000000000000..a76cd7fd17288da03ca7515f1422f9c596e90dcb
--- /dev/null
+++ b/defaultenv/defaultenv-2-security-policy/init/ps1-policy
@@ -0,0 +1 @@
+PROMPT_COMMAND=". /env/bin/ps1-policy"
diff --git a/defaultenv/defaultenv-2-security-policy/init/source-colors b/defaultenv/defaultenv-2-security-policy/init/source-colors
new file mode 100644
index 0000000000000000000000000000000000000000..3df8e02b0ebca4d0de41bf1a3ca3908650719dd1
--- /dev/null
+++ b/defaultenv/defaultenv-2-security-policy/init/source-colors
@@ -0,0 +1 @@
+. /env/data/ansi-colors
diff --git a/defaultenv/defaultenv.c b/defaultenv/defaultenv.c
index 2567653751cb36b3bb6b1a577360738bc3e0a30a..d6cca466a6835da0896823b1f8858d702a10770e 100644
--- a/defaultenv/defaultenv.c
+++ b/defaultenv/defaultenv.c
@@ -49,6 +49,8 @@ static void defaultenv_add_base(void)
defaultenv_append_directory(defaultenv_2_dfu);
if (IS_ENABLED(CONFIG_DEFAULT_ENVIRONMENT_GENERIC_NEW_REBOOT_MODE))
defaultenv_append_directory(defaultenv_2_reboot_mode);
+ if (IS_ENABLED(CONFIG_DEFAULT_ENVIRONMENT_GENERIC_NEW_SECURITY_POLICY))
+ defaultenv_append_directory(defaultenv_2_security_policy);
if (IS_ENABLED(CONFIG_DEFAULT_ENVIRONMENT_GENERIC_NEW_IKCONFIG))
defaultenv_append_directory(defaultenv_2_ikconfig);
if (IS_ENABLED(CONFIG_DEFAULT_ENVIRONMENT_GENERIC))
--
2.47.3
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH v2 07/24] security: policy: support externally provided configs
2025-09-17 13:53 [PATCH v2 00/24] Add security policy support Sascha Hauer
` (5 preceding siblings ...)
2025-09-17 13:53 ` [PATCH v2 06/24] defaultenv: update PS1 according to security policy Sascha Hauer
@ 2025-09-17 13:53 ` Sascha Hauer
2025-09-17 13:53 ` [PATCH v2 08/24] commands: implement sconfig command Sascha Hauer
` (18 subsequent siblings)
25 siblings, 0 replies; 31+ messages in thread
From: Sascha Hauer @ 2025-09-17 13:53 UTC (permalink / raw)
To: BAREBOX; +Cc: Ahmad Fatoum, Ahmad Fatoum
From: Ahmad Fatoum <a.fatoum@barebox.org>
The enforcement of security policies to be up-to-date and removal of
implicit syncing nudges users into checking in the actual security
policy into version control. To allow the policies to live outside the
barebox tree, introduce CONFIG_SECURITY_POLICY_PATH that takes a
space-separated list of configs.
For now, the option is very strict: All files referenced must be placed
into security/ in the barebox source directory. Different build rules
sharing the same source directory can install their configs with
different names and customize via CONFIG_SECURITY_POLICY_PATH which options
to include.
sconfigpost also supports iterating over directories, but this feature
is left out for now, as it needs more extensive testing to verify that
targets are rebuilt as often as needed and not more.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
security/Kconfig.policy | 15 +++++++++++++++
security/Makefile | 37 +++++++++++++++++++++++++++++++++++++
security/policy.c | 3 +++
3 files changed, 55 insertions(+)
diff --git a/security/Kconfig.policy b/security/Kconfig.policy
index 9ea52e91dad3f2c97768fc804203ddc0cad36f79..1f3becd4fba7ee94d4b24980fa0f54ad3cba675a 100644
--- a/security/Kconfig.policy
+++ b/security/Kconfig.policy
@@ -83,6 +83,21 @@ config SECURITY_POLICY_PATH
Absolute paths are disallowed.
+config SECURITY_POLICY_PATH
+ string
+ depends on SECURITY_POLICY
+ prompt "Paths to additional security policies"
+ help
+ Space separated list of security policies that should be
+ compiled into barebox and registered. This option currently
+ requires each security policy to match security/*.sconfig, i.e.
+ be directly located in the security/ directory of the source
+ source tree and have the .sconfig extension.
+ If left empty, only security policies explicitly provided
+ and registered by board code will be available.
+
+ Absolute paths are disallowed.
+
config SECURITY_POLICY_NAMES
bool
diff --git a/security/Makefile b/security/Makefile
index 16b328266a1b35861ee263e8026fc8ebd704aedb..1096cbfb9b16eef1e98c8301762acf4ef1ba4c17 100644
--- a/security/Makefile
+++ b/security/Makefile
@@ -8,6 +8,9 @@ obj-pbl-$(CONFIG_HAVE_OPTEE) += optee.o
obj-$(CONFIG_BLOBGEN) += blobgen.o
obj-$(CONFIG_PASSWORD) += password.o
+# Default password handling
+# ---------------------------------------------------------------------------
+#
ifdef CONFIG_PASSWORD
ifeq ($(CONFIG_PASSWORD_DEFAULT),"")
@@ -29,3 +32,37 @@ include/generated/passwd.h: FORCE
$(obj)/password.o: include/generated/passwd.h
endif # CONFIG_PASSWORD
+
+# External security policy handling
+# ---------------------------------------------------------------------------
+
+external-policy := $(foreach p, \
+ $(call remove_quotes,$(CONFIG_SECURITY_POLICY_PATH)), \
+ $(p:security/%=%))
+
+external-policy-tmp := $(addsuffix .tmp,$(external-policy))
+real-external-policy-tmp := $(addprefix $(obj)/,$(external-policy-tmp))
+
+ifneq ($(external-policy),)
+obj-y += default.sconfig.o
+extra-y += default.sconfig.c
+always-y += policy-list
+$(foreach p, $(external-policy), \
+ $(if $(findstring /,$p),$(error \
+ CONFIG_SECURITY_POLICY_PATH contains path separators.\
+ $(newline)"$p" must start with security/)))
+$(foreach p, $(external-policy), \
+ $(if $(wildcard $(srctree)/$(src)/$p),,$(error \
+ CONFIG_SECURITY_POLICY_PATH contains non-existent files.\
+ $(newline)"$p" does not exist in $$(srctree)/security)))
+endif
+
+$(obj)/policy-list: $(addprefix $(src)/,$(external-policy)) FORCE
+ $(call if_changed,gen_order_src)
+
+targets += $(external-policy-tmp)
+
+$(obj)/default.sconfig.c: $(real-external-policy-tmp) FORCE
+ +$(Q)$(foreach p, $(real-external-policy-tmp), \
+ $(call noop_cmd,security_checkconfig,$p) ;)
+ $(call if_changed_dep,sconfigpost_c,$(real-external-policy-tmp))
diff --git a/security/policy.c b/security/policy.c
index 0984bb6555cc2417ace290af8db7b6a5b6da0d86..44e58157d8416665117096df75edf5688d032106 100644
--- a/security/policy.c
+++ b/security/policy.c
@@ -231,6 +231,9 @@ static int security_init(void)
dev_add_param_string(&security_device, "policy", param_set_readonly,
security_policy_get_name, &policy_name, NULL);
+ if (*CONFIG_SECURITY_POLICY_PATH)
+ security_policy_add(default);
+
return 0;
}
pure_initcall(security_init);
--
2.47.3
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH v2 08/24] commands: implement sconfig command
2025-09-17 13:53 [PATCH v2 00/24] Add security policy support Sascha Hauer
` (6 preceding siblings ...)
2025-09-17 13:53 ` [PATCH v2 07/24] security: policy: support externally provided configs Sascha Hauer
@ 2025-09-17 13:53 ` Sascha Hauer
2025-09-17 13:53 ` [PATCH v2 09/24] docs: security-policies: add documentation Sascha Hauer
` (17 subsequent siblings)
25 siblings, 0 replies; 31+ messages in thread
From: Sascha Hauer @ 2025-09-17 13:53 UTC (permalink / raw)
To: BAREBOX; +Cc: Ahmad Fatoum
The sconfig command provides a convenient interface to test the new
security policy support. It allows inspecting available policies
and optionally switching between them and enabling/disabling them
piecewise for interactive testing of code that is gated behind these
security options.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de
Co-developed-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
commands/Kconfig | 23 +++++
commands/Makefile | 1 +
commands/sconfig.c | 227 ++++++++++++++++++++++++++++++++++++++++++++++
include/security/policy.h | 4 +
4 files changed, 255 insertions(+)
diff --git a/commands/Kconfig b/commands/Kconfig
index 1626912c30bd688d8a900738b40acf6def70d9df..d28f8a6c75054d9b231b88d6be15d90092b8cbd2 100644
--- a/commands/Kconfig
+++ b/commands/Kconfig
@@ -2288,6 +2288,29 @@ endmenu
menu "Security"
+config CMD_SCONFIG
+ depends on SECURITY_POLICY
+ select SECURITY_POLICY_NAMES
+ default y
+ bool "sconfig"
+ help
+ Interact with security policies. By default, this only
+ allows read-access and not selection of new policies
+
+config CMD_SCONFIG_MODIFY
+ depends on CMD_SCONFIG
+ select HAS_INSECURE_DEFAULTS
+ bool "support policy modification"
+ help
+ Say y here if you are developing and want to extend the sconfig
+ command to support selecting a different active policy and
+ modifying it.
+
+ This is an very priviliged operation and the recommendation is
+ to hardcode policy transitions in board code and not from scripts.
+
+ Say n here if unsure.
+
config CMD_AVB_PVALUE
depends on OPTEE_AVB_PERSISTENT_VALUES
tristate
diff --git a/commands/Makefile b/commands/Makefile
index d9403b18d582f0fac042cef57c88aa4a49f6c8a3..c1f1162c2fdd15b455a7b2f8a47cc187c17510d6 100644
--- a/commands/Makefile
+++ b/commands/Makefile
@@ -166,4 +166,5 @@ obj-$(CONFIG_CMD_STACKSMASH) += stacksmash.o
obj-$(CONFIG_CMD_PARTED) += parted.o
obj-$(CONFIG_CMD_EFI_HANDLE_DUMP) += efi_handle_dump.o
obj-$(CONFIG_CMD_HOST) += host.o
+obj-$(CONFIG_CMD_SCONFIG) += sconfig.o
UBSAN_SANITIZE_ubsan.o := y
diff --git a/commands/sconfig.c b/commands/sconfig.c
new file mode 100644
index 0000000000000000000000000000000000000000..02c3a6b1ed9b75f9e27b096dd5bf27c94b7f7f05
--- /dev/null
+++ b/commands/sconfig.c
@@ -0,0 +1,227 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/kernel.h>
+#include <command.h>
+#include <environment.h>
+#include <getopt.h>
+#include <globalvar.h>
+#include <linux/ctype.h>
+#include <stdio.h>
+
+#include <security/policy.h>
+#include <security/config.h>
+
+#define RED "\e[1;31m"
+#define GREEN "\e[1;32m"
+#define YELLOW "\e[1;33m"
+#define PINK "\e[1;35m"
+#define CYAN "\e[1;36m"
+#define NC "\e[0m"
+
+static struct security_policy *last_override;
+static int debug_iteration;
+static struct notifier_block sconfig_notifier;
+
+static const char *red, *green, *nc;
+
+static void sconfig_print(const struct security_policy *policy)
+{
+ for (int i = 0; i < SCONFIG_NUM; i++) {
+ bool allow = is_allowed(policy, i);
+
+ printf("[%s%s%s] %s\n", allow ? green : red,
+ allow ? "✓" : "✗", nc, sconfig_names[i]);
+ }
+}
+
+static int sconfig_command_notify(struct notifier_block *nb,
+ unsigned long opt, void *unused)
+{
+ bool allow = is_allowed(NULL, opt);
+
+ printf("%s%s%s%s\n", allow ? green : red, allow ? "+" : "-", nc,
+ sconfig_names[opt]);
+
+ return 0;
+}
+
+static int do_sconfig_flags(int argc, char *argv[])
+{
+ const struct security_policy *policy;
+ const char *set = NULL;
+ int ret = 0, opt;
+
+ while ((opt = getopt(argc, argv, "li:vs:")) > 0) {
+ switch (opt) {
+ case 'l':
+ security_policy_list();
+ break;
+ case 'i':
+ policy = security_policy_get(optarg);
+ if (!policy) {
+ ret = -ENOENT;
+ goto out;
+ }
+
+ sconfig_print(policy);
+ break;
+ case 'v':
+ if (!IS_ENABLED(CONFIG_CMD_SCONFIG_MODIFY))
+ return COMMAND_ERROR_USAGE;
+ sconfig_register_handler(&sconfig_notifier,
+ sconfig_command_notify);
+ break;
+ case 's':
+ if (!IS_ENABLED(CONFIG_CMD_SCONFIG_MODIFY))
+ return COMMAND_ERROR_USAGE;
+ set = optarg;
+ break;
+ default:
+ ret = COMMAND_ERROR_USAGE;
+ goto out;
+ }
+ }
+
+ if (argc != optind) {
+ ret = COMMAND_ERROR_USAGE;
+ goto out;
+ }
+
+ if (set) {
+ policy = security_policy_get(set);
+ if (!policy) {
+ printf("Policy '%s' not found\n", set);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ ret = security_policy_activate(policy);
+ }
+out:
+ if (sconfig_notifier.notifier_call) {
+ sconfig_unregister_handler(&sconfig_notifier);
+ sconfig_notifier.notifier_call = NULL;
+ }
+
+ return ret;
+}
+
+static struct security_policy *alloc_policy(void)
+{
+ struct security_policy *override;
+
+ override = xmalloc(sizeof(*override));
+
+ if (active_policy)
+ memcpy(override->policy, active_policy->policy,
+ sizeof(override->policy));
+ else
+ memset(override->policy, 0x1, sizeof(override->policy));
+
+ override->name = xasprintf("debug%u", debug_iteration++);
+ override->chained = false;
+
+ return override;
+}
+
+static void free_policy(struct security_policy *policy)
+{
+ security_policy_unregister_one(policy);
+ free(policy);
+}
+
+static int do_sconfig(int argc, char *argv[])
+{
+ struct security_policy *override;
+ bool allow_color;
+ int i, ret;
+
+ allow_color = !streq_ptr(globalvar_get("allow_color"), "0");
+ if (allow_color) {
+ red = RED;
+ green = GREEN;
+ nc = NC;
+ } else {
+ red = green = nc = "";
+ }
+
+ if (argc == 1) {
+ if (active_policy)
+ printf("Active Policy: %s\n\n", active_policy->name);
+ else
+ printf("No Policy is Active\n\n");
+
+ sconfig_print(NULL);
+ return 0;
+ }
+
+ for (i = 1; i < argc; i++) {
+ if ((*argv[i] != '-' && *argv[i] != '+' ) ||
+ !strstarts(argv[i] + 1, "SCONFIG_"))
+ return do_sconfig_flags(argc, argv);;
+ }
+
+ if (!IS_ENABLED(CONFIG_CMD_SCONFIG_MODIFY)) {
+ printf("Runtime security policy modification disallowed\n");
+ return COMMAND_ERROR_USAGE;
+ }
+
+ override = alloc_policy();
+
+ for (i = 1; i < argc; i++) {
+ char ch_action = *argv[i];
+ enum security_config_option sopt;
+
+ ret = sconfig_lookup(argv[i] + 1);
+ if (ret < 0) {
+ printf("No such option: %s\n", argv[i] + 1);
+ return ret;
+ }
+
+ sopt = ret;
+
+ switch (ch_action) {
+ case '+':
+ override->policy[sopt] = true;
+ break;
+ case '-':
+ override->policy[sopt] = false;
+ break;
+ default:
+ return COMMAND_ERROR_USAGE;
+ }
+ }
+
+ __security_policy_register(override);
+
+ ret = security_policy_activate(override);
+ if (ret) {
+ free_policy(override);
+ return ret;
+ }
+
+ free_policy(last_override);
+ last_override = override;
+
+ return 0;
+}
+
+BAREBOX_CMD_HELP_START(sconfig)
+BAREBOX_CMD_HELP_TEXT("Interact with security policies")
+BAREBOX_CMD_HELP_TEXT("")
+BAREBOX_CMD_HELP_TEXT("Options:")
+BAREBOX_CMD_HELP_OPT ("-l", "list registered security policies")
+BAREBOX_CMD_HELP_OPT ("-i POLICY", "show security options of specified POLICY")
+#ifdef CONFIG_CMD_SCONFIG_MODIFY
+BAREBOX_CMD_HELP_OPT ("-v", "verbose output: report options as they are modified")
+BAREBOX_CMD_HELP_OPT ("-s POLICY", "select specified POLICY")
+#endif
+BAREBOX_CMD_HELP_END
+
+BAREBOX_CMD_START(sconfig)
+ .cmd = do_sconfig,
+ BAREBOX_CMD_DESC("interact with security policies")
+ BAREBOX_CMD_OPTS("[-vlsi] [<+->SCONFIG_*]...")
+ BAREBOX_CMD_GROUP(CMD_GRP_SECURITY)
+ BAREBOX_CMD_HELP(cmd_sconfig_help)
+BAREBOX_CMD_END
diff --git a/include/security/policy.h b/include/security/policy.h
index 6f270793bc80b03966c1b47fe9c44c9bfb9263a5..c41220ef3b96fb78862ae28340e41221f3c97781 100644
--- a/include/security/policy.h
+++ b/include/security/policy.h
@@ -42,6 +42,10 @@ static inline int __security_policy_register(const struct security_policy policy
}
#endif
+#ifdef CONFIG_CMD_SCONFIG
+void security_policy_unregister_one(const struct security_policy *policy);
+#endif
+
#define security_policy_add(name) ({ \
extern const struct security_policy __policy_##name[]; \
__security_policy_register(__policy_##name); \
--
2.47.3
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH v2 09/24] docs: security-policies: add documentation
2025-09-17 13:53 [PATCH v2 00/24] Add security policy support Sascha Hauer
` (7 preceding siblings ...)
2025-09-17 13:53 ` [PATCH v2 08/24] commands: implement sconfig command Sascha Hauer
@ 2025-09-17 13:53 ` Sascha Hauer
2025-09-17 13:53 ` [PATCH v2 10/24] commands: go: add security config option Sascha Hauer
` (16 subsequent siblings)
25 siblings, 0 replies; 31+ messages in thread
From: Sascha Hauer @ 2025-09-17 13:53 UTC (permalink / raw)
To: BAREBOX; +Cc: Ahmad Fatoum, Ahmad Fatoum
From: Ahmad Fatoum <a.fatoum@barebox.org>
Let's add some first documentation for the newly added security policy
support.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
Documentation/devel/devel.rst | 1 +
Documentation/devel/security-policies.rst | 96 ++++++++++++++++++++++
Documentation/user/security-policies.rst | 131 ++++++++++++++++++++++++++++++
Documentation/user/user-manual.rst | 1 +
4 files changed, 229 insertions(+)
diff --git a/Documentation/devel/devel.rst b/Documentation/devel/devel.rst
index b90805263bbd669891979b3323ba3797b4e191b1..84074d142e031ef7bde515151e2d513d215f3293 100644
--- a/Documentation/devel/devel.rst
+++ b/Documentation/devel/devel.rst
@@ -13,6 +13,7 @@ Contents:
troubleshooting
filesystems
background-execution
+ security-policies
project-ideas
fuzzing
diff --git a/Documentation/devel/security-policies.rst b/Documentation/devel/security-policies.rst
new file mode 100644
index 0000000000000000000000000000000000000000..8d0b5e7fde37f1893b8ddb8acd29f7eed9fc5a6c
--- /dev/null
+++ b/Documentation/devel/security-policies.rst
@@ -0,0 +1,96 @@
+.. _develop_security-policies:
+
+Security Policies (Developer Manual)
+====================================
+
+Overview
+--------
+
+This document describes how to define new SConfig symbols and integrate them
+into Barebox security policies. SConfig uses the same backend as Kconfig, and
+its configuration files live alongside Kconfig files (e.g. ``common/Sconfig``).
+
+Key principles:
+
+- Except for the name, symbols are always ``bool``.
+- Policies are board-specific and described in ``.sconfig`` files at build-time.
+- Every policy is complete and no implicit defaults are applied by mere building
+- Policy ``.sconfig`` files are post-processed into ``.sconfig.c`` files and
+ then compiled and linked into the final barebox binary.
+
+Creating New Symbols
+--------------------
+
+1. **Add a new symbol** to the appropriate ``Sconfig`` file, such as ``common/Sconfig``:
+
+ .. code-block:: kconfig
+
+ config ENV_HANDLING
+ bool "Allow persisting and loading the environment from storage"
+ depends on $(kconfig-enabled ENV_HANDLING)
+
+2. **Reference it in code** using:
+
+ .. code-block:: c
+
+ #include <security/config.h>
+
+ if (!IS_ALLOWED(SCONFIG_ENV_HANDLING))
+ return -EPERM;
+
+3. **Update policies**:
+
+ Every existing ``.sconfig`` policy must define a value for the new symbol
+ as there are no implicit defaults to ensure every policy explicitly encodes
+ all options in accordance with its security requirements.
+
+ Example in ``myboard-lockdown.sconfig``:
+
+ .. code-block:: none
+
+ SCONFIG_ENV_HANDLING=n
+
+ And in ``myboard-devel.sconfig``:
+
+ .. code-block:: none
+
+ SCONFIG_ENV_HANDLING=y
+
+Linking Policy Files
+--------------------
+
+Policies can be added to the build using ``policy-y`` in the board’s
+Makefile:
+
+.. code-block:: make
+
+ policy-y += myboard-lockdown.sconfig
+
+As policies are enforced to be complete, they may require resynchronization
+(e.g., with ``make olddefconfig``) if the config changes. A build failure
+will alert the user to this fact.
+
+``virt32_secure_defconfig`` is maintained as reference configuration for
+trying out security policies and that it's buildable is ensured by CI.
+
+Tips for Symbol Design
+----------------------
+
+- Avoid naming symbols after board names. Favor functionality.
+- Prefer giving Sconfig symbols the same name as Kconfig symbols, when they
+ address the same goal, but at runtime instead of build-time.
+- When possible, reuse logic in core code by wrapping around
+ ``IS_ALLOWED()`` checks.
+
+Validation & Maintenance
+------------------------
+
+Always run ``make security_olddconfig`` for the security policy reference
+configuration ``virt32_policy_defconfig``::
+
+ export ARCH=arm
+ export CROSS_COMPILE=...
+ make virt32_policy_defconfig
+ make security_olddefconfig
+
+CI also checks this configuration and verifies that it's up-to-date.
diff --git a/Documentation/user/security-policies.rst b/Documentation/user/security-policies.rst
new file mode 100644
index 0000000000000000000000000000000000000000..ba458b10b34bb75ab817c6e1a97272ea7463e37e
--- /dev/null
+++ b/Documentation/user/security-policies.rst
@@ -0,0 +1,131 @@
+.. _use_security-policies:
+
+Security Policies (User Manual)
+===============================
+
+Overview
+--------
+
+Barebox supports structured security configuration through **security policies**,
+a runtime configuration mechanism that allows switching between multiple
+predefined security policies (e.g. ``lockdown``, ``devel``),
+depending on operational requirements.
+
+This replaces ad-hoc board code with a clean, reproducible, and
+auditable configuration-based model.
+
+Concepts
+--------
+
+- **SConfig**: A configuration system using the same backend as
+ Kconfig, designed for **runtime security policies**.
+- **Policies**: Named configurations like ``myboard-lockdown.sconfig``,
+ ``myboard-open.sconfig`` specific to each board.
+
+Usage
+-----
+
+1. **Configure a policy** using menuconfig (or another frontend):
+
+ .. code-block:: shell
+
+ make KPOLICY=arch/arm/boards/myboard/myboard-lockdown.sconfig security_oldconfig
+ make security_menuconfig # Iterates over all policies
+
+2. **Configuration files** (e.g. ``myboard-lockdown.sconfig``) are in Kconfig
+ format with ``SCONFIG_``-prefixed entries.
+
+3. **Build integration**:
+
+ The sconfig files for the board are placed into the ``security/``
+ directory in the source tree and their relative file names
+ (i.e., with the ``security/`` prefix) are added to
+ ``CONFIG_SECURITY_POLICY_PATH``.
+
+ Alternatively, policies can also be be referenced in a board's
+ Makefile::
+
+ .. code-block:: make
+
+ lwl-y += lowlevel.o
+ obj-y += board.o
+ policy-y += myboard-lockdown.sconfig myboard-devel.sconfig
+
+ This latter method can be useful when building multiple boards in
+ the same build, but with different security policies.
+
+4. **Registration**:
+
+ Policies added with ``CONFIG_SECURITY_POLICY_PATH`` are automatically
+ registered for all enabled boards.
+
+ Policies added with policy-y need to be explicitly added by symbol
+ to the set of registered policies in board code:
+
+ .. code-block:: c
+
+ #include <security/policy.h>
+
+ security_policy_add(myboard_lockdown)
+ security_policy_add(myboard_devel)
+
+5. **Runtime selection**:
+
+ In board code, switch to a policy by name:
+
+ .. code-block:: c
+
+ #include <security/policy.h>
+
+ security_policy_select("lockdown");
+
+Limitations
+-----------
+
+Always start with the most restrictive policy and switch to more permissive policies later
+when needed. Forbidding previously allowed options might have undesired side effects which
+include:
+
+- Forbidding mounting of file systems does not affect already mounted file systems
+- Forbidding shell does not affect the already running instance
+
+Trying it out
+-------------
+
+``virt32_secure_defconfig`` is the current reference platform for security
+policy development and evaluation. ``images/barebox-dt-2nd.img`` that results
+from building it can be passed as argument to ``qemu-system-arm -M virt -kernel``.
+
+The easiest way to do this is proabably installing labgrid and running
+``pytest --interactive`` after having built the config.
+
+Differences from Kconfig
+------------------------
+
++-------------------------+------------------------------+-----------------------------+
+| Feature | Kconfig | SConfig |
++=========================+==============================+=============================+
+| Purpose | Build-time configuration | Runtime security policy |
++-------------------------+------------------------------+-----------------------------+
+| File name | .config | ${policy}.sconfig |
++-------------------------+------------------------------+-----------------------------+
+| policies per build | One | Multiple |
++-------------------------+------------------------------+-----------------------------+
+| Symbol types | bool, int, string, ... etc. | bool only |
++-------------------------+------------------------------+-----------------------------+
+| Symbol dependencies | Kconfig symbols | Both Kconfig and Sconfig |
+| | | symbols |
++-------------------------+------------------------------+-----------------------------+
+
+Best Practices
+--------------
+
+- Maintain all ``.sconfig`` files under version control,
+ either as part of the barebox patch stack or in your BSP
+
+- Document reasoning when changing every single security option
+ (even when doing ``security_olddefconfig``).
+
+- Avoid logic duplication in board code — rely on SConfig conditionals.
+
+- Name policies meaningfully: e.g. ``lockdown``, ``tamper``, ``return``.
diff --git a/Documentation/user/user-manual.rst b/Documentation/user/user-manual.rst
index ce0792000a3ce68aa3b9dd2ce685ef7b0f40a2d5..cb01721863ddfb133e331487ebb1c6206e4d704c 100644
--- a/Documentation/user/user-manual.rst
+++ b/Documentation/user/user-manual.rst
@@ -29,6 +29,7 @@ Contents:
bootchooser
remote-control
security
+ security-policies
reset-reason
system-reset
state
--
2.47.3
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH v2 10/24] commands: go: add security config option
2025-09-17 13:53 [PATCH v2 00/24] Add security policy support Sascha Hauer
` (8 preceding siblings ...)
2025-09-17 13:53 ` [PATCH v2 09/24] docs: security-policies: add documentation Sascha Hauer
@ 2025-09-17 13:53 ` Sascha Hauer
2025-09-17 13:53 ` [PATCH v2 11/24] console: ratp: " Sascha Hauer
` (15 subsequent siblings)
25 siblings, 0 replies; 31+ messages in thread
From: Sascha Hauer @ 2025-09-17 13:53 UTC (permalink / raw)
To: BAREBOX; +Cc: Ahmad Fatoum
From: Ahmad Fatoum <a.fatoum@pengutronix.de>
The go command doesn't do any signature verification and allows
executing arbitrary code. Add a security option, so a policy can disable
this command at runtime.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
Sconfig | 1 +
commands/Sconfig | 12 ++++++++++++
commands/go.c | 4 ++++
3 files changed, 17 insertions(+)
diff --git a/Sconfig b/Sconfig
index 6cfd8c8677a655c1b238dadc22aa6d40b161596d..1c5b9d70d09f8df47edc48f6ac295501f66df97e 100644
--- a/Sconfig
+++ b/Sconfig
@@ -5,3 +5,4 @@ mainmenu "Barebox Security Configuration"
source "scripts/Sconfig.include"
source "security/Sconfig"
+source "commands/Sconfig"
diff --git a/commands/Sconfig b/commands/Sconfig
new file mode 100644
index 0000000000000000000000000000000000000000..7e6d937e162ce154b3993d03a9103181ea61af5d
--- /dev/null
+++ b/commands/Sconfig
@@ -0,0 +1,12 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+menu "Command Policy"
+
+config CMD_GO
+ bool "Allow go command"
+ depends on $(kconfig-enabled,CMD_GO)
+ help
+ The go command jumps to an arbitrary address after shutting
+ down barebox and does not do any signature verification.
+
+endmenu
diff --git a/commands/go.c b/commands/go.c
index 3449a2181ad076e30ea96f016245806a59d657c4..640911d90db28c0dc60b713267dcab14627c793c 100644
--- a/commands/go.c
+++ b/commands/go.c
@@ -11,6 +11,7 @@
#include <getopt.h>
#include <linux/ctype.h>
#include <errno.h>
+#include <security/config.h>
#define INT_ARGS_MAX 4
@@ -24,6 +25,9 @@ static int do_go(int argc, char *argv[])
ulong arg[INT_ARGS_MAX] = {};
bool pass_argv = true;
+ if (!IS_ALLOWED(SCONFIG_CMD_GO))
+ return -EPERM;
+
while ((opt = getopt(argc, argv, "+si")) > 0) {
switch (opt) {
case 's':
--
2.47.3
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH v2 11/24] console: ratp: add security config option
2025-09-17 13:53 [PATCH v2 00/24] Add security policy support Sascha Hauer
` (9 preceding siblings ...)
2025-09-17 13:53 ` [PATCH v2 10/24] commands: go: add security config option Sascha Hauer
@ 2025-09-17 13:53 ` Sascha Hauer
2025-09-17 13:53 ` [PATCH v2 12/24] bootm: support calling bootm_optional_signed_images at any time Sascha Hauer
` (14 subsequent siblings)
25 siblings, 0 replies; 31+ messages in thread
From: Sascha Hauer @ 2025-09-17 13:53 UTC (permalink / raw)
To: BAREBOX; +Cc: Ahmad Fatoum
From: Ahmad Fatoum <a.fatoum@pengutronix.de>
For secure systems that disable the regular console, RATP should be
disabled as well, so add an option to do so.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
Sconfig | 1 +
common/Sconfig | 9 +++++++++
common/console.c | 4 +++-
common/ratp/ratp.c | 17 +++++++++++++++++
4 files changed, 30 insertions(+), 1 deletion(-)
diff --git a/Sconfig b/Sconfig
index 1c5b9d70d09f8df47edc48f6ac295501f66df97e..f1ae5c7a1482058d170f99c75b706f66a954a9cb 100644
--- a/Sconfig
+++ b/Sconfig
@@ -5,4 +5,5 @@ mainmenu "Barebox Security Configuration"
source "scripts/Sconfig.include"
source "security/Sconfig"
+source "common/Sconfig"
source "commands/Sconfig"
diff --git a/common/Sconfig b/common/Sconfig
new file mode 100644
index 0000000000000000000000000000000000000000..479ac5cdf2e560a638d39abbc9f91afe2edd7403
--- /dev/null
+++ b/common/Sconfig
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+menu "General Settings"
+
+config RATP
+ bool "Allow remote control via RATP"
+ depends on $(kconfig-enabled,CONSOLE_RATP)
+
+endmenu
diff --git a/common/console.c b/common/console.c
index a31433a659e2b5d7376c7a6da287478441e5d618..ceecb8730e55422b78eea7204dc9b9a70cf97212 100644
--- a/common/console.c
+++ b/common/console.c
@@ -5,6 +5,7 @@
*/
#include <config.h>
+#include <security/config.h>
#include <common.h>
#include <stdarg.h>
#include <malloc.h>
@@ -492,7 +493,8 @@ static int getc_raw(void)
if (cdev->tstc(cdev)) {
int ch = cdev->getc(cdev);
- if (IS_ENABLED(CONFIG_RATP) && ch == 0x01) {
+ if (IS_ENABLED(CONFIG_RATP) && ch == 0x01 &&
+ IS_ALLOWED(SCONFIG_RATP)) {
barebox_ratp(cdev);
return -1;
}
diff --git a/common/ratp/ratp.c b/common/ratp/ratp.c
index 2906f5a09098bd1aa61e7450a035a0e7b2327195..f2735fa885315f95b7a754d12de04c15b36fa822 100644
--- a/common/ratp/ratp.c
+++ b/common/ratp/ratp.c
@@ -14,6 +14,7 @@
#define pr_fmt(fmt) "barebox-ratp: " fmt
#include <common.h>
+#include <security/config.h>
#include <command.h>
#include <malloc.h>
#include <init.h>
@@ -46,6 +47,7 @@ struct ratp_ctx {
struct ratp_bb_pkt *fs_rx;
+ struct sconfig_notifier_block sconfig_notifier;
struct poller_struct poller;
struct work_queue wq;
@@ -456,11 +458,22 @@ static void ratp_work_cancel(struct work_struct *w)
free(rw);
}
+static void barebox_ratp_sconfig_update(struct sconfig_notifier_block *nb,
+ enum security_config_option opt,
+ bool allowed)
+{
+ if (!allowed && ratp_ctx)
+ ratp_unregister(ratp_ctx);
+}
+
int barebox_ratp(struct console_device *cdev)
{
int ret;
struct ratp_ctx *ctx;
+ if (!IS_ALLOWED(SCONFIG_RATP))
+ return -EPERM;
+
if (!cdev->getc || !cdev->putc)
return -EINVAL;
@@ -515,6 +528,10 @@ int barebox_ratp(struct console_device *cdev)
console_set_active(&ctx->ratp_console, CONSOLE_STDOUT | CONSOLE_STDERR |
CONSOLE_STDIN);
+ sconfig_register_handler_filtered(&ctx->sconfig_notifier,
+ barebox_ratp_sconfig_update,
+ SCONFIG_RATP);
+
return 0;
out:
--
2.47.3
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH v2 12/24] bootm: support calling bootm_optional_signed_images at any time
2025-09-17 13:53 [PATCH v2 00/24] Add security policy support Sascha Hauer
` (10 preceding siblings ...)
2025-09-17 13:53 ` [PATCH v2 11/24] console: ratp: " Sascha Hauer
@ 2025-09-17 13:53 ` Sascha Hauer
2025-09-17 13:53 ` [PATCH v2 13/24] bootm: make unsigned image support runtime configurable Sascha Hauer
` (13 subsequent siblings)
25 siblings, 0 replies; 31+ messages in thread
From: Sascha Hauer @ 2025-09-17 13:53 UTC (permalink / raw)
To: BAREBOX; +Cc: Ahmad Fatoum
From: Ahmad Fatoum <a.fatoum@pengutronix.de>
bootm_init is a late initcall and thus the code has the implicit
assumption that bootm_force_signed_images is called after it runs.
Rework the code to allow calling the function at any time.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
common/bootm.c | 32 +++++++++++++++++++++++---------
1 file changed, 23 insertions(+), 9 deletions(-)
diff --git a/common/bootm.c b/common/bootm.c
index 15b18c12faa1856e08e30f59a5c2151558f20ec3..755c9358ce3a17c8ce37a9db13cf18d0aea1b5e7 100644
--- a/common/bootm.c
+++ b/common/bootm.c
@@ -116,12 +116,22 @@ static const char * const bootm_verify_names[] = {
static bool force_signed_images = IS_ENABLED(CONFIG_BOOTM_FORCE_SIGNED_IMAGES);
-void bootm_force_signed_images(void)
+static void bootm_optional_signed_images(void)
{
- static unsigned int verify_mode = 0;
+ /* This function should not be exported */
+ BUG_ON(force_signed_images);
- if (force_signed_images)
- return;
+ globalvar_remove("bootm.verify");
+ /* recreate bootm.verify with a single enumeration as option */
+ globalvar_add_simple_enum("bootm.verify", (unsigned int *)&bootm_verify_mode,
+ bootm_verify_names, ARRAY_SIZE(bootm_verify_names));
+
+ bootm_verify_mode = BOOTM_VERIFY_AVAILABLE;
+}
+
+static void bootm_require_signed_images(void)
+{
+ static unsigned int verify_mode = 0;
/* recreate bootm.verify with a single enumeration as option */
globalvar_remove("bootm.verify");
@@ -129,6 +139,11 @@ void bootm_force_signed_images(void)
&bootm_verify_names[BOOTM_VERIFY_SIGNATURE], 1);
bootm_verify_mode = BOOTM_VERIFY_SIGNATURE;
+}
+
+void bootm_force_signed_images(void)
+{
+ bootm_require_signed_images();
force_signed_images = true;
}
@@ -1086,14 +1101,13 @@ static int bootm_init(void)
globalvar_add_simple("bootm.initrd.loadaddr", NULL);
}
- if (bootm_signed_images_are_forced())
- bootm_verify_mode = BOOTM_VERIFY_SIGNATURE;
-
globalvar_add_simple_bool("bootm.dryrun", &bootm_dryrun);
globalvar_add_simple_int("bootm.verbose", &bootm_verbosity, "%u");
- globalvar_add_simple_enum("bootm.verify", (unsigned int *)&bootm_verify_mode,
- bootm_verify_names, ARRAY_SIZE(bootm_verify_names));
+ if (bootm_signed_images_are_forced())
+ bootm_require_signed_images();
+ else
+ bootm_optional_signed_images();
if (IS_ENABLED(CONFIG_ROOTWAIT_BOOTARG))
globalvar_add_simple_int("linux.rootwait",
--
2.47.3
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH v2 13/24] bootm: make unsigned image support runtime configurable
2025-09-17 13:53 [PATCH v2 00/24] Add security policy support Sascha Hauer
` (11 preceding siblings ...)
2025-09-17 13:53 ` [PATCH v2 12/24] bootm: support calling bootm_optional_signed_images at any time Sascha Hauer
@ 2025-09-17 13:53 ` Sascha Hauer
2025-09-17 13:53 ` [PATCH v2 14/24] ARM: configs: add virt32_secure_defconfig Sascha Hauer
` (12 subsequent siblings)
25 siblings, 0 replies; 31+ messages in thread
From: Sascha Hauer @ 2025-09-17 13:53 UTC (permalink / raw)
To: BAREBOX; +Cc: Ahmad Fatoum
From: Ahmad Fatoum <a.fatoum@pengutronix.de>
To allow runtime unlocking of a device via security policies, add a new
SCONFIG_BOOT_UNSIGNED_IMAGES option and consult it.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
common/Sconfig | 15 +++++++++++++++
common/bootm.c | 26 +++++++++++++++++++++++++-
2 files changed, 40 insertions(+), 1 deletion(-)
diff --git a/common/Sconfig b/common/Sconfig
index 479ac5cdf2e560a638d39abbc9f91afe2edd7403..edbc4bc028af79e2a72bb86de94ecce5c7b7643d 100644
--- a/common/Sconfig
+++ b/common/Sconfig
@@ -7,3 +7,18 @@ config RATP
depends on $(kconfig-enabled,CONSOLE_RATP)
endmenu
+
+menu "Boot Policy"
+
+config BOOT_UNSIGNED_IMAGES
+ bool "Allow booting unsigned images"
+ depends on $(kconfig-enabled,BOOTM_OPTIONAL_SIGNED_IMAGES)
+ help
+ Say y here if you want to allow booting of images with
+ an invalid signature or no signature at all.
+
+ Systems with verified boot chains should say y here
+ or force it at compile time irrespective of policy
+ with CONFIG_BOOTM_FORCE_SIGNED_IMAGES
+
+endmenu
diff --git a/common/bootm.c b/common/bootm.c
index 755c9358ce3a17c8ce37a9db13cf18d0aea1b5e7..17792b2a1d81a0d0164d9b899093395341475fc9 100644
--- a/common/bootm.c
+++ b/common/bootm.c
@@ -16,8 +16,10 @@
#include <magicvar.h>
#include <uncompress.h>
#include <zero_page.h>
+#include <security/config.h>
static LIST_HEAD(handler_list);
+static struct sconfig_notifier_block sconfig_notifier;
static __maybe_unused struct bootm_overrides bootm_overrides;
@@ -114,6 +116,13 @@ static const char * const bootm_verify_names[] = {
[BOOTM_VERIFY_SIGNATURE] = "signature",
};
+/*
+ * There's three ways to influence whether signed images are forced:
+ * 1) CONFIG_BOOTM_FORCE_SIGNED_IMAGES: forced at compile time
+ * 2) SCONFIG_BOOT_UNSIGNED_IMAGES: determined by the active security policy
+ * 3) bootm_force_signed_images(): forced dynamically by board code.
+ * will be deprecated in favor of 2)
+ */
static bool force_signed_images = IS_ENABLED(CONFIG_BOOTM_FORCE_SIGNED_IMAGES);
static void bootm_optional_signed_images(void)
@@ -141,6 +150,16 @@ static void bootm_require_signed_images(void)
bootm_verify_mode = BOOTM_VERIFY_SIGNATURE;
}
+static void bootm_unsigned_sconfig_update(struct sconfig_notifier_block *nb,
+ enum security_config_option opt,
+ bool allowed)
+{
+ if (!allowed)
+ bootm_require_signed_images();
+ else
+ bootm_optional_signed_images();
+}
+
void bootm_force_signed_images(void)
{
bootm_require_signed_images();
@@ -149,7 +168,7 @@ void bootm_force_signed_images(void)
bool bootm_signed_images_are_forced(void)
{
- return force_signed_images;
+ return force_signed_images || !IS_ALLOWED(SCONFIG_BOOT_UNSIGNED_IMAGES);
}
static int uimage_part_num(const char *partname)
@@ -1109,6 +1128,11 @@ static int bootm_init(void)
else
bootm_optional_signed_images();
+ sconfig_register_handler_filtered(&sconfig_notifier,
+ bootm_unsigned_sconfig_update,
+ SCONFIG_BOOT_UNSIGNED_IMAGES);
+
+
if (IS_ENABLED(CONFIG_ROOTWAIT_BOOTARG))
globalvar_add_simple_int("linux.rootwait",
&linux_rootwait_secs, "%d");
--
2.47.3
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH v2 14/24] ARM: configs: add virt32_secure_defconfig
2025-09-17 13:53 [PATCH v2 00/24] Add security policy support Sascha Hauer
` (12 preceding siblings ...)
2025-09-17 13:53 ` [PATCH v2 13/24] bootm: make unsigned image support runtime configurable Sascha Hauer
@ 2025-09-17 13:53 ` Sascha Hauer
2025-09-17 13:53 ` [PATCH v2 15/24] boards: qemu-virt: add security policies Sascha Hauer
` (11 subsequent siblings)
25 siblings, 0 replies; 31+ messages in thread
From: Sascha Hauer @ 2025-09-17 13:53 UTC (permalink / raw)
To: BAREBOX; +Cc: Ahmad Fatoum
From: Ahmad Fatoum <a.fatoum@pengutronix.de>
The security policy support does not allow for incomplete configs and
thus sconfig files must be refreshed when config options they depend on
changes. This means that a security profile that's up-to-date with
respect to one .config is often outdated with respect to another.
To allow easy development and experimentation, let's make 32-bit ARM
Qemu Virt our reference platform and add a new config for it.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
arch/arm/configs/virt32_secure_defconfig | 301 +++++++++++++++++++++++++++++++
test/arm/virt32_secure_defconfig.yaml | 20 ++
2 files changed, 321 insertions(+)
diff --git a/arch/arm/configs/virt32_secure_defconfig b/arch/arm/configs/virt32_secure_defconfig
new file mode 100644
index 0000000000000000000000000000000000000000..34cc49405495b33b4f78e078dfbcd951c433fcd8
--- /dev/null
+++ b/arch/arm/configs/virt32_secure_defconfig
@@ -0,0 +1,301 @@
+CONFIG_ARCH_VERSATILE=y
+CONFIG_ARCH_VEXPRESS=y
+CONFIG_MACH_VEXPRESS=y
+CONFIG_MACH_VIRT=y
+CONFIG_AEABI=y
+CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS=y
+CONFIG_ARM_EXCEPTIONS_PBL=y
+CONFIG_ARM_UNWIND=y
+CONFIG_ARM_SEMIHOSTING=y
+CONFIG_BOOT_ATAGS=y
+CONFIG_ARM_BOOTM_ELF=y
+CONFIG_ARM_BOOTM_FIP=y
+CONFIG_NAME="virt32_secure_defconfig"
+CONFIG_MMU=y
+CONFIG_MALLOC_SIZE=0x0
+CONFIG_KALLSYMS=y
+CONFIG_PROMPT="barebox> "
+CONFIG_HUSH_FANCY_PROMPT=y
+CONFIG_AUTO_COMPLETE=y
+CONFIG_MENU=y
+# CONFIG_TIMESTAMP is not set
+CONFIG_BOOTM_SHOW_TYPE=y
+CONFIG_BOOTM_VERBOSE=y
+CONFIG_BOOTM_INITRD=y
+CONFIG_BOOTM_OFTREE_UIMAGE=y
+CONFIG_BOOTM_AIMAGE=y
+CONFIG_BOOTM_FITIMAGE=y
+CONFIG_BLSPEC=y
+CONFIG_CONSOLE_ALLOW_COLOR=y
+CONFIG_PBL_CONSOLE=y
+CONFIG_CONSOLE_RATP=y
+CONFIG_RATP_CMD_I2C=y
+CONFIG_RATP_CMD_GPIO=y
+CONFIG_PARTITION_DISK_EFI=y
+# CONFIG_PARTITION_DISK_EFI_GPT_NO_FORCE is not set
+# CONFIG_PARTITION_DISK_EFI_GPT_COMPARE is not set
+CONFIG_DEFAULT_ENVIRONMENT_GENERIC_NEW=y
+CONFIG_DEFAULT_ENVIRONMENT_GENERIC_NEW_REBOOT_MODE=y
+CONFIG_DEFAULT_ENVIRONMENT_GENERIC_NEW_SECURITY_POLICY=y
+CONFIG_DEFAULT_ENVIRONMENT_GENERIC_NEW_IKCONFIG=y
+CONFIG_TLV=y
+CONFIG_STATE=y
+CONFIG_BOOTCHOOSER=y
+CONFIG_RESET_SOURCE=y
+CONFIG_MACHINE_ID=y
+CONFIG_SYSTEMD_OF_WATCHDOG=y
+CONFIG_FASTBOOT_SPARSE=y
+CONFIG_FASTBOOT_CMD_OEM=y
+CONFIG_CMD_TUTORIAL=y
+CONFIG_CMD_CLASS=y
+CONFIG_CMD_DEVLOOKUP=y
+CONFIG_CMD_DEVUNBIND=y
+CONFIG_CMD_DMESG=y
+CONFIG_LONGHELP=y
+CONFIG_CMD_IOMEM=y
+CONFIG_CMD_IMD=y
+CONFIG_CMD_MEMINFO=y
+CONFIG_CMD_ARM_MMUINFO=y
+CONFIG_CMD_BLKSTATS=y
+CONFIG_CMD_REGULATOR=y
+CONFIG_CMD_PM_DOMAIN=y
+CONFIG_CMD_NVMEM=y
+CONFIG_CMD_VARINFO=y
+CONFIG_CMD_MMC=y
+CONFIG_CMD_MMC_EXTCSD=y
+CONFIG_CMD_POLLER=y
+CONFIG_CMD_SLICE=y
+CONFIG_CMD_BOOTZ=y
+CONFIG_CMD_GO=y
+CONFIG_CMD_LOADB=y
+CONFIG_CMD_LOADS=y
+CONFIG_CMD_LOADY=y
+CONFIG_CMD_RESET=y
+CONFIG_CMD_SAVES=y
+CONFIG_CMD_UIMAGE=y
+CONFIG_CMD_BOOTCHOOSER=y
+CONFIG_CMD_PARTITION=y
+CONFIG_CMD_FINDMNT=y
+CONFIG_CMD_PARTED=y
+CONFIG_CMD_UBIFORMAT=y
+CONFIG_CMD_CREATENV=y
+CONFIG_CMD_EXPORT=y
+CONFIG_CMD_DEFAULTENV=y
+CONFIG_CMD_LOADENV=y
+CONFIG_CMD_PRINTENV=y
+CONFIG_CMD_MAGICVAR=y
+CONFIG_CMD_MAGICVAR_HELP=y
+CONFIG_CMD_SAVEENV=y
+CONFIG_CMD_CMP=y
+CONFIG_CMD_FILETYPE=y
+CONFIG_CMD_LN=y
+CONFIG_CMD_STAT=y
+CONFIG_CMD_MD5SUM=y
+CONFIG_CMD_SHA1SUM=y
+CONFIG_CMD_SHA224SUM=y
+CONFIG_CMD_SHA256SUM=y
+CONFIG_CMD_BASE64=y
+CONFIG_CMD_SHA384SUM=y
+CONFIG_CMD_SHA512SUM=y
+CONFIG_CMD_FIPTOOL=y
+CONFIG_CMD_FIPTOOL_WRITE=y
+CONFIG_CMD_UNCOMPRESS=y
+CONFIG_CMD_LET=y
+CONFIG_CMD_MSLEEP=y
+CONFIG_CMD_READF=y
+CONFIG_CMD_SLEEP=y
+CONFIG_CMD_DHCP=y
+CONFIG_CMD_PING=y
+CONFIG_CMD_TFTP=y
+CONFIG_CMD_IP=y
+CONFIG_CMD_ETHLOG=y
+CONFIG_CMD_ECHO_E=y
+CONFIG_CMD_EDIT=y
+CONFIG_CMD_MENU=y
+CONFIG_CMD_MENU_MANAGEMENT=y
+CONFIG_CMD_MENUTREE=y
+CONFIG_CMD_SPLASH=y
+CONFIG_CMD_FBTEST=y
+CONFIG_CMD_READLINE=y
+CONFIG_CMD_TIMEOUT=y
+CONFIG_CMD_CRC=y
+CONFIG_CMD_CRC_CMP=y
+CONFIG_CMD_MEMTEST=y
+CONFIG_CMD_MEMTESTER=y
+CONFIG_CMD_MM=y
+CONFIG_CMD_CLK=y
+CONFIG_CMD_DETECT=y
+CONFIG_CMD_TRUNCATE=y
+CONFIG_CMD_SYNC=y
+CONFIG_CMD_FLASH=y
+CONFIG_CMD_GPIO=y
+CONFIG_CMD_I2C=y
+CONFIG_CMD_PWM=y
+CONFIG_CMD_LED=y
+CONFIG_CMD_NANDTEST=y
+CONFIG_CMD_NAND_BITFLIP=y
+CONFIG_CMD_POWEROFF=y
+CONFIG_CMD_SMC=y
+CONFIG_CMD_SPI=y
+CONFIG_CMD_LED_TRIGGER=y
+CONFIG_CMD_USBGADGET=y
+CONFIG_CMD_DFU=y
+CONFIG_CMD_WD=y
+CONFIG_CMD_SCONFIG_MODIFY=y
+CONFIG_CMD_BLOBGEN=y
+CONFIG_CMD_LOGIN=y
+CONFIG_CMD_PASSWD=y
+CONFIG_PASSWD_MODE_STAR=y
+CONFIG_CMD_2048=y
+CONFIG_CMD_BAREBOX_UPDATE=y
+CONFIG_CMD_FIRMWARELOAD=y
+CONFIG_CMD_KALLSYMS=y
+CONFIG_CMD_OF_COMPATIBLE=y
+CONFIG_CMD_OF_DIFF=y
+CONFIG_CMD_OF_NODE=y
+CONFIG_CMD_OF_PROPERTY=y
+CONFIG_CMD_OF_DISPLAY_TIMINGS=y
+CONFIG_CMD_OF_FIXUP=y
+CONFIG_CMD_OF_FIXUP_STATUS=y
+CONFIG_CMD_OF_OVERLAY=y
+CONFIG_CMD_OFTREE=y
+CONFIG_CMD_TIME=y
+CONFIG_CMD_WATCH=y
+CONFIG_CMD_UPTIME=y
+CONFIG_CMD_TLV=y
+CONFIG_CMD_DHRYSTONE=y
+CONFIG_CMD_SPD_DECODE=y
+CONFIG_CMD_SEED=y
+CONFIG_CMD_STACKSMASH=y
+CONFIG_NET=y
+CONFIG_NET_ETHADDR_FROM_MACHINE_ID=y
+CONFIG_NET_NETCONSOLE=y
+CONFIG_NET_FASTBOOT=y
+CONFIG_NET_9P=y
+CONFIG_NET_9P_VIRTIO=y
+CONFIG_DEEP_PROBE_DEFAULT=y
+CONFIG_OF_BAREBOX_DRIVERS=y
+CONFIG_OF_BAREBOX_ENV_IN_FS=y
+CONFIG_OF_OVERLAY_LIVE=y
+CONFIG_AIODEV=y
+CONFIG_SERIAL_AMBA_PL011=y
+CONFIG_DRIVER_SERIAL_NS16550=y
+CONFIG_VIRTIO_CONSOLE=y
+CONFIG_DRIVER_NET_VIRTIO=y
+CONFIG_DRIVER_SPI_GPIO=y
+CONFIG_I2C=y
+CONFIG_I2C_GPIO=y
+CONFIG_I2C_MUX=y
+CONFIG_MTD=y
+CONFIG_MTD_RAW_DEVICE=y
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_DATAFLASH=y
+CONFIG_MTD_M25P80=y
+CONFIG_DRIVER_CFI=y
+CONFIG_NAND=y
+CONFIG_NAND_ALLOW_ERASE_BAD=y
+CONFIG_MTD_UBI=y
+CONFIG_MTD_UBI_FASTMAP=y
+CONFIG_VIRTIO_BLK=y
+CONFIG_DISK_AHCI=y
+CONFIG_DISK_INTF_PLATFORM_IDE=y
+CONFIG_USB_HOST=y
+CONFIG_USB_DWC2_HOST=y
+CONFIG_USB_DWC2_GADGET=y
+CONFIG_USB_EHCI=y
+CONFIG_USB_ULPI=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_ONBOARD_DEV=y
+CONFIG_TYPEC_TUSB320=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_DFU=y
+CONFIG_USB_GADGET_SERIAL=y
+CONFIG_USB_GADGET_FASTBOOT=y
+CONFIG_USB_GADGET_MASS_STORAGE=y
+CONFIG_VIDEO=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_DRIVER_VIDEO_BOCHS_PCI=y
+CONFIG_DRIVER_VIDEO_SIMPLEFB=y
+CONFIG_DRIVER_VIDEO_RAMFB=y
+CONFIG_DRIVER_VIDEO_BACKLIGHT=y
+CONFIG_DRIVER_VIDEO_BACKLIGHT_PWM=y
+CONFIG_DRIVER_VIDEO_SIMPLE_PANEL=y
+CONFIG_MCI=y
+CONFIG_MCI_STARTUP=y
+CONFIG_MCI_MMC_BOOT_PARTITIONS=y
+CONFIG_MCI_DW=y
+CONFIG_MCI_DW_PIO=y
+CONFIG_MCI_MMCI=y
+CONFIG_COMMON_CLK_SCMI=y
+CONFIG_MFD_ACT8846=y
+CONFIG_MFD_DA9063=y
+CONFIG_MFD_MC13XXX=y
+CONFIG_MFD_MC34704=y
+CONFIG_MFD_MC9SDZ60=y
+CONFIG_MFD_STMPE=y
+CONFIG_MFD_STPMIC1=y
+CONFIG_UBOOTVAR=y
+CONFIG_STORAGE_BY_ALIAS=y
+CONFIG_LED=y
+CONFIG_LED_GPIO=y
+CONFIG_LED_PWM=y
+CONFIG_LED_GPIO_OF=y
+CONFIG_LED_TRIGGERS=y
+CONFIG_EEPROM_AT25=y
+CONFIG_EEPROM_AT24=y
+CONFIG_KEYBOARD_GPIO=y
+CONFIG_INPUT_SPECIALKEYS=y
+CONFIG_VIRTIO_INPUT=y
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_POLLER=y
+CONFIG_PWM=y
+CONFIG_HWRNG=y
+CONFIG_HW_RANDOM_VIRTIO=y
+CONFIG_GPIO_74164=y
+CONFIG_GPIO_GENERIC_PLATFORM=y
+CONFIG_GPIO_STMPE=y
+CONFIG_PINCTRL_SINGLE=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED=y
+CONFIG_REGULATOR_ARM_SCMI=y
+CONFIG_REMOTEPROC=y
+CONFIG_RESET_CONTROLLER=y
+CONFIG_PCI_ECAM_GENERIC=y
+CONFIG_ARM_SCMI_PROTOCOL=y
+CONFIG_GENERIC_PHY=y
+CONFIG_USB_NOP_XCEIV=y
+CONFIG_SYSCON_REBOOT_MODE=y
+CONFIG_POWER_RESET_SYSCON=y
+CONFIG_VIRTIO_MMIO=y
+CONFIG_FS_CRAMFS=y
+CONFIG_FS_EXT4=y
+CONFIG_FS_TFTP=y
+CONFIG_FS_NFS=y
+CONFIG_9P_FS=y
+CONFIG_9P_FS_WRITE=y
+CONFIG_FS_FAT=y
+CONFIG_FS_FAT_WRITE=y
+CONFIG_FS_UBIFS=y
+CONFIG_FS_UBIFS_COMPRESSION_LZO=y
+CONFIG_FS_UBIFS_COMPRESSION_ZLIB=y
+CONFIG_FS_UBIFS_COMPRESSION_ZSTD=y
+CONFIG_FS_BPKFS=y
+CONFIG_FS_UIMAGEFS=y
+CONFIG_FS_SMHFS=y
+CONFIG_FS_PSTORE=y
+CONFIG_FS_PSTORE_CONSOLE=y
+CONFIG_FS_PSTORE_RAMOOPS=y
+CONFIG_FS_SQUASHFS=y
+CONFIG_FS_RATP=y
+CONFIG_FS_UBOOTVARFS=y
+# CONFIG_INSECURE is not set
+CONFIG_SECURITY_POLICY=y
+CONFIG_SECURITY_POLICY_INIT="lockdown"
+CONFIG_SECURITY_POLICY_DEFAULT_PANIC=y
+CONFIG_BUG_ON_DATA_CORRUPTION=y
+CONFIG_DIGEST_SHA1_ARM=y
+CONFIG_DIGEST_SHA256_ARM=y
+CONFIG_CRC8=y
+CONFIG_PNG=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_TER16x32=y
diff --git a/test/arm/virt32_secure_defconfig.yaml b/test/arm/virt32_secure_defconfig.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..618cb6a0fb05a4703c1fe25e159a257ed775d7c8
--- /dev/null
+++ b/test/arm/virt32_secure_defconfig.yaml
@@ -0,0 +1,20 @@
+targets:
+ main:
+ drivers:
+ QEMUDriver:
+ qemu_bin: qemu-system-arm
+ machine: virt
+ cpu: cortex-a7
+ memory: 1024M
+ kernel: barebox-dt-2nd.img
+ display: qemu-default
+ BareboxDriver:
+ prompt: 'barebox@[^:]+:[^ ]+ '
+ bootstring: 'commandline:'
+ BareboxTestStrategy: {}
+ features:
+ - virtio-mmio
+images:
+ barebox-dt-2nd.img: !template "$LG_BUILDDIR/images/barebox-dt-2nd.img"
+imports:
+ - ../strategy.py
--
2.47.3
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH v2 15/24] boards: qemu-virt: add security policies
2025-09-17 13:53 [PATCH v2 00/24] Add security policy support Sascha Hauer
` (13 preceding siblings ...)
2025-09-17 13:53 ` [PATCH v2 14/24] ARM: configs: add virt32_secure_defconfig Sascha Hauer
@ 2025-09-17 13:53 ` Sascha Hauer
2025-09-17 13:53 ` [PATCH v2 16/24] boards: qemu-virt: allow setting policy from command line Sascha Hauer
` (10 subsequent siblings)
25 siblings, 0 replies; 31+ messages in thread
From: Sascha Hauer @ 2025-09-17 13:53 UTC (permalink / raw)
To: BAREBOX; +Cc: Ahmad Fatoum, Ahmad Fatoum
From: Ahmad Fatoum <a.fatoum@barebox.org>
To make it easier to experiment with security policies, add four example
configurations, two via the build system and two "externally".
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
arch/arm/configs/virt32_secure_defconfig | 1 +
common/boards/qemu-virt/Makefile | 3 ++
common/boards/qemu-virt/board.c | 8 +++++
common/boards/qemu-virt/qemu-virt-factory.sconfig | 36 ++++++++++++++++++++++
common/boards/qemu-virt/qemu-virt-lockdown.sconfig | 35 +++++++++++++++++++++
security/qemu-virt-devel.sconfig | 36 ++++++++++++++++++++++
security/qemu-virt-tamper.sconfig | 35 +++++++++++++++++++++
7 files changed, 154 insertions(+)
diff --git a/arch/arm/configs/virt32_secure_defconfig b/arch/arm/configs/virt32_secure_defconfig
index 34cc49405495b33b4f78e078dfbcd951c433fcd8..09c98e5e4dc88aa22b3aa10db38efd7b7cac2310 100644
--- a/arch/arm/configs/virt32_secure_defconfig
+++ b/arch/arm/configs/virt32_secure_defconfig
@@ -292,6 +292,7 @@ CONFIG_FS_UBOOTVARFS=y
CONFIG_SECURITY_POLICY=y
CONFIG_SECURITY_POLICY_INIT="lockdown"
CONFIG_SECURITY_POLICY_DEFAULT_PANIC=y
+CONFIG_SECURITY_POLICY_PATH="security/qemu-virt-devel.sconfig security/qemu-virt-tamper.sconfig"
CONFIG_BUG_ON_DATA_CORRUPTION=y
CONFIG_DIGEST_SHA1_ARM=y
CONFIG_DIGEST_SHA256_ARM=y
diff --git a/common/boards/qemu-virt/Makefile b/common/boards/qemu-virt/Makefile
index 30bf4f1955ee9d306b46523863e247e4cf94ab75..2caa6a20c522ac68fd629f38e51fdf1423db4b09 100644
--- a/common/boards/qemu-virt/Makefile
+++ b/common/boards/qemu-virt/Makefile
@@ -9,5 +9,8 @@ ifeq ($(CONFIG_ARM),y)
DTC_CPP_FLAGS_qemu-virt-flash.dtbo := -DCONFIG_ARM
endif
+policy-y += qemu-virt-factory.sconfig
+policy-y += qemu-virt-lockdown.sconfig
+
clean-files := *.dtb *.dtb.S .*.dtc .*.pre .*.dts *.dtb.z
clean-files += *.dtbo *.dtbo.S .*.dtso
diff --git a/common/boards/qemu-virt/board.c b/common/boards/qemu-virt/board.c
index 9882b0c31a3cf9a97ef0e963653c85a3ead961bb..6f88f24b0690c2562b3b3718a56c9f5c46a4455a 100644
--- a/common/boards/qemu-virt/board.c
+++ b/common/boards/qemu-virt/board.c
@@ -7,6 +7,7 @@
#include <init.h>
#include <of.h>
#include <deep-probe.h>
+#include <security/policy.h>
#include "qemu-virt-flash.h"
#ifdef CONFIG_64BIT
@@ -83,6 +84,13 @@ static int virt_board_driver_init(void)
/* of_probe() will happen later at of_populate_initcall */
+ security_policy_add(qemu_virt_factory);
+ security_policy_add(qemu_virt_lockdown);
+ /*
+ * qemu_virt_devel & qemu_virt_tamper intentionally not added here,
+ * so the test suite can exercise CONFIG_SECURITY_POLICY_PATH.
+ */
+
return 0;
}
postcore_initcall(virt_board_driver_init);
diff --git a/common/boards/qemu-virt/qemu-virt-factory.sconfig b/common/boards/qemu-virt/qemu-virt-factory.sconfig
new file mode 100644
index 0000000000000000000000000000000000000000..7fb35e9b722d1694ed089f209c9d1af5892557ca
--- /dev/null
+++ b/common/boards/qemu-virt/qemu-virt-factory.sconfig
@@ -0,0 +1,36 @@
+#
+# Automatically generated file; DO NOT EDIT.
+# Barebox Security Configuration
+#
+SCONFIG_POLICY_NAME="factory"
+
+#
+# General Settings
+#
+SCONFIG_CONSOLE_INPUT=y
+SCONFIG_SHELL=y
+SCONFIG_SHELL_INTERACTIVE=y
+SCONFIG_ENVIRONMENT_LOAD=y
+SCONFIG_RATP=y
+# SCONFIG_FASTBOOT_CMD_OEM is not set
+# end of General Settings
+
+#
+# Boot Policy
+#
+# SCONFIG_BOOT_UNSIGNED_IMAGES is not set
+# end of Boot Policy
+
+#
+# USB Gadget Policy
+#
+SCONFIG_USB_GADGET=y
+# end of USB Gadget Policy
+
+#
+# Command Policy
+#
+# SCONFIG_CMD_GO is not set
+# end of Command Policy
+
+SCONFIG_FS_EXTERNAL=y
diff --git a/common/boards/qemu-virt/qemu-virt-lockdown.sconfig b/common/boards/qemu-virt/qemu-virt-lockdown.sconfig
new file mode 100644
index 0000000000000000000000000000000000000000..04763d2233b41dc53e187641c45c48c9c1115a7d
--- /dev/null
+++ b/common/boards/qemu-virt/qemu-virt-lockdown.sconfig
@@ -0,0 +1,35 @@
+#
+# Automatically generated file; DO NOT EDIT.
+# Barebox Security Configuration
+#
+SCONFIG_POLICY_NAME="lockdown"
+
+#
+# General Settings
+#
+# SCONFIG_CONSOLE_INPUT is not set
+SCONFIG_SHELL=y
+# SCONFIG_ENVIRONMENT_LOAD is not set
+# SCONFIG_RATP is not set
+# SCONFIG_FASTBOOT_CMD_OEM is not set
+# end of General Settings
+
+#
+# Boot Policy
+#
+# SCONFIG_BOOT_UNSIGNED_IMAGES is not set
+# end of Boot Policy
+
+#
+# USB Gadget Policy
+#
+# SCONFIG_USB_GADGET is not set
+# end of USB Gadget Policy
+
+#
+# Command Policy
+#
+# SCONFIG_CMD_GO is not set
+# end of Command Policy
+
+# SCONFIG_FS_EXTERNAL is not set
diff --git a/security/qemu-virt-devel.sconfig b/security/qemu-virt-devel.sconfig
new file mode 100644
index 0000000000000000000000000000000000000000..423374dfbdef5a22f40d30872f6eeb05590e9f3f
--- /dev/null
+++ b/security/qemu-virt-devel.sconfig
@@ -0,0 +1,36 @@
+#
+# Automatically generated file; DO NOT EDIT.
+# Barebox Security Configuration
+#
+SCONFIG_POLICY_NAME="devel"
+
+#
+# General Settings
+#
+SCONFIG_CONSOLE_INPUT=y
+SCONFIG_SHELL=y
+SCONFIG_SHELL_INTERACTIVE=y
+SCONFIG_ENVIRONMENT_LOAD=y
+SCONFIG_RATP=y
+SCONFIG_FASTBOOT_CMD_OEM=y
+# end of General Settings
+
+#
+# Boot Policy
+#
+SCONFIG_BOOT_UNSIGNED_IMAGES=y
+# end of Boot Policy
+
+#
+# USB Gadget Policy
+#
+SCONFIG_USB_GADGET=y
+# end of USB Gadget Policy
+
+#
+# Command Policy
+#
+SCONFIG_CMD_GO=y
+# end of Command Policy
+
+SCONFIG_FS_EXTERNAL=y
diff --git a/security/qemu-virt-tamper.sconfig b/security/qemu-virt-tamper.sconfig
new file mode 100644
index 0000000000000000000000000000000000000000..10058c5b61010e64356df62269260c7a5bb33120
--- /dev/null
+++ b/security/qemu-virt-tamper.sconfig
@@ -0,0 +1,35 @@
+#
+# Automatically generated file; DO NOT EDIT.
+# Barebox Security Configuration
+#
+SCONFIG_POLICY_NAME="tamper"
+
+#
+# General Settings
+#
+# SCONFIG_CONSOLE_INPUT is not set
+# SCONFIG_SHELL is not set
+# SCONFIG_ENVIRONMENT_LOAD is not set
+# SCONFIG_RATP is not set
+# SCONFIG_FASTBOOT_CMD_OEM is not set
+# end of General Settings
+
+#
+# Boot Policy
+#
+# SCONFIG_BOOT_UNSIGNED_IMAGES is not set
+# end of Boot Policy
+
+#
+# USB Gadget Policy
+#
+# SCONFIG_USB_GADGET is not set
+# end of USB Gadget Policy
+
+#
+# Command Policy
+#
+# SCONFIG_CMD_GO is not set
+# end of Command Policy
+
+# SCONFIG_FS_EXTERNAL is not set
--
2.47.3
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH v2 16/24] boards: qemu-virt: allow setting policy from command line
2025-09-17 13:53 [PATCH v2 00/24] Add security policy support Sascha Hauer
` (14 preceding siblings ...)
2025-09-17 13:53 ` [PATCH v2 15/24] boards: qemu-virt: add security policies Sascha Hauer
@ 2025-09-17 13:53 ` Sascha Hauer
2025-09-17 13:53 ` [PATCH v2 17/24] test: py: add basic security policy test Sascha Hauer
` (9 subsequent siblings)
25 siblings, 0 replies; 31+ messages in thread
From: Sascha Hauer @ 2025-09-17 13:53 UTC (permalink / raw)
To: BAREBOX; +Cc: Ahmad Fatoum
From: Ahmad Fatoum <a.fatoum@pengutronix.de>
Security policies will normally be selected after consulting efuses,
secure boot status from the EEPROM or unlock tokens.
For easier experimentation in QEMU, allow setting the security policy
via the command line arguments, e.g.:
pytest --bootarg barebox.security.policy=lockdown
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
common/boards/qemu-virt/Makefile | 2 +-
common/boards/qemu-virt/board.c | 3 ++
common/boards/qemu-virt/commandline.c | 74 +++++++++++++++++++++++++++++++++++
common/boards/qemu-virt/commandline.h | 9 +++++
test/arm/virt32_secure_defconfig.yaml | 1 +
5 files changed, 88 insertions(+), 1 deletion(-)
diff --git a/common/boards/qemu-virt/Makefile b/common/boards/qemu-virt/Makefile
index 2caa6a20c522ac68fd629f38e51fdf1423db4b09..7e1440aecff08942269d60f5d221fc4e69e95ea6 100644
--- a/common/boards/qemu-virt/Makefile
+++ b/common/boards/qemu-virt/Makefile
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-only
-obj-y += board.o
+obj-y += board.o commandline.o
obj-y += qemu-virt-flash.dtbo.o fitimage-pubkey.dtb.o
ifeq ($(CONFIG_RISCV),y)
DTC_CPP_FLAGS_qemu-virt-flash.dtbo := -DCONFIG_RISCV
diff --git a/common/boards/qemu-virt/board.c b/common/boards/qemu-virt/board.c
index 6f88f24b0690c2562b3b3718a56c9f5c46a4455a..6ad35421892703eea32a36a913bc92dbb44acc14 100644
--- a/common/boards/qemu-virt/board.c
+++ b/common/boards/qemu-virt/board.c
@@ -9,6 +9,7 @@
#include <deep-probe.h>
#include <security/policy.h>
#include "qemu-virt-flash.h"
+#include "commandline.h"
#ifdef CONFIG_64BIT
#define MACHINE "virt64"
@@ -91,6 +92,8 @@ static int virt_board_driver_init(void)
* so the test suite can exercise CONFIG_SECURITY_POLICY_PATH.
*/
+ qemu_virt_parse_commandline(root);
+
return 0;
}
postcore_initcall(virt_board_driver_init);
diff --git a/common/boards/qemu-virt/commandline.c b/common/boards/qemu-virt/commandline.c
new file mode 100644
index 0000000000000000000000000000000000000000..16e4750e123dee69c612de52c855889372f2cbc3
--- /dev/null
+++ b/common/boards/qemu-virt/commandline.c
@@ -0,0 +1,74 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#define pr_fmt(fmt) "qemu-virt-commandline: " fmt
+
+#include <linux/parser.h>
+#include <of.h>
+#include <string.h>
+#include <security/policy.h>
+#include <xfuncs.h>
+#include <stdio.h>
+#include "commandline.h"
+
+enum {
+ /* String options */
+ Opt_policy,
+ /* Error token */
+ Opt_err
+};
+
+static const match_table_t tokens = {
+ {Opt_policy, "barebox.security.policy=%s"},
+ {Opt_err, NULL}
+};
+
+int qemu_virt_parse_commandline(struct device_node *np)
+{
+ const char *bootargs;
+ char *p, *options, *tmp_options, *policy = NULL;
+ substring_t args[MAX_OPT_ARGS];
+ int ret;
+
+ np = of_get_child_by_name(np, "chosen");
+ if (!np)
+ return -ENOENT;
+
+ ret = of_property_read_string(np, "bootargs", &bootargs);
+ if (ret < 0)
+ return 0;
+
+ options = tmp_options = xstrdup(bootargs);
+
+ while ((p = strsep(&options, " ")) != NULL) {
+ int token;
+
+ if (!*p)
+ continue;
+
+ token = match_token(p, tokens, args);
+ switch (token) {
+ case Opt_policy:
+ if (!IS_ENABLED(CONFIG_SECURITY_POLICY)) {
+ pr_err("CONFIG_SECURITY_POLICY support is missing\n");
+ continue;
+ }
+
+ policy = match_strdup(&args[0]);
+ if (!policy) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ ret = security_policy_select(policy);
+ if (ret)
+ goto out;
+ default:
+ continue;
+ }
+ }
+
+ ret = 0;
+out:
+ free(policy);
+ free(tmp_options);
+ return ret;
+}
diff --git a/common/boards/qemu-virt/commandline.h b/common/boards/qemu-virt/commandline.h
new file mode 100644
index 0000000000000000000000000000000000000000..8759784e07c57e3492dbabaa8ab9b4d50cc6f73a
--- /dev/null
+++ b/common/boards/qemu-virt/commandline.h
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#ifndef QEMU_VIRT_COMMANDLINE_H_
+#define QEMU_VIRT_COMMANDLINE_H_
+
+struct device_node;
+
+int qemu_virt_parse_commandline(struct device_node *root);
+
+#endif
diff --git a/test/arm/virt32_secure_defconfig.yaml b/test/arm/virt32_secure_defconfig.yaml
index 618cb6a0fb05a4703c1fe25e159a257ed775d7c8..a1537c634811d10957b7fd0cc49d6b66c1b80e06 100644
--- a/test/arm/virt32_secure_defconfig.yaml
+++ b/test/arm/virt32_secure_defconfig.yaml
@@ -7,6 +7,7 @@ targets:
cpu: cortex-a7
memory: 1024M
kernel: barebox-dt-2nd.img
+ boot_args: barebox.security.policy=devel
display: qemu-default
BareboxDriver:
prompt: 'barebox@[^:]+:[^ ]+ '
--
2.47.3
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH v2 17/24] test: py: add basic security policy test
2025-09-17 13:53 [PATCH v2 00/24] Add security policy support Sascha Hauer
` (15 preceding siblings ...)
2025-09-17 13:53 ` [PATCH v2 16/24] boards: qemu-virt: allow setting policy from command line Sascha Hauer
@ 2025-09-17 13:53 ` Sascha Hauer
2025-09-17 13:53 ` [PATCH v2 18/24] usbserial: add inline wrappers Sascha Hauer
` (8 subsequent siblings)
25 siblings, 0 replies; 31+ messages in thread
From: Sascha Hauer @ 2025-09-17 13:53 UTC (permalink / raw)
To: BAREBOX; +Cc: Ahmad Fatoum
From: Ahmad Fatoum <a.fatoum@pengutronix.de>
This simple test checks that the security policies were added and that a
number of options that we expect to be there indeed change as expected.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
test/arm/virt32_secure_defconfig.yaml | 1 +
test/py/test_policies.py | 48 +++++++++++++++++++++++++++++++++++
2 files changed, 49 insertions(+)
diff --git a/test/arm/virt32_secure_defconfig.yaml b/test/arm/virt32_secure_defconfig.yaml
index a1537c634811d10957b7fd0cc49d6b66c1b80e06..3a26e09ef683093279d9fd068e6e8e968cb34a9e 100644
--- a/test/arm/virt32_secure_defconfig.yaml
+++ b/test/arm/virt32_secure_defconfig.yaml
@@ -15,6 +15,7 @@ targets:
BareboxTestStrategy: {}
features:
- virtio-mmio
+ - policies
images:
barebox-dt-2nd.img: !template "$LG_BUILDDIR/images/barebox-dt-2nd.img"
imports:
diff --git a/test/py/test_policies.py b/test/py/test_policies.py
new file mode 100644
index 0000000000000000000000000000000000000000..b4ece29c95974b182aa1275d1710742f52ad4cea
--- /dev/null
+++ b/test/py/test_policies.py
@@ -0,0 +1,48 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+import pytest
+
+
+def test_security_policies(barebox, env):
+ if 'policies' not in env.get_target_features():
+ pytest.skip('policies feature flag missing')
+
+ assert 'Active Policy: devel' in barebox.run_check('sconfig')
+
+ assert set(barebox.run_check('sconfig -l')) == \
+ set(['devel', 'factory', 'lockdown', 'tamper'])
+
+ assert barebox.run_check('varinfo global.bootm.verify') == \
+ ['bootm.verify: available (type: enum) '
+ '(values: "none", "hash", "signature", "available")']
+
+ barebox.run_check('sconfig -s factory')
+ assert 'Active Policy: factory' in barebox.run_check('sconfig')
+
+ stdout = barebox.run_check('sconfig -v -s devel')
+ assert set(['+SCONFIG_BOOT_UNSIGNED_IMAGES',
+ '+SCONFIG_CMD_GO']) <= set(stdout)
+ assert 'Active Policy: devel' in barebox.run_check('sconfig')
+
+ stdout, _, rc = barebox.run('go')
+ assert 'go - start application at address or file' in stdout
+ assert 'go: Operation not permitted' not in stdout
+ assert rc == 1
+
+ stdout = barebox.run_check('sconfig -v -s tamper')
+ assert set(['-SCONFIG_BOOT_UNSIGNED_IMAGES',
+ '-SCONFIG_RATP',
+ '-SCONFIG_CMD_GO']) <= set(stdout)
+ assert 'Active Policy: tamper' in barebox.run_check('sconfig')
+
+ _, _, rc = barebox.run('sconfig -s devel')
+ assert rc != 0
+ assert 'Active Policy: tamper' in barebox.run_check('sconfig')
+
+ stdout, _, rc = barebox.run('go')
+ assert 'go - start application at address or file' not in stdout
+ assert 'go: Operation not permitted' in stdout
+ assert rc == 127
+
+ assert barebox.run_check('varinfo global.bootm.verify') == \
+ ['bootm.verify: signature (type: enum)']
--
2.47.3
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH v2 18/24] usbserial: add inline wrappers
2025-09-17 13:53 [PATCH v2 00/24] Add security policy support Sascha Hauer
` (16 preceding siblings ...)
2025-09-17 13:53 ` [PATCH v2 17/24] test: py: add basic security policy test Sascha Hauer
@ 2025-09-17 13:53 ` Sascha Hauer
2025-09-17 13:53 ` [PATCH v2 19/24] security: usbgadget: add usbgadget security policy Sascha Hauer
` (7 subsequent siblings)
25 siblings, 0 replies; 31+ messages in thread
From: Sascha Hauer @ 2025-09-17 13:53 UTC (permalink / raw)
To: BAREBOX
We'll need static inline wrappers in following patches, let's add them.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
include/linux/usb/usbserial.h | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/include/linux/usb/usbserial.h b/include/linux/usb/usbserial.h
index e1375c489a027448c8e75ce1ce051c279650bcc9..2d33a8e25a7f86a8956805dec1742757e2a7c60f 100644
--- a/include/linux/usb/usbserial.h
+++ b/include/linux/usb/usbserial.h
@@ -7,7 +7,18 @@ struct usb_serial_pdata {
bool acm;
};
+#ifdef CONFIG_USB_GADGET_SERIAL
int usb_serial_register(struct usb_serial_pdata *pdata);
void usb_serial_unregister(void);
+#else
+static inline int usb_serial_register(struct usb_serial_pdata *pdata)
+{
+ return -ENOSYS;
+}
+
+static inline void usb_serial_unregister(void)
+{
+}
+#endif
#endif /* _USB_SERIAL_H */
--
2.47.3
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH v2 19/24] security: usbgadget: add usbgadget security policy
2025-09-17 13:53 [PATCH v2 00/24] Add security policy support Sascha Hauer
` (17 preceding siblings ...)
2025-09-17 13:53 ` [PATCH v2 18/24] usbserial: add inline wrappers Sascha Hauer
@ 2025-09-17 13:53 ` Sascha Hauer
2025-09-17 13:53 ` [PATCH v2 20/24] security: fastboot: add security policy for fastboot oem Sascha Hauer
` (6 subsequent siblings)
25 siblings, 0 replies; 31+ messages in thread
From: Sascha Hauer @ 2025-09-17 13:53 UTC (permalink / raw)
To: BAREBOX
USB gadget might be considered dangerous in secure environments, so add
a security policy for it.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
Sconfig | 1 +
common/usbgadget.c | 26 ++++++++++++++++++++++++++
drivers/usb/gadget/Sconfig | 11 +++++++++++
drivers/usb/gadget/composite.c | 4 ++++
drivers/usb/gadget/legacy/serial.c | 4 ++++
5 files changed, 46 insertions(+)
diff --git a/Sconfig b/Sconfig
index f1ae5c7a1482058d170f99c75b706f66a954a9cb..7d7657e79061f4bf200519cf1fab8810b544f97e 100644
--- a/Sconfig
+++ b/Sconfig
@@ -6,4 +6,5 @@ source "scripts/Sconfig.include"
source "security/Sconfig"
source "common/Sconfig"
+source "drivers/usb/gadget/Sconfig"
source "commands/Sconfig"
diff --git a/common/usbgadget.c b/common/usbgadget.c
index 1333eaa413eafb766dc74e37e14d5082e93879ac..dc7b3ddc808ee0b1c63d81b914ff915bcc92a863 100644
--- a/common/usbgadget.c
+++ b/common/usbgadget.c
@@ -18,6 +18,7 @@
#include <globalvar.h>
#include <magicvar.h>
#include <system-partitions.h>
+#include <security/config.h>
static int autostart;
static int nv_loaded;
@@ -81,6 +82,9 @@ int usbgadget_register(struct f_multi_opts *opts)
int ret;
struct device *dev;
+ if (!IS_ALLOWED(SCONFIG_USB_GADGET))
+ return -EPERM;
+
/*
* Creating a gadget with both DFU and Fastboot may not work.
* fastboot 1:8.1.0+r23-5 can deal with it, but dfu-util 0.9
@@ -106,6 +110,9 @@ int usbgadget_prepare_register(const struct usbgadget_funcs *funcs)
struct f_multi_opts *opts;
int ret;
+ if (!IS_ALLOWED(SCONFIG_USB_GADGET))
+ return -EPERM;
+
opts = usbgadget_prepare(funcs);
if (IS_ERR(opts))
return PTR_ERR(opts);
@@ -161,6 +168,21 @@ void usbgadget_autostart(bool enable)
usbgadget_do_autostart();
}
+static void usbgadget_sconfig_update(struct sconfig_notifier_block *nb,
+ enum security_config_option opt,
+ bool allowed)
+{
+ if (allowed) {
+ if (autostart)
+ usbgadget_do_autostart();
+ } else {
+ usb_multi_unregister();
+ usb_serial_unregister();
+ }
+}
+
+static struct sconfig_notifier_block sconfig_notifier;
+
static int usbgadget_globalvars_init(void)
{
globalvar_add_simple_bool("usbgadget.acm", &acm);
@@ -169,6 +191,10 @@ static int usbgadget_globalvars_init(void)
globalvar_add_bool("usbgadget.autostart", usbgadget_autostart_set,
&autostart, NULL);
+ sconfig_register_handler_filtered(&sconfig_notifier,
+ usbgadget_sconfig_update,
+ SCONFIG_USB_GADGET);
+
return 0;
}
coredevice_initcall(usbgadget_globalvars_init);
diff --git a/drivers/usb/gadget/Sconfig b/drivers/usb/gadget/Sconfig
new file mode 100644
index 0000000000000000000000000000000000000000..38797301e514c203f75f876fa54971846d39d292
--- /dev/null
+++ b/drivers/usb/gadget/Sconfig
@@ -0,0 +1,11 @@
+
+menu "USB Gadget Policy"
+
+config USB_GADGET
+ bool "Allow USB gadget"
+ depends on $(kconfig-enabled,USB_GADGET)
+ help
+ USB gadget support might be potentially dangerous in secure environments.
+ The DFU and fastboot protocols allow to modify system partitions.
+
+endmenu
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 98f7b5bf7fb412b77f8a926375df3f0ffbbc96da..2a9984e37ad3ec1325822eb2d328481ceb3ff906 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -15,6 +15,7 @@
#include <linux/usb/composite.h>
#include <linux/bitfield.h>
#include <linux/uuid.h>
+#include <security/config.h>
#include <asm/unaligned.h>
#include <asm/byteorder.h>
@@ -2489,6 +2490,9 @@ int usb_composite_probe(struct usb_composite_driver *driver)
{
struct usb_gadget_driver *gadget_driver;
+ if (!IS_ALLOWED(SCONFIG_USB_GADGET))
+ return -EPERM;
+
if (!driver || !driver->dev || !driver->bind)
return -EINVAL;
diff --git a/drivers/usb/gadget/legacy/serial.c b/drivers/usb/gadget/legacy/serial.c
index 913d174a917794e7cab0f8006b8fd814887029f4..700e9db3a57462e331936efd303c6614544b251a 100644
--- a/drivers/usb/gadget/legacy/serial.c
+++ b/drivers/usb/gadget/legacy/serial.c
@@ -15,6 +15,7 @@
#include <linux/usb/gadget.h>
#include <linux/usb/composite.h>
#include <linux/usb/usbserial.h>
+#include <security/config.h>
#include <asm/byteorder.h>
#include "u_serial.h"
@@ -253,6 +254,9 @@ int usb_serial_register(struct usb_serial_pdata *pdata)
{
int ret;
+ if (!IS_ALLOWED(SCONFIG_USB_GADGET))
+ return -EPERM;
+
if (usb_serial_registered) {
pr_err("USB serial gadget already registered\n");
return -EBUSY;
--
2.47.3
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH v2 20/24] security: fastboot: add security policy for fastboot oem
2025-09-17 13:53 [PATCH v2 00/24] Add security policy support Sascha Hauer
` (18 preceding siblings ...)
2025-09-17 13:53 ` [PATCH v2 19/24] security: usbgadget: add usbgadget security policy Sascha Hauer
@ 2025-09-17 13:53 ` Sascha Hauer
2025-09-17 13:53 ` [PATCH v2 21/24] security: shell: add policy for executing the shell Sascha Hauer
` (5 subsequent siblings)
25 siblings, 0 replies; 31+ messages in thread
From: Sascha Hauer @ 2025-09-17 13:53 UTC (permalink / raw)
To: BAREBOX
Fastboot OEM commands allow to execute arbitrary commands via fastboot,
so add a security policy for it to limit access to this functionality.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
common/Sconfig | 4 ++++
common/fastboot.c | 6 ++++++
2 files changed, 10 insertions(+)
diff --git a/common/Sconfig b/common/Sconfig
index edbc4bc028af79e2a72bb86de94ecce5c7b7643d..9142685a1d3f9846e69b746e545420eab5935661 100644
--- a/common/Sconfig
+++ b/common/Sconfig
@@ -6,6 +6,10 @@ config RATP
bool "Allow remote control via RATP"
depends on $(kconfig-enabled,CONSOLE_RATP)
+config FASTBOOT_CMD_OEM
+ bool "Allow Fastboot OEM commands"
+ depends on $(kconfig-enabled,FASTBOOT_CMD_OEM)
+
endmenu
menu "Boot Policy"
diff --git a/common/fastboot.c b/common/fastboot.c
index e5c79c22376caa81dbd6bb9385e103a7afd7dfe9..b661d610a3ce32fd4c148537a4a2f9308d00fdf9 100644
--- a/common/fastboot.c
+++ b/common/fastboot.c
@@ -42,6 +42,7 @@
#include <linux/types.h>
#include <linux/stat.h>
#include <linux/mtd/mtd.h>
+#include <security/config.h>
#include <fastboot.h>
#include <system-partitions.h>
@@ -968,6 +969,11 @@ static void __maybe_unused cb_oem(struct fastboot *fb, const char *cmd)
{
pr_debug("%s: \"%s\"\n", __func__, cmd);
+ if (!IS_ALLOWED(SCONFIG_FASTBOOT_CMD_OEM)) {
+ fastboot_tx_print(fb, FASTBOOT_MSG_FAIL, "OEM commands not allowed");
+ return;
+ }
+
fb_run_command(fb, cmd, cmd_oem_dispatch_info, ARRAY_SIZE(cmd_oem_dispatch_info));
}
--
2.47.3
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH v2 21/24] security: shell: add policy for executing the shell
2025-09-17 13:53 [PATCH v2 00/24] Add security policy support Sascha Hauer
` (19 preceding siblings ...)
2025-09-17 13:53 ` [PATCH v2 20/24] security: fastboot: add security policy for fastboot oem Sascha Hauer
@ 2025-09-17 13:53 ` Sascha Hauer
2025-09-17 13:53 ` [PATCH v2 22/24] security: add security policy for loading barebox environment Sascha Hauer
` (4 subsequent siblings)
25 siblings, 0 replies; 31+ messages in thread
From: Sascha Hauer @ 2025-09-17 13:53 UTC (permalink / raw)
To: BAREBOX
Executing shell scripts can be dangerous in secure environments, so add
a security policy for it. While shell scripts can be executed securely
if made sure that no scripts from unknown sources are executed,
executing an interactive shell for sure is not desired in secure
environments, so offer two options: One for disabling the shell entirely
and one for disabling interactive shells.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
common/Sconfig | 18 ++++++++++++++++++
common/console.c | 1 +
common/console_ctrlc.c | 4 ++++
common/console_simple.c | 1 +
common/hush.c | 13 +++++++++++++
common/parser.c | 7 +++++++
6 files changed, 44 insertions(+)
diff --git a/common/Sconfig b/common/Sconfig
index 9142685a1d3f9846e69b746e545420eab5935661..ac027022e932dffd429f0b34cb8e1a199b0b595b 100644
--- a/common/Sconfig
+++ b/common/Sconfig
@@ -2,6 +2,24 @@
menu "General Settings"
+config SHELL
+ bool "Allow executing shell scripts"
+ depends on $(kconfig-enabled,SHELL_HUSH) || $(kconfig-enabled,SHELL_SIMPLE)
+ help
+ Say y here if you want to allow executing shell scripts. Shell scripts are
+ potentially dangerous when coming from untrusted sources. Enable this option
+ only when only trusted scripts can be executed, i.e. ENVIRONMENT_LOAD and
+ untrusted filesystems are disabled.
+
+config SHELL_INTERACTIVE
+ bool "Allow executing interactive shell"
+ depends on SHELL
+ help
+ An interactive shell cannot be safely executed in trusted environments. Disable
+ this option in lockdown security configs.
+
+ Disabling this option also disables interruption with ctrl-c keystrokes.
+
config RATP
bool "Allow remote control via RATP"
depends on $(kconfig-enabled,CONSOLE_RATP)
diff --git a/common/console.c b/common/console.c
index ceecb8730e55422b78eea7204dc9b9a70cf97212..8eff3dba925f6de077dd194651a137f30870989d 100644
--- a/common/console.c
+++ b/common/console.c
@@ -25,6 +25,7 @@
#include <linux/list.h>
#include <linux/stringify.h>
#include <debug_ll.h>
+#include <security/config.h>
LIST_HEAD(console_list);
EXPORT_SYMBOL(console_list);
diff --git a/common/console_ctrlc.c b/common/console_ctrlc.c
index 0272eec280d1d8f6d4a1827580a3ee1fb4bc8da6..6fbe07252effeb6d78eff1d47c0c2fe998e80bc1 100644
--- a/common/console_ctrlc.c
+++ b/common/console_ctrlc.c
@@ -5,6 +5,7 @@
#include <sched.h>
#include <globalvar.h>
#include <magicvar.h>
+#include <security/config.h>
static int ctrlc_abort;
static int ctrlc_allowed;
@@ -18,6 +19,9 @@ int ctrlc_non_interruptible(void)
{
int ret = 0;
+ if (!IS_ALLOWED(SCONFIG_SHELL_INTERACTIVE))
+ return 0;
+
if (!ctrlc_allowed)
return 0;
diff --git a/common/console_simple.c b/common/console_simple.c
index d2feb58ea3e2ff1c4b382350156ea3d30b88eb95..dc748d8b698140f589598190f75b0ba23892a9a4 100644
--- a/common/console_simple.c
+++ b/common/console_simple.c
@@ -6,6 +6,7 @@
#include <errno.h>
#include <debug_ll.h>
#include <console.h>
+#include <security/config.h>
LIST_HEAD(console_list);
EXPORT_SYMBOL(console_list);
diff --git a/common/hush.c b/common/hush.c
index 21348c4b7510f074c9bdf27bc35dce0b17648648..8515e7733828715147fdbfba25844af3cca61e35 100644
--- a/common/hush.c
+++ b/common/hush.c
@@ -118,6 +118,7 @@
#include <binfmt.h>
#include <init.h>
#include <shell.h>
+#include <security/config.h>
/*cmd_boot.c*/
extern int do_bootd(int flag, int argc, char *argv[]); /* do_bootd */
@@ -1693,6 +1694,9 @@ char *shell_expand(char *str)
o_string o = {};
char *res, *parsed;
+ if (!IS_ALLOWED(SCONFIG_SHELL))
+ return str;
+
remove_quotes_in_str(str);
o.quote = 1;
@@ -1910,6 +1914,9 @@ int run_command(const char *cmd)
struct p_context ctx = {};
int ret;
+ if (!IS_ALLOWED(SCONFIG_SHELL))
+ return -EPERM;
+
initialize_context(&ctx);
ret = parse_string_outer(&ctx, cmd, FLAG_PARSE_SEMICOLON);
@@ -1922,6 +1929,9 @@ static int execute_script(const char *path, int argc, char *argv[])
{
int ret;
+ if (!IS_ALLOWED(SCONFIG_SHELL))
+ return -EPERM;
+
env_push_context();
ret = source_script(path, argc, argv);
env_pop_context();
@@ -1963,6 +1973,9 @@ int run_shell(void)
struct p_context ctx = {};
int exit = 0;
+ if (!IS_ALLOWED(SCONFIG_SHELL_INTERACTIVE))
+ return -EPERM;
+
login();
do {
diff --git a/common/parser.c b/common/parser.c
index 387cd64c42677419ca12bbde5bb7a811c03fa11d..16fff052cf63b7a0e237bc2de1188b27af1b9809 100644
--- a/common/parser.c
+++ b/common/parser.c
@@ -5,6 +5,7 @@
#include <password.h>
#include <environment.h>
#include <shell.h>
+#include <security/config.h>
/*
* not yet supported
@@ -190,6 +191,9 @@ int run_command(const char *cmd)
int argc, inquotes;
int rc = 0;
+ if (!IS_ALLOWED(SCONFIG_SHELL))
+ return -EPERM;
+
#ifdef DEBUG
pr_debug("[RUN_COMMAND] cmd[%p]=\"", cmd);
puts (cmd ? cmd : "NULL"); /* use puts - string may be loooong */
@@ -269,6 +273,9 @@ int run_shell(void)
static char lastcommand[CONFIG_CBSIZE] = { 0, };
int len;
+ if (!IS_ALLOWED(SCONFIG_SHELL_INTERACTIVE))
+ return -EPERM;
+
login();
for (;;) {
--
2.47.3
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH v2 22/24] security: add security policy for loading barebox environment
2025-09-17 13:53 [PATCH v2 00/24] Add security policy support Sascha Hauer
` (20 preceding siblings ...)
2025-09-17 13:53 ` [PATCH v2 21/24] security: shell: add policy for executing the shell Sascha Hauer
@ 2025-09-17 13:53 ` Sascha Hauer
2025-09-17 13:53 ` [PATCH v2 23/24] security: add filesystem security policies Sascha Hauer
` (3 subsequent siblings)
25 siblings, 0 replies; 31+ messages in thread
From: Sascha Hauer @ 2025-09-17 13:53 UTC (permalink / raw)
To: BAREBOX
In secure environments we shouldn't load a persistent and potentially
manipulated environment. Add a security policy for it.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
common/Sconfig | 8 ++++++++
common/environment.c | 6 ++++++
2 files changed, 14 insertions(+)
diff --git a/common/Sconfig b/common/Sconfig
index ac027022e932dffd429f0b34cb8e1a199b0b595b..ec68bc2737af02cff3ce38c7bc1b9d59af2336c5 100644
--- a/common/Sconfig
+++ b/common/Sconfig
@@ -20,6 +20,14 @@ config SHELL_INTERACTIVE
Disabling this option also disables interruption with ctrl-c keystrokes.
+config ENVIRONMENT_LOAD
+ bool "Allow loading barebox environment from persistent media"
+ depends on $(kconfig-enabled,ENV_HANDLING)
+ help
+ The barebox environment doesn't have any security measures and could be
+ manipulated by an attacker. Loading it from persistent media imposes a
+ security risk and should thus be disabled.
+
config RATP
bool "Allow remote control via RATP"
depends on $(kconfig-enabled,CONSOLE_RATP)
diff --git a/common/environment.c b/common/environment.c
index 33ab4c43295da0c66811d16649d0d6cc1a711277..62b8120cbd7d839b0d995bfe67b4e869a9e12aee 100644
--- a/common/environment.c
+++ b/common/environment.c
@@ -30,6 +30,7 @@
#include <efi/partition.h>
#include <bootsource.h>
#include <magicvar.h>
+#include <security/config.h>
#else
#define EXPORT_SYMBOL(x)
#endif
@@ -449,6 +450,11 @@ int envfs_load(const char *filename, const char *dir, unsigned flags)
int ret = 0;
size_t size, rsize;
+#ifdef __BAREBOX__
+ if (!IS_ALLOWED(SCONFIG_ENVIRONMENT_LOAD))
+ return -EPERM;
+#endif
+
if (!filename)
filename = default_environment_path_get();
if (!filename)
--
2.47.3
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH v2 23/24] security: add filesystem security policies
2025-09-17 13:53 [PATCH v2 00/24] Add security policy support Sascha Hauer
` (21 preceding siblings ...)
2025-09-17 13:53 ` [PATCH v2 22/24] security: add security policy for loading barebox environment Sascha Hauer
@ 2025-09-17 13:53 ` Sascha Hauer
2025-09-22 16:16 ` Ahmad Fatoum
2025-09-17 13:53 ` [PATCH v2 24/24] security: console: add security policy for console input Sascha Hauer
` (2 subsequent siblings)
25 siblings, 1 reply; 31+ messages in thread
From: Sascha Hauer @ 2025-09-17 13:53 UTC (permalink / raw)
To: BAREBOX
We don't have any trusted filesystems in barebox and a manipulated
filesystem could trick barebox into crashing or loading untrusted data,
so add a security policy for the barebox filesystems.
With SCONFIG_FS_EXTERNAL set barebox will allow mounting all filesystems
whereas with this option disabled only ramfs can be mounted. ramfs is
special: It is basically essential for barebox and also has no untrusted
data input.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
Sconfig | 1 +
fs/Sconfig | 5 +++++
fs/fs.c | 4 ++++
3 files changed, 10 insertions(+)
diff --git a/Sconfig b/Sconfig
index 7d7657e79061f4bf200519cf1fab8810b544f97e..cdb2ceccb1b46b038c0d4fa8dbd203737031dec5 100644
--- a/Sconfig
+++ b/Sconfig
@@ -8,3 +8,4 @@ source "security/Sconfig"
source "common/Sconfig"
source "drivers/usb/gadget/Sconfig"
source "commands/Sconfig"
+source "fs/Sconfig"
diff --git a/fs/Sconfig b/fs/Sconfig
new file mode 100644
index 0000000000000000000000000000000000000000..cdb58230f0e79addf8c0f719844af400e0d19939
--- /dev/null
+++ b/fs/Sconfig
@@ -0,0 +1,5 @@
+
+config FS_EXTERNAL
+ bool "Allow mounting external file systems"
+ help
+ Say y to permit mounting file systems beyond devfs and ramfs.
diff --git a/fs/fs.c b/fs/fs.c
index 54bd35786857ab0e588277870fd1630d9292e116..5dcdf223756f470f94da15947e3f4e30bc27c1bd 100644
--- a/fs/fs.c
+++ b/fs/fs.c
@@ -35,6 +35,7 @@
#include <libfile.h>
#include <parseopt.h>
#include <linux/namei.h>
+#include <security/config.h>
char *mkmodestr(unsigned long mode, char *str)
{
@@ -774,6 +775,9 @@ static int fs_probe(struct device *dev)
struct fs_driver *fsdrv = container_of(drv, struct fs_driver, drv);
int ret;
+ if (!IS_ALLOWED(SCONFIG_FS_EXTERNAL) && strcmp(fsdrv->drv.name, "ramfs"))
+ return -EPERM;
+
ret = dev->driver->probe(dev);
if (ret)
return ret;
--
2.47.3
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH v2 24/24] security: console: add security policy for console input
2025-09-17 13:53 [PATCH v2 00/24] Add security policy support Sascha Hauer
` (22 preceding siblings ...)
2025-09-17 13:53 ` [PATCH v2 23/24] security: add filesystem security policies Sascha Hauer
@ 2025-09-17 13:53 ` Sascha Hauer
2025-09-22 16:18 ` [PATCH v2 00/24] Add security policy support Ahmad Fatoum
2025-09-23 8:08 ` Sascha Hauer
25 siblings, 0 replies; 31+ messages in thread
From: Sascha Hauer @ 2025-09-17 13:53 UTC (permalink / raw)
To: BAREBOX
Disabling the input path of the console is the safest bet to make
barebox fully non interactive. Add a security policy for this case.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
common/Sconfig | 11 ++++++++++-
common/console.c | 6 ++++++
common/console_simple.c | 6 ++++++
3 files changed, 22 insertions(+), 1 deletion(-)
diff --git a/common/Sconfig b/common/Sconfig
index ec68bc2737af02cff3ce38c7bc1b9d59af2336c5..b5c585b11b20a9f106f62813263f739d74f3667f 100644
--- a/common/Sconfig
+++ b/common/Sconfig
@@ -2,6 +2,15 @@
menu "General Settings"
+config CONSOLE_INPUT
+ bool "Allow console input"
+ depends on $(kconfig-enabled,CONSOLE_SIMPLE) || $(kconfig-enabled,CONSOLE_FULL)
+ help
+ Say y here if you want to allow input on consoles. Disabling this is the safest
+ thing to make sure that a barebox build is fully non interactive. When you
+ still need to react to input for example to trigger a recovery boot then consider
+ disabling this option and disable SHELL_INTERACTIVE instead.
+
config SHELL
bool "Allow executing shell scripts"
depends on $(kconfig-enabled,SHELL_HUSH) || $(kconfig-enabled,SHELL_SIMPLE)
@@ -13,7 +22,7 @@ config SHELL
config SHELL_INTERACTIVE
bool "Allow executing interactive shell"
- depends on SHELL
+ depends on SHELL && CONSOLE_INPUT
help
An interactive shell cannot be safely executed in trusted environments. Disable
this option in lockdown security configs.
diff --git a/common/console.c b/common/console.c
index 8eff3dba925f6de077dd194651a137f30870989d..95e5fb4df33cc41f41207153d96b02406bb6d3cc 100644
--- a/common/console.c
+++ b/common/console.c
@@ -513,6 +513,9 @@ static int tstc_raw(void)
{
struct console_device *cdev;
+ if (!IS_ALLOWED(SCONFIG_CONSOLE_INPUT))
+ return 0;
+
for_each_console(cdev) {
if (!(cdev->f_active & CONSOLE_STDIN))
continue;
@@ -528,6 +531,9 @@ int getchar(void)
unsigned char ch;
uint64_t start;
+ if (!IS_ALLOWED(SCONFIG_CONSOLE_INPUT))
+ return -1;
+
/*
* For 100us we read the characters from the serial driver
* into a kfifo. This helps us not to lose characters
diff --git a/common/console_simple.c b/common/console_simple.c
index dc748d8b698140f589598190f75b0ba23892a9a4..c5f554bbee9bef92c54474a4bb48b7f162039618 100644
--- a/common/console_simple.c
+++ b/common/console_simple.c
@@ -45,6 +45,9 @@ EXPORT_SYMBOL(console_putc);
int tstc(void)
{
+ if (!IS_ALLOWED(SCONFIG_CONSOLE_INPUT))
+ return 0;
+
if (!console)
return 0;
@@ -54,6 +57,9 @@ EXPORT_SYMBOL(tstc);
int getchar(void)
{
+ if (!IS_ALLOWED(SCONFIG_CONSOLE_INPUT))
+ return -1;
+
if (!console)
return -EINVAL;
return console->getc(console);
--
2.47.3
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v2 04/24] Add security policy support
2025-09-17 13:53 ` [PATCH v2 04/24] Add security policy support Sascha Hauer
@ 2025-09-22 16:14 ` Ahmad Fatoum
2025-09-23 8:11 ` Sascha Hauer
0 siblings, 1 reply; 31+ messages in thread
From: Ahmad Fatoum @ 2025-09-22 16:14 UTC (permalink / raw)
To: Sascha Hauer, BAREBOX; +Cc: Ahmad Fatoum
On 17.09.25 15:53, Sascha Hauer wrote:
> +bool is_allowed(const struct security_policy *policy, unsigned option)
> +{
> + policy = policy ?: active_policy;
> +
> + if (WARN(option > SCONFIG_NUM))
> + return false;
> +
> + if (!policy && *CONFIG_SECURITY_POLICY_INIT) {
> + security_policy_select(CONFIG_SECURITY_POLICY_INIT);
> + policy = active_policy;
> + }
> +
> + if (policy) {
> + bool allow = __is_allowed(policy, option);
> +
> + policy_debug(policy, option, "%s for %pS\n",
> + allow ? "allowed" : "denied", (void *)_RET_IP_);
> +
> + return allow;
> + }
> +
> + if (IS_ENABLED(CONFIG_SECURITY_POLICY_DEFAULT_PERMISSIVE))
> + pr_warn_once("option %s checked before security policy was set!\n",
> + sconfig_name(option));
> + else
> + return false;
Not having a security policy selected outside of permissive mode is a bug, so
I don't think silent forbidding is a good idea.
At the very least, we should print the warning outside permissive mode as well,
if only to tell people if they select the policy too late in their board code.
What's wrong with a panic though?
> +
> + return true;
> +}
> +
> +int security_policy_activate(const struct security_policy *policy)
> +{
> + const struct security_policy *old_policy = active_policy;
> +
> + if (policy == old_policy)
> + return 0;
> +
> + active_policy = policy;
> +
> + for (int i = 0; i < SCONFIG_NUM; i++) {
> + if (__is_allowed(policy, i) == __is_allowed(old_policy, i))
> + continue;
> +
> + notifier_call_chain(&sconfig_notifier_list, i, NULL);
> + }
> +
> + return 0;
> +}
> +
> +const struct security_policy *security_policy_get(const char *name)
> +{
> + const struct policy_list_entry *entry;
> +
> + list_for_each_entry(entry, &policy_list, list) {
> + if (!strcmp(name, entry->policy->name))
> + return entry->policy;
> + }
> +
> + return NULL;
> +}
> +
> +int security_policy_select(const char *name)
> +{
> + const struct security_policy *policy;
> +
> + policy = security_policy_get(name);
> + if (!policy) {
> + policy_err("Policy '%s' not found!\n", name);
> + return -ENOENT;
> + }
> +
> + return security_policy_activate(policy);
> +}
> +
> +int __security_policy_register(const struct security_policy policy[])
> +{
> + int ret = 0;
> +
> + do {
> + struct policy_list_entry *entry;
> +
> + if (security_policy_get(policy->name)) {
> + policy_err("policy '%s' already registered\n", policy->name);
> + ret = -EBUSY;
> + continue;
> + }
> +
> + entry = xzalloc(sizeof(*entry));
> + entry->policy = policy;
> + list_add_tail(&entry->list, &policy_list);
> + } while ((policy++)->chained);
> +
> + return ret;
> +}
> +
> +#ifdef CONFIG_CMD_SCONFIG
> +void security_policy_unregister_one(const struct security_policy *policy)
> +{
> + struct policy_list_entry *entry;
> +
> + if (!policy)
> + return;
> +
> + list_for_each_entry(entry, &policy_list, list) {
> + if (entry->policy == policy) {
> + list_del(&entry->list);
> + return;
> + }
> + }
> +}
> +#endif
> +
> +void security_policy_list(void)
> +{
> + const struct policy_list_entry *entry;
> +
> + list_for_each_entry(entry, &policy_list, list) {
> + printf("%s\n", entry->policy->name);
> + }
> +}
> +
> +static int sconfig_handler_filtered(struct notifier_block *nb,
> + unsigned long opt, void *data)
> +{
> + struct sconfig_notifier_block *snb
> + = container_of(nb, struct sconfig_notifier_block, nb);
> + bool allow;
> +
> + if (snb->opt != opt)
> + return NOTIFY_DONE;
> +
> + allow = is_allowed(NULL, opt);
> +
> + policy_debug(active_policy, opt, "calling %pS to %s\n",
> + snb->cb_filtered, allow ? "allow" : "deny");
> +
> + snb->cb_filtered(snb, opt, is_allowed(NULL, opt));
> + return NOTIFY_OK;
> +}
> +
> +int __sconfig_register_handler_filtered(struct sconfig_notifier_block *snb,
> + sconfig_notifier_callback_t cb,
> + enum security_config_option opt)
> +{
> + snb->cb_filtered = cb;
> + snb->opt = opt;
> + return sconfig_register_handler(&snb->nb, sconfig_handler_filtered);
> +}
> +
> +struct device security_device = {
> + .name = "security",
> + .id = DEVICE_ID_SINGLE,
> +};
> +
> +static char *policy_name = "";
> +
> +static int security_policy_get_name(struct param_d *param, void *priv)
> +{
> + if (!active_policy) {
> + policy_name = "";
> + return 0;
> + }
> +
> + free_const(policy_name);
> + policy_name = strdup(active_policy->name);
> + return 0;
> +}
> +
> +static int security_init(void)
> +{
> + register_device(&security_device);
> +
> + dev_add_param_string(&security_device, "policy", param_set_readonly,
> + security_policy_get_name, &policy_name, NULL);
> +
> + return 0;
> +}
> +pure_initcall(security_init);
> diff --git a/security/sconfig_names.c b/security/sconfig_names.c
> new file mode 100644
> index 0000000000000000000000000000000000000000..c830c4eb389202403e049db6a71b70f0f18b76f5
> --- /dev/null
> +++ b/security/sconfig_names.c
> @@ -0,0 +1,18 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +
> +#include <security/config.h>
> +#include <string.h>
> +#include <errno.h>
> +#include <linux/kernel.h>
> +
> +#include <generated/sconfig_names.h>
> +
> +int sconfig_lookup(const char *name)
> +{
> + for (int i = 0; i < ARRAY_SIZE(sconfig_names); i++) {
> + if (!strcmp(name, sconfig_names[i]))
> + return i;
> + }
> +
> + return -ENOENT;
> +}
>
--
Pengutronix e.K. | |
Steuerwalder Str. 21 | http://www.pengutronix.de/ |
31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v2 23/24] security: add filesystem security policies
2025-09-17 13:53 ` [PATCH v2 23/24] security: add filesystem security policies Sascha Hauer
@ 2025-09-22 16:16 ` Ahmad Fatoum
2025-09-23 8:08 ` Sascha Hauer
0 siblings, 1 reply; 31+ messages in thread
From: Ahmad Fatoum @ 2025-09-22 16:16 UTC (permalink / raw)
To: Sascha Hauer, BAREBOX
On 17.09.25 15:53, Sascha Hauer wrote:
> We don't have any trusted filesystems in barebox and a manipulated
> filesystem could trick barebox into crashing or loading untrusted data,
> so add a security policy for the barebox filesystems.
>
> With SCONFIG_FS_EXTERNAL set barebox will allow mounting all filesystems
> whereas with this option disabled only ramfs can be mounted. ramfs is
> special: It is basically essential for barebox and also has no untrusted
> data input.
>
> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> ---
> Sconfig | 1 +
> fs/Sconfig | 5 +++++
> fs/fs.c | 4 ++++
> 3 files changed, 10 insertions(+)
>
> diff --git a/Sconfig b/Sconfig
> index 7d7657e79061f4bf200519cf1fab8810b544f97e..cdb2ceccb1b46b038c0d4fa8dbd203737031dec5 100644
> --- a/Sconfig
> +++ b/Sconfig
> @@ -8,3 +8,4 @@ source "security/Sconfig"
> source "common/Sconfig"
> source "drivers/usb/gadget/Sconfig"
> source "commands/Sconfig"
> +source "fs/Sconfig"
> diff --git a/fs/Sconfig b/fs/Sconfig
> new file mode 100644
> index 0000000000000000000000000000000000000000..cdb58230f0e79addf8c0f719844af400e0d19939
> --- /dev/null
> +++ b/fs/Sconfig
> @@ -0,0 +1,5 @@
> +
> +config FS_EXTERNAL
> + bool "Allow mounting external file systems"
> + help
> + Say y to permit mounting file systems beyond devfs and ramfs.
> diff --git a/fs/fs.c b/fs/fs.c
> index 54bd35786857ab0e588277870fd1630d9292e116..5dcdf223756f470f94da15947e3f4e30bc27c1bd 100644
> --- a/fs/fs.c
> +++ b/fs/fs.c
> @@ -35,6 +35,7 @@
> #include <libfile.h>
> #include <parseopt.h>
> #include <linux/namei.h>
> +#include <security/config.h>
>
> char *mkmodestr(unsigned long mode, char *str)
> {
> @@ -774,6 +775,9 @@ static int fs_probe(struct device *dev)
> struct fs_driver *fsdrv = container_of(drv, struct fs_driver, drv);
> int ret;
>
> + if (!IS_ALLOWED(SCONFIG_FS_EXTERNAL) && strcmp(fsdrv->drv.name, "ramfs"))
> + return -EPERM;
devfs is listed in the Kconfig help text, but missing here.
Cheers,
Ahmad
> +
> ret = dev->driver->probe(dev);
> if (ret)
> return ret;
>
--
Pengutronix e.K. | |
Steuerwalder Str. 21 | http://www.pengutronix.de/ |
31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v2 00/24] Add security policy support
2025-09-17 13:53 [PATCH v2 00/24] Add security policy support Sascha Hauer
` (23 preceding siblings ...)
2025-09-17 13:53 ` [PATCH v2 24/24] security: console: add security policy for console input Sascha Hauer
@ 2025-09-22 16:18 ` Ahmad Fatoum
2025-09-23 8:08 ` Sascha Hauer
25 siblings, 0 replies; 31+ messages in thread
From: Ahmad Fatoum @ 2025-09-22 16:18 UTC (permalink / raw)
To: Sascha Hauer, BAREBOX; +Cc: Ahmad Fatoum
Hello Sascha,
On 17.09.25 15:53, Sascha Hauer wrote:
> Changes in v2:
Thanks for taking over. I have no further comments besides the two I just
sent. I think this is ready to go into next with the two comments addressed.
Cheers,
Ahmad
> - drop security policies for each filesystem. This needs to be reworked.
> A filesystem can safely be mounted when the source is trusted (i.e.
> the fs image is compiled into barebox, or is authorized using upcoming
> dm-verity support) no matter which filesystem type is mounted.
> Therefore just add a policy which selects between "all fs allowed" and
> "no fs allowed except ramfs".
> - fix adding policy-y to non leaf directories
> - remove policy-list files before recreating them to avoid stale entries
> - Drop $(ARCH) string from .sconfig files
> - bail out with a user friendly message when make security_* is invoked
> with security policies being disabled in the config
> - document that policies should always go from restrictive to relaxed,
> not the other way round
> - Link to v1: https://lore.barebox.org/20250820-security-policies-v1-0-76fde70fdbd8@pengutronix.de
>
> Changes in v1:
> - Link to RFC:
> https://lore.kernel.org/all/20250814130702.4039241-1-a.fatoum@pengutronix.de/
> - Add more actual security policies
> - Fix some typos in Documentation
> - Catch invalid policy names in sconfig command
>
> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> ---
> Ahmad Fatoum (16):
> kconfig: allow setting CONFIG_ from the outside
> scripts: include scripts/include for all host tools
> kbuild: implement loopable loop_cmd
> Add security policy support
> kbuild: allow security config use without source tree modification
> defaultenv: update PS1 according to security policy
> security: policy: support externally provided configs
> docs: security-policies: add documentation
> commands: go: add security config option
> console: ratp: add security config option
> bootm: support calling bootm_optional_signed_images at any time
> bootm: make unsigned image support runtime configurable
> ARM: configs: add virt32_secure_defconfig
> boards: qemu-virt: add security policies
> boards: qemu-virt: allow setting policy from command line
> test: py: add basic security policy test
>
> Sascha Hauer (8):
> commands: implement sconfig command
> usbserial: add inline wrappers
> security: usbgadget: add usbgadget security policy
> security: fastboot: add security policy for fastboot oem
> security: shell: add policy for executing the shell
> security: add security policy for loading barebox environment
> security: add filesystem security policies
> security: console: add security policy for console input
>
> .gitignore | 4 +
> Documentation/devel/devel.rst | 1 +
> Documentation/devel/security-policies.rst | 96 ++++
> Documentation/user/defaultenv-2.rst | 2 +
> Documentation/user/security-policies.rst | 131 +++++
> Documentation/user/user-manual.rst | 1 +
> Makefile | 95 +++-
> Sconfig | 11 +
> arch/arm/configs/virt32_secure_defconfig | 302 ++++++++++++
> commands/Kconfig | 23 +
> commands/Makefile | 1 +
> commands/Sconfig | 12 +
> commands/go.c | 4 +
> commands/sconfig.c | 227 +++++++++
> common/Kconfig | 5 +
> common/Sconfig | 63 +++
> common/boards/qemu-virt/Makefile | 5 +-
> common/boards/qemu-virt/board.c | 11 +
> common/boards/qemu-virt/commandline.c | 74 +++
> common/boards/qemu-virt/commandline.h | 9 +
> common/boards/qemu-virt/qemu-virt-factory.sconfig | 36 ++
> common/boards/qemu-virt/qemu-virt-lockdown.sconfig | 35 ++
> common/bootm.c | 58 ++-
> common/console.c | 11 +-
> common/console_ctrlc.c | 4 +
> common/console_simple.c | 7 +
> common/environment.c | 6 +
> common/fastboot.c | 6 +
> common/hush.c | 13 +
> common/parser.c | 7 +
> common/ratp/ratp.c | 17 +
> common/usbgadget.c | 26 +
> defaultenv/Makefile | 1 +
> .../defaultenv-2-security-policy/bin/ps1-policy | 20 +
> .../defaultenv-2-security-policy/init/ps1-policy | 1 +
> .../init/source-colors | 1 +
> defaultenv/defaultenv.c | 2 +
> drivers/usb/gadget/Sconfig | 11 +
> drivers/usb/gadget/composite.c | 4 +
> drivers/usb/gadget/legacy/serial.c | 4 +
> fs/Sconfig | 5 +
> fs/fs.c | 4 +
> include/linux/usb/usbserial.h | 11 +
> include/security/config.h | 76 +++
> include/security/defs.h | 22 +
> include/security/policy.h | 54 +++
> scripts/Kbuild.include | 41 ++
> scripts/Makefile | 1 -
> scripts/Makefile.build | 18 +-
> scripts/Makefile.lib | 47 ++
> scripts/Makefile.policy | 38 ++
> scripts/Sconfig.include | 6 +
> scripts/basic/.gitignore | 1 +
> scripts/basic/Makefile | 4 +-
> scripts/basic/sconfigpost.c | 540 +++++++++++++++++++++
> scripts/include/list.h | 7 +
> scripts/kconfig/Makefile | 3 +
> scripts/kconfig/list.h | 132 -----
> security/Kconfig | 2 +
> security/Kconfig.policy | 104 ++++
> security/Makefile | 39 ++
> security/Sconfig | 34 ++
> security/policy.c | 239 +++++++++
> security/qemu-virt-devel.sconfig | 36 ++
> security/qemu-virt-tamper.sconfig | 35 ++
> security/sconfig_names.c | 18 +
> test/arm/virt32_secure_defconfig.yaml | 22 +
> test/py/test_policies.py | 48 ++
> 68 files changed, 2778 insertions(+), 156 deletions(-)
> ---
> base-commit: f3be3a8e9ae884bdfb116238e9049b1eb2759810
> change-id: 20250820-security-policies-43f73477d321
>
> Best regards,
--
Pengutronix e.K. | |
Steuerwalder Str. 21 | http://www.pengutronix.de/ |
31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v2 00/24] Add security policy support
2025-09-17 13:53 [PATCH v2 00/24] Add security policy support Sascha Hauer
` (24 preceding siblings ...)
2025-09-22 16:18 ` [PATCH v2 00/24] Add security policy support Ahmad Fatoum
@ 2025-09-23 8:08 ` Sascha Hauer
25 siblings, 0 replies; 31+ messages in thread
From: Sascha Hauer @ 2025-09-23 8:08 UTC (permalink / raw)
To: BAREBOX, Sascha Hauer; +Cc: Ahmad Fatoum, Ahmad Fatoum
On Wed, 17 Sep 2025 15:53:20 +0200, Sascha Hauer wrote:
> Security policies are a mechanism for barebox to prevent, when so
> desired, security relevant code from being executed.
>
> Security policies are controlled via a second Kconfig menu structure
> (called Sconfig) which collects security relevant options.
>
> While the normal Kconfig menu structure is about feature support
> enabled at compile time, a security policy determines whether a
> feature is allowed or prohibited at runtime with an explicit focus
> on security.
>
> [...]
Applied, thanks!
[01/24] kconfig: allow setting CONFIG_ from the outside
https://git.pengutronix.de/cgit/barebox/commit/?id=9a4281052b8f (link may not be stable)
[02/24] scripts: include scripts/include for all host tools
https://git.pengutronix.de/cgit/barebox/commit/?id=b1dd33f59373 (link may not be stable)
[03/24] kbuild: implement loopable loop_cmd
https://git.pengutronix.de/cgit/barebox/commit/?id=daaa3560414e (link may not be stable)
[04/24] Add security policy support
https://git.pengutronix.de/cgit/barebox/commit/?id=03a1030ea708 (link may not be stable)
[05/24] kbuild: allow security config use without source tree modification
https://git.pengutronix.de/cgit/barebox/commit/?id=74b1901d06f2 (link may not be stable)
[06/24] defaultenv: update PS1 according to security policy
https://git.pengutronix.de/cgit/barebox/commit/?id=98e1b8ef80b9 (link may not be stable)
[07/24] security: policy: support externally provided configs
https://git.pengutronix.de/cgit/barebox/commit/?id=d94aa6a99dfa (link may not be stable)
[08/24] commands: implement sconfig command
https://git.pengutronix.de/cgit/barebox/commit/?id=56de5ea4fe40 (link may not be stable)
[09/24] docs: security-policies: add documentation
https://git.pengutronix.de/cgit/barebox/commit/?id=9d8f7062b581 (link may not be stable)
[10/24] commands: go: add security config option
https://git.pengutronix.de/cgit/barebox/commit/?id=58401df16031 (link may not be stable)
[11/24] console: ratp: add security config option
https://git.pengutronix.de/cgit/barebox/commit/?id=d1f12e4aaaff (link may not be stable)
[12/24] bootm: support calling bootm_optional_signed_images at any time
https://git.pengutronix.de/cgit/barebox/commit/?id=48f1c4c70944 (link may not be stable)
[13/24] bootm: make unsigned image support runtime configurable
https://git.pengutronix.de/cgit/barebox/commit/?id=9dbde2ceea58 (link may not be stable)
[14/24] ARM: configs: add virt32_secure_defconfig
https://git.pengutronix.de/cgit/barebox/commit/?id=cc285c8c0ab4 (link may not be stable)
[15/24] boards: qemu-virt: add security policies
https://git.pengutronix.de/cgit/barebox/commit/?id=332277872144 (link may not be stable)
[16/24] boards: qemu-virt: allow setting policy from command line
https://git.pengutronix.de/cgit/barebox/commit/?id=cea49ae7bb88 (link may not be stable)
[17/24] test: py: add basic security policy test
https://git.pengutronix.de/cgit/barebox/commit/?id=b3773336f564 (link may not be stable)
[18/24] usbserial: add inline wrappers
https://git.pengutronix.de/cgit/barebox/commit/?id=4ee3cb57d9d9 (link may not be stable)
[19/24] security: usbgadget: add usbgadget security policy
https://git.pengutronix.de/cgit/barebox/commit/?id=0a14e84181ea (link may not be stable)
[20/24] security: fastboot: add security policy for fastboot oem
https://git.pengutronix.de/cgit/barebox/commit/?id=816b93d4bff7 (link may not be stable)
[21/24] security: shell: add policy for executing the shell
https://git.pengutronix.de/cgit/barebox/commit/?id=c3dede9a094a (link may not be stable)
[22/24] security: add security policy for loading barebox environment
https://git.pengutronix.de/cgit/barebox/commit/?id=0460dcb1b4a5 (link may not be stable)
[23/24] security: add filesystem security policies
https://git.pengutronix.de/cgit/barebox/commit/?id=7db9682703cd (link may not be stable)
[24/24] security: console: add security policy for console input
https://git.pengutronix.de/cgit/barebox/commit/?id=1d03e88d966d (link may not be stable)
Best regards,
--
Sascha Hauer <s.hauer@pengutronix.de>
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v2 23/24] security: add filesystem security policies
2025-09-22 16:16 ` Ahmad Fatoum
@ 2025-09-23 8:08 ` Sascha Hauer
0 siblings, 0 replies; 31+ messages in thread
From: Sascha Hauer @ 2025-09-23 8:08 UTC (permalink / raw)
To: Ahmad Fatoum; +Cc: BAREBOX
On Mon, Sep 22, 2025 at 06:16:34PM +0200, Ahmad Fatoum wrote:
> On 17.09.25 15:53, Sascha Hauer wrote:
> > We don't have any trusted filesystems in barebox and a manipulated
> > filesystem could trick barebox into crashing or loading untrusted data,
> > so add a security policy for the barebox filesystems.
> >
> > With SCONFIG_FS_EXTERNAL set barebox will allow mounting all filesystems
> > whereas with this option disabled only ramfs can be mounted. ramfs is
> > special: It is basically essential for barebox and also has no untrusted
> > data input.
> >
> > Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> > ---
> > Sconfig | 1 +
> > fs/Sconfig | 5 +++++
> > fs/fs.c | 4 ++++
> > 3 files changed, 10 insertions(+)
> >
> > diff --git a/Sconfig b/Sconfig
> > index 7d7657e79061f4bf200519cf1fab8810b544f97e..cdb2ceccb1b46b038c0d4fa8dbd203737031dec5 100644
> > --- a/Sconfig
> > +++ b/Sconfig
> > @@ -8,3 +8,4 @@ source "security/Sconfig"
> > source "common/Sconfig"
> > source "drivers/usb/gadget/Sconfig"
> > source "commands/Sconfig"
> > +source "fs/Sconfig"
> > diff --git a/fs/Sconfig b/fs/Sconfig
> > new file mode 100644
> > index 0000000000000000000000000000000000000000..cdb58230f0e79addf8c0f719844af400e0d19939
> > --- /dev/null
> > +++ b/fs/Sconfig
> > @@ -0,0 +1,5 @@
> > +
> > +config FS_EXTERNAL
> > + bool "Allow mounting external file systems"
> > + help
> > + Say y to permit mounting file systems beyond devfs and ramfs.
> > diff --git a/fs/fs.c b/fs/fs.c
> > index 54bd35786857ab0e588277870fd1630d9292e116..5dcdf223756f470f94da15947e3f4e30bc27c1bd 100644
> > --- a/fs/fs.c
> > +++ b/fs/fs.c
> > @@ -35,6 +35,7 @@
> > #include <libfile.h>
> > #include <parseopt.h>
> > #include <linux/namei.h>
> > +#include <security/config.h>
> >
> > char *mkmodestr(unsigned long mode, char *str)
> > {
> > @@ -774,6 +775,9 @@ static int fs_probe(struct device *dev)
> > struct fs_driver *fsdrv = container_of(drv, struct fs_driver, drv);
> > int ret;
> >
> > + if (!IS_ALLOWED(SCONFIG_FS_EXTERNAL) && strcmp(fsdrv->drv.name, "ramfs"))
> > + return -EPERM;
>
> devfs is listed in the Kconfig help text, but missing here.
Fixed
Sascha
--
Pengutronix e.K. | |
Steuerwalder Str. 21 | http://www.pengutronix.de/ |
31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v2 04/24] Add security policy support
2025-09-22 16:14 ` Ahmad Fatoum
@ 2025-09-23 8:11 ` Sascha Hauer
0 siblings, 0 replies; 31+ messages in thread
From: Sascha Hauer @ 2025-09-23 8:11 UTC (permalink / raw)
To: Ahmad Fatoum; +Cc: BAREBOX, Ahmad Fatoum
On Mon, Sep 22, 2025 at 06:14:36PM +0200, Ahmad Fatoum wrote:
> On 17.09.25 15:53, Sascha Hauer wrote:
> > +bool is_allowed(const struct security_policy *policy, unsigned option)
> > +{
> > + policy = policy ?: active_policy;
> > +
> > + if (WARN(option > SCONFIG_NUM))
> > + return false;
> > +
> > + if (!policy && *CONFIG_SECURITY_POLICY_INIT) {
> > + security_policy_select(CONFIG_SECURITY_POLICY_INIT);
> > + policy = active_policy;
> > + }
> > +
> > + if (policy) {
> > + bool allow = __is_allowed(policy, option);
> > +
> > + policy_debug(policy, option, "%s for %pS\n",
> > + allow ? "allowed" : "denied", (void *)_RET_IP_);
> > +
> > + return allow;
> > + }
> > +
> > + if (IS_ENABLED(CONFIG_SECURITY_POLICY_DEFAULT_PERMISSIVE))
> > + pr_warn_once("option %s checked before security policy was set!\n",
> > + sconfig_name(option));
> > + else
> > + return false;
>
> Not having a security policy selected outside of permissive mode is a bug, so
> I don't think silent forbidding is a good idea.
>
> At the very least, we should print the warning outside permissive mode as well,
> if only to tell people if they select the policy too late in their board code.
>
> What's wrong with a panic though?
The rationale was:
- It's forbidden, so it's safe
- I assumed the caller would print an error
- It might offer a bit more flexibility on when we select the security
policy
Anyway, we still make this more relaxed in the future should we want to.
For now I have put back the panic() here.
Sascha
--
Pengutronix e.K. | |
Steuerwalder Str. 21 | http://www.pengutronix.de/ |
31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
^ permalink raw reply [flat|nested] 31+ messages in thread
end of thread, other threads:[~2025-09-23 8:12 UTC | newest]
Thread overview: 31+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-09-17 13:53 [PATCH v2 00/24] Add security policy support Sascha Hauer
2025-09-17 13:53 ` [PATCH v2 01/24] kconfig: allow setting CONFIG_ from the outside Sascha Hauer
2025-09-17 13:53 ` [PATCH v2 02/24] scripts: include scripts/include for all host tools Sascha Hauer
2025-09-17 13:53 ` [PATCH v2 03/24] kbuild: implement loopable loop_cmd Sascha Hauer
2025-09-17 13:53 ` [PATCH v2 04/24] Add security policy support Sascha Hauer
2025-09-22 16:14 ` Ahmad Fatoum
2025-09-23 8:11 ` Sascha Hauer
2025-09-17 13:53 ` [PATCH v2 05/24] kbuild: allow security config use without source tree modification Sascha Hauer
2025-09-17 13:53 ` [PATCH v2 06/24] defaultenv: update PS1 according to security policy Sascha Hauer
2025-09-17 13:53 ` [PATCH v2 07/24] security: policy: support externally provided configs Sascha Hauer
2025-09-17 13:53 ` [PATCH v2 08/24] commands: implement sconfig command Sascha Hauer
2025-09-17 13:53 ` [PATCH v2 09/24] docs: security-policies: add documentation Sascha Hauer
2025-09-17 13:53 ` [PATCH v2 10/24] commands: go: add security config option Sascha Hauer
2025-09-17 13:53 ` [PATCH v2 11/24] console: ratp: " Sascha Hauer
2025-09-17 13:53 ` [PATCH v2 12/24] bootm: support calling bootm_optional_signed_images at any time Sascha Hauer
2025-09-17 13:53 ` [PATCH v2 13/24] bootm: make unsigned image support runtime configurable Sascha Hauer
2025-09-17 13:53 ` [PATCH v2 14/24] ARM: configs: add virt32_secure_defconfig Sascha Hauer
2025-09-17 13:53 ` [PATCH v2 15/24] boards: qemu-virt: add security policies Sascha Hauer
2025-09-17 13:53 ` [PATCH v2 16/24] boards: qemu-virt: allow setting policy from command line Sascha Hauer
2025-09-17 13:53 ` [PATCH v2 17/24] test: py: add basic security policy test Sascha Hauer
2025-09-17 13:53 ` [PATCH v2 18/24] usbserial: add inline wrappers Sascha Hauer
2025-09-17 13:53 ` [PATCH v2 19/24] security: usbgadget: add usbgadget security policy Sascha Hauer
2025-09-17 13:53 ` [PATCH v2 20/24] security: fastboot: add security policy for fastboot oem Sascha Hauer
2025-09-17 13:53 ` [PATCH v2 21/24] security: shell: add policy for executing the shell Sascha Hauer
2025-09-17 13:53 ` [PATCH v2 22/24] security: add security policy for loading barebox environment Sascha Hauer
2025-09-17 13:53 ` [PATCH v2 23/24] security: add filesystem security policies Sascha Hauer
2025-09-22 16:16 ` Ahmad Fatoum
2025-09-23 8:08 ` Sascha Hauer
2025-09-17 13:53 ` [PATCH v2 24/24] security: console: add security policy for console input Sascha Hauer
2025-09-22 16:18 ` [PATCH v2 00/24] Add security policy support Ahmad Fatoum
2025-09-23 8:08 ` Sascha Hauer
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox