On Tuesday 23 August 2022 07:05:33 Stefan Roese wrote: > Hi Pali, > > On 09.08.22 21:42, Pali Rohár wrote: > > For obvious reasons BootROMS rejects unsigned images when secure boot is > > enabled in OTP secure bits. So check for OPT secure bits and do not allow > > flashing unsigned images when secure boot is enabled. Access to OTP via > > U-Boot fuse API is currently implemented only for A38x and A37xx SoCs. > > > > Additionally Armada 3700 BootROM rejects signed trusted image when secure > > boot is not enabled in OTP. So add also check for this case. On the other > > hand Armada 38x BootROM acceps images with secure boot header when secure > > boot is not enabled in OTP. > > > > OTP secure bits may have burned also boot device source. Check it also and > > reject flashing images to target storage which does not match OTP. > > > > Signed-off-by: Pali Rohár <p...@kernel.org> > > > > --- > > Changes in v2: > > * Add missing dependency on MVEBU_EFUSE > > * Use only for A38x and A37xx > > Running a world CI build leads to these errors: > > $ make clearfog_gt_8k_defconfig > ... > $ make -sj > cmd/mvebu/bubt.c:809:12: warning: 'fuse_read_u64' defined but not used > [-Wunused-function] > 809 | static u64 fuse_read_u64(u32 bank) > | ^~~~~~~~~~~~~ > > Could you please please take a look and fix this issue?
There is missing guard to not compile that function for A7k/A8k. I will fix it in v3. > Thanks, > Stefan > > > --- > > cmd/mvebu/Kconfig | 1 + > > cmd/mvebu/bubt.c | 127 +++++++++++++++++++++++++++++++++++++++++++--- > > 2 files changed, 120 insertions(+), 8 deletions(-) > > > > diff --git a/cmd/mvebu/Kconfig b/cmd/mvebu/Kconfig > > index 120397d6d4d0..9ec3aa983a51 100644 > > --- a/cmd/mvebu/Kconfig > > +++ b/cmd/mvebu/Kconfig > > @@ -5,6 +5,7 @@ config CMD_MVEBU_BUBT > > bool "bubt" > > select SHA256 if ARMADA_3700 > > select SHA512 if ARMADA_3700 > > + select MVEBU_EFUSE if ARMADA_38X || ARMADA_3700 > > help > > bubt - Burn a u-boot image to flash > > For details about bubt command please see the documentation > > diff --git a/cmd/mvebu/bubt.c b/cmd/mvebu/bubt.c > > index 3b6ffb7ffd1f..feb1e778a98c 100644 > > --- a/cmd/mvebu/bubt.c > > +++ b/cmd/mvebu/bubt.c > > @@ -13,6 +13,8 @@ > > #include <vsprintf.h> > > #include <errno.h> > > #include <dm.h> > > +#include <fuse.h> > > +#include <mach/efuse.h> > > #include <spi_flash.h> > > #include <spi.h> > > @@ -121,6 +123,17 @@ struct a38x_main_hdr_v1 { > > u8 checksum; /* 0x1F */ > > }; > > +/* > > + * Header for the optional headers, version 1 (Armada 370/XP/375/38x/39x) > > + */ > > +struct a38x_opt_hdr_v1 { > > + u8 headertype; > > + u8 headersz_msb; > > + u16 headersz_lsb; > > + u8 data[0]; > > +}; > > +#define A38X_OPT_HDR_V1_SECURE_TYPE 0x1 > > + > > struct a38x_boot_mode { > > unsigned int id; > > const char *name; > > @@ -706,6 +719,7 @@ static int check_image_header(void) > > { > > u8 checksum; > > u32 checksum32, exp_checksum32; > > + u32 offset, size; > > const struct a38x_main_hdr_v1 *hdr = > > (struct a38x_main_hdr_v1 *)get_load_addr(); > > const size_t image_size = a38x_header_size(hdr); > > @@ -752,6 +766,38 @@ static int check_image_header(void) > > printf("Image checksum...OK!\n"); > > return 0; > > } > > + > > +#if defined(CONFIG_ARMADA_38X) > > +static int a38x_image_is_secure(const struct a38x_main_hdr_v1 *hdr) > > +{ > > + u32 image_size = a38x_header_size(hdr); > > + struct a38x_opt_hdr_v1 *ohdr; > > + u32 ohdr_size; > > + > > + if (hdr->version != 1) > > + return 0; > > + > > + if (!hdr->ext) > > + return 0; > > + > > + ohdr = (struct a38x_opt_hdr_v1 *)(hdr + 1); > > + do { > > + if (ohdr->headertype == A38X_OPT_HDR_V1_SECURE_TYPE) > > + return 1; > > + > > + ohdr_size = (ohdr->headersz_msb << 16) | > > le16_to_cpu(ohdr->headersz_lsb); > > + > > + if (!*((u8 *)ohdr + ohdr_size - 4)) > > + break; > > + > > + ohdr = (struct a38x_opt_hdr_v1 *)((u8 *)ohdr + ohdr_size); > > + if ((u8 *)ohdr >= (u8 *)hdr + image_size) > > + break; > > + } while (1); > > + > > + return 0; > > +} > > +#endif > > #else /* Not ARMADA? */ > > static int check_image_header(void) > > { > > @@ -760,20 +806,58 @@ static int check_image_header(void) > > } > > #endif > > +static u64 fuse_read_u64(u32 bank) > > +{ > > + u32 val[2]; > > + int ret; > > + > > + ret = fuse_read(bank, 0, &val[0]); > > + if (ret < 0) > > + return -1; > > + > > + ret = fuse_read(bank, 1, &val[1]); > > + if (ret < 0) > > + return -1; > > + > > + return ((u64)val[1] << 32) | val[0]; > > +} > > + > > +#if defined(CONFIG_ARMADA_3700) > > +static inline u8 maj3(u8 val) > > +{ > > + /* return majority vote of 3 bits */ > > + return ((val & 0x7) == 3 || (val & 0x7) > 4) ? 1 : 0; > > +} > > +#endif > > + > > static int bubt_check_boot_mode(const struct bubt_dev *dst) > > { > > #if defined(CONFIG_ARMADA_3700) || defined(CONFIG_ARMADA_32BIT) > > - int mode; > > + int mode, secure_mode; > > #if defined(CONFIG_ARMADA_3700) > > const struct tim_boot_flash_sign *boot_modes = tim_boot_flash_signs; > > const struct common_tim_data *hdr = > > (struct common_tim_data *)get_load_addr(); > > u32 id = hdr->boot_flash_sign; > > + int is_secure = hdr->trusted != 0; > > + u64 otp_secure_bits = fuse_read_u64(1); > > + int otp_secure_boot = ((maj3(otp_secure_bits >> 0) << 0) | > > + (maj3(otp_secure_bits >> 4) << 1)) == 2; > > + unsigned int otp_boot_device = (maj3(otp_secure_bits >> 48) << 0) | > > + (maj3(otp_secure_bits >> 52) << 1) | > > + (maj3(otp_secure_bits >> 56) << 2) | > > + (maj3(otp_secure_bits >> 60) << 3); > > #elif defined(CONFIG_ARMADA_32BIT) > > const struct a38x_boot_mode *boot_modes = a38x_boot_modes; > > const struct a38x_main_hdr_v1 *hdr = > > (struct a38x_main_hdr_v1 *)get_load_addr(); > > u32 id = hdr->blockid; > > +#if defined(CONFIG_ARMADA_38X) > > + int is_secure = a38x_image_is_secure(hdr); > > + u64 otp_secure_bits = fuse_read_u64(EFUSE_LINE_SECURE_BOOT); > > + int otp_secure_boot = otp_secure_bits & 0x1; > > + unsigned int otp_boot_device = (otp_secure_bits >> 8) & 0x7; > > +#endif > > #endif > > for (mode = 0; boot_modes[mode].name; mode++) { > > @@ -786,15 +870,42 @@ static int bubt_check_boot_mode(const struct bubt_dev > > *dst) > > return -ENOEXEC; > > } > > - if (strcmp(boot_modes[mode].name, dst->name) == 0) > > - return 0; > > + if (strcmp(boot_modes[mode].name, dst->name) != 0) { > > + printf("Error: image meant to be booted from \"%s\", not > > \"%s\"!\n", > > + boot_modes[mode].name, dst->name); > > + return -ENOEXEC; > > + } > > - printf("Error: image meant to be booted from \"%s\", not \"%s\"!\n", > > - boot_modes[mode].name, dst->name); > > - return -ENOEXEC; > > -#else > > - return 0; > > +#if defined(CONFIG_ARMADA_38X) || defined(CONFIG_ARMADA_3700) > > + if (otp_secure_bits == (u64)-1) { > > + printf("Error: cannot read OTP secure bits\n"); > > + return -ENOEXEC; > > + } else { > > + if (otp_secure_boot && !is_secure) { > > + printf("Error: secure boot is enabled in OTP but image > > does not have secure boot header!\n"); > > + return -ENOEXEC; > > + } else if (!otp_secure_boot && is_secure) { > > +#if defined(CONFIG_ARMADA_3700) > > + /* > > + * Armada 3700 BootROM rejects trusted image when > > secure boot is not enabled. > > + * Armada 385 BootROM accepts image with secure boot > > header also when secure boot is not enabled. > > + */ > > + printf("Error: secure boot is disabled in OTP but image > > has secure boot header!\n"); > > + return -ENOEXEC; > > #endif > > + } else if (otp_boot_device && otp_boot_device != id) { > > + for (secure_mode = 0; boot_modes[secure_mode].name; > > secure_mode++) { > > + if (boot_modes[secure_mode].id == > > otp_boot_device) > > + break; > > + } > > + printf("Error: boot source is set to \"%s\" in OTP but > > image is for \"%s\"!\n", > > + boot_modes[secure_mode].name ?: "unknown", > > dst->name); > > + return -ENOEXEC; > > + } > > + } > > +#endif > > +#endif > > + return 0; > > } > > static int bubt_verify(const struct bubt_dev *dst) > > Viele Grüße, > Stefan Roese > > -- > DENX Software Engineering GmbH, Managing Director: Wolfgang Denk > HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany > Phone: (+49)-8142-66989-51 Fax: (+49)-8142-66989-80 Email: s...@denx.de