mail archive of the barebox mailing list
 help / color / mirror / Atom feed
From: Ahmad Fatoum <a.fatoum@pengutronix.de>
To: barebox@lists.infradead.org
Cc: Ahmad Fatoum <a.fatoum@pengutronix.de>
Subject: [PATCH 3/3] firmware: add external firmware PBL support
Date: Mon, 15 Aug 2022 15:09:55 +0200	[thread overview]
Message-ID: <20220815130955.2332697-3-a.fatoum@pengutronix.de> (raw)
In-Reply-To: <20220815130955.2332697-1-a.fatoum@pengutronix.de>

Normally, barebox embds firmware into the binary referencing it, which
means that device tree blobs, RAM training code and e.g. TF-A for i.MX8M
end up in the prebootloader, while, e.g. Freescale FMan microcode ends
up in barebox proper. The only exception so far was barebox proper:
When only the PBL fits in on-chip SRAM, barebox proper is chainloaded
from the boot medium. To avoid TOCTOU attack, it's read fully into DRAM
after setup and then a SHA256 is calculated and compared against the
hash embedded in barebox PBL, which in a secure boot system would be
trusted by virtue of the PBL as a whole being verified beforehand by
the BootROM.

Reuse this mechanism to support arbitrary firmware, which is now termed
external firmware. Such firmware is placed beyond the piggydata (barebox
proper) and only offset and hash are included in the prebootloader
image. The new get_builtin_firmware_ext() is used to retrieve this
external firmware after integrity verification with SHA256.

This enables referencing firmware blobs from PBL that would bloat the
size of the PBL beyond what can fit into on-chip SRAM, e.g. very big
OP-TEE binaries. As users of get_builtin_firmware() didn't have to worry
about TOCTOU so far, we panic when a firmware verification fails to
ensure that we never load an OP-TEE that has been modified in-transit
in transit. We can't include the OP-TEE binary in barebox proper,
because we need to install it in EL3, but barebox proper on the i.MX8M
runs as BL33 in a lower exception level.

Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
 arch/arm/lib/pbl.lds.S | 11 +++++++++++
 firmware/Makefile      | 37 ++++++++++++++++++++++++++++++++++++-
 include/firmware.h     | 31 +++++++++++++++++++++++++++++++
 3 files changed, 78 insertions(+), 1 deletion(-)

diff --git a/arch/arm/lib/pbl.lds.S b/arch/arm/lib/pbl.lds.S
index e77b3220fcb0..87d9b297f0dc 100644
--- a/arch/arm/lib/pbl.lds.S
+++ b/arch/arm/lib/pbl.lds.S
@@ -62,6 +62,10 @@ SECTIONS
 	}
 	__shasum_end = .;
 
+	.pblext_shasum : {
+		KEEP(*(.pblext_shasum.*))
+	}
+
 	.rel_dyn_start : { *(.__rel_dyn_start) }
 #ifdef CONFIG_CPU_32
 	.rel.dyn : { *(.rel*) }
@@ -101,6 +105,13 @@ SECTIONS
 	}
 	__piggydata_end = .;
 
+	. = ALIGN(4);
+	__pblext_start = .;
+	.pblext : {
+		*(.pblext.*)
+	}
+	__pblext_end = .;
+
 	.image_end : { KEEP(*(.__image_end)) }
 
 	pbl_image_size =  . - BASE;
diff --git a/firmware/Makefile b/firmware/Makefile
index 87bd033f6e5c..eb8b59a3b1aa 100644
--- a/firmware/Makefile
+++ b/firmware/Makefile
@@ -51,16 +51,51 @@ filechk_fwbin = { \
 $(obj)/%.gen.S: FORCE
 	$(call filechk,fwbin)
 
+FWEXTNAME    = $(patsubst $(obj)/%.extgen.S,%,$@)
+FWEXTSTR     = $(subst /,_,$(subst .,_,$(subst -,_,$(FWEXTNAME))))
+
+filechk_fwextbin = { \
+	echo "/* Generated by $(src)/Makefile */"		;\
+	echo "    .section .pblext.$(FWEXTSTR)",\"a\"		;\
+	echo "    .p2align $(ASM_ALIGN)"			;\
+	echo ".global _fwext_$(FWEXTSTR)_start"			;\
+	echo "_fwext_$(FWEXTSTR)_start:"			;\
+	echo "    .incbin \"$(fwdir)/$(FWEXTNAME)\""		;\
+	echo ".global _fwext_$(FWEXTSTR)_end"			;\
+	echo "_fwext_$(FWEXTSTR)_end:"				;\
+	echo "    .section .pblext_shasum.$(FWEXTSTR), \"a\""	;\
+	echo "    .p2align $(ASM_ALIGN)"			;\
+	echo ".global _fwext_$(FWEXTSTR)_sha_start"		;\
+	echo "_fwext_$(FWEXTSTR)_sha_start:"			;\
+	echo "    .incbin \"$(objdir)/firmware/$(FWEXTNAME).sha.bin\""	;\
+	echo ".global _fwext_$(FWEXTSTR)_sha_end"		;\
+	echo "_fwext_$(FWEXTSTR)_sha_end:"			;\
+}
+
+$(obj)/%.extgen.S: $(obj)/%.sha.bin FORCE
+	$(call filechk,fwextbin)
+
+$(obj)/%.sha.bin: $(obj)/%.sum FORCE
+	$(call if_changed,sha256bin)
+
+$(obj)/%.sum: $(obj)/% FORCE
+	$(call if_changed,sha256sum)
+
+clean-files += *.sha.bin *.sum
+
 # The .o files depend on the binaries directly; the .S files don't.
 $(patsubst %,$(obj)/%.gen.o, $(obj-pbl-y)): $(obj)/%.gen.o: $(fwdir)/%
 
 # The same for pbl:
 $(patsubst %,$(obj)/%.gen.pbl.o, $(obj-pbl-y)): $(obj)/%.gen.pbl.o: $(fwdir)/%
+$(patsubst %,$(obj)/%.extgen.pbl.o, $(pbl-y)): $(obj)/%.extgen.pbl.o: $(fwdir)/%
 
-obj-pbl-y			 += $(patsubst %,%.gen.o, $(fw-external-y))
+pbl-y := $(addsuffix .extgen.o, $(fw-external-y))
 
 targets := $(patsubst $(obj)/%,%, \
                                 $(shell find $(obj) -name \*.gen.S 2>/dev/null))
+targets += $(patsubst $(obj)/%,%, \
+                                $(shell find $(obj) -name \*.extgen.S 2>/dev/null))
 
 # just to build a built-in.o. Otherwise compilation fails when no
 # firmware is built.
diff --git a/include/firmware.h b/include/firmware.h
index 2583342230ae..b96726bd4416 100644
--- a/include/firmware.h
+++ b/include/firmware.h
@@ -6,8 +6,11 @@
 #ifndef FIRMWARE_H
 #define FIRMWARE_H
 
+#include <pbl.h>
 #include <types.h>
 #include <driver.h>
+#include <debug_ll.h>
+#include <linux/kernel.h>
 
 struct firmware_handler {
 	char *id; /* unique identifier for this firmware device */
@@ -57,6 +60,16 @@ static inline void firmware_set_searchpath(const char *path)
 
 void firmwaremgr_list_handlers(void);
 
+static inline void firmware_ext_verify(const void *data_start, size_t data_size,
+				       const void *hash_start, size_t hash_size)
+{
+	if (pbl_barebox_verify(data_start, data_size,
+			       hash_start, hash_size) != 0) {
+		putc_ll('!');
+		panic("hash mismatch, refusing to decompress");
+	}
+}
+
 #define get_builtin_firmware(name, start, size) \
 	{							\
 		extern char _fw_##name##_start[];		\
@@ -65,4 +78,22 @@ void firmwaremgr_list_handlers(void);
 		*size = _fw_##name##_end - _fw_##name##_start;	\
 	}
 
+#define get_builtin_firmware_ext(name, base, start, size)		\
+	{								\
+		extern char _fwext_##name##_start[];			\
+		extern char _fwext_##name##_end[];			\
+		extern char _fwext_##name##_sha_start[];		\
+		extern char _fwext_##name##_sha_end[];			\
+		long offset = (long)bl33 - (long)_text;			\
+		*start = (typeof(*start)) _fwext_##name##_start;	\
+		*size = _fwext_##name##_end - _fwext_##name##_start;	\
+		*start += offset;					\
+		firmware_ext_verify(					\
+			*start, *size,					\
+			_fwext_##name##_sha_start,			\
+			_fwext_##name##_sha_end -			\
+			_fwext_##name##_sha_start			\
+		);							\
+	}
+
 #endif /* FIRMWARE_H */
-- 
2.30.2




  parent reply	other threads:[~2022-08-15 13:12 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-08-15 13:09 [PATCH 1/3] kbuild: make sha256sum command available generally Ahmad Fatoum
2022-08-15 13:09 ` [PATCH 2/3] pbl: export pbl_barebox_verify Ahmad Fatoum
2022-08-15 13:09 ` Ahmad Fatoum [this message]
2022-08-15 13:41   ` [PATCH 3/4] pbl: replace __piggydata_end with __image_end Ahmad Fatoum
2022-08-16  8:42   ` [PATCH 3/3] firmware: add external firmware PBL support Sascha Hauer
2022-08-17 12:08     ` Ahmad Fatoum

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220815130955.2332697-3-a.fatoum@pengutronix.de \
    --to=a.fatoum@pengutronix.de \
    --cc=barebox@lists.infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox