* [PATCH 00/24] Add security policy support
@ 2025-08-20 13:17 Sascha Hauer
2025-08-20 13:17 ` [PATCH 01/24] kconfig: allow setting CONFIG_ from the outside Sascha Hauer
` (23 more replies)
0 siblings, 24 replies; 30+ messages in thread
From: Sascha Hauer @ 2025-08-20 13:17 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 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 | 121 +++++
Documentation/user/user-manual.rst | 1 +
Makefile | 81 +++-
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 | 24 +
common/boards/qemu-virt/qemu-virt-lockdown.sconfig | 24 +
common/bootm.c | 58 ++-
common/console.c | 15 +-
common/console_simple.c | 11 +
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/9p/vfs_super.c | 4 +
fs/Sconfig | 76 +++
fs/cramfs/cramfs.c | 4 +
fs/efi.c | 4 +
fs/efivarfs.c | 4 +
fs/ext4/ext_barebox.c | 5 +
fs/fat/fat.c | 5 +
fs/jffs2/fs.c | 5 +
fs/nfs.c | 6 +
fs/pstore/ram.c | 4 +
fs/qemu_fw_cfg.c | 6 +
fs/smhfs.c | 5 +
fs/squashfs/squashfs.c | 4 +
fs/tftp.c | 6 +
fs/ubifs/ubifs.c | 6 +
fs/ubootvarfs.c | 6 +
fs/uimagefs.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 | 43 ++
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 | 101 ++++
security/Makefile | 39 ++
security/Sconfig | 42 ++
security/policy.c | 246 ++++++++++
security/qemu-virt-devel.sconfig | 24 +
security/qemu-virt-tamper.sconfig | 24 +
security/sconfig_names.c | 18 +
test/arm/virt32_secure_defconfig.yaml | 22 +
test/py/test_policies.py | 49 ++
82 files changed, 2875 insertions(+), 156 deletions(-)
---
base-commit: 284e9d9c4a7d3037c8cf97acc63c6153a83f8652
change-id: 20250820-security-policies-43f73477d321
Best regards,
--
Sascha Hauer <s.hauer@pengutronix.de>
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 01/24] kconfig: allow setting CONFIG_ from the outside
2025-08-20 13:17 [PATCH 00/24] Add security policy support Sascha Hauer
@ 2025-08-20 13:17 ` Sascha Hauer
2025-08-20 13:17 ` [PATCH 02/24] scripts: include scripts/include for all host tools Sascha Hauer
` (22 subsequent siblings)
23 siblings, 0 replies; 30+ messages in thread
From: Sascha Hauer @ 2025-08-20 13:17 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.39.5
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 02/24] scripts: include scripts/include for all host tools
2025-08-20 13:17 [PATCH 00/24] Add security policy support Sascha Hauer
2025-08-20 13:17 ` [PATCH 01/24] kconfig: allow setting CONFIG_ from the outside Sascha Hauer
@ 2025-08-20 13:17 ` Sascha Hauer
2025-08-20 13:17 ` [PATCH 03/24] kbuild: implement loopable loop_cmd Sascha Hauer
` (21 subsequent siblings)
23 siblings, 0 replies; 30+ messages in thread
From: Sascha Hauer @ 2025-08-20 13:17 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 836176d541c3e806726e25cad6e195a0911d8e6f..209999618e8830e9495e3ff2297b50408ad625ae 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.39.5
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 03/24] kbuild: implement loopable loop_cmd
2025-08-20 13:17 [PATCH 00/24] Add security policy support Sascha Hauer
2025-08-20 13:17 ` [PATCH 01/24] kconfig: allow setting CONFIG_ from the outside Sascha Hauer
2025-08-20 13:17 ` [PATCH 02/24] scripts: include scripts/include for all host tools Sascha Hauer
@ 2025-08-20 13:17 ` Sascha Hauer
2025-08-20 13:17 ` [PATCH 04/24] Add security policy support Sascha Hauer
` (20 subsequent siblings)
23 siblings, 0 replies; 30+ messages in thread
From: Sascha Hauer @ 2025-08-20 13:17 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.39.5
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 04/24] Add security policy support
2025-08-20 13:17 [PATCH 00/24] Add security policy support Sascha Hauer
` (2 preceding siblings ...)
2025-08-20 13:17 ` [PATCH 03/24] kbuild: implement loopable loop_cmd Sascha Hauer
@ 2025-08-20 13:17 ` Sascha Hauer
2025-08-20 13:17 ` [PATCH 05/24] kbuild: allow security config use without source tree modification Sascha Hauer
` (19 subsequent siblings)
23 siblings, 0 replies; 30+ messages in thread
From: Sascha Hauer @ 2025-08-20 13:17 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 | 71 +++++-
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 | 39 ++++
scripts/Sconfig.include | 6 +
scripts/basic/.gitignore | 1 +
scripts/basic/Makefile | 2 +
scripts/basic/sconfigpost.c | 540 ++++++++++++++++++++++++++++++++++++++++++++
security/Kconfig | 2 +
security/Kconfig.policy | 86 +++++++
security/Makefile | 2 +
security/Sconfig | 42 ++++
security/policy.c | 243 ++++++++++++++++++++
security/sconfig_names.c | 18 ++
20 files changed, 1305 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 209999618e8830e9495e3ff2297b50408ad625ae..a2e5697b09fe219739bf2c4de45db8d54e09fc32 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= $@
@@ -1171,6 +1175,60 @@ 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
+
+endif
+
# ---------------------------------------------------------------------------
# Devicetree files
@@ -1299,8 +1357,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
@@ -1321,7 +1379,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
@@ -1485,6 +1544,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..ee6ddf53bccbdc427227b8b0e8fe9eeefb470047
--- /dev/null
+++ b/Sconfig
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+mainmenu "Barebox/$(ARCH) 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 591da3d750ec74596a59f57692fbf545a10dd6d7..d6b4f0344a31c0d36f5de352ac49a28d63b9ad8e 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 ($(need-dtbslist)$(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 e6f0e254960a69b7aa3273bdc5469e75c39db977..f84d1456526c1c4dfca837ff0f36c0d542b6ae1e 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)))
@@ -652,3 +659,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..4c71774bbbc98f9de9cf5463e5ef431de60be6ac
--- /dev/null
+++ b/scripts/Makefile.policy
@@ -0,0 +1,39 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+real-policy-y := $(addprefix $(obj)/, $(policy-y))
+
+targets += $(addsuffix .tmp, $(real-policy-y))
+
+# policy-list
+# ---------------------------------------------------------------------------
+
+subdir-policylist := $(addsuffix /policy-list, $(subdir-ym))
+real-policy-y += $(subdir-policylist)
+
+ifneq ($(policy-y)$(policy-),)
+always-y += $(obj)/policy-list
+
+$(subdir-policylist): $(obj)/%/policy-list: $(obj)/% ;
+
+$(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 372fd275fde935a9d7e16512b6eb685abe0e6059..de58002f9656f927a33321b1f165538068e723c4 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..6c5cb5687c17c5a66f8757191c00d1c3d75a9312
--- /dev/null
+++ b/security/Kconfig.policy
@@ -0,0 +1,86 @@
+# 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.
+
+choice
+ prompt "Initial Security Policy"
+ default SECURITY_POLICY_DEFAULT_PERMISSIVE
+
+config SECURITY_POLICY_DEFAULT_PERMISSIVE
+ bool "Permissive by default"
+ select HAS_INSECURE_DEFAULTS
+ help
+ In absence of a selected security policy, everything is allowed.
+ A warning will be printed the first time a security policy would
+ need to be consulted.
+
+ 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_DEFAULT_PANIC
+ bool "Panic"
+ help
+ In absence of a selected security policy, panic on the first
+ time a security policy is to be consulted.
+
+ If CONFIG_SECURITY_POLICY_INIT is not set, this expects a
+ security policy to be selected prior to late_initcall.
+
+endchoice
+
+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..f7bf67e6e05bd77e362b61b82228f68abd64f8bd
--- /dev/null
+++ b/security/Sconfig
@@ -0,0 +1,42 @@
+# 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.
+
+config SECURITY_POLICY_SELECT
+ bool "Allow selecting a different security policy"
+ depends on $(kconfig-enabled,SECURITY_POLICY)
+ default y
+ help
+ Say n here if selecting this policy is final and all subsequent calls
+ to security_policy_select should be refused.
diff --git a/security/policy.c b/security/policy.c
new file mode 100644
index 0000000000000000000000000000000000000000..10d6148866ab2eba6cc8ff0d78e99025d83ed3e8
--- /dev/null
+++ b/security/policy.c
@@ -0,0 +1,243 @@
+// 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
+ panic(pr_fmt("option %s checked before security policy was set!"),
+ sconfig_name(option));
+
+ 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;
+
+ if (old_policy && !IS_ALLOWED(SCONFIG_SECURITY_POLICY_SELECT)) {
+ pr_err("Policy %s is permanent once selected\n",
+ active_policy->name);
+ return -EPERM;
+ }
+
+ 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.39.5
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 05/24] kbuild: allow security config use without source tree modification
2025-08-20 13:17 [PATCH 00/24] Add security policy support Sascha Hauer
` (3 preceding siblings ...)
2025-08-20 13:17 ` [PATCH 04/24] Add security policy support Sascha Hauer
@ 2025-08-20 13:17 ` Sascha Hauer
2025-08-20 13:17 ` [PATCH 06/24] defaultenv: update PS1 according to security policy Sascha Hauer
` (18 subsequent siblings)
23 siblings, 0 replies; 30+ messages in thread
From: Sascha Hauer @ 2025-08-20 13:17 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 a2e5697b09fe219739bf2c4de45db8d54e09fc32..6027b5c37c82a99d1e9518edb790e9934378afab 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.
@@ -1213,8 +1213,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 4c71774bbbc98f9de9cf5463e5ef431de60be6ac..7629afc432269e70d5fa7403fef3bad28f00135a 100644
--- a/scripts/Makefile.policy
+++ b/scripts/Makefile.policy
@@ -23,7 +23,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.39.5
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 06/24] defaultenv: update PS1 according to security policy
2025-08-20 13:17 [PATCH 00/24] Add security policy support Sascha Hauer
` (4 preceding siblings ...)
2025-08-20 13:17 ` [PATCH 05/24] kbuild: allow security config use without source tree modification Sascha Hauer
@ 2025-08-20 13:17 ` Sascha Hauer
2025-08-20 15:33 ` [PATCH] fixup! " Ahmad Fatoum
2025-08-20 13:17 ` [PATCH 07/24] security: policy: support externally provided configs Sascha Hauer
` (17 subsequent siblings)
23 siblings, 1 reply; 30+ messages in thread
From: Sascha Hauer @ 2025-08-20 13:17 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 ad211d1fa519547f128e982423071328235b8ea8..290aab447b6243e48bf51068d5295b08d9299db8 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -1091,6 +1091,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..af121bbbaeedfbf6ade22431d3b7bf1de862701f
--- /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.39.5
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 07/24] security: policy: support externally provided configs
2025-08-20 13:17 [PATCH 00/24] Add security policy support Sascha Hauer
` (5 preceding siblings ...)
2025-08-20 13:17 ` [PATCH 06/24] defaultenv: update PS1 according to security policy Sascha Hauer
@ 2025-08-20 13:17 ` Sascha Hauer
2025-08-20 13:17 ` [PATCH 08/24] commands: implement sconfig command Sascha Hauer
` (16 subsequent siblings)
23 siblings, 0 replies; 30+ messages in thread
From: Sascha Hauer @ 2025-08-20 13:17 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 6c5cb5687c17c5a66f8757191c00d1c3d75a9312..bf938a9f3dd87fc21009f0260f3cf8be7937bd36 100644
--- a/security/Kconfig.policy
+++ b/security/Kconfig.policy
@@ -80,6 +80,21 @@ config SECURITY_POLICY_DEFAULT_PANIC
endchoice
+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..3e92fb776fb2aed36cb79ee267b02c7c279eabce 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 exit 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 10d6148866ab2eba6cc8ff0d78e99025d83ed3e8..774e64968cbab2d5e63155caacebf0a2d31627da 100644
--- a/security/policy.c
+++ b/security/policy.c
@@ -238,6 +238,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.39.5
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 08/24] commands: implement sconfig command
2025-08-20 13:17 [PATCH 00/24] Add security policy support Sascha Hauer
` (6 preceding siblings ...)
2025-08-20 13:17 ` [PATCH 07/24] security: policy: support externally provided configs Sascha Hauer
@ 2025-08-20 13:17 ` Sascha Hauer
2025-08-20 13:17 ` [PATCH 09/24] docs: security-policies: add documentation Sascha Hauer
` (15 subsequent siblings)
23 siblings, 0 replies; 30+ messages in thread
From: Sascha Hauer @ 2025-08-20 13:17 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 02b45d8cbe09da68b4a032c83d6f8ba3cca6d5ee..9b9dc57599f60ae415fac4ceb48b0b780d69fb13 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 fadf9e7cc7e0e2d58a3a51b303b1d6a58f772f7a..211f92d4f38c9b18d64c2d1c1f8f3b6f109f9732 100644
--- a/commands/Makefile
+++ b/commands/Makefile
@@ -165,4 +165,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..bd354c6301e04a6ea293d806554b6152010b0bc2
--- /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] [<+->CAP]...")
+ 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.39.5
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 09/24] docs: security-policies: add documentation
2025-08-20 13:17 [PATCH 00/24] Add security policy support Sascha Hauer
` (7 preceding siblings ...)
2025-08-20 13:17 ` [PATCH 08/24] commands: implement sconfig command Sascha Hauer
@ 2025-08-20 13:17 ` Sascha Hauer
2025-08-20 13:17 ` [PATCH 10/24] commands: go: add security config option Sascha Hauer
` (14 subsequent siblings)
23 siblings, 0 replies; 30+ messages in thread
From: Sascha Hauer @ 2025-08-20 13:17 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 | 121 ++++++++++++++++++++++++++++++
Documentation/user/user-manual.rst | 1 +
Makefile | 2 +-
security/Kconfig.policy | 4 +-
6 files changed, 222 insertions(+), 3 deletions(-)
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..94b470ee693deb0688b0d61128f5257fa412e403
--- /dev/null
+++ b/Documentation/user/security-policies.rst
@@ -0,0 +1,121 @@
+.. _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");
+
+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
diff --git a/Makefile b/Makefile
index 6027b5c37c82a99d1e9518edb790e9934378afab..49658e5fe28f913e4c12b9dd5b52fb91cc19a79a 100644
--- a/Makefile
+++ b/Makefile
@@ -1215,7 +1215,7 @@ security_%config: collect-policies $(KPOLICY.tmp) FORCE
$(@:security_%=%),$p.tmp))
ifeq ($(KPOLICY_TMPUPDATE),)
+$(Q)$(foreach p, $(KPOLICY), \
- cp 2>/dev/null $p.tmp $(call resolve-srctree,$p) || true;)
+ cp 2>/dev/null $p.tmp $(call resolve-srctree,$p);)
endif
quiet_cmd_sconfigpost = SCONFPP $@
diff --git a/security/Kconfig.policy b/security/Kconfig.policy
index bf938a9f3dd87fc21009f0260f3cf8be7937bd36..afe1c17735edd4387c6b0b88b0429c51ea52dcac 100644
--- a/security/Kconfig.policy
+++ b/security/Kconfig.policy
@@ -54,11 +54,11 @@ config SECURITY_POLICY_INIT
the restrictions if needed instead of the other way round.
choice
- prompt "Initial Security Policy"
+ prompt "Behavior on missing security policy"
default SECURITY_POLICY_DEFAULT_PERMISSIVE
config SECURITY_POLICY_DEFAULT_PERMISSIVE
- bool "Permissive by default"
+ bool "Permissive"
select HAS_INSECURE_DEFAULTS
help
In absence of a selected security policy, everything is allowed.
--
2.39.5
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 10/24] commands: go: add security config option
2025-08-20 13:17 [PATCH 00/24] Add security policy support Sascha Hauer
` (8 preceding siblings ...)
2025-08-20 13:17 ` [PATCH 09/24] docs: security-policies: add documentation Sascha Hauer
@ 2025-08-20 13:17 ` Sascha Hauer
2025-08-20 13:17 ` [PATCH 11/24] console: ratp: " Sascha Hauer
` (13 subsequent siblings)
23 siblings, 0 replies; 30+ messages in thread
From: Sascha Hauer @ 2025-08-20 13:17 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 ee6ddf53bccbdc427227b8b0e8fe9eeefb470047..93f5760ad96fdde7141c47e2680dc5f4bc142ca7 100644
--- a/Sconfig
+++ b/Sconfig
@@ -5,3 +5,4 @@ mainmenu "Barebox/$(ARCH) 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.39.5
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 11/24] console: ratp: add security config option
2025-08-20 13:17 [PATCH 00/24] Add security policy support Sascha Hauer
` (9 preceding siblings ...)
2025-08-20 13:17 ` [PATCH 10/24] commands: go: add security config option Sascha Hauer
@ 2025-08-20 13:17 ` Sascha Hauer
2025-08-20 13:17 ` [PATCH 12/24] bootm: support calling bootm_optional_signed_images at any time Sascha Hauer
` (12 subsequent siblings)
23 siblings, 0 replies; 30+ messages in thread
From: Sascha Hauer @ 2025-08-20 13:17 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 93f5760ad96fdde7141c47e2680dc5f4bc142ca7..899a1fb5783fb79def32e5af160b39208fea2edc 100644
--- a/Sconfig
+++ b/Sconfig
@@ -5,4 +5,5 @@ mainmenu "Barebox/$(ARCH) 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 dc552e4c5dacafd6649ee4ddea86084d0b7278ad..65e4f1f852243fa15d19e68d724cf340b950df06 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.39.5
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 12/24] bootm: support calling bootm_optional_signed_images at any time
2025-08-20 13:17 [PATCH 00/24] Add security policy support Sascha Hauer
` (10 preceding siblings ...)
2025-08-20 13:17 ` [PATCH 11/24] console: ratp: " Sascha Hauer
@ 2025-08-20 13:17 ` Sascha Hauer
2025-08-20 13:17 ` [PATCH 13/24] bootm: make unsigned image support runtime configurable Sascha Hauer
` (11 subsequent siblings)
23 siblings, 0 replies; 30+ messages in thread
From: Sascha Hauer @ 2025-08-20 13:17 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.39.5
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 13/24] bootm: make unsigned image support runtime configurable
2025-08-20 13:17 [PATCH 00/24] Add security policy support Sascha Hauer
` (11 preceding siblings ...)
2025-08-20 13:17 ` [PATCH 12/24] bootm: support calling bootm_optional_signed_images at any time Sascha Hauer
@ 2025-08-20 13:17 ` Sascha Hauer
2025-08-20 13:17 ` [PATCH 14/24] ARM: configs: add virt32_secure_defconfig Sascha Hauer
` (10 subsequent siblings)
23 siblings, 0 replies; 30+ messages in thread
From: Sascha Hauer @ 2025-08-20 13:17 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.39.5
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 14/24] ARM: configs: add virt32_secure_defconfig
2025-08-20 13:17 [PATCH 00/24] Add security policy support Sascha Hauer
` (12 preceding siblings ...)
2025-08-20 13:17 ` [PATCH 13/24] bootm: make unsigned image support runtime configurable Sascha Hauer
@ 2025-08-20 13:17 ` Sascha Hauer
2025-08-20 13:17 ` [PATCH 15/24] boards: qemu-virt: add security policies Sascha Hauer
` (9 subsequent siblings)
23 siblings, 0 replies; 30+ messages in thread
From: Sascha Hauer @ 2025-08-20 13:17 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.39.5
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 15/24] boards: qemu-virt: add security policies
2025-08-20 13:17 [PATCH 00/24] Add security policy support Sascha Hauer
` (13 preceding siblings ...)
2025-08-20 13:17 ` [PATCH 14/24] ARM: configs: add virt32_secure_defconfig Sascha Hauer
@ 2025-08-20 13:17 ` Sascha Hauer
2025-08-21 6:57 ` Ahmad Fatoum
2025-08-20 13:18 ` [PATCH 16/24] boards: qemu-virt: allow setting policy from command line Sascha Hauer
` (8 subsequent siblings)
23 siblings, 1 reply; 30+ messages in thread
From: Sascha Hauer @ 2025-08-20 13:17 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 | 24 ++++++++++++++++++++++
common/boards/qemu-virt/qemu-virt-lockdown.sconfig | 24 ++++++++++++++++++++++
security/qemu-virt-devel.sconfig | 24 ++++++++++++++++++++++
security/qemu-virt-tamper.sconfig | 24 ++++++++++++++++++++++
7 files changed, 108 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..b19d02b37f7c308e8e93da17349981301902d851
--- /dev/null
+++ b/common/boards/qemu-virt/qemu-virt-factory.sconfig
@@ -0,0 +1,24 @@
+#
+# Automatically generated file; DO NOT EDIT.
+# Barebox/arm Security Configuration
+#
+SCONFIG_POLICY_NAME="factory"
+SCONFIG_SECURITY_POLICY_SELECT=y
+
+#
+# General Settings
+#
+SCONFIG_RATP=y
+# end of General Settings
+
+#
+# Boot Policy
+#
+# SCONFIG_BOOT_UNSIGNED_IMAGES is not set
+# end of Boot Policy
+
+#
+# Command Policy
+#
+# SCONFIG_CMD_GO is not set
+# end of Command Policy
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..e11e5e069c61f6b968716b75a836bfda2676057e
--- /dev/null
+++ b/common/boards/qemu-virt/qemu-virt-lockdown.sconfig
@@ -0,0 +1,24 @@
+#
+# Automatically generated file; DO NOT EDIT.
+# Barebox/arm Security Configuration
+#
+SCONFIG_POLICY_NAME="lockdown"
+SCONFIG_SECURITY_POLICY_SELECT=y
+
+#
+# General Settings
+#
+# SCONFIG_RATP is not set
+# end of General Settings
+
+#
+# Boot Policy
+#
+# SCONFIG_BOOT_UNSIGNED_IMAGES is not set
+# end of Boot Policy
+
+#
+# Command Policy
+#
+# SCONFIG_CMD_GO is not set
+# end of Command Policy
diff --git a/security/qemu-virt-devel.sconfig b/security/qemu-virt-devel.sconfig
new file mode 100644
index 0000000000000000000000000000000000000000..4513917a95cca07d415fcc856589dca92a289707
--- /dev/null
+++ b/security/qemu-virt-devel.sconfig
@@ -0,0 +1,24 @@
+#
+# Automatically generated file; DO NOT EDIT.
+# Barebox/arm Security Configuration
+#
+SCONFIG_POLICY_NAME="devel"
+SCONFIG_SECURITY_POLICY_SELECT=y
+
+#
+# General Settings
+#
+SCONFIG_RATP=y
+# end of General Settings
+
+#
+# Boot Policy
+#
+SCONFIG_BOOT_UNSIGNED_IMAGES=y
+# end of Boot Policy
+
+#
+# Command Policy
+#
+SCONFIG_CMD_GO=y
+# end of Command Policy
diff --git a/security/qemu-virt-tamper.sconfig b/security/qemu-virt-tamper.sconfig
new file mode 100644
index 0000000000000000000000000000000000000000..f2453a9936c19fe8a31879d1ee48cd0ce6655d5e
--- /dev/null
+++ b/security/qemu-virt-tamper.sconfig
@@ -0,0 +1,24 @@
+#
+# Automatically generated file; DO NOT EDIT.
+# Barebox/arm Security Configuration
+#
+SCONFIG_POLICY_NAME="tamper"
+# SCONFIG_SECURITY_POLICY_SELECT is not set
+
+#
+# General Settings
+#
+# SCONFIG_RATP is not set
+# end of General Settings
+
+#
+# Boot Policy
+#
+# SCONFIG_BOOT_UNSIGNED_IMAGES is not set
+# end of Boot Policy
+
+#
+# Command Policy
+#
+# SCONFIG_CMD_GO is not set
+# end of Command Policy
--
2.39.5
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 16/24] boards: qemu-virt: allow setting policy from command line
2025-08-20 13:17 [PATCH 00/24] Add security policy support Sascha Hauer
` (14 preceding siblings ...)
2025-08-20 13:17 ` [PATCH 15/24] boards: qemu-virt: add security policies Sascha Hauer
@ 2025-08-20 13:18 ` Sascha Hauer
2025-08-20 13:18 ` [PATCH 17/24] test: py: add basic security policy test Sascha Hauer
` (7 subsequent siblings)
23 siblings, 0 replies; 30+ messages in thread
From: Sascha Hauer @ 2025-08-20 13:18 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.39.5
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 17/24] test: py: add basic security policy test
2025-08-20 13:17 [PATCH 00/24] Add security policy support Sascha Hauer
` (15 preceding siblings ...)
2025-08-20 13:18 ` [PATCH 16/24] boards: qemu-virt: allow setting policy from command line Sascha Hauer
@ 2025-08-20 13:18 ` Sascha Hauer
2025-08-20 13:18 ` [PATCH 18/24] usbserial: add inline wrappers Sascha Hauer
` (6 subsequent siblings)
23 siblings, 0 replies; 30+ messages in thread
From: Sascha Hauer @ 2025-08-20 13:18 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 | 49 +++++++++++++++++++++++++++++++++++
2 files changed, 50 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..28ab16d2cf6899942d84bdc44b98e624701439cd
--- /dev/null
+++ b/test/py/test_policies.py
@@ -0,0 +1,49 @@
+# 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_SECURITY_POLICY_SELECT',
+ '-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.39.5
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 18/24] usbserial: add inline wrappers
2025-08-20 13:17 [PATCH 00/24] Add security policy support Sascha Hauer
` (16 preceding siblings ...)
2025-08-20 13:18 ` [PATCH 17/24] test: py: add basic security policy test Sascha Hauer
@ 2025-08-20 13:18 ` Sascha Hauer
2025-08-20 13:18 ` [PATCH 19/24] security: usbgadget: add usbgadget security policy Sascha Hauer
` (5 subsequent siblings)
23 siblings, 0 replies; 30+ messages in thread
From: Sascha Hauer @ 2025-08-20 13:18 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.39.5
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 19/24] security: usbgadget: add usbgadget security policy
2025-08-20 13:17 [PATCH 00/24] Add security policy support Sascha Hauer
` (17 preceding siblings ...)
2025-08-20 13:18 ` [PATCH 18/24] usbserial: add inline wrappers Sascha Hauer
@ 2025-08-20 13:18 ` Sascha Hauer
2025-08-20 13:18 ` [PATCH 20/24] security: fastboot: add security policy for fastboot oem Sascha Hauer
` (4 subsequent siblings)
23 siblings, 0 replies; 30+ messages in thread
From: Sascha Hauer @ 2025-08-20 13:18 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 899a1fb5783fb79def32e5af160b39208fea2edc..878d5055af2967617219cbadbfd8bee3f85236bd 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.39.5
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 20/24] security: fastboot: add security policy for fastboot oem
2025-08-20 13:17 [PATCH 00/24] Add security policy support Sascha Hauer
` (18 preceding siblings ...)
2025-08-20 13:18 ` [PATCH 19/24] security: usbgadget: add usbgadget security policy Sascha Hauer
@ 2025-08-20 13:18 ` Sascha Hauer
2025-08-20 13:18 ` [PATCH 21/24] security: shell: add policy for executing the shell Sascha Hauer
` (3 subsequent siblings)
23 siblings, 0 replies; 30+ messages in thread
From: Sascha Hauer @ 2025-08-20 13:18 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 603391de77392aa7e1e61e32fd1844642f8ea42c..5c83b102e13909d49401ce03f9a98c6077894ee0 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>
@@ -966,6 +967,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.39.5
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 21/24] security: shell: add policy for executing the shell
2025-08-20 13:17 [PATCH 00/24] Add security policy support Sascha Hauer
` (19 preceding siblings ...)
2025-08-20 13:18 ` [PATCH 20/24] security: fastboot: add security policy for fastboot oem Sascha Hauer
@ 2025-08-20 13:18 ` Sascha Hauer
2025-08-20 13:18 ` [PATCH 22/24] security: add security policy for loading barebox environment Sascha Hauer
` (2 subsequent siblings)
23 siblings, 0 replies; 30+ messages in thread
From: Sascha Hauer @ 2025-08-20 13:18 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 | 5 +++++
common/console_simple.c | 5 +++++
common/hush.c | 13 +++++++++++++
common/parser.c | 7 +++++++
5 files changed, 48 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 65e4f1f852243fa15d19e68d724cf340b950df06..ee498fadf3700376b6325be10911b2081ff1ebb3 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);
@@ -673,6 +674,10 @@ EXPORT_SYMBOL(ctrlc_non_interruptible);
int ctrlc(void)
{
resched();
+
+ if (!IS_ALLOWED(SCONFIG_SHELL_INTERACTIVE))
+ return 0;
+
return ctrlc_non_interruptible();
}
EXPORT_SYMBOL(ctrlc);
diff --git a/common/console_simple.c b/common/console_simple.c
index 702087bd23d75c3c7d3d0aec25c97f0e88064ef1..f00fd567ed5d1ec7b0a8f00179953c08dda49de3 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);
@@ -70,6 +71,10 @@ EXPORT_SYMBOL(console_flush);
int ctrlc (void)
{
int ret = 0;
+
+ if (!IS_ALLOWED(SCONFIG_SHELL_INTERACTIVE))
+ return 0;
+
#ifdef CONFIG_ARCH_HAS_CTRLC
ret = arch_ctrlc();
#else
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.39.5
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 22/24] security: add security policy for loading barebox environment
2025-08-20 13:17 [PATCH 00/24] Add security policy support Sascha Hauer
` (20 preceding siblings ...)
2025-08-20 13:18 ` [PATCH 21/24] security: shell: add policy for executing the shell Sascha Hauer
@ 2025-08-20 13:18 ` Sascha Hauer
2025-08-20 13:18 ` [PATCH 23/24] security: add filesystem security policies Sascha Hauer
2025-08-20 13:18 ` [PATCH 24/24] security: console: add security policy for console input Sascha Hauer
23 siblings, 0 replies; 30+ messages in thread
From: Sascha Hauer @ 2025-08-20 13:18 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.39.5
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 23/24] security: add filesystem security policies
2025-08-20 13:17 [PATCH 00/24] Add security policy support Sascha Hauer
` (21 preceding siblings ...)
2025-08-20 13:18 ` [PATCH 22/24] security: add security policy for loading barebox environment Sascha Hauer
@ 2025-08-20 13:18 ` Sascha Hauer
2025-08-20 14:39 ` Ahmad Fatoum
2025-08-20 13:18 ` [PATCH 24/24] security: console: add security policy for console input Sascha Hauer
23 siblings, 1 reply; 30+ messages in thread
From: Sascha Hauer @ 2025-08-20 13:18 UTC (permalink / raw)
To: BAREBOX
We don't have any trusted filesystems in barebox and a manipulated
filesystem could trick barebox into crashing, so add security policies
for the barebox filesystems.
Some filesystems might be considered secure in special cases, so each
filesystem gets its own option. devfs and ramfs are not optional though
as these are purely internal and do not read untrusted data.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
Sconfig | 1 +
fs/9p/vfs_super.c | 4 +++
fs/Sconfig | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++
fs/cramfs/cramfs.c | 4 +++
fs/efi.c | 4 +++
fs/efivarfs.c | 4 +++
fs/ext4/ext_barebox.c | 5 ++++
fs/fat/fat.c | 5 ++++
fs/jffs2/fs.c | 5 ++++
fs/nfs.c | 6 ++++
fs/pstore/ram.c | 4 +++
fs/qemu_fw_cfg.c | 6 ++++
fs/smhfs.c | 5 ++++
fs/squashfs/squashfs.c | 4 +++
fs/tftp.c | 6 ++++
fs/ubifs/ubifs.c | 6 ++++
fs/ubootvarfs.c | 6 ++++
fs/uimagefs.c | 4 +++
18 files changed, 155 insertions(+)
diff --git a/Sconfig b/Sconfig
index 878d5055af2967617219cbadbfd8bee3f85236bd..183a6687f0d1687ccb1a6191a629ccace0eb929e 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/9p/vfs_super.c b/fs/9p/vfs_super.c
index 6a451d9ef514fbe7d9cc636add2c240cbcf9cf86..911511e25932a53ce8479974282a50630f8a2987 100644
--- a/fs/9p/vfs_super.c
+++ b/fs/9p/vfs_super.c
@@ -20,6 +20,7 @@
#include <net/9p/9p.h>
#include <net/9p/client.h>
#include <net/9p/transport.h>
+#include <security/config.h>
#include "v9fs.h"
#include "v9fs_vfs.h"
@@ -98,6 +99,9 @@ int v9fs_mount(struct device *dev)
struct p9_fid *fid;
int retval = 0;
+ if (!IS_ALLOWED(SCONFIG_9P_FS))
+ return -EPERM;
+
p9_debug(P9_DEBUG_VFS, "\n");
v9ses = kzalloc(sizeof(struct v9fs_session_info), GFP_KERNEL);
diff --git a/fs/Sconfig b/fs/Sconfig
new file mode 100644
index 0000000000000000000000000000000000000000..1d7ad28c08de9cc019dfc39b0162f3b9acd6c4a0
--- /dev/null
+++ b/fs/Sconfig
@@ -0,0 +1,76 @@
+menu "Filesystems"
+
+config FS_EXTERNAL
+ bool "Allow mounting external file systems"
+ help
+ Say y to permit mounting file systems beyond devfs and ramfs.
+
+if FS_EXTERNAL
+
+config FS_CRAMFS
+ bool "Allow CRAMFS"
+ depends on $(kconfig-enabled,FS_CRAMFS)
+
+config FS_EXT4
+ bool "Allow ext4 FS"
+ depends on $(kconfig-enabled,FS_EXT4)
+
+config FS_TFTP
+ bool "Allow TFTP"
+ depends on $(kconfig-enabled,FS_TFTP)
+
+config FS_NFS
+ bool "Allow NFS"
+ depends on $(kconfig-enabled,FS_NFS)
+
+config 9P_FS
+ bool "Allow 9P FS"
+ depends on $(kconfig-enabled,9P_FS)
+
+config FS_EFI
+ bool "Allow EFI FS"
+ depends on $(kconfig-enabled,FS_EFI)
+
+config FS_EFIVARS
+ bool "Allow EFI VAR FS"
+ depends on $(kconfig-enabled,FS_EFIVARS)
+
+config FS_FAT
+ bool "Allow FAT FS"
+ depends on $(kconfig-enabled,FS_FAT)
+
+config FS_JFFS2
+ bool "Allow JFFS2"
+ depends on $(kconfig-enabled,FS_JFFS2)
+
+config FS_UBIFS
+ bool "Allow UBIFS"
+ depends on $(kconfig-enabled,FS_UBIFS)
+
+config FS_UIMAGEFS
+ bool "Allow uImage FS"
+ depends on $(kconfig-enabled,FS_UIMAGEFS)
+
+config FS_SMHFS
+ bool "Allow SMHFS"
+ depends on $(kconfig-enabled,FS_SMHFS)
+
+config FS_PSTORE
+ bool "Allow pstore FS"
+ depends on $(kconfig-enabled,FS_PSTORE)
+
+config FS_SQUASHFS
+ bool "Allow squashfs"
+ depends on $(kconfig-enabled,FS_SQUASHFS)
+
+config FS_UBOOTVARFS
+ bool "Allow U-Boot Variable FS"
+ depends on $(kconfig-enabled,FS_UBOOTVARFS)
+
+config QEMU_FW_CFG
+ bool "Allow Qemu FW FS"
+ depends on $(kconfig-enabled,QEMU_FW_CFG)
+
+endif
+
+endmenu
diff --git a/fs/cramfs/cramfs.c b/fs/cramfs/cramfs.c
index 641a6d2b0526f01b5ea64f9a59aa9086883e2b57..594f97a808f27525f3bab05bc8e88e7e5eeafc89 100644
--- a/fs/cramfs/cramfs.c
+++ b/fs/cramfs/cramfs.c
@@ -31,6 +31,7 @@
#include <errno.h>
#include <fs.h>
#include <xfuncs.h>
+#include <security/config.h>
#include <asm/byteorder.h>
#include <linux/stat.h>
@@ -450,6 +451,9 @@ static int cramfs_probe(struct device *dev)
struct super_block *sb;
struct inode *root;
+ if (!IS_ALLOWED(SCONFIG_FS_CRAMFS))
+ return -EPERM;
+
fsdev = dev_to_fs_device(dev);
sb = &fsdev->sb;
diff --git a/fs/efi.c b/fs/efi.c
index da15c9078051c167b56f75a81a083810f16061ce..e4c33b959f46f3eecc9f32cb0143607063f871a2 100644
--- a/fs/efi.c
+++ b/fs/efi.c
@@ -31,6 +31,7 @@
#include <efi/efi-payload.h>
#include <efi/efi-device.h>
#include <linux/stddef.h>
+#include <security/config.h>
struct efifs_priv {
struct efi_file_handle *root_dir;
@@ -399,6 +400,9 @@ static int efifs_probe(struct device *dev)
struct device *efi = get_device_by_name(fsdev->backingstore);
struct efi_device *udev = container_of(efi, struct efi_device, dev);
+ if (!IS_ALLOWED(SCONFIG_FS_EFI))
+ return -EPERM;
+
priv = xzalloc(sizeof(struct efifs_priv));
priv->protocol = udev->protocol;
dev->priv = priv;
diff --git a/fs/efivarfs.c b/fs/efivarfs.c
index 9717a6340676ae447f54851f4346908699d04517..386c633e8f327dc4234c3ed43f27f421dc868242 100644
--- a/fs/efivarfs.c
+++ b/fs/efivarfs.c
@@ -30,6 +30,7 @@
#include <linux/ctype.h>
#include <efi/efi-payload.h>
#include <efi/efi-device.h>
+#include <security/config.h>
struct efivarfs_inode {
s16 *name;
@@ -302,6 +303,9 @@ static int efivarfs_probe(struct device *dev)
size_t size;
struct efivarfs_priv *priv;
+ if (!IS_ALLOWED(SCONFIG_FS_EFIVARS))
+ return -EPERM;
+
name[0] = 0;
priv = xzalloc(sizeof(*priv));
diff --git a/fs/ext4/ext_barebox.c b/fs/ext4/ext_barebox.c
index e75478684ff39418fcfac0d53287aa2e67949361..12c497d070b3704ad1e23f5c2f1c18d9d69de1d3 100644
--- a/fs/ext4/ext_barebox.c
+++ b/fs/ext4/ext_barebox.c
@@ -25,6 +25,8 @@
#include <linux/ctype.h>
#include <xfuncs.h>
#include <fcntl.h>
+#include <security/config.h>
+
#include "ext4_common.h"
ssize_t ext4fs_devread(struct ext_filesystem *fs, sector_t __sector, int byte_offset,
@@ -257,6 +259,9 @@ static int ext_probe(struct device *dev)
struct super_block *sb = &fsdev->sb;
struct inode *inode;
+ if (!IS_ALLOWED(SCONFIG_FS_EXT4))
+ return -EPERM;
+
fs = xzalloc(sizeof(*fs));
dev->priv = fs;
diff --git a/fs/fat/fat.c b/fs/fat/fat.c
index 15a7b2a9692723f1a13c797bc89047a4c6fe44a3..82925aee026a848a0c97b9f20c1121a0586b6c11 100644
--- a/fs/fat/fat.c
+++ b/fs/fat/fat.c
@@ -25,6 +25,8 @@
#include <linux/ctype.h>
#include <xfuncs.h>
#include <fcntl.h>
+#include <security/config.h>
+
#include "ff.h"
#include "integer.h"
#include "diskio.h"
@@ -346,6 +348,9 @@ static int fat_probe(struct device *dev)
struct fat_priv *priv = xzalloc(sizeof(struct fat_priv));
int ret;
+ if (!IS_ALLOWED(SCONFIG_FS_FAT))
+ return -EPERM;
+
dev->priv = priv;
ret = fsdev_open_cdev(fsdev);
diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c
index 5952ea9e904fa03240245a8977429814d69c28d6..cb01a791632386e33023ce940a32dd7c50aece55 100644
--- a/fs/jffs2/fs.c
+++ b/fs/jffs2/fs.c
@@ -20,6 +20,8 @@
#include <linux/mtd/mtd.h>
#include <linux/pagemap.h>
#include <linux/stat.h>
+#include <security/config.h>
+
#include "compr.h"
#include "nodelist.h"
#include "os-linux.h"
@@ -400,6 +402,9 @@ static int jffs2_probe(struct device *dev)
struct jffs2_sb_info *ctx;
int ret;
+ if (!IS_ALLOWED(SCONFIG_FS_JFFS2))
+ return -EPERM;
+
fsdev = dev_to_fs_device(dev);
sb = &fsdev->sb;
diff --git a/fs/nfs.c b/fs/nfs.c
index 17e1e7cfa1f1d66fab3b1b3e5efd3dc0fcb26327..d43f5b595f6ee3d5ad10ffcfbc5fc0bd85cce2e8 100644
--- a/fs/nfs.c
+++ b/fs/nfs.c
@@ -36,6 +36,7 @@
#include <parseopt.h>
#include <bootargs.h>
#include <magicvar.h>
+#include <security/config.h>
#define SUNRPC_PORT 111
@@ -1442,6 +1443,11 @@ static int nfs_probe(struct device *dev)
struct inode *inode;
int ret;
+ if (!IS_ALLOWED(SCONFIG_FS_NFS)) {
+ ret = -EPERM;
+ goto err;
+ }
+
dev->priv = npriv;
INIT_LIST_HEAD(&npriv->packets);
diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c
index e48317e09d5b86f50871c01c098aabe6c8e476ec..29c3ccbe2d468c15de713f2ef6f0dc5e2e293d86 100644
--- a/fs/pstore/ram.c
+++ b/fs/pstore/ram.c
@@ -38,6 +38,7 @@
#include <common.h>
#include <of.h>
#include <of_address.h>
+#include <security/config.h>
#define RAMOOPS_KERNMSG_HDR "===="
#define MIN_MEM_SIZE 4096UL
@@ -538,6 +539,9 @@ static int ramoops_probe(struct device *dev)
int err = -EINVAL;
char kernelargs[512];
+ if (!IS_ALLOWED(SCONFIG_FS_PSTORE))
+ return -EPERM;
+
if (IS_ENABLED(CONFIG_OFTREE) && !pdata) {
pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
if (!pdata) {
diff --git a/fs/qemu_fw_cfg.c b/fs/qemu_fw_cfg.c
index caf5415746494d1f087bed4f9603f7d2bc47b9b0..49b8da0e45b99a03b2a25f41bdf41ac74565bc92 100644
--- a/fs/qemu_fw_cfg.c
+++ b/fs/qemu_fw_cfg.c
@@ -19,6 +19,7 @@
#include <wchar.h>
#include <linux/err.h>
#include <linux/ctype.h>
+#include <security/config.h>
struct fw_cfg_fs_inode {
struct inode inode;
@@ -348,6 +349,11 @@ static int fw_cfg_fs_probe(struct device *dev)
struct super_block *sb = &fsdev->sb;
int ret;
+ if (!IS_ALLOWED(SCONFIG_FS_QEMU_FW_CFG)) {
+ ret = -EPERM;
+ goto free_data;
+ }
+
dev->priv = data;
data->next_ino = U16_MAX + 1;
diff --git a/fs/smhfs.c b/fs/smhfs.c
index 3a3b4bdc1d94239fcacd0c485e6e2ff3067df9ec..f66f64a9976216283d7b33582758f305a86aace0 100644
--- a/fs/smhfs.c
+++ b/fs/smhfs.c
@@ -23,6 +23,7 @@
#include <errno.h>
#include <linux/stat.h>
#include <asm/semihosting.h>
+#include <security/config.h>
static int file_to_fd(const struct file *f)
{
@@ -129,7 +130,11 @@ static int smhfs_stat(struct device __always_unused *dev,
static int smhfs_probe(struct device __always_unused *dev)
{
+ if (!IS_ALLOWED(SCONFIG_FS_SMHFS))
+ return -EPERM;
+
/* TODO: Add provisions to detect if debugger is connected */
+
return 0;
}
diff --git a/fs/squashfs/squashfs.c b/fs/squashfs/squashfs.c
index 471bcae4eb034d04bf5a9322dc981703b899783a..841d347582e3510ff1e112b9e1338016c1d43bfa 100644
--- a/fs/squashfs/squashfs.c
+++ b/fs/squashfs/squashfs.c
@@ -7,6 +7,7 @@
#include <errno.h>
#include <fs.h>
#include <xfuncs.h>
+#include <security/config.h>
#include <linux/fs.h>
#include <linux/stat.h>
@@ -95,6 +96,9 @@ static int squashfs_probe(struct device *dev)
int ret;
struct super_block *sb;
+ if (!IS_ALLOWED(SCONFIG_FS_SQUASHFS))
+ return -EPERM;
+
fsdev = dev_to_fs_device(dev);
sb = &fsdev->sb;
diff --git a/fs/tftp.c b/fs/tftp.c
index 01ebcbfc7ae44e57fda0745cc05030704b9ea695..3ba13030b8850ea9dc2aab6d0ec874acce22bc03 100644
--- a/fs/tftp.c
+++ b/fs/tftp.c
@@ -36,6 +36,7 @@
#include <parseopt.h>
#include <linux/sizes.h>
#include <linux/netfs.h>
+#include <security/config.h>
#include "tftp-selftest.h"
@@ -1063,6 +1064,11 @@ static int tftp_probe(struct device *dev)
struct inode *inode;
int ret;
+ if (!IS_ALLOWED(SCONFIG_FS_CRAMFS)) {
+ ret = -EPERM;
+ goto err;
+ }
+
dev->priv = priv;
ret = resolv(fsdev->backingstore, &priv->server);
diff --git a/fs/ubifs/ubifs.c b/fs/ubifs/ubifs.c
index 45b41ed7541dbfef1e9ca82afee2297a4727b571..e85cd6db053c9582c2b41de7a1947c35d0757843 100644
--- a/fs/ubifs/ubifs.c
+++ b/fs/ubifs/ubifs.c
@@ -21,6 +21,7 @@
#include <linux/zlib.h>
#include <linux/zstd.h>
#include <linux/mtd/mtd.h>
+#include <security/config.h>
#include "ubifs.h"
@@ -456,6 +457,11 @@ static int ubifs_probe(struct device *dev)
struct ubifs_priv *priv = xzalloc(sizeof(struct ubifs_priv));
int ret;
+ if (!IS_ALLOWED(SCONFIG_FS_UBIFS)) {
+ ret = -EPERM;
+ goto err_free;
+ }
+
dev->priv = priv;
ret = fsdev_open_cdev(fsdev);
diff --git a/fs/ubootvarfs.c b/fs/ubootvarfs.c
index 8cb0d0fa6499c90a0f5fef97eaa8bfb35c3211dc..c3130e9ce7390ff0e2ea7d10b6d7944c42449242 100644
--- a/fs/ubootvarfs.c
+++ b/fs/ubootvarfs.c
@@ -19,6 +19,7 @@
#include <wchar.h>
#include <linux/err.h>
#include <linux/ctype.h>
+#include <security/config.h>
/**
* Some theory of operation:
@@ -433,6 +434,11 @@ static int ubootvarfs_probe(struct device *dev)
void *map;
int ret;
+ if (!IS_ALLOWED(SCONFIG_FS_UBOOTVARFS)) {
+ ret = -EPERM;
+ goto free_data;
+ }
+
dev->priv = data;
data->fd = open(fsdev->backingstore, O_RDWR);
diff --git a/fs/uimagefs.c b/fs/uimagefs.c
index be268d3679d93e242cb1249cc64cc5720added01..624b408ba1a38adef25b25289f330de24fb3129f 100644
--- a/fs/uimagefs.c
+++ b/fs/uimagefs.c
@@ -18,6 +18,7 @@
#include <rtc.h>
#include <crc.h>
#include <libfile.h>
+#include <security/config.h>
static bool uimagefs_is_data_file(struct uimagefs_handle_data *d)
{
@@ -497,6 +498,9 @@ static int uimagefs_probe(struct device *dev)
struct uimagefs_handle *priv;
int ret = 0;
+ if (!IS_ALLOWED(SCONFIG_FS_UIMAGEFS))
+ return -EPERM;
+
priv = xzalloc(sizeof(struct uimagefs_handle));
INIT_LIST_HEAD(&priv->list);
dev->priv = priv;
--
2.39.5
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 24/24] security: console: add security policy for console input
2025-08-20 13:17 [PATCH 00/24] Add security policy support Sascha Hauer
` (22 preceding siblings ...)
2025-08-20 13:18 ` [PATCH 23/24] security: add filesystem security policies Sascha Hauer
@ 2025-08-20 13:18 ` Sascha Hauer
23 siblings, 0 replies; 30+ messages in thread
From: Sascha Hauer @ 2025-08-20 13:18 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 ee498fadf3700376b6325be10911b2081ff1ebb3..24fbee6904d446ecb55f22f1e3e9beeddb3ceeb0 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 f00fd567ed5d1ec7b0a8f00179953c08dda49de3..0e8a4bff2a692067765cb3d6feb93dd5b070ff82 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.39.5
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH 23/24] security: add filesystem security policies
2025-08-20 13:18 ` [PATCH 23/24] security: add filesystem security policies Sascha Hauer
@ 2025-08-20 14:39 ` Ahmad Fatoum
0 siblings, 0 replies; 30+ messages in thread
From: Ahmad Fatoum @ 2025-08-20 14:39 UTC (permalink / raw)
To: Sascha Hauer, BAREBOX
On 8/20/25 15:18, Sascha Hauer wrote:
> @@ -1063,6 +1064,11 @@ static int tftp_probe(struct device *dev)
> struct inode *inode;
> int ret;
>
> + if (!IS_ALLOWED(SCONFIG_FS_CRAMFS)) {
Should be SCONFIG_FS_TFTP.
--
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] 30+ messages in thread
* [PATCH] fixup! defaultenv: update PS1 according to security policy
2025-08-20 13:17 ` [PATCH 06/24] defaultenv: update PS1 according to security policy Sascha Hauer
@ 2025-08-20 15:33 ` Ahmad Fatoum
0 siblings, 0 replies; 30+ messages in thread
From: Ahmad Fatoum @ 2025-08-20 15:33 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
defaultenv: ps1-policy: remove stray semicolons
The semicolon next to $RED is inside the string, so it makes it into the
prompt. For the other one, it doesn't matter, so remove those too for
uniformity.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
defaultenv/defaultenv-2-security-policy/bin/ps1-policy | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/defaultenv/defaultenv-2-security-policy/bin/ps1-policy b/defaultenv/defaultenv-2-security-policy/bin/ps1-policy
index af121bbbaeed..5c8b26415d77 100755
--- a/defaultenv/defaultenv-2-security-policy/bin/ps1-policy
+++ b/defaultenv/defaultenv-2-security-policy/bin/ps1-policy
@@ -4,13 +4,13 @@ if [ -n "$security.policy" ]; then
elif [ "$security.policy" = "factory" ]; then
PS1_policy_color="$PINK"
elif [ "$security.policy" = "lockdown" ]; then
- PS1_policy_color="$RED;"
+ PS1_policy_color="$RED"
elif [ "$security.policy" = "tamper" ]; then
- PS1_policy_color="$RED_INV";
+ PS1_policy_color="$RED_INV"
elif [ "$security.policy" = "return" ]; then
- PS1_policy_color="$PINK_INV";
+ PS1_policy_color="$PINK_INV"
elif [[ "$security.policy" = "debug*" ]]; then
- PS1_policy_color="$CYAN";
+ PS1_policy_color="$CYAN"
else
PS1_policy_color="$NC"
fi
--
2.39.5
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH 15/24] boards: qemu-virt: add security policies
2025-08-20 13:17 ` [PATCH 15/24] boards: qemu-virt: add security policies Sascha Hauer
@ 2025-08-21 6:57 ` Ahmad Fatoum
2025-08-21 14:15 ` Sascha Hauer
0 siblings, 1 reply; 30+ messages in thread
From: Ahmad Fatoum @ 2025-08-21 6:57 UTC (permalink / raw)
To: Sascha Hauer, BAREBOX; +Cc: Ahmad Fatoum
Hi,
On 8/20/25 15:17, Sascha Hauer wrote:
> 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".
The configs need a make security_olddefconfig due to the addition of the
new symbols in later commits.
Cheers,
Ahmad
>
> 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 | 24 ++++++++++++++++++++++
> common/boards/qemu-virt/qemu-virt-lockdown.sconfig | 24 ++++++++++++++++++++++
> security/qemu-virt-devel.sconfig | 24 ++++++++++++++++++++++
> security/qemu-virt-tamper.sconfig | 24 ++++++++++++++++++++++
> 7 files changed, 108 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..b19d02b37f7c308e8e93da17349981301902d851
> --- /dev/null
> +++ b/common/boards/qemu-virt/qemu-virt-factory.sconfig
> @@ -0,0 +1,24 @@
> +#
> +# Automatically generated file; DO NOT EDIT.
> +# Barebox/arm Security Configuration
> +#
> +SCONFIG_POLICY_NAME="factory"
> +SCONFIG_SECURITY_POLICY_SELECT=y
> +
> +#
> +# General Settings
> +#
> +SCONFIG_RATP=y
> +# end of General Settings
> +
> +#
> +# Boot Policy
> +#
> +# SCONFIG_BOOT_UNSIGNED_IMAGES is not set
> +# end of Boot Policy
> +
> +#
> +# Command Policy
> +#
> +# SCONFIG_CMD_GO is not set
> +# end of Command Policy
> 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..e11e5e069c61f6b968716b75a836bfda2676057e
> --- /dev/null
> +++ b/common/boards/qemu-virt/qemu-virt-lockdown.sconfig
> @@ -0,0 +1,24 @@
> +#
> +# Automatically generated file; DO NOT EDIT.
> +# Barebox/arm Security Configuration
> +#
> +SCONFIG_POLICY_NAME="lockdown"
> +SCONFIG_SECURITY_POLICY_SELECT=y
> +
> +#
> +# General Settings
> +#
> +# SCONFIG_RATP is not set
> +# end of General Settings
> +
> +#
> +# Boot Policy
> +#
> +# SCONFIG_BOOT_UNSIGNED_IMAGES is not set
> +# end of Boot Policy
> +
> +#
> +# Command Policy
> +#
> +# SCONFIG_CMD_GO is not set
> +# end of Command Policy
> diff --git a/security/qemu-virt-devel.sconfig b/security/qemu-virt-devel.sconfig
> new file mode 100644
> index 0000000000000000000000000000000000000000..4513917a95cca07d415fcc856589dca92a289707
> --- /dev/null
> +++ b/security/qemu-virt-devel.sconfig
> @@ -0,0 +1,24 @@
> +#
> +# Automatically generated file; DO NOT EDIT.
> +# Barebox/arm Security Configuration
> +#
> +SCONFIG_POLICY_NAME="devel"
> +SCONFIG_SECURITY_POLICY_SELECT=y
> +
> +#
> +# General Settings
> +#
> +SCONFIG_RATP=y
> +# end of General Settings
> +
> +#
> +# Boot Policy
> +#
> +SCONFIG_BOOT_UNSIGNED_IMAGES=y
> +# end of Boot Policy
> +
> +#
> +# Command Policy
> +#
> +SCONFIG_CMD_GO=y
> +# end of Command Policy
> diff --git a/security/qemu-virt-tamper.sconfig b/security/qemu-virt-tamper.sconfig
> new file mode 100644
> index 0000000000000000000000000000000000000000..f2453a9936c19fe8a31879d1ee48cd0ce6655d5e
> --- /dev/null
> +++ b/security/qemu-virt-tamper.sconfig
> @@ -0,0 +1,24 @@
> +#
> +# Automatically generated file; DO NOT EDIT.
> +# Barebox/arm Security Configuration
> +#
> +SCONFIG_POLICY_NAME="tamper"
> +# SCONFIG_SECURITY_POLICY_SELECT is not set
> +
> +#
> +# General Settings
> +#
> +# SCONFIG_RATP is not set
> +# end of General Settings
> +
> +#
> +# Boot Policy
> +#
> +# SCONFIG_BOOT_UNSIGNED_IMAGES is not set
> +# end of Boot Policy
> +
> +#
> +# Command Policy
> +#
> +# SCONFIG_CMD_GO is not set
> +# end of Command Policy
>
--
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] 30+ messages in thread
* Re: [PATCH 15/24] boards: qemu-virt: add security policies
2025-08-21 6:57 ` Ahmad Fatoum
@ 2025-08-21 14:15 ` Sascha Hauer
2025-08-21 14:22 ` Ahmad Fatoum
0 siblings, 1 reply; 30+ messages in thread
From: Sascha Hauer @ 2025-08-21 14:15 UTC (permalink / raw)
To: Ahmad Fatoum; +Cc: BAREBOX, Ahmad Fatoum
On Thu, Aug 21, 2025 at 08:57:10AM +0200, Ahmad Fatoum wrote:
> Hi,
>
> On 8/20/25 15:17, Sascha Hauer wrote:
> > 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".
>
> The configs need a make security_olddefconfig due to the addition of the
> new symbols in later commits.
Indeed.
One thing I just noticed is that the qemu-virt board is built for both
32bit and 64bit boards. The sconfig files are currently suitable for the
32bit variant, but enabling security policies in multi_v8_defconfig
results in a
Security policy qemu-virt-lockdown.sconfig.tmp was not up to date.
This is not a problem since security policies are only enabled in
virt32_secure_defconfig, but nevertheless that's something we might want
to improve somehow.
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] 30+ messages in thread
* Re: [PATCH 15/24] boards: qemu-virt: add security policies
2025-08-21 14:15 ` Sascha Hauer
@ 2025-08-21 14:22 ` Ahmad Fatoum
0 siblings, 0 replies; 30+ messages in thread
From: Ahmad Fatoum @ 2025-08-21 14:22 UTC (permalink / raw)
To: Sascha Hauer; +Cc: BAREBOX, Ahmad Fatoum
Hi,
On 8/21/25 16:15, Sascha Hauer wrote:
> On Thu, Aug 21, 2025 at 08:57:10AM +0200, Ahmad Fatoum wrote:
>> Hi,
>>
>> On 8/20/25 15:17, Sascha Hauer wrote:
>>> 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".
>>
>> The configs need a make security_olddefconfig due to the addition of the
>> new symbols in later commits.
>
> Indeed.
>
> One thing I just noticed is that the qemu-virt board is built for both
> 32bit and 64bit boards. The sconfig files are currently suitable for the
> 32bit variant, but enabling security policies in multi_v8_defconfig
> results in a
>
> Security policy qemu-virt-lockdown.sconfig.tmp was not up to date.
>
> This is not a problem since security policies are only enabled in
> virt32_secure_defconfig, but nevertheless that's something we might want
> to improve somehow.
You can get the same message too in multi_v7_defconfig if we start
configuring things differently to virt32_secure_defconfig..
There's potential for future improvement for sure, yes.
Cheers,
Ahmad
>
> 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] 30+ messages in thread
end of thread, other threads:[~2025-08-21 19:14 UTC | newest]
Thread overview: 30+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-08-20 13:17 [PATCH 00/24] Add security policy support Sascha Hauer
2025-08-20 13:17 ` [PATCH 01/24] kconfig: allow setting CONFIG_ from the outside Sascha Hauer
2025-08-20 13:17 ` [PATCH 02/24] scripts: include scripts/include for all host tools Sascha Hauer
2025-08-20 13:17 ` [PATCH 03/24] kbuild: implement loopable loop_cmd Sascha Hauer
2025-08-20 13:17 ` [PATCH 04/24] Add security policy support Sascha Hauer
2025-08-20 13:17 ` [PATCH 05/24] kbuild: allow security config use without source tree modification Sascha Hauer
2025-08-20 13:17 ` [PATCH 06/24] defaultenv: update PS1 according to security policy Sascha Hauer
2025-08-20 15:33 ` [PATCH] fixup! " Ahmad Fatoum
2025-08-20 13:17 ` [PATCH 07/24] security: policy: support externally provided configs Sascha Hauer
2025-08-20 13:17 ` [PATCH 08/24] commands: implement sconfig command Sascha Hauer
2025-08-20 13:17 ` [PATCH 09/24] docs: security-policies: add documentation Sascha Hauer
2025-08-20 13:17 ` [PATCH 10/24] commands: go: add security config option Sascha Hauer
2025-08-20 13:17 ` [PATCH 11/24] console: ratp: " Sascha Hauer
2025-08-20 13:17 ` [PATCH 12/24] bootm: support calling bootm_optional_signed_images at any time Sascha Hauer
2025-08-20 13:17 ` [PATCH 13/24] bootm: make unsigned image support runtime configurable Sascha Hauer
2025-08-20 13:17 ` [PATCH 14/24] ARM: configs: add virt32_secure_defconfig Sascha Hauer
2025-08-20 13:17 ` [PATCH 15/24] boards: qemu-virt: add security policies Sascha Hauer
2025-08-21 6:57 ` Ahmad Fatoum
2025-08-21 14:15 ` Sascha Hauer
2025-08-21 14:22 ` Ahmad Fatoum
2025-08-20 13:18 ` [PATCH 16/24] boards: qemu-virt: allow setting policy from command line Sascha Hauer
2025-08-20 13:18 ` [PATCH 17/24] test: py: add basic security policy test Sascha Hauer
2025-08-20 13:18 ` [PATCH 18/24] usbserial: add inline wrappers Sascha Hauer
2025-08-20 13:18 ` [PATCH 19/24] security: usbgadget: add usbgadget security policy Sascha Hauer
2025-08-20 13:18 ` [PATCH 20/24] security: fastboot: add security policy for fastboot oem Sascha Hauer
2025-08-20 13:18 ` [PATCH 21/24] security: shell: add policy for executing the shell Sascha Hauer
2025-08-20 13:18 ` [PATCH 22/24] security: add security policy for loading barebox environment Sascha Hauer
2025-08-20 13:18 ` [PATCH 23/24] security: add filesystem security policies Sascha Hauer
2025-08-20 14:39 ` Ahmad Fatoum
2025-08-20 13:18 ` [PATCH 24/24] security: console: add security policy for console input Sascha Hauer
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox