diff options
115 files changed, 9310 insertions, 206 deletions
diff --git a/.gitignore b/.gitignore index 9110eda646..6bb0adefa7 100644 --- a/.gitignore +++ b/.gitignore @@ -3,29 +3,31 @@ # subdirectories here. Add them in the ".gitignore" file # in that subdirectory instead. # -# Normal rules +# Normal rules (sorted alphabetically) # .* -*.o -*.o.* *.a -*.s -*.su -*.mod.c +*.bin +*.cfgtmp +*.dtb +*.dtb.S +*.elf +*.exe +*.gcda +*.gcno *.i *.lex.c *.lst +*.mod.c +*.o +*.o.* *.order -*.elf -*.swp -*.bin *.patch -*.cfgtmp +*.s +*.su +*.swp *.tab.[ch] -# host programs on Cygwin -*.exe - # Build tree /build-* @@ -86,7 +88,3 @@ GTAGS *.orig *~ \#*# - -# gcc code coverage files -*.gcda -*.gcno diff --git a/MAINTAINERS b/MAINTAINERS index 642c448093..b2c9717cb7 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -184,7 +184,7 @@ F: arch/arm/mach-s5pc1xx/ F: arch/arm/cpu/armv7/s5p-common/ ARM SNAPDRAGON -M: Mateusz Kulikowski <mateusz.kulikowski@gmail.com> +M: Ramon Fried <ramon.fried@gmail.com> S: Maintained F: arch/arm/mach-snapdragon/ @@ -3,7 +3,7 @@ VERSION = 2018 PATCHLEVEL = 07 SUBLEVEL = -EXTRAVERSION = -rc1 +EXTRAVERSION = -rc2 NAME = # *DOCUMENTATION* @@ -263,8 +263,9 @@ HOSTCXXFLAGS = -O2 # Some Linux distributions (including RHEL7, SLES13, Debian 8) still # have older compilers as their default, so we make it explicit for # these that our host tools are GNU11 (i.e. C11 w/ GNU extensions). +CSTD_FLAG := -std=gnu11 ifeq ($(HOSTOS),linux) -HOSTCFLAGS += --std=gnu11 +HOSTCFLAGS += $(CSTD_FLAG) endif ifeq ($(HOSTOS),cygwin) @@ -370,7 +371,7 @@ KBUILD_CPPFLAGS := -D__KERNEL__ -D__UBOOT__ KBUILD_CFLAGS := -Wall -Wstrict-prototypes \ -Wno-format-security \ - -fno-builtin -ffreestanding + -fno-builtin -ffreestanding $(CSTD_FLAG) KBUILD_CFLAGS += -fshort-wchar KBUILD_AFLAGS := -D__ASSEMBLY__ diff --git a/arch/arc/dts/.gitignore b/arch/arc/dts/.gitignore deleted file mode 100644 index b60ed208c7..0000000000 --- a/arch/arc/dts/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.dtb diff --git a/arch/arm/cpu/armv8/fsl-layerscape/mp.c b/arch/arm/cpu/armv8/fsl-layerscape/mp.c index dd89d0a83f..7627fd13e7 100644 --- a/arch/arm/cpu/armv8/fsl-layerscape/mp.c +++ b/arch/arm/cpu/armv8/fsl-layerscape/mp.c @@ -191,14 +191,14 @@ int is_core_online(u64 cpu_id) return table[SPIN_TABLE_ELEM_STATUS_IDX] == 1; } -int cpu_reset(int nr) +int cpu_reset(u32 nr) { puts("Feature is not implemented.\n"); return 0; } -int cpu_disable(int nr) +int cpu_disable(u32 nr) { puts("Feature is not implemented.\n"); @@ -231,7 +231,7 @@ static int core_to_pos(int nr) return i; } -int cpu_status(int nr) +int cpu_status(u32 nr) { u64 *table; int pos; @@ -257,7 +257,7 @@ int cpu_status(int nr) return 0; } -int cpu_release(int nr, int argc, char * const argv[]) +int cpu_release(u32 nr, int argc, char * const argv[]) { u64 boot_addr; u64 *table = (u64 *)get_spin_tbl_addr(); diff --git a/arch/arm/cpu/armv8/zynqmp/mp.c b/arch/arm/cpu/armv8/zynqmp/mp.c index 7e270a7dc2..2a71870ae7 100644 --- a/arch/arm/cpu/armv8/zynqmp/mp.c +++ b/arch/arm/cpu/armv8/zynqmp/mp.c @@ -45,7 +45,7 @@ int is_core_valid(unsigned int core) return 0; } -int cpu_reset(int nr) +int cpu_reset(u32 nr) { puts("Feature is not implemented.\n"); return 0; @@ -131,7 +131,7 @@ static void enable_clock_r5(void) udelay(0x500); } -int cpu_disable(int nr) +int cpu_disable(u32 nr) { if (nr >= ZYNQMP_CORE_APU0 && nr <= ZYNQMP_CORE_APU3) { u32 val = readl(&crfapb_base->rst_fpd_apu); @@ -144,7 +144,7 @@ int cpu_disable(int nr) return 0; } -int cpu_status(int nr) +int cpu_status(u32 nr) { if (nr >= ZYNQMP_CORE_APU0 && nr <= ZYNQMP_CORE_APU3) { u32 addr_low = readl(((u8 *)&apu_base->rvbar_addr0_l) + nr * 8); @@ -220,7 +220,7 @@ void initialize_tcm(bool mode) } } -int cpu_release(int nr, int argc, char * const argv[]) +int cpu_release(u32 nr, int argc, char * const argv[]) { if (nr >= ZYNQMP_CORE_APU0 && nr <= ZYNQMP_CORE_APU3) { u64 boot_addr = simple_strtoull(argv[0], NULL, 16); diff --git a/arch/arm/dts/.gitignore b/arch/arm/dts/.gitignore deleted file mode 100644 index b60ed208c7..0000000000 --- a/arch/arm/dts/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.dtb diff --git a/arch/arm/dts/dragonboard410c-uboot.dtsi b/arch/arm/dts/dragonboard410c-uboot.dtsi index b968f5eb68..3a1ea13ee5 100644 --- a/arch/arm/dts/dragonboard410c-uboot.dtsi +++ b/arch/arm/dts/dragonboard410c-uboot.dtsi @@ -6,10 +6,6 @@ */ / { - config { - u-boot,mmc-env-partition = "boot"; - }; - soc { u-boot,dm-pre-reloc; @@ -21,14 +17,14 @@ }; }; - qcom,gcc@1800000 { - u-boot,dm-pre-reloc; - }; + qcom,gcc@1800000 { + u-boot,dm-pre-reloc; + }; - serial@78b0000 { - u-boot,dm-pre-reloc; + serial@78b0000 { + u-boot,dm-pre-reloc; + }; }; - }; }; diff --git a/arch/arm/include/asm/arch-meson/clock.h b/arch/arm/include/asm/arch-meson/clock.h new file mode 100644 index 0000000000..c0ff00fc9a --- /dev/null +++ b/arch/arm/include/asm/arch-meson/clock.h @@ -0,0 +1,117 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright 2016 - AmLogic, Inc. + * Copyright 2018 - Beniamino Galvani <b.galvani@gmail.com> + */ +#ifndef _ARCH_MESON_CLOCK_H_ +#define _ARCH_MESON_CLOCK_H_ + +/* + * Clock controller register offsets + * + * Register offsets from the data sheet are listed in comment blocks below. + * Those offsets must be multiplied by 4 before adding them to the base address + * to get the right value + */ +#define SCR 0x2C /* 0x0b offset in data sheet */ +#define TIMEOUT_VALUE 0x3c /* 0x0f offset in data sheet */ + +#define HHI_GP0_PLL_CNTL 0x40 /* 0x10 offset in data sheet */ +#define HHI_GP0_PLL_CNTL2 0x44 /* 0x11 offset in data sheet */ +#define HHI_GP0_PLL_CNTL3 0x48 /* 0x12 offset in data sheet */ +#define HHI_GP0_PLL_CNTL4 0x4c /* 0x13 offset in data sheet */ +#define HHI_GP0_PLL_CNTL5 0x50 /* 0x14 offset in data sheet */ +#define HHI_GP0_PLL_CNTL1 0x58 /* 0x16 offset in data sheet */ + +#define HHI_XTAL_DIVN_CNTL 0xbc /* 0x2f offset in data sheet */ +#define HHI_TIMER90K 0xec /* 0x3b offset in data sheet */ + +#define HHI_MEM_PD_REG0 0x100 /* 0x40 offset in data sheet */ +#define HHI_MEM_PD_REG1 0x104 /* 0x41 offset in data sheet */ +#define HHI_VPU_MEM_PD_REG1 0x108 /* 0x42 offset in data sheet */ +#define HHI_VIID_CLK_DIV 0x128 /* 0x4a offset in data sheet */ +#define HHI_VIID_CLK_CNTL 0x12c /* 0x4b offset in data sheet */ + +#define HHI_GCLK_MPEG0 0x140 /* 0x50 offset in data sheet */ +#define HHI_GCLK_MPEG1 0x144 /* 0x51 offset in data sheet */ +#define HHI_GCLK_MPEG2 0x148 /* 0x52 offset in data sheet */ +#define HHI_GCLK_OTHER 0x150 /* 0x54 offset in data sheet */ +#define HHI_GCLK_AO 0x154 /* 0x55 offset in data sheet */ +#define HHI_SYS_OSCIN_CNTL 0x158 /* 0x56 offset in data sheet */ +#define HHI_SYS_CPU_CLK_CNTL1 0x15c /* 0x57 offset in data sheet */ +#define HHI_SYS_CPU_RESET_CNTL 0x160 /* 0x58 offset in data sheet */ +#define HHI_VID_CLK_DIV 0x164 /* 0x59 offset in data sheet */ + +#define HHI_MPEG_CLK_CNTL 0x174 /* 0x5d offset in data sheet */ +#define HHI_AUD_CLK_CNTL 0x178 /* 0x5e offset in data sheet */ +#define HHI_VID_CLK_CNTL 0x17c /* 0x5f offset in data sheet */ +#define HHI_AUD_CLK_CNTL2 0x190 /* 0x64 offset in data sheet */ +#define HHI_VID_CLK_CNTL2 0x194 /* 0x65 offset in data sheet */ +#define HHI_SYS_CPU_CLK_CNTL0 0x19c /* 0x67 offset in data sheet */ +#define HHI_VID_PLL_CLK_DIV 0x1a0 /* 0x68 offset in data sheet */ +#define HHI_AUD_CLK_CNTL3 0x1a4 /* 0x69 offset in data sheet */ +#define HHI_MALI_CLK_CNTL 0x1b0 /* 0x6c offset in data sheet */ +#define HHI_VPU_CLK_CNTL 0x1bC /* 0x6f offset in data sheet */ + +#define HHI_HDMI_CLK_CNTL 0x1CC /* 0x73 offset in data sheet */ +#define HHI_VDEC_CLK_CNTL 0x1E0 /* 0x78 offset in data sheet */ +#define HHI_VDEC2_CLK_CNTL 0x1E4 /* 0x79 offset in data sheet */ +#define HHI_VDEC3_CLK_CNTL 0x1E8 /* 0x7a offset in data sheet */ +#define HHI_VDEC4_CLK_CNTL 0x1EC /* 0x7b offset in data sheet */ +#define HHI_HDCP22_CLK_CNTL 0x1F0 /* 0x7c offset in data sheet */ +#define HHI_VAPBCLK_CNTL 0x1F4 /* 0x7d offset in data sheet */ + +#define HHI_VPU_CLKB_CNTL 0x20C /* 0x83 offset in data sheet */ +#define HHI_USB_CLK_CNTL 0x220 /* 0x88 offset in data sheet */ +#define HHI_32K_CLK_CNTL 0x224 /* 0x89 offset in data sheet */ +#define HHI_GEN_CLK_CNTL 0x228 /* 0x8a offset in data sheet */ +#define HHI_GEN_CLK_CNTL 0x228 /* 0x8a offset in data sheet */ + +#define HHI_PCM_CLK_CNTL 0x258 /* 0x96 offset in data sheet */ +#define HHI_NAND_CLK_CNTL 0x25C /* 0x97 offset in data sheet */ +#define HHI_SD_EMMC_CLK_CNTL 0x264 /* 0x99 offset in data sheet */ + +#define HHI_MPLL_CNTL 0x280 /* 0xa0 offset in data sheet */ +#define HHI_MPLL_CNTL2 0x284 /* 0xa1 offset in data sheet */ +#define HHI_MPLL_CNTL3 0x288 /* 0xa2 offset in data sheet */ +#define HHI_MPLL_CNTL4 0x28C /* 0xa3 offset in data sheet */ +#define HHI_MPLL_CNTL5 0x290 /* 0xa4 offset in data sheet */ +#define HHI_MPLL_CNTL6 0x294 /* 0xa5 offset in data sheet */ +#define HHI_MPLL_CNTL7 0x298 /* 0xa6 offset in data sheet */ +#define HHI_MPLL_CNTL8 0x29C /* 0xa7 offset in data sheet */ +#define HHI_MPLL_CNTL9 0x2A0 /* 0xa8 offset in data sheet */ +#define HHI_MPLL_CNTL10 0x2A4 /* 0xa9 offset in data sheet */ + +#define HHI_MPLL3_CNTL0 0x2E0 /* 0xb8 offset in data sheet */ +#define HHI_MPLL3_CNTL1 0x2E4 /* 0xb9 offset in data sheet */ +#define HHI_VDAC_CNTL0 0x2F4 /* 0xbd offset in data sheet */ +#define HHI_VDAC_CNTL1 0x2F8 /* 0xbe offset in data sheet */ + +#define HHI_SYS_PLL_CNTL 0x300 /* 0xc0 offset in data sheet */ +#define HHI_SYS_PLL_CNTL2 0x304 /* 0xc1 offset in data sheet */ +#define HHI_SYS_PLL_CNTL3 0x308 /* 0xc2 offset in data sheet */ +#define HHI_SYS_PLL_CNTL4 0x30c /* 0xc3 offset in data sheet */ +#define HHI_SYS_PLL_CNTL5 0x310 /* 0xc4 offset in data sheet */ +#define HHI_DPLL_TOP_I 0x318 /* 0xc6 offset in data sheet */ +#define HHI_DPLL_TOP2_I 0x31C /* 0xc7 offset in data sheet */ +#define HHI_HDMI_PLL_CNTL 0x320 /* 0xc8 offset in data sheet */ +#define HHI_HDMI_PLL_CNTL2 0x324 /* 0xc9 offset in data sheet */ +#define HHI_HDMI_PLL_CNTL3 0x328 /* 0xca offset in data sheet */ +#define HHI_HDMI_PLL_CNTL4 0x32C /* 0xcb offset in data sheet */ +#define HHI_HDMI_PLL_CNTL5 0x330 /* 0xcc offset in data sheet */ +#define HHI_HDMI_PLL_CNTL6 0x334 /* 0xcd offset in data sheet */ +#define HHI_HDMI_PLL_CNTL_I 0x338 /* 0xce offset in data sheet */ +#define HHI_HDMI_PLL_CNTL7 0x33C /* 0xcf offset in data sheet */ + +#define HHI_HDMI_PHY_CNTL0 0x3A0 /* 0xe8 offset in data sheet */ +#define HHI_HDMI_PHY_CNTL1 0x3A4 /* 0xe9 offset in data sheet */ +#define HHI_HDMI_PHY_CNTL2 0x3A8 /* 0xea offset in data sheet */ +#define HHI_HDMI_PHY_CNTL3 0x3AC /* 0xeb offset in data sheet */ + +#define HHI_VID_LOCK_CLK_CNTL 0x3C8 /* 0xf2 offset in data sheet */ +#define HHI_BT656_CLK_CNTL 0x3D4 /* 0xf5 offset in data sheet */ +#define HHI_SAR_CLK_CNTL 0x3D8 /* 0xf6 offset in data sheet */ + +ulong meson_measure_clk_rate(unsigned int clk); + +#endif diff --git a/arch/arm/include/asm/arch-meson/gx.h b/arch/arm/include/asm/arch-meson/gx.h index 03fb6b03de..4bc9475d35 100644 --- a/arch/arm/include/asm/arch-meson/gx.h +++ b/arch/arm/include/asm/arch-meson/gx.h @@ -56,14 +56,4 @@ /* Ethernet memory power domain */ #define GX_MEM_PD_REG_0_ETH_MASK (BIT(2) | BIT(3)) -/* Clock gates */ -#define GX_GCLK_MPEG_0 GX_HIU_ADDR(0x50) -#define GX_GCLK_MPEG_1 GX_HIU_ADDR(0x51) -#define GX_GCLK_MPEG_2 GX_HIU_ADDR(0x52) -#define GX_GCLK_MPEG_OTHER GX_HIU_ADDR(0x53) -#define GX_GCLK_MPEG_AO GX_HIU_ADDR(0x54) - -#define GX_GCLK_MPEG_0_I2C BIT(9) -#define GX_GCLK_MPEG_1_ETH BIT(3) - #endif /* __GX_H__ */ diff --git a/arch/arm/lib/image.c b/arch/arm/lib/image.c index 1a04e2b875..699bf44e70 100644 --- a/arch/arm/lib/image.c +++ b/arch/arm/lib/image.c @@ -26,7 +26,8 @@ struct Image_header { uint32_t res5; }; -int booti_setup(ulong image, ulong *relocated_addr, ulong *size) +int booti_setup(ulong image, ulong *relocated_addr, ulong *size, + bool force_reloc) { struct Image_header *ih; uint64_t dst; @@ -63,7 +64,7 @@ int booti_setup(ulong image, ulong *relocated_addr, ulong *size) * images->ep. Otherwise, relocate the image to the base of RAM * since memory below it is not accessible via the linear mapping. */ - if (le64_to_cpu(ih->flags) & BIT(3)) + if (!force_reloc && (le64_to_cpu(ih->flags) & BIT(3))) dst = image - text_offset; else dst = gd->bd->bi_dram[0].start; diff --git a/arch/arm/lib/vectors.S b/arch/arm/lib/vectors.S index 79afc27e84..d629cb1dc2 100644 --- a/arch/arm/lib/vectors.S +++ b/arch/arm/lib/vectors.S @@ -133,7 +133,7 @@ not_used: irq: fiq: 1: - bl 1b /* hang and never return */ + b 1b /* hang and never return */ #else /* !CONFIG_SPL_BUILD */ diff --git a/arch/arm/mach-davinci/include/mach/gpio.h b/arch/arm/mach-davinci/include/mach/gpio.h index f1d4d9e9e0..d4b25c3d60 100644 --- a/arch/arm/mach-davinci/include/mach/gpio.h +++ b/arch/arm/mach-davinci/include/mach/gpio.h @@ -39,7 +39,7 @@ struct davinci_gpio_bank { unsigned int irq_num; unsigned int irq_mask; unsigned long *in_use; - unsigned long base; + struct davinci_gpio *base; }; #define davinci_gpio_bank01 ((struct davinci_gpio *)DAVINCI_GPIO_BANK01) @@ -48,7 +48,9 @@ struct davinci_gpio_bank { #define davinci_gpio_bank67 ((struct davinci_gpio *)DAVINCI_GPIO_BANK67) #define davinci_gpio_bank8 ((struct davinci_gpio *)DAVINCI_GPIO_BANK8) +#ifndef CONFIG_DM_GPIO #define gpio_status() gpio_info() +#endif #define GPIO_NAME_SIZE 20 #if defined(CONFIG_SOC_DM644X) /* GPIO0 to GPIO53, omit the V3.3 volts one */ @@ -63,4 +65,14 @@ struct davinci_gpio_bank { void gpio_info(void); +#ifdef CONFIG_DM_GPIO + +/* Information about a GPIO bank */ +struct davinci_gpio_platdata { + int bank_index; + ulong base; /* address of registers in physical memory */ + const char *port_name; +}; +#endif + #endif diff --git a/arch/arm/mach-imx/mx6/mp.c b/arch/arm/mach-imx/mx6/mp.c index c3806dca3a..eda168d867 100644 --- a/arch/arm/mach-imx/mx6/mp.c +++ b/arch/arm/mach-imx/mx6/mp.c @@ -29,20 +29,20 @@ static uint32_t cpu_ctrl_mask[MAX_CPUS] = { SRC_SCR_CORE_3_ENABLE_MASK }; -int cpu_reset(int nr) +int cpu_reset(u32 nr) { /* Software reset of the CPU N */ src->scr |= cpu_reset_mask[nr]; return 0; } -int cpu_status(int nr) +int cpu_status(u32 nr) { printf("core %d => %d\n", nr, !!(src->scr & cpu_ctrl_mask[nr])); return 0; } -int cpu_release(int nr, int argc, char *const argv[]) +int cpu_release(u32 nr, int argc, char *const argv[]) { uint32_t boot_addr; @@ -78,7 +78,7 @@ int is_core_valid(unsigned int core) return 1; } -int cpu_disable(int nr) +int cpu_disable(u32 nr) { /* Disable the CPU N */ src->scr &= ~cpu_ctrl_mask[nr]; diff --git a/arch/arm/mach-meson/Kconfig b/arch/arm/mach-meson/Kconfig index 0350787daa..9a06ccc861 100644 --- a/arch/arm/mach-meson/Kconfig +++ b/arch/arm/mach-meson/Kconfig @@ -3,6 +3,7 @@ if ARCH_MESON config MESON_GXBB bool "Support Meson GXBaby" select ARM64 + select CLK select DM select DM_SERIAL help @@ -12,6 +13,7 @@ config MESON_GXBB config MESON_GXL bool "Support Meson GXL" select ARM64 + select CLK select DM select DM_SERIAL help diff --git a/arch/arm/mach-meson/eth.c b/arch/arm/mach-meson/eth.c index 061f19a0e3..8b28bc8531 100644 --- a/arch/arm/mach-meson/eth.c +++ b/arch/arm/mach-meson/eth.c @@ -48,7 +48,6 @@ void meson_gx_eth_init(phy_interface_t mode, unsigned int flags) return; } - /* Enable power and clock gate */ - setbits_le32(GX_GCLK_MPEG_1, GX_GCLK_MPEG_1_ETH); + /* Enable power gate */ clrbits_le32(GX_MEM_PD_REG_0, GX_MEM_PD_REG_0_ETH_MASK); } diff --git a/arch/arm/mach-omap2/omap3/clock.c b/arch/arm/mach-omap2/omap3/clock.c index b9d92c62b1..9a03bfa9d3 100644 --- a/arch/arm/mach-omap2/omap3/clock.c +++ b/arch/arm/mach-omap2/omap3/clock.c @@ -750,23 +750,23 @@ void per_clocks_enable(void) setbits_le32(&prcm_base->iclken_per, 0x00000800); #endif -#ifdef CONFIG_OMAP3_GPIO_2 +#if (CONFIG_IS_ENABLED(OMAP3_GPIO_2) || CONFIG_IS_ENABLED(CMD_GPIO)) setbits_le32(&prcm_base->fclken_per, 0x00002000); setbits_le32(&prcm_base->iclken_per, 0x00002000); #endif -#ifdef CONFIG_OMAP3_GPIO_3 +#if (CONFIG_IS_ENABLED(OMAP3_GPIO_3) || CONFIG_IS_ENABLED(CMD_GPIO)) setbits_le32(&prcm_base->fclken_per, 0x00004000); setbits_le32(&prcm_base->iclken_per, 0x00004000); #endif -#ifdef CONFIG_OMAP3_GPIO_4 +#if (CONFIG_IS_ENABLED(OMAP3_GPIO_4) || CONFIG_IS_ENABLED(CMD_GPIO)) setbits_le32(&prcm_base->fclken_per, 0x00008000); setbits_le32(&prcm_base->iclken_per, 0x00008000); #endif -#ifdef CONFIG_OMAP3_GPIO_5 +#if (CONFIG_IS_ENABLED(OMAP3_GPIO_5) || CONFIG_IS_ENABLED(CMD_GPIO)) setbits_le32(&prcm_base->fclken_per, 0x00010000); setbits_le32(&prcm_base->iclken_per, 0x00010000); #endif -#ifdef CONFIG_OMAP3_GPIO_6 +#if (CONFIG_IS_ENABLED(OMAP3_GPIO_6) || CONFIG_IS_ENABLED(CMD_GPIO)) setbits_le32(&prcm_base->fclken_per, 0x00020000); setbits_le32(&prcm_base->iclken_per, 0x00020000); #endif diff --git a/arch/arm/mach-sunxi/board.c b/arch/arm/mach-sunxi/board.c index 7ac8360c01..58fef05bd7 100644 --- a/arch/arm/mach-sunxi/board.c +++ b/arch/arm/mach-sunxi/board.c @@ -207,9 +207,6 @@ void s_init(void) eth_init_board(); } -#ifdef CONFIG_SPL_BUILD -#endif - /* The sunxi internal brom will try to loader external bootloader * from mmc0, nand flash, mmc2. */ diff --git a/arch/m68k/include/asm/processor.h b/arch/m68k/include/asm/processor.h index 3fafa6ff1a..4af69190b7 100644 --- a/arch/m68k/include/asm/processor.h +++ b/arch/m68k/include/asm/processor.h @@ -11,8 +11,4 @@ n: /* Macros for setting and retrieving special purpose registers */ #define setvbr(v) asm volatile("movec %0,%%VBR" : : "r" (v)) -#ifndef __ASSEMBLY__ - -#endif /* ifndef ASSEMBLY*/ - #endif /* __ASM_M68K_PROCESSOR_H */ diff --git a/arch/microblaze/dts/.gitignore b/arch/microblaze/dts/.gitignore deleted file mode 100644 index b60ed208c7..0000000000 --- a/arch/microblaze/dts/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.dtb diff --git a/arch/mips/dts/.gitignore b/arch/mips/dts/.gitignore deleted file mode 100644 index b60ed208c7..0000000000 --- a/arch/mips/dts/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.dtb diff --git a/arch/nios2/dts/.gitignore b/arch/nios2/dts/.gitignore deleted file mode 100644 index b60ed208c7..0000000000 --- a/arch/nios2/dts/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.dtb diff --git a/arch/powerpc/cpu/mpc85xx/mp.c b/arch/powerpc/cpu/mpc85xx/mp.c index 42501ca3ce..b0aa72ed6e 100644 --- a/arch/powerpc/cpu/mpc85xx/mp.c +++ b/arch/powerpc/cpu/mpc85xx/mp.c @@ -42,7 +42,7 @@ int hold_cores_in_reset(int verbose) return 0; } -int cpu_reset(int nr) +int cpu_reset(u32 nr) { volatile ccsr_pic_t *pic = (void *)(CONFIG_SYS_MPC8xxx_PIC_ADDR); out_be32(&pic->pir, 1 << nr); @@ -53,7 +53,7 @@ int cpu_reset(int nr) return 0; } -int cpu_status(int nr) +int cpu_status(u32 nr) { u32 *table, id = get_my_id(); @@ -79,7 +79,7 @@ int cpu_status(int nr) } #ifdef CONFIG_FSL_CORENET -int cpu_disable(int nr) +int cpu_disable(u32 nr) { volatile ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR); @@ -95,7 +95,7 @@ int is_core_disabled(int nr) { return (coredisrl & (1 << nr)); } #else -int cpu_disable(int nr) +int cpu_disable(u32 nr) { volatile ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR); @@ -137,7 +137,7 @@ static u8 boot_entry_map[4] = { BOOT_ENTRY_R3_LOWER, }; -int cpu_release(int nr, int argc, char * const argv[]) +int cpu_release(u32 nr, int argc, char * const argv[]) { u32 i, val, *table = (u32 *)&__spin_table + nr * NUM_BOOT_ENTRY; u64 boot_addr; diff --git a/arch/powerpc/cpu/mpc86xx/mp.c b/arch/powerpc/cpu/mpc86xx/mp.c index 97bd160df8..ce300eac5b 100644 --- a/arch/powerpc/cpu/mpc86xx/mp.c +++ b/arch/powerpc/cpu/mpc86xx/mp.c @@ -13,7 +13,7 @@ DECLARE_GLOBAL_DATA_PTR; -int cpu_reset(int nr) +int cpu_reset(u32 nr) { /* dummy function so common/cmd_mp.c will build * should be implemented in the future, when cpu_release() @@ -23,13 +23,13 @@ int cpu_reset(int nr) return 1; } -int cpu_status(int nr) +int cpu_status(u32 nr) { /* dummy function so common/cmd_mp.c will build */ return 0; } -int cpu_disable(int nr) +int cpu_disable(u32 nr) { volatile immap_t *immap = (immap_t *) CONFIG_SYS_CCSRBAR; volatile ccsr_gur_t *gur = &immap->im_gur; @@ -66,7 +66,7 @@ int is_core_disabled(int nr) { return 0; } -int cpu_release(int nr, int argc, char * const argv[]) +int cpu_release(u32 nr, int argc, char * const argv[]) { /* dummy function so common/cmd_mp.c will build * should be implemented in the future */ diff --git a/arch/sandbox/dts/.gitignore b/arch/sandbox/dts/.gitignore deleted file mode 100644 index b60ed208c7..0000000000 --- a/arch/sandbox/dts/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.dtb diff --git a/arch/x86/dts/.gitignore b/arch/x86/dts/.gitignore deleted file mode 100644 index b60ed208c7..0000000000 --- a/arch/x86/dts/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.dtb diff --git a/board/amlogic/libretech-cc/libretech-cc.c b/board/amlogic/libretech-cc/libretech-cc.c index e89bf773cc..ccab1272c5 100644 --- a/board/amlogic/libretech-cc/libretech-cc.c +++ b/board/amlogic/libretech-cc/libretech-cc.c @@ -32,10 +32,6 @@ int misc_init_r(void) meson_gx_eth_init(PHY_INTERFACE_MODE_RMII, MESON_GXL_USE_INTERNAL_RMII_PHY); - /* Enable power and clock gate */ - setbits_le32(GX_GCLK_MPEG_1, GX_GCLK_MPEG_1_ETH); - clrbits_le32(GX_MEM_PD_REG_0, GX_MEM_PD_REG_0_ETH_MASK); - if (!eth_env_get_enetaddr("ethaddr", mac_addr)) { len = meson_sm_read_efuse(EFUSE_MAC_OFFSET, mac_addr, EFUSE_MAC_SIZE); diff --git a/board/amlogic/odroid-c2/odroid-c2.c b/board/amlogic/odroid-c2/odroid-c2.c index 1b7fd8199b..c47b9ce9cb 100644 --- a/board/amlogic/odroid-c2/odroid-c2.c +++ b/board/amlogic/odroid-c2/odroid-c2.c @@ -30,9 +30,6 @@ int misc_init_r(void) meson_gx_eth_init(PHY_INTERFACE_MODE_RGMII, 0); - /* Enable power and clock gate */ - setbits_le32(GX_GCLK_MPEG_0, GX_GCLK_MPEG_0_I2C); - /* Reset PHY on GPIOZ_14 */ clrbits_le32(GX_GPIO_EN(3), BIT(14)); clrbits_le32(GX_GPIO_OUT(3), BIT(14)); diff --git a/board/davinci/da8xxevm/da850evm.c b/board/davinci/da8xxevm/da850evm.c index c565ba7831..5583b45792 100644 --- a/board/davinci/da8xxevm/da850evm.c +++ b/board/davinci/da8xxevm/da850evm.c @@ -9,6 +9,7 @@ */ #include <common.h> +#include <dm.h> #include <environment.h> #include <i2c.h> #include <net.h> @@ -24,6 +25,7 @@ #include <linux/errno.h> #include <hwconfig.h> #include <asm/mach-types.h> +#include <asm/gpio.h> #ifdef CONFIG_MMC_DAVINCI #include <mmc.h> diff --git a/board/synopsys/emdk/README b/board/synopsys/emdk/README new file mode 100644 index 0000000000..706b547a9e --- /dev/null +++ b/board/synopsys/emdk/README @@ -0,0 +1,82 @@ +================================================================================ +Useful notes on bulding and using of U-Boot on ARC EM Development Kit (AKA EMDK) +================================================================================ + + BOARD OVERVIEW + + The DesignWare ARC EM Development Kit is FPGA-bases platform for rapid + software development on the ARC EM family of processors. + + Since this board is based on FPGA it's possible to load and use different + versions of ARC EM CPUs. U-Boot is built to be run on the simplest + possible configuration which means the same one binary will work on more + advanced configurations as well. + + The board has the following features useful for U-Boot: + * On-board 2-channel FTDI TTL-to-USB converter + - The first channel is used for serial debug port (which makes it possible + to use a serial connection on pretty much any host machine be it + Windows, Linux or Mac). + On Linux machine typucally FTDI serial port would be /dev/ttyUSB0. + There's no HW flow-control and baud-rate is 115200. + + - The second channel is used for built-in Digilent USB JTAG probe. + That means no extra hardware is required to access ARC core from a + debugger on development host. Both proprietary MetaWare debugger and + open source OpenOCD + GDB client are supported. + + - Also with help of this FTDI chip it is possible to reset entire + board with help of a special `rff-ftdi-reset` utility, see: + https://github.com/foss-for-synopsys-dwc-arc-processors/rff-ftdi-reset + + * Micro SD-card slot + - U-Boot expects to see the very first partition on the card formatted as + FAT file-system and uses it for keeping its environment in `uboot.env` + file. Note uboot.env is not just a text file but it is auto-generated + file created by U-Boot on invocation of `saveenv` command. + It contains a checksum which makes this saved environment invalid in + case of maual modification. + + - There might be more useful files on that first FAT partition like + user applications, data files etc. + + * 256 KiB of "ROM" + - This so-called "ROM" is a part of FPGA image and even though it + might be unlocked for writes its initial content will be restored + on the next power-on. + + + BUILDING U-BOOT + + 1. Configure U-Boot: + ------------------------->8---------------------- + make emdk_defconfig + ------------------------->8---------------------- + + 2. To build Elf file (for example to be used with host debugger via JTAG + connection to the target board): + ------------------------->8---------------------- + make mdbtrick + ------------------------->8---------------------- + + This will produce `u-boot` Elf file. + + 3. To build binary image to be put in "ROM": + ------------------------->8---------------------- + make u-boot.bin + ------------------------->8---------------------- + + + EXECUTING U-BOOT + + 1. The EMDK board is supposed to auto-start U-Boot image stored in ROM on + power-on. For that make sure VCCIO DIP-switches are all in "off" state. + + 2. Though it is possible to load U-Boot as a simple Elf file via JTAG right + in "ROM" and start it from the debugger. One important note here we first + need to enable writes into "ROM" by writing 1 to 0xf0001000. + + 2.1. In case of proprietary MetaWare debugger run: + ------------------------->8---------------------- + mdb -dll=opxdarc.so -OK -preloadexec="eval *(int*)0xf0001000=0" u-boot + ------------------------->8---------------------- diff --git a/cmd/Kconfig b/cmd/Kconfig index 1eb55e5250..45c83359ad 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -1754,6 +1754,22 @@ config CMD_TRACE for analsys (e.g. using bootchart). See doc/README.trace for full details. +config CMD_AVB + bool "avb - Android Verified Boot 2.0 operations" + depends on LIBAVB + default n + help + Enables a "avb" command to perform verification of partitions using + Android Verified Boot 2.0 functionality. It includes such subcommands: + avb init - initialize avb2 subsystem + avb read_rb - read rollback index + avb write_rb - write rollback index + avb is_unlocked - check device lock state + avb get_uuid - read and print uuid of a partition + avb read_part - read data from partition + avb read_part_hex - read data from partition and output to stdout + avb write_part - write data to partition + avb verify - run full verification chain endmenu config CMD_UBI diff --git a/cmd/Makefile b/cmd/Makefile index e0088df33b..13cf7bf6c2 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -155,6 +155,9 @@ obj-$(CONFIG_CMD_REGULATOR) += regulator.o obj-$(CONFIG_CMD_BLOB) += blob.o +# Android Verified Boot 2.0 +obj-$(CONFIG_CMD_AVB) += avb.o + obj-$(CONFIG_X86) += x86/ endif # !CONFIG_SPL_BUILD diff --git a/cmd/avb.c b/cmd/avb.c new file mode 100644 index 0000000000..f045a0c64c --- /dev/null +++ b/cmd/avb.c @@ -0,0 +1,372 @@ + +/* + * (C) Copyright 2018, Linaro Limited + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <avb_verify.h> +#include <command.h> +#include <image.h> +#include <malloc.h> +#include <mmc.h> + +#define AVB_BOOTARGS "avb_bootargs" +static struct AvbOps *avb_ops; + +static const char * const requested_partitions[] = {"boot", + "system", + "vendor", + NULL}; + +int do_avb_init(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + unsigned long mmc_dev; + + if (argc != 2) + return CMD_RET_USAGE; + + mmc_dev = simple_strtoul(argv[1], NULL, 16); + + if (avb_ops) + avb_ops_free(avb_ops); + + avb_ops = avb_ops_alloc(mmc_dev); + if (avb_ops) + return CMD_RET_SUCCESS; + + return CMD_RET_FAILURE; +} + +int do_avb_read_part(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + const char *part; + s64 offset; + size_t bytes, bytes_read = 0; + void *buffer; + + if (!avb_ops) { + printf("AVB 2.0 is not initialized, please run 'avb init'\n"); + return CMD_RET_USAGE; + } + + if (argc != 5) + return CMD_RET_USAGE; + + part = argv[1]; + offset = simple_strtoul(argv[2], NULL, 16); + bytes = simple_strtoul(argv[3], NULL, 16); + buffer = (void *)simple_strtoul(argv[4], NULL, 16); + + if (avb_ops->read_from_partition(avb_ops, part, offset, bytes, + buffer, &bytes_read) == + AVB_IO_RESULT_OK) { + printf("Read %zu bytes\n", bytes_read); + return CMD_RET_SUCCESS; + } + + return CMD_RET_FAILURE; +} + +int do_avb_read_part_hex(cmd_tbl_t *cmdtp, int flag, int argc, + char *const argv[]) +{ + const char *part; + s64 offset; + size_t bytes, bytes_read = 0; + char *buffer; + + if (!avb_ops) { + printf("AVB 2.0 is not initialized, please run 'avb init'\n"); + return CMD_RET_USAGE; + } + + if (argc != 4) + return CMD_RET_USAGE; + + part = argv[1]; + offset = simple_strtoul(argv[2], NULL, 16); + bytes = simple_strtoul(argv[3], NULL, 16); + + buffer = malloc(bytes); + if (!buffer) { + printf("Failed to tlb_allocate buffer for data\n"); + return CMD_RET_FAILURE; + } + memset(buffer, 0, bytes); + + if (avb_ops->read_from_partition(avb_ops, part, offset, bytes, buffer, + &bytes_read) == AVB_IO_RESULT_OK) { + printf("Requested %zu, read %zu bytes\n", bytes, bytes_read); + printf("Data: "); + for (int i = 0; i < bytes_read; i++) + printf("%02X", buffer[i]); + + printf("\n"); + + free(buffer); + return CMD_RET_SUCCESS; + } + + free(buffer); + return CMD_RET_FAILURE; +} + +int do_avb_write_part(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + const char *part; + s64 offset; + size_t bytes; + void *buffer; + + if (!avb_ops) { + printf("AVB 2.0 is not initialized, run 'avb init' first\n"); + return CMD_RET_FAILURE; + } + + if (argc != 5) + return CMD_RET_USAGE; + + part = argv[1]; + offset = simple_strtoul(argv[2], NULL, 16); + bytes = simple_strtoul(argv[3], NULL, 16); + buffer = (void *)simple_strtoul(argv[4], NULL, 16); + + if (avb_ops->write_to_partition(avb_ops, part, offset, bytes, buffer) == + AVB_IO_RESULT_OK) { + printf("Wrote %zu bytes\n", bytes); + return CMD_RET_SUCCESS; + } + + return CMD_RET_FAILURE; +} + +int do_avb_read_rb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + size_t index; + u64 rb_idx; + + if (!avb_ops) { + printf("AVB 2.0 is not initialized, run 'avb init' first\n"); + return CMD_RET_FAILURE; + } + + if (argc != 2) + return CMD_RET_USAGE; + + index = (size_t)simple_strtoul(argv[1], NULL, 16); + + if (avb_ops->read_rollback_index(avb_ops, index, &rb_idx) == + AVB_IO_RESULT_OK) { + printf("Rollback index: %llu\n", rb_idx); + return CMD_RET_SUCCESS; + } + return CMD_RET_FAILURE; +} + +int do_avb_write_rb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + size_t index; + u64 rb_idx; + + if (!avb_ops) { + printf("AVB 2.0 is not initialized, run 'avb init' first\n"); + return CMD_RET_FAILURE; + } + + if (argc != 3) + return CMD_RET_USAGE; + + index = (size_t)simple_strtoul(argv[1], NULL, 16); + rb_idx = simple_strtoul(argv[2], NULL, 16); + + if (avb_ops->write_rollback_index(avb_ops, index, rb_idx) == + AVB_IO_RESULT_OK) + return CMD_RET_SUCCESS; + + return CMD_RET_FAILURE; +} + +int do_avb_get_uuid(cmd_tbl_t *cmdtp, int flag, + int argc, char * const argv[]) +{ + const char *part; + char buffer[UUID_STR_LEN + 1]; + + if (!avb_ops) { + printf("AVB 2.0 is not initialized, run 'avb init' first\n"); + return CMD_RET_FAILURE; + } + + if (argc != 2) + return CMD_RET_USAGE; + + part = argv[1]; + + if (avb_ops->get_unique_guid_for_partition(avb_ops, part, buffer, + UUID_STR_LEN + 1) == + AVB_IO_RESULT_OK) { + printf("'%s' UUID: %s\n", part, buffer); + return CMD_RET_SUCCESS; + } + + return CMD_RET_FAILURE; +} + +int do_avb_verify_part(cmd_tbl_t *cmdtp, int flag, + int argc, char *const argv[]) +{ + AvbSlotVerifyResult slot_result; + AvbSlotVerifyData *out_data; + char *cmdline; + char *extra_args; + + bool unlocked = false; + int res = CMD_RET_FAILURE; + + if (!avb_ops) { + printf("AVB 2.0 is not initialized, run 'avb init' first\n"); + return CMD_RET_FAILURE; + } + + if (argc != 1) + return CMD_RET_USAGE; + + printf("## Android Verified Boot 2.0 version %s\n", + avb_version_string()); + + if (avb_ops->read_is_device_unlocked(avb_ops, &unlocked) != + AVB_IO_RESULT_OK) { + printf("Can't determine device lock state.\n"); + return CMD_RET_FAILURE; + } + + slot_result = + avb_slot_verify(avb_ops, + requested_partitions, + "", + unlocked, + AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE, + &out_data); + + switch (slot_result) { + case AVB_SLOT_VERIFY_RESULT_OK: + /* Until we don't have support of changing unlock states, we + * assume that we are by default in locked state. + * So in this case we can boot only when verification is + * successful; we also supply in cmdline GREEN boot state + */ + printf("Verification passed successfully\n"); + + /* export additional bootargs to AVB_BOOTARGS env var */ + + extra_args = avb_set_state(avb_ops, AVB_GREEN); + if (extra_args) + cmdline = append_cmd_line(out_data->cmdline, + extra_args); + else + cmdline = out_data->cmdline; + + env_set(AVB_BOOTARGS, cmdline); + + res = CMD_RET_SUCCESS; + break; + case AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION: + printf("Verification failed\n"); + break; + case AVB_SLOT_VERIFY_RESULT_ERROR_IO: + printf("I/O error occurred during verification\n"); + break; + case AVB_SLOT_VERIFY_RESULT_ERROR_OOM: + printf("OOM error occurred during verification\n"); + break; + case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA: + printf("Corrupted dm-verity metadata detected\n"); + break; + case AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION: + printf("Unsupported version avbtool was used\n"); + break; + case AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX: + printf("Checking rollback index failed\n"); + break; + case AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED: + printf("Public key was rejected\n"); + break; + default: + printf("Unknown error occurred\n"); + } + + return res; +} + +int do_avb_is_unlocked(cmd_tbl_t *cmdtp, int flag, + int argc, char * const argv[]) +{ + bool unlock; + + if (!avb_ops) { + printf("AVB not initialized, run 'avb init' first\n"); + return CMD_RET_FAILURE; + } + + if (argc != 1) { + printf("--%s(-1)\n", __func__); + return CMD_RET_USAGE; + } + + if (avb_ops->read_is_device_unlocked(avb_ops, &unlock) == + AVB_IO_RESULT_OK) { + printf("Unlocked = %d\n", unlock); + return CMD_RET_SUCCESS; + } + + return CMD_RET_FAILURE; +} + +static cmd_tbl_t cmd_avb[] = { + U_BOOT_CMD_MKENT(init, 2, 0, do_avb_init, "", ""), + U_BOOT_CMD_MKENT(read_rb, 2, 0, do_avb_read_rb, "", ""), + U_BOOT_CMD_MKENT(write_rb, 3, 0, do_avb_write_rb, "", ""), + U_BOOT_CMD_MKENT(is_unlocked, 1, 0, do_avb_is_unlocked, "", ""), + U_BOOT_CMD_MKENT(get_uuid, 2, 0, do_avb_get_uuid, "", ""), + U_BOOT_CMD_MKENT(read_part, 5, 0, do_avb_read_part, "", ""), + U_BOOT_CMD_MKENT(read_part_hex, 4, 0, do_avb_read_part_hex, "", ""), + U_BOOT_CMD_MKENT(write_part, 5, 0, do_avb_write_part, "", ""), + U_BOOT_CMD_MKENT(verify, 1, 0, do_avb_verify_part, "", ""), +}; + +static int do_avb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + cmd_tbl_t *cp; + + cp = find_cmd_tbl(argv[1], cmd_avb, ARRAY_SIZE(cmd_avb)); + + argc--; + argv++; + + if (!cp || argc > cp->maxargs) + return CMD_RET_USAGE; + + if (flag == CMD_FLAG_REPEAT) + return CMD_RET_FAILURE; + + return cp->cmd(cmdtp, flag, argc, argv); +} + +U_BOOT_CMD( + avb, 29, 0, do_avb, + "Provides commands for testing Android Verified Boot 2.0 functionality", + "init <dev> - initialize avb2 for <dev>\n" + "avb read_rb <num> - read rollback index at location <num>\n" + "avb write_rb <num> <rb> - write rollback index <rb> to <num>\n" + "avb is_unlocked - returns unlock status of the device\n" + "avb get_uuid <partname> - read and print uuid of partition <part>\n" + "avb read_part <partname> <offset> <num> <addr> - read <num> bytes from\n" + " partition <partname> to buffer <addr>\n" + "avb read_part_hex <partname> <offset> <num> - read <num> bytes from\n" + " partition <partname> and print to stdout\n" + "avb write_part <partname> <offset> <num> <addr> - write <num> bytes to\n" + " <partname> by <offset> using data from <addr>\n" + "avb verify - run verification process using hash data\n" + " from vbmeta structure\n" + ); diff --git a/cmd/booti.c b/cmd/booti.c index 45fbb99b68..04353b68ec 100644 --- a/cmd/booti.c +++ b/cmd/booti.c @@ -37,7 +37,7 @@ static int booti_start(cmd_tbl_t *cmdtp, int flag, int argc, debug("* kernel: cmdline image address = 0x%08lx\n", ld); } - ret = booti_setup(ld, &relocated_addr, &image_size); + ret = booti_setup(ld, &relocated_addr, &image_size, false); if (ret != 0) return 1; diff --git a/cmd/iotrace.c b/cmd/iotrace.c index 601b8c8e32..fa6c68b198 100644 --- a/cmd/iotrace.c +++ b/cmd/iotrace.c @@ -9,12 +9,13 @@ static void do_print_stats(void) { - ulong start, size, offset, count; + ulong start, size, needed_size, offset, count; printf("iotrace is %sabled\n", iotrace_get_enabled() ? "en" : "dis"); - iotrace_get_buffer(&start, &size, &offset, &count); + iotrace_get_buffer(&start, &size, &needed_size, &offset, &count); printf("Start: %08lx\n", start); - printf("Size: %08lx\n", size); + printf("Actual Size: %08lx\n", size); + printf("Needed Size: %08lx\n", needed_size); iotrace_get_region(&start, &size); printf("Region: %08lx\n", start); printf("Size: %08lx\n", size); @@ -24,6 +25,36 @@ static void do_print_stats(void) printf("CRC32: %08lx\n", (ulong)iotrace_get_checksum()); } +static void do_print_trace(void) +{ + ulong start, size, needed_size, offset, count; + + struct iotrace_record *cur_record; + + iotrace_get_buffer(&start, &size, &needed_size, &offset, &count); + + if (!start || !size || !count) + return; + + printf("Timestamp Value Address\n"); + + cur_record = (struct iotrace_record *)start; + for (int i = 0; i < count; i++) { + if (cur_record->flags & IOT_WRITE) + printf("%08llu: 0x%08lx --> 0x%08llx\n", + cur_record->timestamp, + cur_record->value, + (unsigned long long)cur_record->addr); + else + printf("%08llu: 0x%08lx <-- 0x%08llx\n", + cur_record->timestamp, + cur_record->value, + (unsigned long long)cur_record->addr); + + cur_record++; + } +} + static int do_set_buffer(int argc, char * const argv[]) { ulong addr = 0, size = 0; @@ -76,6 +107,9 @@ int do_iotrace(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) case 's': do_print_stats(); break; + case 'd': + do_print_trace(); + break; default: return CMD_RET_USAGE; } @@ -90,5 +124,6 @@ U_BOOT_CMD( "iotrace buffer <address> <size> - set iotrace buffer\n" "iotrace limit <address> <size> - set iotrace region limit\n" "iotrace pause - pause tracing\n" - "iotrace resume - resume tracing" + "iotrace resume - resume tracing\n" + "iotrace dump - dump iotrace buffer" ); @@ -935,6 +935,7 @@ U_BOOT_CMD( "mmc part - lists available partition on current mmc device\n" "mmc dev [dev] [part] - show or set current mmc device [partition]\n" "mmc list - lists available devices\n" +#if CONFIG_IS_ENABLED(MMC_HW_PARTITIONING) "mmc hwpartition [args...] - does hardware partitioning\n" " arguments (sizes in 512-byte blocks):\n" " [user [enh start cnt] [wrrel {on|off}]] - sets user data area attributes\n" @@ -942,6 +943,7 @@ U_BOOT_CMD( " [check|set|complete] - mode, complete set partitioning completed\n" " WARNING: Partitioning is a write-once setting once it is set to complete.\n" " Power cycling is required to initialize partitions after set to complete.\n" +#endif #ifdef CONFIG_SUPPORT_EMMC_BOOT "mmc bootbus dev boot_bus_width reset_boot_bus_width boot_mode\n" " - Set the BOOT_BUS_WIDTH field of the specified device\n" diff --git a/common/Makefile b/common/Makefile index b3da72ebb2..66584f8f48 100644 --- a/common/Makefile +++ b/common/Makefile @@ -120,3 +120,5 @@ obj-$(CONFIG_$(SPL_)LOG) += log.o obj-$(CONFIG_$(SPL_)LOG_CONSOLE) += log_console.o obj-y += s_record.o obj-y += xyzModem.o + +obj-$(CONFIG_LIBAVB) += avb_verify.o diff --git a/common/avb_verify.c b/common/avb_verify.c new file mode 100644 index 0000000000..f9a00f8871 --- /dev/null +++ b/common/avb_verify.c @@ -0,0 +1,741 @@ +/* + * (C) Copyright 2018, Linaro Limited + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <avb_verify.h> +#include <fastboot.h> +#include <image.h> +#include <malloc.h> +#include <part.h> + +const unsigned char avb_root_pub[1032] = { + 0x0, 0x0, 0x10, 0x0, 0x55, 0xd9, 0x4, 0xad, 0xd8, 0x4, + 0xaf, 0xe3, 0xd3, 0x84, 0x6c, 0x7e, 0xd, 0x89, 0x3d, 0xc2, + 0x8c, 0xd3, 0x12, 0x55, 0xe9, 0x62, 0xc9, 0xf1, 0xf, 0x5e, + 0xcc, 0x16, 0x72, 0xab, 0x44, 0x7c, 0x2c, 0x65, 0x4a, 0x94, + 0xb5, 0x16, 0x2b, 0x0, 0xbb, 0x6, 0xef, 0x13, 0x7, 0x53, + 0x4c, 0xf9, 0x64, 0xb9, 0x28, 0x7a, 0x1b, 0x84, 0x98, 0x88, + 0xd8, 0x67, 0xa4, 0x23, 0xf9, 0xa7, 0x4b, 0xdc, 0x4a, 0xf, + 0xf7, 0x3a, 0x18, 0xae, 0x54, 0xa8, 0x15, 0xfe, 0xb0, 0xad, + 0xac, 0x35, 0xda, 0x3b, 0xad, 0x27, 0xbc, 0xaf, 0xe8, 0xd3, + 0x2f, 0x37, 0x34, 0xd6, 0x51, 0x2b, 0x6c, 0x5a, 0x27, 0xd7, + 0x96, 0x6, 0xaf, 0x6b, 0xb8, 0x80, 0xca, 0xfa, 0x30, 0xb4, + 0xb1, 0x85, 0xb3, 0x4d, 0xaa, 0xaa, 0xc3, 0x16, 0x34, 0x1a, + 0xb8, 0xe7, 0xc7, 0xfa, 0xf9, 0x9, 0x77, 0xab, 0x97, 0x93, + 0xeb, 0x44, 0xae, 0xcf, 0x20, 0xbc, 0xf0, 0x80, 0x11, 0xdb, + 0x23, 0xc, 0x47, 0x71, 0xb9, 0x6d, 0xd6, 0x7b, 0x60, 0x47, + 0x87, 0x16, 0x56, 0x93, 0xb7, 0xc2, 0x2a, 0x9a, 0xb0, 0x4c, + 0x1, 0xc, 0x30, 0xd8, 0x93, 0x87, 0xf0, 0xed, 0x6e, 0x8b, + 0xbe, 0x30, 0x5b, 0xf6, 0xa6, 0xaf, 0xdd, 0x80, 0x7c, 0x45, + 0x5e, 0x8f, 0x91, 0x93, 0x5e, 0x44, 0xfe, 0xb8, 0x82, 0x7, + 0xee, 0x79, 0xca, 0xbf, 0x31, 0x73, 0x62, 0x58, 0xe3, 0xcd, + 0xc4, 0xbc, 0xc2, 0x11, 0x1d, 0xa1, 0x4a, 0xbf, 0xfe, 0x27, + 0x7d, 0xa1, 0xf6, 0x35, 0xa3, 0x5e, 0xca, 0xdc, 0x57, 0x2f, + 0x3e, 0xf0, 0xc9, 0x5d, 0x86, 0x6a, 0xf8, 0xaf, 0x66, 0xa7, + 0xed, 0xcd, 0xb8, 0xed, 0xa1, 0x5f, 0xba, 0x9b, 0x85, 0x1a, + 0xd5, 0x9, 0xae, 0x94, 0x4e, 0x3b, 0xcf, 0xcb, 0x5c, 0xc9, + 0x79, 0x80, 0xf7, 0xcc, 0xa6, 0x4a, 0xa8, 0x6a, 0xd8, 0xd3, + 0x31, 0x11, 0xf9, 0xf6, 0x2, 0x63, 0x2a, 0x1a, 0x2d, 0xd1, + 0x1a, 0x66, 0x1b, 0x16, 0x41, 0xbd, 0xbd, 0xf7, 0x4d, 0xc0, + 0x4a, 0xe5, 0x27, 0x49, 0x5f, 0x7f, 0x58, 0xe3, 0x27, 0x2d, + 0xe5, 0xc9, 0x66, 0xe, 0x52, 0x38, 0x16, 0x38, 0xfb, 0x16, + 0xeb, 0x53, 0x3f, 0xe6, 0xfd, 0xe9, 0xa2, 0x5e, 0x25, 0x59, + 0xd8, 0x79, 0x45, 0xff, 0x3, 0x4c, 0x26, 0xa2, 0x0, 0x5a, + 0x8e, 0xc2, 0x51, 0xa1, 0x15, 0xf9, 0x7b, 0xf4, 0x5c, 0x81, + 0x9b, 0x18, 0x47, 0x35, 0xd8, 0x2d, 0x5, 0xe9, 0xad, 0xf, + 0x35, 0x74, 0x15, 0xa3, 0x8e, 0x8b, 0xcc, 0x27, 0xda, 0x7c, + 0x5d, 0xe4, 0xfa, 0x4, 0xd3, 0x5, 0xb, 0xba, 0x3a, 0xb2, + 0x49, 0x45, 0x2f, 0x47, 0xc7, 0xd, 0x41, 0x3f, 0x97, 0x80, + 0x4d, 0x3f, 0xc1, 0xb5, 0xbb, 0x70, 0x5f, 0xa7, 0x37, 0xaf, + 0x48, 0x22, 0x12, 0x45, 0x2e, 0xf5, 0xf, 0x87, 0x92, 0xe2, + 0x84, 0x1, 0xf9, 0x12, 0xf, 0x14, 0x15, 0x24, 0xce, 0x89, + 0x99, 0xee, 0xb9, 0xc4, 0x17, 0x70, 0x70, 0x15, 0xea, 0xbe, + 0xc6, 0x6c, 0x1f, 0x62, 0xb3, 0xf4, 0x2d, 0x16, 0x87, 0xfb, + 0x56, 0x1e, 0x45, 0xab, 0xae, 0x32, 0xe4, 0x5e, 0x91, 0xed, + 0x53, 0x66, 0x5e, 0xbd, 0xed, 0xad, 0xe6, 0x12, 0x39, 0xd, + 0x83, 0xc9, 0xe8, 0x6b, 0x6c, 0x2d, 0xa5, 0xee, 0xc4, 0x5a, + 0x66, 0xae, 0x8c, 0x97, 0xd7, 0xd, 0x6c, 0x49, 0xc7, 0xf5, + 0xc4, 0x92, 0x31, 0x8b, 0x9, 0xee, 0x33, 0xda, 0xa9, 0x37, + 0xb6, 0x49, 0x18, 0xf8, 0xe, 0x60, 0x45, 0xc8, 0x33, 0x91, + 0xef, 0x20, 0x57, 0x10, 0xbe, 0x78, 0x2d, 0x83, 0x26, 0xd6, + 0xca, 0x61, 0xf9, 0x2f, 0xe0, 0xbf, 0x5, 0x30, 0x52, 0x5a, + 0x12, 0x1c, 0x0, 0xa7, 0x5d, 0xcc, 0x7c, 0x2e, 0xc5, 0x95, + 0x8b, 0xa3, 0x3b, 0xf0, 0x43, 0x2e, 0x5e, 0xdd, 0x0, 0xdb, + 0xd, 0xb3, 0x37, 0x99, 0xa9, 0xcd, 0x9c, 0xb7, 0x43, 0xf7, + 0x35, 0x44, 0x21, 0xc2, 0x82, 0x71, 0xab, 0x8d, 0xaa, 0xb4, + 0x41, 0x11, 0xec, 0x1e, 0x8d, 0xfc, 0x14, 0x82, 0x92, 0x4e, + 0x83, 0x6a, 0xa, 0x6b, 0x35, 0x5e, 0x5d, 0xe9, 0x5c, 0xcc, + 0x8c, 0xde, 0x39, 0xd1, 0x4a, 0x5b, 0x5f, 0x63, 0xa9, 0x64, + 0xe0, 0xa, 0xcb, 0xb, 0xb8, 0x5a, 0x7c, 0xc3, 0xb, 0xe6, + 0xbe, 0xfe, 0x8b, 0xf, 0x7d, 0x34, 0x8e, 0x2, 0x66, 0x74, + 0x1, 0x6c, 0xca, 0x76, 0xac, 0x7c, 0x67, 0x8, 0x2f, 0x3f, + 0x1a, 0xa6, 0x2c, 0x60, 0xb3, 0xff, 0xda, 0x8d, 0xb8, 0x12, + 0xc, 0x0, 0x7f, 0xcc, 0x50, 0xa1, 0x5c, 0x64, 0xa1, 0xe2, + 0x5f, 0x32, 0x65, 0xc9, 0x9c, 0xbe, 0xd6, 0xa, 0x13, 0x87, + 0x3c, 0x2a, 0x45, 0x47, 0xc, 0xca, 0x42, 0x82, 0xfa, 0x89, + 0x65, 0xe7, 0x89, 0xb4, 0x8f, 0xf7, 0x1e, 0xe6, 0x23, 0xa5, + 0xd0, 0x59, 0x37, 0x79, 0x92, 0xd7, 0xce, 0x3d, 0xfd, 0xe3, + 0xa1, 0xb, 0xcf, 0x6c, 0x85, 0xa0, 0x65, 0xf3, 0x5c, 0xc6, + 0x4a, 0x63, 0x5f, 0x6e, 0x3a, 0x3a, 0x2a, 0x8b, 0x6a, 0xb6, + 0x2f, 0xbb, 0xf8, 0xb2, 0x4b, 0x62, 0xbc, 0x1a, 0x91, 0x25, + 0x66, 0xe3, 0x69, 0xca, 0x60, 0x49, 0xb, 0xf6, 0x8a, 0xbe, + 0x3e, 0x76, 0x53, 0xc2, 0x7a, 0xa8, 0x4, 0x17, 0x75, 0xf1, + 0xf3, 0x3, 0x62, 0x1b, 0x85, 0xb2, 0xb0, 0xef, 0x80, 0x15, + 0xb6, 0xd4, 0x4e, 0xdf, 0x71, 0xac, 0xdb, 0x2a, 0x4, 0xd4, + 0xb4, 0x21, 0xba, 0x65, 0x56, 0x57, 0xe8, 0xfa, 0x84, 0xa2, + 0x7d, 0x13, 0xe, 0xaf, 0xd7, 0x9a, 0x58, 0x2a, 0xa3, 0x81, + 0x84, 0x8d, 0x9, 0xa0, 0x6a, 0xc1, 0xbb, 0xd9, 0xf5, 0x86, + 0xac, 0xbd, 0x75, 0x61, 0x9, 0xe6, 0x8c, 0x3d, 0x77, 0xb2, + 0xed, 0x30, 0x20, 0xe4, 0x0, 0x1d, 0x97, 0xe8, 0xbf, 0xc7, + 0x0, 0x1b, 0x21, 0xb1, 0x16, 0xe7, 0x41, 0x67, 0x2e, 0xec, + 0x38, 0xbc, 0xe5, 0x1b, 0xb4, 0x6, 0x23, 0x31, 0x71, 0x1c, + 0x49, 0xcd, 0x76, 0x4a, 0x76, 0x36, 0x8d, 0xa3, 0x89, 0x8b, + 0x4a, 0x7a, 0xf4, 0x87, 0xc8, 0x15, 0xf, 0x37, 0x39, 0xf6, + 0x6d, 0x80, 0x19, 0xef, 0x5c, 0xa8, 0x66, 0xce, 0x1b, 0x16, + 0x79, 0x21, 0xdf, 0xd7, 0x31, 0x30, 0xc4, 0x21, 0xdd, 0x34, + 0x5b, 0xd2, 0x1a, 0x2b, 0x3e, 0x5d, 0xf7, 0xea, 0xca, 0x5, + 0x8e, 0xb7, 0xcb, 0x49, 0x2e, 0xa0, 0xe3, 0xf4, 0xa7, 0x48, + 0x19, 0x10, 0x9c, 0x4, 0xa7, 0xf4, 0x28, 0x74, 0xc8, 0x6f, + 0x63, 0x20, 0x2b, 0x46, 0x24, 0x26, 0x19, 0x1d, 0xd1, 0x2c, + 0x31, 0x6d, 0x5a, 0x29, 0xa2, 0x6, 0xa6, 0xb2, 0x41, 0xcc, + 0xa, 0x27, 0x96, 0x9, 0x96, 0xac, 0x47, 0x65, 0x78, 0x68, + 0x51, 0x98, 0xd6, 0xd8, 0xa6, 0x2d, 0xa0, 0xcf, 0xec, 0xe2, + 0x74, 0xf2, 0x82, 0xe3, 0x97, 0xd9, 0x7e, 0xd4, 0xf8, 0xb, + 0x70, 0x43, 0x3d, 0xb1, 0x7b, 0x97, 0x80, 0xd6, 0xcb, 0xd7, + 0x19, 0xbc, 0x63, 0xb, 0xfd, 0x4d, 0x88, 0xfe, 0x67, 0xac, + 0xb8, 0xcc, 0x50, 0xb7, 0x68, 0xb3, 0x5b, 0xd6, 0x1e, 0x25, + 0xfc, 0x5f, 0x3c, 0x8d, 0xb1, 0x33, 0x7c, 0xb3, 0x49, 0x1, + 0x3f, 0x71, 0x55, 0xe, 0x51, 0xba, 0x61, 0x26, 0xfa, 0xea, + 0xe5, 0xb5, 0xe8, 0xaa, 0xcf, 0xcd, 0x96, 0x9f, 0xd6, 0xc1, + 0x5f, 0x53, 0x91, 0xad, 0x5, 0xde, 0x20, 0xe7, 0x51, 0xda, + 0x5b, 0x95, 0x67, 0xed, 0xf4, 0xee, 0x42, 0x65, 0x70, 0x13, + 0xb, 0x70, 0x14, 0x1c, 0xc9, 0xe0, 0x19, 0xca, 0x5f, 0xf5, + 0x1d, 0x70, 0x4b, 0x6c, 0x6, 0x74, 0xec, 0xb5, 0x2e, 0x77, + 0xe1, 0x74, 0xa1, 0xa3, 0x99, 0xa0, 0x85, 0x9e, 0xf1, 0xac, + 0xd8, 0x7e, +}; + +/** + * ============================================================================ + * Boot states support (GREEN, YELLOW, ORANGE, RED) and dm_verity + * ============================================================================ + */ +char *avb_set_state(AvbOps *ops, enum avb_boot_state boot_state) +{ + struct AvbOpsData *data; + char *cmdline = NULL; + + if (!ops) + return NULL; + + data = (struct AvbOpsData *)ops->user_data; + if (!data) + return NULL; + + data->boot_state = boot_state; + switch (boot_state) { + case AVB_GREEN: + cmdline = "androidboot.verifiedbootstate=green"; + break; + case AVB_YELLOW: + cmdline = "androidboot.verifiedbootstate=yellow"; + break; + case AVB_ORANGE: + cmdline = "androidboot.verifiedbootstate=orange"; + case AVB_RED: + break; + } + + return cmdline; +} + +char *append_cmd_line(char *cmdline_orig, char *cmdline_new) +{ + char *cmd_line; + + if (!cmdline_new) + return cmdline_orig; + + if (cmdline_orig) + cmd_line = cmdline_orig; + else + cmd_line = " "; + + cmd_line = avb_strdupv(cmd_line, " ", cmdline_new, NULL); + + return cmd_line; +} + +static int avb_find_dm_args(char **args, char *str) +{ + int i; + + if (!str) + return -1; + + for (i = 0; i < AVB_MAX_ARGS, args[i]; ++i) { + if (strstr(args[i], str)) + return i; + } + + return -1; +} + +static char *avb_set_enforce_option(const char *cmdline, const char *option) +{ + char *cmdarg[AVB_MAX_ARGS]; + char *newargs = NULL; + int i = 0; + int total_args; + + memset(cmdarg, 0, sizeof(cmdarg)); + cmdarg[i++] = strtok((char *)cmdline, " "); + + do { + cmdarg[i] = strtok(NULL, " "); + if (!cmdarg[i]) + break; + + if (++i >= AVB_MAX_ARGS) { + printf("%s: Can't handle more then %d args\n", + __func__, i); + return NULL; + } + } while (true); + + total_args = i; + i = avb_find_dm_args(&cmdarg[0], VERITY_TABLE_OPT_LOGGING); + if (i >= 0) { + cmdarg[i] = (char *)option; + } else { + i = avb_find_dm_args(&cmdarg[0], VERITY_TABLE_OPT_RESTART); + if (i < 0) { + printf("%s: No verity options found\n", __func__); + return NULL; + } + + cmdarg[i] = (char *)option; + } + + for (i = 0; i <= total_args; i++) + newargs = append_cmd_line(newargs, cmdarg[i]); + + return newargs; +} + +char *avb_set_ignore_corruption(const char *cmdline) +{ + char *newargs = NULL; + + newargs = avb_set_enforce_option(cmdline, VERITY_TABLE_OPT_LOGGING); + if (newargs) + newargs = append_cmd_line(newargs, + "androidboot.veritymode=eio"); + + return newargs; +} + +char *avb_set_enforce_verity(const char *cmdline) +{ + char *newargs; + + newargs = avb_set_enforce_option(cmdline, VERITY_TABLE_OPT_RESTART); + if (newargs) + newargs = append_cmd_line(newargs, + "androidboot.veritymode=enforcing"); + return newargs; +} + +/** + * ============================================================================ + * IO(mmc) auxiliary functions + * ============================================================================ + */ +static unsigned long mmc_read_and_flush(struct mmc_part *part, + lbaint_t start, + lbaint_t sectors, + void *buffer) +{ + unsigned long blks; + void *tmp_buf; + size_t buf_size; + bool unaligned = is_buf_unaligned(buffer); + + if (start < part->info.start) { + printf("%s: partition start out of bounds\n", __func__); + return 0; + } + if ((start + sectors) > (part->info.start + part->info.size)) { + sectors = part->info.start + part->info.size - start; + printf("%s: read sector aligned to partition bounds (%ld)\n", + __func__, sectors); + } + + /* + * Reading fails on unaligned buffers, so we have to + * use aligned temporary buffer and then copy to destination + */ + + if (unaligned) { + printf("Handling unaligned read buffer..\n"); + tmp_buf = get_sector_buf(); + buf_size = get_sector_buf_size(); + if (sectors > buf_size / part->info.blksz) + sectors = buf_size / part->info.blksz; + } else { + tmp_buf = buffer; + } + + blks = part->mmc->block_dev.block_read(part->mmc_blk, + start, sectors, tmp_buf); + /* flush cache after read */ + flush_cache((ulong)tmp_buf, sectors * part->info.blksz); + + if (unaligned) + memcpy(buffer, tmp_buf, sectors * part->info.blksz); + + return blks; +} + +static unsigned long mmc_write(struct mmc_part *part, lbaint_t start, + lbaint_t sectors, void *buffer) +{ + void *tmp_buf; + size_t buf_size; + bool unaligned = is_buf_unaligned(buffer); + + if (start < part->info.start) { + printf("%s: partition start out of bounds\n", __func__); + return 0; + } + if ((start + sectors) > (part->info.start + part->info.size)) { + sectors = part->info.start + part->info.size - start; + printf("%s: sector aligned to partition bounds (%ld)\n", + __func__, sectors); + } + if (unaligned) { + tmp_buf = get_sector_buf(); + buf_size = get_sector_buf_size(); + printf("Handling unaligned wrire buffer..\n"); + if (sectors > buf_size / part->info.blksz) + sectors = buf_size / part->info.blksz; + + memcpy(tmp_buf, buffer, sectors * part->info.blksz); + } else { + tmp_buf = buffer; + } + + return part->mmc->block_dev.block_write(part->mmc_blk, + start, sectors, tmp_buf); +} + +static struct mmc_part *get_partition(AvbOps *ops, const char *partition) +{ + int ret; + u8 dev_num; + int part_num = 0; + struct mmc_part *part; + struct blk_desc *mmc_blk; + + part = malloc(sizeof(struct mmc_part)); + if (!part) + return NULL; + + dev_num = get_boot_device(ops); + part->mmc = find_mmc_device(dev_num); + if (!part->mmc) { + printf("No MMC device at slot %x\n", dev_num); + return NULL; + } + + if (mmc_init(part->mmc)) { + printf("MMC initialization failed\n"); + return NULL; + } + + ret = mmc_switch_part(part->mmc, part_num); + if (ret) + return NULL; + + mmc_blk = mmc_get_blk_desc(part->mmc); + if (!mmc_blk) { + printf("Error - failed to obtain block descriptor\n"); + return NULL; + } + + ret = part_get_info_by_name(mmc_blk, partition, &part->info); + if (!ret) { + printf("Can't find partition '%s'\n", partition); + return NULL; + } + + part->dev_num = dev_num; + part->mmc_blk = mmc_blk; + + return part; +} + +static AvbIOResult mmc_byte_io(AvbOps *ops, + const char *partition, + s64 offset, + size_t num_bytes, + void *buffer, + size_t *out_num_read, + enum mmc_io_type io_type) +{ + ulong ret; + struct mmc_part *part; + u64 start_offset, start_sector, sectors, residue; + u8 *tmp_buf; + size_t io_cnt = 0; + + if (!partition || !buffer || io_type > IO_WRITE) + return AVB_IO_RESULT_ERROR_IO; + + part = get_partition(ops, partition); + if (!part) + return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION; + + start_offset = calc_offset(part, offset); + while (num_bytes) { + start_sector = start_offset / part->info.blksz; + sectors = num_bytes / part->info.blksz; + /* handle non block-aligned reads */ + if (start_offset % part->info.blksz || + num_bytes < part->info.blksz) { + tmp_buf = get_sector_buf(); + if (start_offset % part->info.blksz) { + residue = part->info.blksz - + (start_offset % part->info.blksz); + if (residue > num_bytes) + residue = num_bytes; + } else { + residue = num_bytes; + } + + if (io_type == IO_READ) { + ret = mmc_read_and_flush(part, + part->info.start + + start_sector, + 1, tmp_buf); + + if (ret != 1) { + printf("%s: read error (%ld, %lld)\n", + __func__, ret, start_sector); + return AVB_IO_RESULT_ERROR_IO; + } + /* + * if this is not aligned at sector start, + * we have to adjust the tmp buffer + */ + tmp_buf += (start_offset % part->info.blksz); + memcpy(buffer, (void *)tmp_buf, residue); + } else { + ret = mmc_read_and_flush(part, + part->info.start + + start_sector, + 1, tmp_buf); + + if (ret != 1) { + printf("%s: read error (%ld, %lld)\n", + __func__, ret, start_sector); + return AVB_IO_RESULT_ERROR_IO; + } + memcpy((void *)tmp_buf + + start_offset % part->info.blksz, + buffer, residue); + + ret = mmc_write(part, part->info.start + + start_sector, 1, tmp_buf); + if (ret != 1) { + printf("%s: write error (%ld, %lld)\n", + __func__, ret, start_sector); + return AVB_IO_RESULT_ERROR_IO; + } + } + + io_cnt += residue; + buffer += residue; + start_offset += residue; + num_bytes -= residue; + continue; + } + + if (sectors) { + if (io_type == IO_READ) { + ret = mmc_read_and_flush(part, + part->info.start + + start_sector, + sectors, buffer); + } else { + ret = mmc_write(part, + part->info.start + + start_sector, + sectors, buffer); + } + + if (!ret) { + printf("%s: sector read error\n", __func__); + return AVB_IO_RESULT_ERROR_IO; + } + + io_cnt += ret * part->info.blksz; + buffer += ret * part->info.blksz; + start_offset += ret * part->info.blksz; + num_bytes -= ret * part->info.blksz; + } + } + + /* Set counter for read operation */ + if (io_type == IO_READ && out_num_read) + *out_num_read = io_cnt; + + return AVB_IO_RESULT_OK; +} + +/** + * ============================================================================ + * AVB 2.0 operations + * ============================================================================ + */ + +/** + * read_from_partition() - reads @num_bytes from @offset from partition + * identified by a string name + * + * @ops: contains AVB ops handlers + * @partition_name: partition name, NUL-terminated UTF-8 string + * @offset: offset from the beginning of partition + * @num_bytes: amount of bytes to read + * @buffer: destination buffer to store data + * @out_num_read: + * + * @return: + * AVB_IO_RESULT_OK, if partition was found and read operation succeed + * AVB_IO_RESULT_ERROR_IO, if i/o error occurred from the underlying i/o + * subsystem + * AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION, if there is no partition with + * the given name + */ +static AvbIOResult read_from_partition(AvbOps *ops, + const char *partition_name, + s64 offset_from_partition, + size_t num_bytes, + void *buffer, + size_t *out_num_read) +{ + return mmc_byte_io(ops, partition_name, offset_from_partition, + num_bytes, buffer, out_num_read, IO_READ); +} + +/** + * write_to_partition() - writes N bytes to a partition identified by a string + * name + * + * @ops: AvbOps, contains AVB ops handlers + * @partition_name: partition name + * @offset_from_partition: offset from the beginning of partition + * @num_bytes: amount of bytes to write + * @buf: data to write + * @out_num_read: + * + * @return: + * AVB_IO_RESULT_OK, if partition was found and read operation succeed + * AVB_IO_RESULT_ERROR_IO, if input/output error occurred + * AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION, if partition, specified in + * @partition_name was not found + */ +static AvbIOResult write_to_partition(AvbOps *ops, + const char *partition_name, + s64 offset_from_partition, + size_t num_bytes, + const void *buffer) +{ + return mmc_byte_io(ops, partition_name, offset_from_partition, + num_bytes, (void *)buffer, NULL, IO_WRITE); +} + +/** + * validate_vmbeta_public_key() - checks if the given public key used to sign + * the vbmeta partition is trusted + * + * @ops: AvbOps, contains AVB ops handlers + * @public_key_data: public key for verifying vbmeta partition signature + * @public_key_length: length of public key + * @public_key_metadata: + * @public_key_metadata_length: + * @out_key_is_trusted: + * + * @return: + * AVB_IO_RESULT_OK, if partition was found and read operation succeed + */ +static AvbIOResult validate_vbmeta_public_key(AvbOps *ops, + const u8 *public_key_data, + size_t public_key_length, + const u8 + *public_key_metadata, + size_t + public_key_metadata_length, + bool *out_key_is_trusted) +{ + if (!public_key_length || !public_key_data || !out_key_is_trusted) + return AVB_IO_RESULT_ERROR_IO; + + *out_key_is_trusted = false; + if (public_key_length != sizeof(avb_root_pub)) + return AVB_IO_RESULT_ERROR_IO; + + if (memcmp(avb_root_pub, public_key_data, public_key_length) == 0) + *out_key_is_trusted = true; + + return AVB_IO_RESULT_OK; +} + +/** + * read_rollback_index() - gets the rollback index corresponding to the + * location of given by @out_rollback_index. + * + * @ops: contains AvbOps handlers + * @rollback_index_slot: + * @out_rollback_index: used to write a retrieved rollback index. + * + * @return + * AVB_IO_RESULT_OK, if the roolback index was retrieved + */ +static AvbIOResult read_rollback_index(AvbOps *ops, + size_t rollback_index_slot, + u64 *out_rollback_index) +{ + /* For now we always return 0 as the stored rollback index. */ + printf("%s not supported yet\n", __func__); + + if (out_rollback_index) + *out_rollback_index = 0; + + return AVB_IO_RESULT_OK; +} + +/** + * write_rollback_index() - sets the rollback index corresponding to the + * location of given by @out_rollback_index. + * + * @ops: contains AvbOps handlers + * @rollback_index_slot: + * @rollback_index: rollback index to write. + * + * @return + * AVB_IO_RESULT_OK, if the roolback index was retrieved + */ +static AvbIOResult write_rollback_index(AvbOps *ops, + size_t rollback_index_slot, + u64 rollback_index) +{ + /* For now this is a no-op. */ + printf("%s not supported yet\n", __func__); + + return AVB_IO_RESULT_OK; +} + +/** + * read_is_device_unlocked() - gets whether the device is unlocked + * + * @ops: contains AVB ops handlers + * @out_is_unlocked: device unlock state is stored here, true if unlocked, + * false otherwise + * + * @return: + * AVB_IO_RESULT_OK: state is retrieved successfully + * AVB_IO_RESULT_ERROR_IO: an error occurred + */ +static AvbIOResult read_is_device_unlocked(AvbOps *ops, bool *out_is_unlocked) +{ + /* For now we always return that the device is unlocked. */ + + printf("%s not supported yet\n", __func__); + + *out_is_unlocked = true; + + return AVB_IO_RESULT_OK; +} + +/** + * get_unique_guid_for_partition() - gets the GUID for a partition identified + * by a string name + * + * @ops: contains AVB ops handlers + * @partition: partition name (NUL-terminated UTF-8 string) + * @guid_buf: buf, used to copy in GUID string. Example of value: + * 527c1c6d-6361-4593-8842-3c78fcd39219 + * @guid_buf_size: @guid_buf buffer size + * + * @return: + * AVB_IO_RESULT_OK, on success (GUID found) + * AVB_IO_RESULT_ERROR_IO, if incorrect buffer size (@guid_buf_size) was + * provided + * AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION, if partition was not found + */ +static AvbIOResult get_unique_guid_for_partition(AvbOps *ops, + const char *partition, + char *guid_buf, + size_t guid_buf_size) +{ + struct mmc_part *part; + size_t uuid_size; + + part = get_partition(ops, partition); + if (!part) + return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION; + + uuid_size = sizeof(part->info.uuid); + if (uuid_size > guid_buf_size) + return AVB_IO_RESULT_ERROR_IO; + + memcpy(guid_buf, part->info.uuid, uuid_size); + guid_buf[uuid_size - 1] = 0; + + return AVB_IO_RESULT_OK; +} + +/** + * ============================================================================ + * AVB2.0 AvbOps alloc/initialisation/free + * ============================================================================ + */ +AvbOps *avb_ops_alloc(int boot_device) +{ + struct AvbOpsData *ops_data; + + ops_data = avb_calloc(sizeof(struct AvbOpsData)); + if (!ops_data) + return NULL; + + ops_data->ops.user_data = ops_data; + + ops_data->ops.read_from_partition = read_from_partition; + ops_data->ops.write_to_partition = write_to_partition; + ops_data->ops.validate_vbmeta_public_key = validate_vbmeta_public_key; + ops_data->ops.read_rollback_index = read_rollback_index; + ops_data->ops.write_rollback_index = write_rollback_index; + ops_data->ops.read_is_device_unlocked = read_is_device_unlocked; + ops_data->ops.get_unique_guid_for_partition = + get_unique_guid_for_partition; + + ops_data->mmc_dev = boot_device; + + return &ops_data->ops; +} + +void avb_ops_free(AvbOps *ops) +{ + struct AvbOpsData *ops_data; + + if (ops) + return; + + ops_data = ops->user_data; + + if (ops_data) + avb_free(ops_data); +} diff --git a/common/bootm.c b/common/bootm.c index e789f6818a..e517d9f118 100644 --- a/common/bootm.c +++ b/common/bootm.c @@ -202,8 +202,23 @@ static int bootm_find_os(cmd_tbl_t *cmdtp, int flag, int argc, } if (images.os.type == IH_TYPE_KERNEL_NOLOAD) { - images.os.load = images.os.image_start; - images.ep += images.os.load; + if (CONFIG_IS_ENABLED(CMD_BOOTI) && + images.os.arch == IH_ARCH_ARM64) { + ulong image_addr; + ulong image_size; + + ret = booti_setup(images.os.image_start, &image_addr, + &image_size, true); + if (ret != 0) + return 1; + + images.os.type = IH_TYPE_KERNEL; + images.os.load = image_addr; + images.ep = image_addr; + } else { + images.os.load = images.os.image_start; + images.ep += images.os.image_start; + } } images.os.start = map_to_sysmem(os_hdr); diff --git a/common/console.c b/common/console.c index 2688af56e1..2ba33dc574 100644 --- a/common/console.c +++ b/common/console.c @@ -502,8 +502,10 @@ void putc(const char c) return; } #endif + if (!gd) + return; #ifdef CONFIG_CONSOLE_RECORD - if (gd && (gd->flags & GD_FLG_RECORD) && gd->console_out.start) + if ((gd->flags & GD_FLG_RECORD) && gd->console_out.start) membuff_putbyte(&gd->console_out, c); #endif #ifdef CONFIG_SILENT_CONSOLE @@ -541,8 +543,10 @@ void puts(const char *s) return; } #endif + if (!gd) + return; #ifdef CONFIG_CONSOLE_RECORD - if (gd && (gd->flags & GD_FLG_RECORD) && gd->console_out.start) + if ((gd->flags & GD_FLG_RECORD) && gd->console_out.start) membuff_put(&gd->console_out, s, strlen(s)); #endif #ifdef CONFIG_SILENT_CONSOLE diff --git a/common/iotrace.c b/common/iotrace.c index 2f03a6082e..49bee3c92a 100644 --- a/common/iotrace.c +++ b/common/iotrace.c @@ -11,38 +11,12 @@ DECLARE_GLOBAL_DATA_PTR; -/* Support up to the machine word length for now */ -typedef ulong iovalue_t; - -enum iotrace_flags { - IOT_8 = 0, - IOT_16, - IOT_32, - - IOT_READ = 0 << 3, - IOT_WRITE = 1 << 3, -}; - -/** - * struct iotrace_record - Holds a single I/O trace record - * - * @flags: I/O access type - * @timestamp: Timestamp of access - * @addr: Address of access - * @value: Value written or read - */ -struct iotrace_record { - enum iotrace_flags flags; - u64 timestamp; - phys_addr_t addr; - iovalue_t value; -}; - /** * struct iotrace - current trace status and checksum * * @start: Start address of iotrace buffer - * @size: Size of iotrace buffer in bytes + * @size: Actual size of iotrace buffer in bytes + * @needed_size: Needed of iotrace buffer in bytes * @offset: Current write offset into iotrace buffer * @region_start: Address of IO region to trace * @region_size: Size of region to trace. if 0 will trace all address space @@ -52,6 +26,7 @@ struct iotrace_record { static struct iotrace { ulong start; ulong size; + ulong needed_size; ulong offset; ulong region_start; ulong region_size; @@ -82,7 +57,12 @@ static void add_record(int flags, const void *ptr, ulong value) rec = (struct iotrace_record *)map_sysmem( iotrace.start + iotrace.offset, sizeof(value)); + } else { + WARN_ONCE(1, "WARNING: iotrace buffer exhausted, please check needed length using \"iotrace stats\"\n"); + iotrace.needed_size += sizeof(struct iotrace_record); + return; } + rec->timestamp = timer_get_us(); rec->flags = flags; rec->addr = map_to_sysmem(ptr); @@ -92,6 +72,7 @@ static void add_record(int flags, const void *ptr, ulong value) iotrace.crc32 = crc32(iotrace.crc32, (unsigned char *)rec, sizeof(*rec)); + iotrace.needed_size += sizeof(struct iotrace_record); iotrace.offset += sizeof(struct iotrace_record); } @@ -189,10 +170,11 @@ void iotrace_set_buffer(ulong start, ulong size) iotrace.crc32 = 0; } -void iotrace_get_buffer(ulong *start, ulong *size, ulong *offset, ulong *count) +void iotrace_get_buffer(ulong *start, ulong *size, ulong *needed_size, ulong *offset, ulong *count) { *start = iotrace.start; *size = iotrace.size; + *needed_size = iotrace.needed_size; *offset = iotrace.offset; *count = iotrace.offset / sizeof(struct iotrace_record); } diff --git a/common/log.c b/common/log.c index 3b5588ebe7..59869cd29d 100644 --- a/common/log.c +++ b/common/log.c @@ -38,12 +38,16 @@ static const char *log_level_name[LOGL_COUNT] = { const char *log_get_cat_name(enum log_category_t cat) { - if (cat > LOGC_COUNT) - return "invalid"; + const char *name; + + if (cat < 0 || cat >= LOGC_COUNT) + return "<invalid>"; if (cat >= LOGC_NONE) return log_cat_name[cat - LOGC_NONE]; - return uclass_get_name((enum uclass_id)cat); + name = uclass_get_name((enum uclass_id)cat); + + return name ? name : "<missing>"; } enum log_category_t log_get_cat_by_name(const char *name) diff --git a/configs/da850evm_defconfig b/configs/da850evm_defconfig index bb1368b9ad..6a2b7ae670 100644 --- a/configs/da850evm_defconfig +++ b/configs/da850evm_defconfig @@ -23,7 +23,6 @@ CONFIG_SYS_PROMPT="U-Boot > " CONFIG_CRC32_VERIFY=y # CONFIG_CMD_EEPROM is not set # CONFIG_CMD_FLASH is not set -# CONFIG_CMD_GPIO is not set # CONFIG_CMD_GPT is not set # CONFIG_CMD_PART is not set # CONFIG_CMD_SETEXPR is not set @@ -37,6 +36,7 @@ CONFIG_CMD_DIAG=y CONFIG_OF_CONTROL=y CONFIG_ENV_IS_IN_SPI_FLASH=y CONFIG_DM=y +CONFIG_DM_GPIO=y CONFIG_DM_I2C=y CONFIG_DM_I2C_COMPAT=y CONFIG_DM_SPI_FLASH=y diff --git a/configs/khadas-vim_defconfig b/configs/khadas-vim_defconfig index 49a653f042..1eb13df4b4 100644 --- a/configs/khadas-vim_defconfig +++ b/configs/khadas-vim_defconfig @@ -16,10 +16,15 @@ CONFIG_OF_BOARD_SETUP=y CONFIG_CMD_GPIO=y # CONFIG_CMD_LOADS is not set CONFIG_CMD_MMC=y +CONFIG_CMD_USB=y # CONFIG_CMD_SETEXPR is not set +CONFIG_CMD_REGULATOR=y CONFIG_OF_CONTROL=y CONFIG_NET_RANDOM_ETHADDR=y CONFIG_DM_GPIO=y +CONFIG_DM_REGULATOR=y +CONFIG_DM_REGULATOR_FIXED=y +CONFIG_DM_RESET=y CONFIG_DM_MMC=y CONFIG_MMC_MESON_GX=y CONFIG_PHY_ADDR_ENABLE=y @@ -34,3 +39,12 @@ CONFIG_DEBUG_UART_ANNOUNCE=y CONFIG_DEBUG_UART_SKIP_INIT=y CONFIG_MESON_SERIAL=y CONFIG_OF_LIBFDT_OVERLAY=y +CONFIG_USB=y +CONFIG_DM_USB=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_XHCI_DWC3=y +CONFIG_USB_XHCI_DWC3_OF_SIMPLE=y +CONFIG_USB_DWC3=y +CONFIG_USB_STORAGE=y +CONFIG_PHY=y +CONFIG_MESON_GXL_USB_PHY=y diff --git a/configs/libretech-cc_defconfig b/configs/libretech-cc_defconfig index 7ba2fa1fe2..d4f2f58c8a 100644 --- a/configs/libretech-cc_defconfig +++ b/configs/libretech-cc_defconfig @@ -13,13 +13,21 @@ CONFIG_OF_BOARD_SETUP=y # CONFIG_DISPLAY_BOARDINFO is not set # CONFIG_CMD_BDI is not set # CONFIG_CMD_IMI is not set +CONFIG_CMD_ADC=y CONFIG_CMD_GPIO=y # CONFIG_CMD_LOADS is not set CONFIG_CMD_MMC=y +CONFIG_CMD_USB=y # CONFIG_CMD_SETEXPR is not set +CONFIG_CMD_REGULATOR=y +CONFIG_ADC=y +CONFIG_SARADC_MESON=y CONFIG_OF_CONTROL=y CONFIG_NET_RANDOM_ETHADDR=y CONFIG_DM_GPIO=y +CONFIG_DM_REGULATOR=y +CONFIG_DM_REGULATOR_FIXED=y +CONFIG_DM_RESET=y CONFIG_DM_MMC=y CONFIG_MMC_MESON_GX=y CONFIG_PHY_ADDR_ENABLE=y @@ -34,3 +42,12 @@ CONFIG_DEBUG_UART_ANNOUNCE=y CONFIG_DEBUG_UART_SKIP_INIT=y CONFIG_MESON_SERIAL=y CONFIG_OF_LIBFDT_OVERLAY=y +CONFIG_USB=y +CONFIG_DM_USB=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_XHCI_DWC3=y +CONFIG_USB_XHCI_DWC3_OF_SIMPLE=y +CONFIG_USB_DWC3=y +CONFIG_USB_STORAGE=y +CONFIG_PHY=y +CONFIG_MESON_GXL_USB_PHY=y diff --git a/configs/odroid-c2_defconfig b/configs/odroid-c2_defconfig index ecc8d03e31..9be69adcac 100644 --- a/configs/odroid-c2_defconfig +++ b/configs/odroid-c2_defconfig @@ -18,11 +18,15 @@ CONFIG_CMD_I2C=y # CONFIG_CMD_LOADS is not set CONFIG_CMD_MMC=y # CONFIG_CMD_SETEXPR is not set +CONFIG_CMD_REGULATOR=y CONFIG_OF_CONTROL=y CONFIG_NET_RANDOM_ETHADDR=y CONFIG_DM_GPIO=y CONFIG_DM_I2C=y CONFIG_SYS_I2C_MESON=y +CONFIG_DM_REGULATOR=y +CONFIG_DM_REGULATOR_FIXED=y +CONFIG_DM_RESET=y CONFIG_DM_MMC=y CONFIG_MMC_MESON_GX=y CONFIG_DM_ETH=y diff --git a/configs/p212_defconfig b/configs/p212_defconfig index 344c04aa8d..f9b282e2da 100644 --- a/configs/p212_defconfig +++ b/configs/p212_defconfig @@ -16,10 +16,15 @@ CONFIG_OF_BOARD_SETUP=y CONFIG_CMD_GPIO=y # CONFIG_CMD_LOADS is not set CONFIG_CMD_MMC=y +CONFIG_CMD_USB=y # CONFIG_CMD_SETEXPR is not set +CONFIG_CMD_REGULATOR=y CONFIG_OF_CONTROL=y CONFIG_NET_RANDOM_ETHADDR=y CONFIG_DM_GPIO=y +CONFIG_DM_REGULATOR=y +CONFIG_DM_REGULATOR_FIXED=y +CONFIG_DM_RESET=y CONFIG_DM_MMC=y CONFIG_MMC_MESON_GX=y CONFIG_PHY_ADDR_ENABLE=y @@ -34,3 +39,12 @@ CONFIG_DEBUG_UART_ANNOUNCE=y CONFIG_DEBUG_UART_SKIP_INIT=y CONFIG_MESON_SERIAL=y CONFIG_OF_LIBFDT_OVERLAY=y +CONFIG_USB=y +CONFIG_DM_USB=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_XHCI_DWC3=y +CONFIG_USB_XHCI_DWC3_OF_SIMPLE=y +CONFIG_USB_DWC3=y +CONFIG_USB_STORAGE=y +CONFIG_PHY=y +CONFIG_MESON_GXL_USB_PHY=y diff --git a/doc/README.avb2 b/doc/README.avb2 new file mode 100644 index 0000000000..67784b529e --- /dev/null +++ b/doc/README.avb2 @@ -0,0 +1,97 @@ +Android Verified Boot 2.0 + +This file contains information about the current support of Android Verified +Boot 2.0 in U-boot + +1. OVERVIEW +--------------------------------- +Verified Boot establishes a chain of trust from the bootloader to system images +* Provides integrity checking for: + - Android Boot image: Linux kernel + ramdisk. RAW hashing of the whole + partition is done and the hash is compared with the one stored in + the VBMeta image + - system/vendor partitions: verifying root hash of dm-verity hashtrees. +* Provides capabilities for rollback protection. + +Integrity of the bootloader (U-boot BLOB and environment) is out of scope. + +For additional details check: +https://android.googlesource.com/platform/external/avb/+/master/README.md + + +2. AVB 2.0 U-BOOT SHELL COMMANDS +----------------------------------- +Provides CLI interface to invoke AVB 2.0 verification + misc. commands for +different testing purposes: + +avb init <dev> - initialize avb 2.0 for <dev> +avb verify - run verification process using hash data from vbmeta structure +avb read_rb <num> - read rollback index at location <num> +avb write_rb <num> <rb> - write rollback index <rb> to <num> +avb is_unlocked - returns unlock status of the device +avb get_uuid <partname> - read and print uuid of partition <partname> +avb read_part <partname> <offset> <num> <addr> - read <num> bytes from +partition <partname> to buffer <addr> +avb write_part <partname> <offset> <num> <addr> - write <num> bytes to +<partname> by <offset> using data from <addr> + + +3. PARTITIONS TAMPERING (EXAMPLE) +----------------------------------- +Boot or system/vendor (dm-verity metadata section) is tampered: +=> avb init 1 +=> avb verify +avb_slot_verify.c:175: ERROR: boot: Hash of data does not match digest in +descriptor. +Slot verification result: ERROR_IO + +Vbmeta partition is tampered: +=> avb init 1 +=> avb verify +avb_vbmeta_image.c:206: ERROR: Hash does not match! +avb_slot_verify.c:388: ERROR: vbmeta: Error verifying vbmeta image: +HASH_MISMATCH +Slot verification result: ERROR_IO + + +4. ENABLE ON YOUR BOARD +----------------------------------- +The following options must be enabled: +CONFIG_LIBAVB=y +CONFIG_CMD_AVB=y + + +Then add `avb verify` invocation to your android boot sequence of commands, +e.g.: + +=> avb_verify=avb init $mmcdev; avb verify; +=> if run avb_verify; then \ + echo AVB verification OK. Continue boot; \ + set bootargs $bootargs $avb_bootargs; \ + else \ + echo AVB verification failed; \ + exit; \ + fi; \ + +=> emmc_android_boot= \ + echo Trying to boot Android from eMMC ...; \ + ... \ + run avb_verify; \ + mmc read ${fdtaddr} ${fdt_start} ${fdt_size}; \ + mmc read ${loadaddr} ${boot_start} ${boot_size}; \ + bootm $loadaddr $loadaddr $fdtaddr; \ + + +To switch on automatic generation of vbmeta partition in AOSP build, add these +lines to device configuration mk file: + +BOARD_AVB_ENABLE := true +BOARD_AVB_ALGORITHM := SHA512_RSA4096 +BOARD_BOOTIMAGE_PARTITION_SIZE := <boot partition size> + +After flashing U-boot don't forget to update environment and write new +partition table: +=> env default -f -a +=> setenv partitions $partitions_android +=> env save +=> gpt write mmc 1 $partitions_android diff --git a/drivers/adc/meson-saradc.c b/drivers/adc/meson-saradc.c index bcab76d050..f7c919d3b0 100644 --- a/drivers/adc/meson-saradc.c +++ b/drivers/adc/meson-saradc.c @@ -654,7 +654,7 @@ static int meson_saradc_probe(struct udevice *dev) struct meson_saradc_priv *priv = dev_get_priv(dev); int ret; - ret = regmap_init_mem(dev, &priv->regmap); + ret = regmap_init_mem(dev_ofnode(dev), &priv->regmap); if (ret) return ret; diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index 0792373cfc..f9502b36ba 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -37,6 +37,13 @@ config BLOCK_CACHE it will prevent repeated reads from directory structures and other filesystem data structures. +config SPL_BLOCK_CACHE + bool "Use block device cache in SPL" + depends on SPL_BLK + default n + help + This option enables the disk-block cache in SPL + config IDE bool "Support IDE controllers" select HAVE_BLOCK_DEVICE diff --git a/drivers/block/Makefile b/drivers/block/Makefile index 5fcafb193e..0e80ce9405 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -11,4 +11,4 @@ endif obj-$(CONFIG_IDE) += ide.o obj-$(CONFIG_SANDBOX) += sandbox.o -obj-$(CONFIG_BLOCK_CACHE) += blkcache.o +obj-$(CONFIG_$(SPL_)BLOCK_CACHE) += blkcache.o diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 58139b13a8..426c67db9b 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_$(SPL_TPL_)CLK) += clk-uclass.o clk_fixed_rate.o obj-y += tegra/ obj-$(CONFIG_ARCH_ASPEED) += aspeed/ +obj-$(CONFIG_ARCH_MESON) += clk_meson.o obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ obj-$(CONFIG_CLK_AT91) += at91/ obj-$(CONFIG_CLK_MVEBU) += mvebu/ diff --git a/drivers/clk/clk_meson.c b/drivers/clk/clk_meson.c new file mode 100644 index 0000000000..3850128e5c --- /dev/null +++ b/drivers/clk/clk_meson.c @@ -0,0 +1,393 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2018 - Beniamino Galvani <b.galvani@gmail.com> + * (C) Copyright 2018 - BayLibre, SAS + * Author: Neil Armstrong <narmstrong@baylibre.com> + */ + +#include <common.h> +#include <asm/arch/clock.h> +#include <asm/io.h> +#include <clk-uclass.h> +#include <div64.h> +#include <dm.h> +#include <dt-bindings/clock/gxbb-clkc.h> +#include "clk_meson.h" + +#define XTAL_RATE 24000000 + +struct meson_clk { + void __iomem *addr; +}; + +static ulong meson_clk_get_rate_by_id(struct clk *clk, unsigned long id); + +struct meson_gate gates[] = { + /* Everything Else (EE) domain gates */ + MESON_GATE(CLKID_DDR, HHI_GCLK_MPEG0, 0), + MESON_GATE(CLKID_DOS, HHI_GCLK_MPEG0, 1), + MESON_GATE(CLKID_ISA, HHI_GCLK_MPEG0, 5), + MESON_GATE(CLKID_PL301, HHI_GCLK_MPEG0, 6), + MESON_GATE(CLKID_PERIPHS, HHI_GCLK_MPEG0, 7), + MESON_GATE(CLKID_SPICC, HHI_GCLK_MPEG0, 8), + MESON_GATE(CLKID_I2C, HHI_GCLK_MPEG0, 9), + MESON_GATE(CLKID_SAR_ADC, HHI_GCLK_MPEG0, 10), + MESON_GATE(CLKID_SMART_CARD, HHI_GCLK_MPEG0, 11), + MESON_GATE(CLKID_RNG0, HHI_GCLK_MPEG0, 12), + MESON_GATE(CLKID_UART0, HHI_GCLK_MPEG0, 13), + MESON_GATE(CLKID_SDHC, HHI_GCLK_MPEG0, 14), + MESON_GATE(CLKID_STREAM, HHI_GCLK_MPEG0, 15), + MESON_GATE(CLKID_ASYNC_FIFO, HHI_GCLK_MPEG0, 16), + MESON_GATE(CLKID_SDIO, HHI_GCLK_MPEG0, 17), + MESON_GATE(CLKID_ABUF, HHI_GCLK_MPEG0, 18), + MESON_GATE(CLKID_HIU_IFACE, HHI_GCLK_MPEG0, 19), + MESON_GATE(CLKID_ASSIST_MISC, HHI_GCLK_MPEG0, 23), + MESON_GATE(CLKID_SD_EMMC_A, HHI_GCLK_MPEG0, 24), + MESON_GATE(CLKID_SD_EMMC_B, HHI_GCLK_MPEG0, 25), + MESON_GATE(CLKID_SD_EMMC_C, HHI_GCLK_MPEG0, 26), + MESON_GATE(CLKID_SPI, HHI_GCLK_MPEG0, 30), + + MESON_GATE(CLKID_I2S_SPDIF, HHI_GCLK_MPEG1, 2), + MESON_GATE(CLKID_ETH, HHI_GCLK_MPEG1, 3), + MESON_GATE(CLKID_DEMUX, HHI_GCLK_MPEG1, 4), + MESON_GATE(CLKID_AIU_GLUE, HHI_GCLK_MPEG1, 6), + MESON_GATE(CLKID_IEC958, HHI_GCLK_MPEG1, 7), + MESON_GATE(CLKID_I2S_OUT, HHI_GCLK_MPEG1, 8), + MESON_GATE(CLKID_AMCLK, HHI_GCLK_MPEG1, 9), + MESON_GATE(CLKID_AIFIFO2, HHI_GCLK_MPEG1, 10), + MESON_GATE(CLKID_MIXER, HHI_GCLK_MPEG1, 11), + MESON_GATE(CLKID_MIXER_IFACE, HHI_GCLK_MPEG1, 12), + MESON_GATE(CLKID_ADC, HHI_GCLK_MPEG1, 13), + MESON_GATE(CLKID_BLKMV, HHI_GCLK_MPEG1, 14), + MESON_GATE(CLKID_AIU, HHI_GCLK_MPEG1, 15), + MESON_GATE(CLKID_UART1, HHI_GCLK_MPEG1, 16), + MESON_GATE(CLKID_G2D, HHI_GCLK_MPEG1, 20), + MESON_GATE(CLKID_USB0, HHI_GCLK_MPEG1, 21), + MESON_GATE(CLKID_USB1, HHI_GCLK_MPEG1, 22), + MESON_GATE(CLKID_RESET, HHI_GCLK_MPEG1, 23), + MESON_GATE(CLKID_NAND, HHI_GCLK_MPEG1, 24), + MESON_GATE(CLKID_DOS_PARSER, HHI_GCLK_MPEG1, 25), + MESON_GATE(CLKID_USB, HHI_GCLK_MPEG1, 26), + MESON_GATE(CLKID_VDIN1, HHI_GCLK_MPEG1, 28), + MESON_GATE(CLKID_AHB_ARB0, HHI_GCLK_MPEG1, 29), + MESON_GATE(CLKID_EFUSE, HHI_GCLK_MPEG1, 30), + MESON_GATE(CLKID_BOOT_ROM, HHI_GCLK_MPEG1, 31), + + MESON_GATE(CLKID_AHB_DATA_BUS, HHI_GCLK_MPEG2, 1), + MESON_GATE(CLKID_AHB_CTRL_BUS, HHI_GCLK_MPEG2, 2), + MESON_GATE(CLKID_HDMI_INTR_SYNC, HHI_GCLK_MPEG2, 3), + MESON_GATE(CLKID_HDMI_PCLK, HHI_GCLK_MPEG2, 4), + MESON_GATE(CLKID_USB1_DDR_BRIDGE, HHI_GCLK_MPEG2, 8), + MESON_GATE(CLKID_USB0_DDR_BRIDGE, HHI_GCLK_MPEG2, 9), + MESON_GATE(CLKID_MMC_PCLK, HHI_GCLK_MPEG2, 11), + MESON_GATE(CLKID_DVIN, HHI_GCLK_MPEG2, 12), + MESON_GATE(CLKID_UART2, HHI_GCLK_MPEG2, 15), + MESON_GATE(CLKID_SANA, HHI_GCLK_MPEG2, 22), + MESON_GATE(CLKID_VPU_INTR, HHI_GCLK_MPEG2, 25), + MESON_GATE(CLKID_SEC_AHB_AHB3_BRIDGE, HHI_GCLK_MPEG2, 26), + MESON_GATE(CLKID_CLK81_A53, HHI_GCLK_MPEG2, 29), + + MESON_GATE(CLKID_VCLK2_VENCI0, HHI_GCLK_OTHER, 1), + MESON_GATE(CLKID_VCLK2_VENCI1, HHI_GCLK_OTHER, 2), + MESON_GATE(CLKID_VCLK2_VENCP0, HHI_GCLK_OTHER, 3), + MESON_GATE(CLKID_VCLK2_VENCP1, HHI_GCLK_OTHER, 4), + MESON_GATE(CLKID_GCLK_VENCI_INT0, HHI_GCLK_OTHER, 8), + MESON_GATE(CLKID_DAC_CLK, HHI_GCLK_OTHER, 10), + MESON_GATE(CLKID_AOCLK_GATE, HHI_GCLK_OTHER, 14), + MESON_GATE(CLKID_IEC958_GATE, HHI_GCLK_OTHER, 16), + MESON_GATE(CLKID_ENC480P, HHI_GCLK_OTHER, 20), + MESON_GATE(CLKID_RNG1, HHI_GCLK_OTHER, 21), + MESON_GATE(CLKID_GCLK_VENCI_INT1, HHI_GCLK_OTHER, 22), + MESON_GATE(CLKID_VCLK2_VENCLMCC, HHI_GCLK_OTHER, 24), + MESON_GATE(CLKID_VCLK2_VENCL, HHI_GCLK_OTHER, 25), + MESON_GATE(CLKID_VCLK_OTHER, HHI_GCLK_OTHER, 26), + MESON_GATE(CLKID_EDP, HHI_GCLK_OTHER, 31), + + /* Always On (AO) domain gates */ + MESON_GATE(CLKID_AO_MEDIA_CPU, HHI_GCLK_AO, 0), + MESON_GATE(CLKID_AO_AHB_SRAM, HHI_GCLK_AO, 1), + MESON_GATE(CLKID_AO_AHB_BUS, HHI_GCLK_AO, 2), + MESON_GATE(CLKID_AO_IFACE, HHI_GCLK_AO, 3), + MESON_GATE(CLKID_AO_I2C, HHI_GCLK_AO, 4), + + /* PLL Gates */ + /* CLKID_FCLK_DIV2 is critical for the SCPI Processor */ + MESON_GATE(CLKID_FCLK_DIV3, HHI_MPLL_CNTL6, 28), + MESON_GATE(CLKID_FCLK_DIV4, HHI_MPLL_CNTL6, 29), + MESON_GATE(CLKID_FCLK_DIV5, HHI_MPLL_CNTL6, 30), + MESON_GATE(CLKID_FCLK_DIV7, HHI_MPLL_CNTL6, 31), + MESON_GATE(CLKID_MPLL0, HHI_MPLL_CNTL7, 14), + MESON_GATE(CLKID_MPLL1, HHI_MPLL_CNTL8, 14), + MESON_GATE(CLKID_MPLL2, HHI_MPLL_CNTL9, 14), + /* CLKID_CLK81 is critical for the system */ + + /* Peripheral Gates */ + MESON_GATE(CLKID_SAR_ADC_CLK, HHI_SAR_CLK_CNTL, 8), + MESON_GATE(CLKID_SD_EMMC_A_CLK0, HHI_SD_EMMC_CLK_CNTL, 7), + MESON_GATE(CLKID_SD_EMMC_B_CLK0, HHI_SD_EMMC_CLK_CNTL, 23), + MESON_GATE(CLKID_SD_EMMC_C_CLK0, HHI_NAND_CLK_CNTL, 7), +}; + +static int meson_set_gate(struct clk *clk, bool on) +{ + struct meson_clk *priv = dev_get_priv(clk->dev); + struct meson_gate *gate; + + if (clk->id >= ARRAY_SIZE(gates)) + return -ENOENT; + + gate = &gates[clk->id]; + + if (gate->reg == 0) + return 0; + + clrsetbits_le32(priv->addr + gate->reg, + BIT(gate->bit), on ? BIT(gate->bit) : 0); + return 0; +} + +static int meson_clk_enable(struct clk *clk) +{ + return meson_set_gate(clk, true); +} + +static int meson_clk_disable(struct clk *clk) +{ + return meson_set_gate(clk, false); +} + +static unsigned long meson_clk81_get_rate(struct clk *clk) +{ + struct meson_clk *priv = dev_get_priv(clk->dev); + unsigned long parent_rate; + u32 reg; + int parents[] = { + -1, + -1, + CLKID_FCLK_DIV7, + CLKID_MPLL1, + CLKID_MPLL2, + CLKID_FCLK_DIV4, + CLKID_FCLK_DIV3, + CLKID_FCLK_DIV5 + }; + + /* mux */ + reg = readl(priv->addr + HHI_MPEG_CLK_CNTL); + reg = (reg >> 12) & 7; + + switch (reg) { + case 0: + parent_rate = XTAL_RATE; + break; + case 1: + return -ENOENT; + default: + parent_rate = meson_clk_get_rate_by_id(clk, parents[reg]); + } + + /* divider */ + reg = readl(priv->addr + HHI_MPEG_CLK_CNTL); + reg = reg & ((1 << 7) - 1); + + return parent_rate / reg; +} + +static long mpll_rate_from_params(unsigned long parent_rate, + unsigned long sdm, + unsigned long n2) +{ + unsigned long divisor = (SDM_DEN * n2) + sdm; + + if (n2 < N2_MIN) + return -EINVAL; + + return DIV_ROUND_UP_ULL((u64)parent_rate * SDM_DEN, divisor); +} + +static struct parm meson_mpll0_parm[3] = { + {HHI_MPLL_CNTL7, 0, 14}, /* psdm */ + {HHI_MPLL_CNTL7, 16, 9}, /* pn2 */ +}; + +static struct parm meson_mpll1_parm[3] = { + {HHI_MPLL_CNTL8, 0, 14}, /* psdm */ + {HHI_MPLL_CNTL8, 16, 9}, /* pn2 */ +}; + +static struct parm meson_mpll2_parm[3] = { + {HHI_MPLL_CNTL9, 0, 14}, /* psdm */ + {HHI_MPLL_CNTL9, 16, 9}, /* pn2 */ +}; + +/* + * MultiPhase Locked Loops are outputs from a PLL with additional frequency + * scaling capabilities. MPLL rates are calculated as: + * + * f(N2_integer, SDM_IN ) = 2.0G/(N2_integer + SDM_IN/16384) + */ +static ulong meson_mpll_get_rate(struct clk *clk, unsigned long id) +{ + struct meson_clk *priv = dev_get_priv(clk->dev); + struct parm *psdm, *pn2; + unsigned long reg, sdm, n2; + unsigned long parent_rate; + + switch (id) { + case CLKID_MPLL0: + psdm = &meson_mpll0_parm[0]; + pn2 = &meson_mpll0_parm[1]; + break; + case CLKID_MPLL1: + psdm = &meson_mpll1_parm[0]; + pn2 = &meson_mpll1_parm[1]; + break; + case CLKID_MPLL2: + psdm = &meson_mpll2_parm[0]; + pn2 = &meson_mpll2_parm[1]; + break; + default: + return -ENOENT; + } + + parent_rate = meson_clk_get_rate_by_id(clk, CLKID_FIXED_PLL); + if (IS_ERR_VALUE(parent_rate)) + return parent_rate; + + reg = readl(priv->addr + psdm->reg_off); + sdm = PARM_GET(psdm->width, psdm->shift, reg); + + reg = readl(priv->addr + pn2->reg_off); + n2 = PARM_GET(pn2->width, pn2->shift, reg); + + return mpll_rate_from_params(parent_rate, sdm, n2); +} + +static struct parm meson_fixed_pll_parm[3] = { + {HHI_MPLL_CNTL, 0, 9}, /* pm */ + {HHI_MPLL_CNTL, 9, 5}, /* pn */ + {HHI_MPLL_CNTL, 16, 2}, /* pod */ +}; + +static struct parm meson_sys_pll_parm[3] = { + {HHI_SYS_PLL_CNTL, 0, 9}, /* pm */ + {HHI_SYS_PLL_CNTL, 9, 5}, /* pn */ + {HHI_SYS_PLL_CNTL, 10, 2}, /* pod */ +}; + +static ulong meson_pll_get_rate(struct clk *clk, unsigned long id) +{ + struct meson_clk *priv = dev_get_priv(clk->dev); + struct parm *pm, *pn, *pod; + unsigned long parent_rate_mhz = XTAL_RATE / 1000000; + u16 n, m, od; + u32 reg; + + switch (id) { + case CLKID_FIXED_PLL: + pm = &meson_fixed_pll_parm[0]; + pn = &meson_fixed_pll_parm[1]; + pod = &meson_fixed_pll_parm[2]; + break; + case CLKID_SYS_PLL: + pm = &meson_sys_pll_parm[0]; + pn = &meson_sys_pll_parm[1]; + pod = &meson_sys_pll_parm[2]; + break; + default: + return -ENOENT; + } + + reg = readl(priv->addr + pn->reg_off); + n = PARM_GET(pn->width, pn->shift, reg); + + reg = readl(priv->addr + pm->reg_off); + m = PARM_GET(pm->width, pm->shift, reg); + + reg = readl(priv->addr + pod->reg_off); + od = PARM_GET(pod->width, pod->shift, reg); + + return ((parent_rate_mhz * m / n) >> od) * 1000000; +} + +static ulong meson_clk_get_rate_by_id(struct clk *clk, unsigned long id) +{ + ulong rate; + + switch (id) { + case CLKID_FIXED_PLL: + case CLKID_SYS_PLL: + rate = meson_pll_get_rate(clk, id); + break; + case CLKID_FCLK_DIV2: + rate = meson_pll_get_rate(clk, CLKID_FIXED_PLL) / 2; + break; + case CLKID_FCLK_DIV3: + rate = meson_pll_get_rate(clk, CLKID_FIXED_PLL) / 3; + break; + case CLKID_FCLK_DIV4: + rate = meson_pll_get_rate(clk, CLKID_FIXED_PLL) / 4; + break; + case CLKID_FCLK_DIV5: + rate = meson_pll_get_rate(clk, CLKID_FIXED_PLL) / 5; + break; + case CLKID_FCLK_DIV7: + rate = meson_pll_get_rate(clk, CLKID_FIXED_PLL) / 7; + break; + case CLKID_MPLL0: + case CLKID_MPLL1: + case CLKID_MPLL2: + rate = meson_mpll_get_rate(clk, id); + break; + case CLKID_CLK81: + rate = meson_clk81_get_rate(clk); + break; + default: + if (gates[id].reg != 0) { + /* a clock gate */ + rate = meson_clk81_get_rate(clk); + break; + } + return -ENOENT; + } + + printf("clock %lu has rate %lu\n", id, rate); + return rate; +} + +static ulong meson_clk_get_rate(struct clk *clk) +{ + return meson_clk_get_rate_by_id(clk, clk->id); +} + +static int meson_clk_probe(struct udevice *dev) +{ + struct meson_clk *priv = dev_get_priv(dev); + + priv->addr = dev_read_addr_ptr(dev); + + debug("meson-clk: probed at addr %p\n", priv->addr); + + return 0; +} + +static struct clk_ops meson_clk_ops = { + .disable = meson_clk_disable, + .enable = meson_clk_enable, + .get_rate = meson_clk_get_rate, +}; + +static const struct udevice_id meson_clk_ids[] = { + { .compatible = "amlogic,gxbb-clkc" }, + { .compatible = "amlogic,gxl-clkc" }, + { } +}; + +U_BOOT_DRIVER(meson_clk) = { + .name = "meson_clk", + .id = UCLASS_CLK, + .of_match = meson_clk_ids, + .priv_auto_alloc_size = sizeof(struct meson_clk), + .ops = &meson_clk_ops, + .probe = meson_clk_probe, +}; diff --git a/drivers/clk/clk_meson.h b/drivers/clk/clk_meson.h new file mode 100644 index 0000000000..7adc55a980 --- /dev/null +++ b/drivers/clk/clk_meson.h @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * (C) Copyright 2018 - Beniamino Galvani <b.galvani@gmail.com> + * (C) Copyright 2018 - BayLibre, SAS + * Author: Neil Armstrong <narmstrong@baylibre.com> + */ + +#ifndef CLK_MESON_H +#define CLK_MESON_H + +/* Gate Structure */ + +struct meson_gate { + unsigned int reg; + unsigned int bit; +}; + +#define MESON_GATE(id, _reg, _bit) \ + [id] = { \ + .reg = (_reg), \ + .bit = (_bit), \ + } + +/* PLL Parameters */ + +struct parm { + u16 reg_off; + u8 shift; + u8 width; +}; + +#define PMASK(width) GENMASK(width - 1, 0) +#define SETPMASK(width, shift) GENMASK(shift + width - 1, shift) +#define CLRPMASK(width, shift) (~SETPMASK(width, shift)) + +#define PARM_GET(width, shift, reg) \ + (((reg) & SETPMASK(width, shift)) >> (shift)) +#define PARM_SET(width, shift, reg, val) \ + (((reg) & CLRPMASK(width, shift)) | ((val) << (shift))) + +/* MPLL Parameters */ + +#define SDM_DEN 16384 +#define N2_MIN 4 +#define N2_MAX 511 + +#endif diff --git a/drivers/gpio/da8xx_gpio.c b/drivers/gpio/da8xx_gpio.c index e410f5f9df..1a1d37ae2a 100644 --- a/drivers/gpio/da8xx_gpio.c +++ b/drivers/gpio/da8xx_gpio.c @@ -7,11 +7,14 @@ */ #include <common.h> +#include <dm.h> +#include <fdtdec.h> #include <asm/io.h> #include <asm/gpio.h> #include <asm/arch/hardware.h> #include <asm/arch/davinci_misc.h> +#ifndef CONFIG_DM_GPIO static struct gpio_registry { int is_registered; char name[GPIO_NAME_SIZE]; @@ -303,7 +306,7 @@ static const struct pinmux_config gpio_pinmux[] = { #define davinci_configure_pin_mux(a, b) #endif /* CONFIG_SOC_DA8XX */ -int gpio_request(unsigned gpio, const char *label) +int gpio_request(unsigned int gpio, const char *label) { if (gpio >= MAX_NUM_GPIOS) return -1; @@ -320,7 +323,7 @@ int gpio_request(unsigned gpio, const char *label) return 0; } -int gpio_free(unsigned gpio) +int gpio_free(unsigned int gpio) { if (gpio >= MAX_NUM_GPIOS) return -1; @@ -333,42 +336,30 @@ int gpio_free(unsigned gpio) /* Do not configure as input or change pin mux here */ return 0; } +#endif -int gpio_direction_input(unsigned gpio) +static int _gpio_direction_output(struct davinci_gpio *bank, unsigned int gpio, int value) { - struct davinci_gpio *bank; - - bank = GPIO_BANK(gpio); - setbits_le32(&bank->dir, 1U << GPIO_BIT(gpio)); + clrbits_le32(&bank->dir, 1U << GPIO_BIT(gpio)); + gpio_set_value(gpio, value); return 0; } -int gpio_direction_output(unsigned gpio, int value) +static int _gpio_direction_input(struct davinci_gpio *bank, unsigned int gpio) { - struct davinci_gpio *bank; - - bank = GPIO_BANK(gpio); - clrbits_le32(&bank->dir, 1U << GPIO_BIT(gpio)); - gpio_set_value(gpio, value); + setbits_le32(&bank->dir, 1U << GPIO_BIT(gpio)); return 0; } -int gpio_get_value(unsigned gpio) +static int _gpio_get_value(struct davinci_gpio *bank, unsigned int gpio) { - struct davinci_gpio *bank; unsigned int ip; - - bank = GPIO_BANK(gpio); ip = in_le32(&bank->in_data) & (1U << GPIO_BIT(gpio)); return ip ? 1 : 0; } -int gpio_set_value(unsigned gpio, int value) +static int _gpio_set_value(struct davinci_gpio *bank, unsigned int gpio, int value) { - struct davinci_gpio *bank; - - bank = GPIO_BANK(gpio); - if (value) bank->set_data = 1U << GPIO_BIT(gpio); else @@ -377,14 +368,21 @@ int gpio_set_value(unsigned gpio, int value) return 0; } +static int _gpio_get_dir(struct davinci_gpio *bank, unsigned int gpio) +{ + return in_le32(&bank->dir) & (1U << GPIO_BIT(gpio)); +} + +#ifndef CONFIG_DM_GPIO + void gpio_info(void) { - unsigned gpio, dir, val; + unsigned int gpio, dir, val; struct davinci_gpio *bank; for (gpio = 0; gpio < MAX_NUM_GPIOS; ++gpio) { bank = GPIO_BANK(gpio); - dir = in_le32(&bank->dir) & (1U << GPIO_BIT(gpio)); + dir = _gpio_get_dir(bank, gpio); val = gpio_get_value(gpio); printf("% 4d: %s: %d [%c] %s\n", @@ -393,3 +391,150 @@ void gpio_info(void) gpio_registry[gpio].name); } } + +int gpio_direction_input(unsigned int gpio) +{ + struct davinci_gpio *bank; + + bank = GPIO_BANK(gpio); + return _gpio_direction_input(bank, gpio); +} + +int gpio_direction_output(unsigned int gpio, int value) +{ + struct davinci_gpio *bank; + + bank = GPIO_BANK(gpio); + return _gpio_direction_output(bank, gpio, value); +} + +int gpio_get_value(unsigned int gpio) +{ + struct davinci_gpio *bank; + + bank = GPIO_BANK(gpio); + return _gpio_get_value(bank, gpio); +} + +int gpio_set_value(unsigned int gpio, int value) +{ + struct davinci_gpio *bank; + + bank = GPIO_BANK(gpio); + return _gpio_set_value(bank, gpio, value); +} + +#else /* CONFIG_DM_GPIO */ + +static struct davinci_gpio *davinci_get_gpio_bank(struct udevice *dev, unsigned int offset) +{ + struct davinci_gpio_bank *bank = dev_get_priv(dev); + + /* The device tree is not broken into banks but the infrastructure is + * expecting it this way, so we'll first include the 0x10 offset, then + * calculate the bank manually based on the offset. + */ + + return ((struct davinci_gpio *)bank->base) + 0x10 + (offset >> 5); +} + +static int davinci_gpio_direction_input(struct udevice *dev, unsigned int offset) +{ + struct davinci_gpio *base = davinci_get_gpio_bank(dev, offset); + + _gpio_direction_input(base, offset); + return 0; +} + +static int davinci_gpio_direction_output(struct udevice *dev, unsigned int offset, + int value) +{ + struct davinci_gpio *base = davinci_get_gpio_bank(dev, offset); + + _gpio_direction_output(base, offset, value); + return 0; +} + +static int davinci_gpio_get_value(struct udevice *dev, unsigned int offset) +{ + struct davinci_gpio *base = davinci_get_gpio_bank(dev, offset); + + return _gpio_get_value(base, offset); +} + +static int davinci_gpio_set_value(struct udevice *dev, unsigned int offset, + int value) +{ + struct davinci_gpio *base = davinci_get_gpio_bank(dev, offset); + + _gpio_set_value(base, offset, value); + + return 0; +} + +static int davinci_gpio_get_function(struct udevice *dev, unsigned int offset) +{ + unsigned int dir; + struct davinci_gpio *base = davinci_get_gpio_bank(dev, offset); + + dir = _gpio_get_dir(base, offset); + + if (dir) + return GPIOF_INPUT; + + return GPIOF_OUTPUT; +} + +static const struct dm_gpio_ops gpio_davinci_ops = { + .direction_input = davinci_gpio_direction_input, + .direction_output = davinci_gpio_direction_output, + .get_value = davinci_gpio_get_value, + .set_value = davinci_gpio_set_value, + .get_function = davinci_gpio_get_function, +}; + +static int davinci_gpio_probe(struct udevice *dev) +{ + struct davinci_gpio_bank *bank = dev_get_priv(dev); + struct davinci_gpio_platdata *plat = dev_get_platdata(dev); + struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); + const void *fdt = gd->fdt_blob; + int node = dev_of_offset(dev); + + uc_priv->bank_name = plat->port_name; + uc_priv->gpio_count = fdtdec_get_int(fdt, node, "ti,ngpio", -1); + bank->base = (struct davinci_gpio *)plat->base; + return 0; +} + +static const struct udevice_id davinci_gpio_ids[] = { + { .compatible = "ti,dm6441-gpio" }, + { } +}; + +static int davinci_gpio_ofdata_to_platdata(struct udevice *dev) +{ + struct davinci_gpio_platdata *plat = dev_get_platdata(dev); + fdt_addr_t addr; + + addr = devfdt_get_addr(dev); + if (addr == FDT_ADDR_T_NONE) + return -EINVAL; + + plat->base = addr; + return 0; +} + +U_BOOT_DRIVER(gpio_davinci) = { + .name = "gpio_davinci", + .id = UCLASS_GPIO, + .ops = &gpio_davinci_ops, + .ofdata_to_platdata = of_match_ptr(davinci_gpio_ofdata_to_platdata), + .of_match = davinci_gpio_ids, + .bind = dm_scan_fdt_dev, + .platdata_auto_alloc_size = sizeof(struct davinci_gpio_platdata), + .probe = davinci_gpio_probe, + .priv_auto_alloc_size = sizeof(struct davinci_gpio_bank), +}; + +#endif diff --git a/drivers/gpio/omap_gpio.c b/drivers/gpio/omap_gpio.c index d128f942a0..79a975ce71 100644 --- a/drivers/gpio/omap_gpio.c +++ b/drivers/gpio/omap_gpio.c @@ -288,11 +288,17 @@ static int omap_gpio_probe(struct udevice *dev) struct gpio_bank *bank = dev_get_priv(dev); struct omap_gpio_platdata *plat = dev_get_platdata(dev); struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); + int banknum; + char name[18], *str; - uc_priv->bank_name = plat->port_name; + banknum = plat->bank_index; + sprintf(name, "GPIO%d_", banknum + 1); + str = strdup(name); + if (!str) + return -ENOMEM; + uc_priv->bank_name = str; uc_priv->gpio_count = GPIO_PER_BANK; bank->base = (void *)plat->base; - return 0; } diff --git a/drivers/i2c/meson_i2c.c b/drivers/i2c/meson_i2c.c index 8c9318d4f1..7d06d95cf3 100644 --- a/drivers/i2c/meson_i2c.c +++ b/drivers/i2c/meson_i2c.c @@ -3,8 +3,8 @@ * (C) Copyright 2017 - Beniamino Galvani <b.galvani@gmail.com> */ #include <common.h> -#include <asm/arch/i2c.h> #include <asm/io.h> +#include <clk.h> #include <dm.h> #include <i2c.h> @@ -42,6 +42,7 @@ struct i2c_regs { }; struct meson_i2c { + struct clk clk; struct i2c_regs *regs; struct i2c_msg *msg; /* Current I2C message */ bool last; /* Whether the message is the last */ @@ -221,9 +222,13 @@ static int meson_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, static int meson_i2c_set_bus_speed(struct udevice *bus, unsigned int speed) { struct meson_i2c *i2c = dev_get_priv(bus); - unsigned int clk_rate = MESON_I2C_CLK_RATE; + ulong clk_rate; unsigned int div; + clk_rate = clk_get_rate(&i2c->clk); + if (IS_ERR_VALUE(clk_rate)) + return -EINVAL; + div = DIV_ROUND_UP(clk_rate, speed * 4); /* clock divider has 12 bits */ @@ -238,7 +243,7 @@ static int meson_i2c_set_bus_speed(struct udevice *bus, unsigned int speed) clrsetbits_le32(&i2c->regs->ctrl, REG_CTRL_CLKDIVEXT_MASK, (div >> 10) << REG_CTRL_CLKDIVEXT_SHIFT); - debug("meson i2c: set clk %u, src %u, div %u\n", speed, clk_rate, div); + debug("meson i2c: set clk %u, src %lu, div %u\n", speed, clk_rate, div); return 0; } @@ -246,6 +251,15 @@ static int meson_i2c_set_bus_speed(struct udevice *bus, unsigned int speed) static int meson_i2c_probe(struct udevice *bus) { struct meson_i2c *i2c = dev_get_priv(bus); + int ret; + + ret = clk_get_by_index(bus, 0, &i2c->clk); + if (ret < 0) + return ret; + + ret = clk_enable(&i2c->clk); + if (ret) + return ret; i2c->regs = dev_read_addr_ptr(bus); clrbits_le32(&i2c->regs->ctrl, REG_CTRL_START); diff --git a/drivers/misc/swap_case.c b/drivers/misc/swap_case.c index 56cd0700fa..b777404c09 100644 --- a/drivers/misc/swap_case.c +++ b/drivers/misc/swap_case.c @@ -21,7 +21,7 @@ */ struct swap_case_platdata { u16 command; - u32 bar[2]; + u32 bar[6]; }; #define offset_to_barnum(offset) \ diff --git a/drivers/mtd/spi/sandbox.c b/drivers/mtd/spi/sandbox.c index 7893efee12..f23c0e13e0 100644 --- a/drivers/mtd/spi/sandbox.c +++ b/drivers/mtd/spi/sandbox.c @@ -567,16 +567,17 @@ int sandbox_sf_bind_emul(struct sandbox_state *state, int busnum, int cs, strncpy(name, spec, sizeof(name) - 6); name[sizeof(name) - 6] = '\0'; strcat(name, "-emul"); - str = strdup(name); - if (!str) - return -ENOMEM; drv = lists_driver_lookup_name("sandbox_sf_emul"); if (!drv) { puts("Cannot find sandbox_sf_emul driver\n"); return -ENOENT; } + str = strdup(name); + if (!str) + return -ENOMEM; ret = device_bind(bus, drv, str, NULL, of_offset, &emul); if (ret) { + free(str); printf("Cannot create emul device for spec '%s' (err=%d)\n", spec, ret); return ret; diff --git a/dts/.gitignore b/dts/.gitignore deleted file mode 100644 index 1b3718065c..0000000000 --- a/dts/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -*.dtb -*.dtb.S diff --git a/fs/btrfs/btrfs.h b/fs/btrfs/btrfs.h index 27d78837c5..986d078679 100644 --- a/fs/btrfs/btrfs.h +++ b/fs/btrfs/btrfs.h @@ -13,7 +13,6 @@ struct btrfs_info { struct btrfs_super_block sb; - struct btrfs_root_backup *root_backup; struct btrfs_root tree_root; struct btrfs_root fs_root; diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index ad6641f314..e680caa56a 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -15,18 +15,34 @@ #define BTRFS_SUPER_INFO_SIZE 4096 -static int btrfs_newest_root_backup(struct btrfs_super_block *sb) +/* + * checks if a valid root backup is present. + * considers the case when all root backups empty valid. + * returns -1 in case of invalid root backup and 0 for valid. + */ +static int btrfs_check_super_roots(struct btrfs_super_block *sb) { struct btrfs_root_backup *root_backup; int i, newest = -1; + int num_empty = 0; for (i = 0; i < BTRFS_NUM_BACKUP_ROOTS; ++i) { root_backup = sb->super_roots + i; + + if (root_backup->tree_root == 0 && root_backup->tree_root_gen == 0) + num_empty++; + if (root_backup->tree_root_gen == sb->generation) newest = i; } - return newest; + if (num_empty == BTRFS_NUM_BACKUP_ROOTS) { + return 0; + } else if (newest >= 0) { + return 0; + } + + return -1; } static inline int is_power_of_2(u64 x) @@ -166,7 +182,7 @@ int btrfs_read_superblock(void) char raw_sb[BTRFS_SUPER_INFO_SIZE]; struct btrfs_super_block *sb = (struct btrfs_super_block *) raw_sb; u64 dev_total_bytes; - int i, root_backup_idx; + int i; dev_total_bytes = (u64) btrfs_part_info->size * btrfs_part_info->blksz; @@ -211,17 +227,15 @@ int btrfs_read_superblock(void) return -1; } - root_backup_idx = btrfs_newest_root_backup(&btrfs_info.sb); - if (root_backup_idx < 0) { + if (btrfs_check_super_roots(&btrfs_info.sb)) { printf("%s: No valid root_backup found!\n", __func__); return -1; } - btrfs_info.root_backup = btrfs_info.sb.super_roots + root_backup_idx; - if (btrfs_info.root_backup->num_devices != 1) { + if (btrfs_info.sb.num_devices != 1) { printf("%s: Unsupported number of devices (%lli). This driver " "only supports filesystem on one device.\n", __func__, - btrfs_info.root_backup->num_devices); + btrfs_info.sb.num_devices); return -1; } diff --git a/include/avb_verify.h b/include/avb_verify.h new file mode 100644 index 0000000000..eaa60f5393 --- /dev/null +++ b/include/avb_verify.h @@ -0,0 +1,96 @@ + +/* + * (C) Copyright 2018, Linaro Limited + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _AVB_VERIFY_H +#define _AVB_VERIFY_H + +#include <../lib/libavb/libavb.h> +#include <mmc.h> + +#define AVB_MAX_ARGS 1024 +#define VERITY_TABLE_OPT_RESTART "restart_on_corruption" +#define VERITY_TABLE_OPT_LOGGING "ignore_corruption" +#define ALLOWED_BUF_ALIGN 8 + +enum avb_boot_state { + AVB_GREEN, + AVB_YELLOW, + AVB_ORANGE, + AVB_RED, +}; + +struct AvbOpsData { + struct AvbOps ops; + int mmc_dev; + enum avb_boot_state boot_state; +}; + +struct mmc_part { + int dev_num; + struct mmc *mmc; + struct blk_desc *mmc_blk; + disk_partition_t info; +}; + +enum mmc_io_type { + IO_READ, + IO_WRITE +}; + +AvbOps *avb_ops_alloc(int boot_device); +void avb_ops_free(AvbOps *ops); + +char *avb_set_state(AvbOps *ops, enum avb_boot_state boot_state); +char *avb_set_enforce_verity(const char *cmdline); +char *avb_set_ignore_corruption(const char *cmdline); + +char *append_cmd_line(char *cmdline_orig, char *cmdline_new); + +/** + * ============================================================================ + * I/O helper inline functions + * ============================================================================ + */ +static inline uint64_t calc_offset(struct mmc_part *part, int64_t offset) +{ + u64 part_size = part->info.size * part->info.blksz; + + if (offset < 0) + return part_size + offset; + + return offset; +} + +static inline size_t get_sector_buf_size(void) +{ + return (size_t)CONFIG_FASTBOOT_BUF_SIZE; +} + +static inline void *get_sector_buf(void) +{ + return (void *)CONFIG_FASTBOOT_BUF_ADDR; +} + +static inline bool is_buf_unaligned(void *buffer) +{ + return (bool)((uintptr_t)buffer % ALLOWED_BUF_ALIGN); +} + +static inline int get_boot_device(AvbOps *ops) +{ + struct AvbOpsData *data; + + if (ops) { + data = ops->user_data; + if (data) + return data->mmc_dev; + } + + return -1; +} + +#endif /* _AVB_VERIFY_H */ diff --git a/include/blk.h b/include/blk.h index fc0c239e46..86f6d5057f 100644 --- a/include/blk.h +++ b/include/blk.h @@ -111,7 +111,7 @@ struct blk_desc { #define PAD_TO_BLOCKSIZE(size, blk_desc) \ (PAD_SIZE(size, blk_desc->blksz)) -#ifdef CONFIG_BLOCK_CACHE +#if CONFIG_IS_ENABLED(BLOCK_CACHE) /** * blkcache_read() - attempt to read a set of blocks from cache * diff --git a/include/common.h b/include/common.h index 60c79137e2..940161f175 100644 --- a/include/common.h +++ b/include/common.h @@ -536,10 +536,10 @@ void show_activity(int arg); /* Multicore arch functions */ #ifdef CONFIG_MP -int cpu_status(int nr); -int cpu_reset(int nr); -int cpu_disable(int nr); -int cpu_release(int nr, int argc, char * const argv[]); +int cpu_status(u32 nr); +int cpu_reset(u32 nr); +int cpu_disable(u32 nr); +int cpu_release(u32 nr, int argc, char * const argv[]); #endif #else /* __ASSEMBLY__ */ diff --git a/include/configs/UCP1020.h b/include/configs/UCP1020.h index 6231a1e4ae..b5ff5d3fe1 100644 --- a/include/configs/UCP1020.h +++ b/include/configs/UCP1020.h @@ -70,8 +70,6 @@ #define CONFIG_NETMASK 255.255.255.0 #define CONFIG_ETHPRIME "eTSEC1" -#ifndef CONFIG_SPI_FLASH -#endif #define CONFIG_SYS_REDUNDAND_ENVIRONMENT #define CONFIG_SYS_L2_SIZE (256 << 10) diff --git a/include/configs/da850evm.h b/include/configs/da850evm.h index d2cd440311..ebfdd1c7a3 100644 --- a/include/configs/da850evm.h +++ b/include/configs/da850evm.h @@ -40,7 +40,6 @@ #ifdef CONFIG_DIRECT_NOR_BOOT #define CONFIG_ARCH_CPU_INIT -#define CONFIG_DA8XX_GPIO #define CONFIG_SYS_DV_NOR_BOOT_CFG (0x11) #endif @@ -227,6 +226,7 @@ #define CONFIG_MTD_PARTITIONS /* required for UBI partition support */ #endif +#define CONFIG_DA8XX_GPIO /* * U-Boot general configuration */ diff --git a/include/configs/dragonboard410c.h b/include/configs/dragonboard410c.h index 86fa735470..46a7179f1b 100644 --- a/include/configs/dragonboard410c.h +++ b/include/configs/dragonboard410c.h @@ -94,6 +94,7 @@ REFLASH(dragonboard/u-boot.img, 8)\ #define CONFIG_ENV_SIZE 0x2000 #define CONFIG_SYS_MMC_ENV_DEV 0 /* mmc0 = emmc, mmc1 = sd */ +#define CONFIG_SYS_MMC_ENV_PART 2 /* Set env partition to BOOT2 partition */ /* Size of malloc() pool */ #define CONFIG_SYS_MALLOC_LEN (CONFIG_ENV_SIZE + SZ_8M) diff --git a/include/configs/meson-gx-common.h b/include/configs/meson-gx-common.h index 6e61b704a3..7435f3475e 100644 --- a/include/configs/meson-gx-common.h +++ b/include/configs/meson-gx-common.h @@ -23,10 +23,17 @@ #define GICD_BASE 0xc4301000 #define GICC_BASE 0xc4302000 +#ifdef CONFIG_CMD_USB +#define BOOT_TARGET_DEVICES_USB(func) func(USB, usb, 0) +#else +#define BOOT_TARGET_DEVICES_USB(func) +#endif + #define BOOT_TARGET_DEVICES(func) \ func(MMC, mmc, 0) \ func(MMC, mmc, 1) \ func(MMC, mmc, 2) \ + BOOT_TARGET_DEVICES_USB(func) \ func(PXE, pxe, na) \ func(DHCP, dhcp, na) diff --git a/include/configs/vme8349.h b/include/configs/vme8349.h index 0d8ae0b099..2456475f27 100644 --- a/include/configs/vme8349.h +++ b/include/configs/vme8349.h @@ -257,9 +257,6 @@ #undef PCI_ONE_PCI1 #endif -#ifndef VME_CADDY2 -#endif - #undef CONFIG_EEPRO100 #undef CONFIG_TULIP diff --git a/include/environment/ti/boot.h b/include/environment/ti/boot.h index a43b211df5..2893cd4287 100644 --- a/include/environment/ti/boot.h +++ b/include/environment/ti/boot.h @@ -13,6 +13,16 @@ #define CONSOLEDEV "ttyO2" #endif +#define VBMETA_PART_SIZE (64 * 1024) + +#if defined(CONFIG_LIBAVB) +#define VBMETA_PART \ + "name=vbmeta,size=" __stringify(VBMETA_PART_SIZE) \ + ",uuid=${uuid_gpt_vbmeta};" +#else +#define VBMETA_PART "" +#endif + #ifndef PARTS_DEFAULT /* Define the default GPT table for eMMC */ #define PARTS_DEFAULT \ @@ -37,9 +47,23 @@ "name=cache,size=256M,uuid=${uuid_gpt_cache};" \ "name=ipu1,size=1M,uuid=${uuid_gpt_ipu1};" \ "name=ipu2,size=1M,uuid=${uuid_gpt_ipu2};" \ + VBMETA_PART \ "name=userdata,size=-,uuid=${uuid_gpt_userdata}" #endif /* PARTS_DEFAULT */ +#if defined(CONFIG_CMD_AVB) +#define AVB_VERIFY_CHECK "if run avb_verify; then " \ + "echo AVB verification OK.;" \ + "set bootargs $bootargs $avb_bootargs;" \ + "else " \ + "echo AVB verification failed.;" \ + "exit; fi;" +#define AVB_VERIFY_CMD "avb_verify=avb init 1; avb verify;\0" +#else +#define AVB_VERIFY_CHECK "" +#define AVB_VERIFY_CMD "" +#endif + #define DEFAULT_COMMON_BOOT_TI_ARGS \ "console=" CONSOLEDEV ",115200n8\0" \ "fdtfile=undefined\0" \ @@ -48,6 +72,7 @@ "bootfile=zImage\0" \ "usbtty=cdc_acm\0" \ "vram=16M\0" \ + AVB_VERIFY_CMD \ "partitions=" PARTS_DEFAULT "\0" \ "optargs=\0" \ "dofastboot=0\0" \ @@ -66,6 +91,7 @@ "setenv machid fe6; " \ "mmc dev $mmcdev; " \ "mmc rescan; " \ + AVB_VERIFY_CHECK \ "part start mmc ${mmcdev} environment fdt_start; " \ "part size mmc ${mmcdev} environment fdt_size; " \ "part start mmc ${mmcdev} boot boot_start; " \ diff --git a/include/image.h b/include/image.h index 95d5934344..420b8ff576 100644 --- a/include/image.h +++ b/include/image.h @@ -17,6 +17,7 @@ #include "compiler.h" #include <asm/byteorder.h> +#include <stdbool.h> /* Define this to avoid #ifdefs later on */ struct lmb; @@ -881,9 +882,11 @@ int bootz_setup(ulong image, ulong *start, ulong *end); * @image: Address of image * @start: Returns start address of image * @size : Returns size image + * @force_reloc: Ignore image->ep field, always place image to RAM start * @return 0 if OK, 1 if the image was not recognised */ -int booti_setup(ulong image, ulong *relocated_addr, ulong *size); +int booti_setup(ulong image, ulong *relocated_addr, ulong *size, + bool force_reloc); /*******************************************************************/ /* New uImage format specific code (prefixed with fit_) */ diff --git a/include/iotrace.h b/include/iotrace.h index 1efb117343..be1d2753e1 100644 --- a/include/iotrace.h +++ b/include/iotrace.h @@ -6,8 +6,36 @@ #ifndef __IOTRACE_H #define __IOTRACE_H +//#include <common.h> #include <linux/types.h> +/* Support up to the machine word length for now */ +typedef ulong iovalue_t; + +enum iotrace_flags { + IOT_8 = 0, + IOT_16, + IOT_32, + + IOT_READ = 0 << 3, + IOT_WRITE = 1 << 3, +}; + +/** + * struct iotrace_record - Holds a single I/O trace record + * + * @flags: I/O access type + * @timestamp: Timestamp of access + * @addr: Address of access + * @value: Value written or read + */ +struct iotrace_record { + enum iotrace_flags flags; + u64 timestamp; + phys_addr_t addr; + iovalue_t value; +}; + /* * This file is designed to be included in arch/<arch>/include/asm/io.h. * It redirects all IO access through a tracing/checksumming feature for @@ -118,11 +146,12 @@ void iotrace_set_buffer(ulong start, ulong size); * iotrace_get_buffer() - Get buffer information * * @start: Returns start address of buffer - * @size: Returns size of buffer in bytes + * @size: Returns actual size of buffer in bytes + * @needed_size: Returns needed size of buffer in bytes * @offset: Returns the byte offset where the next output trace record will * @count: Returns the number of trace records recorded * be written (or would be if the buffer was large enough) */ -void iotrace_get_buffer(ulong *start, ulong *size, ulong *offset, ulong *count); +void iotrace_get_buffer(ulong *start, ulong *size, ulong *needed_size, ulong *offset, ulong *count); #endif /* __IOTRACE_H */ diff --git a/include/log.h b/include/log.h index a3edd25546..3e99d6e62b 100644 --- a/include/log.h +++ b/include/log.h @@ -274,7 +274,8 @@ struct log_filter { * log_get_cat_name() - Get the name of a category * * @cat: Category to look up - * @return category name (which may be a uclass driver name) + * @return category name (which may be a uclass driver name) if found, or + * "<invalid>" if invalid, or "<missing>" if not found */ const char *log_get_cat_name(enum log_category_t cat); diff --git a/lib/Kconfig b/lib/Kconfig index dd54516f30..a77bf1c688 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -187,6 +187,20 @@ config TPM endmenu +menu "Android Verified Boot" + +config LIBAVB + bool "Android Verified Boot 2.0 support" + depends on ANDROID_BOOT_IMAGE + default n + help + This enables support of Android Verified Boot 2.0 which can be used + to assure the end user of the integrity of the software running on a + device. Introduces such features as boot chain of trust, rollback + protection etc. + +endmenu + menu "Hashing Support" config SHA1 diff --git a/lib/Makefile b/lib/Makefile index 427d359159..5f583aed37 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -56,6 +56,7 @@ obj-$(CONFIG_$(SPL_)ZLIB) += zlib/ obj-$(CONFIG_$(SPL_)GZIP) += gunzip.o obj-$(CONFIG_$(SPL_)LZO) += lzo/ +obj-$(CONFIG_LIBAVB) += libavb/ obj-$(CONFIG_$(SPL_TPL_)SAVEENV) += qsort.o obj-$(CONFIG_$(SPL_TPL_)OF_LIBFDT) += libfdt/ diff --git a/lib/libavb/Makefile b/lib/libavb/Makefile new file mode 100644 index 0000000000..b983fe768e --- /dev/null +++ b/lib/libavb/Makefile @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# (C) Copyright 2017 Linaro Limited + +obj-$(CONFIG_LIBAVB) += avb_chain_partition_descriptor.o avb_cmdline.o +obj-$(CONFIG_LIBAVB) += avb_crypto.o avb_footer.o avb_hashtree_descriptor.o +obj-$(CONFIG_LIBAVB) += avb_property_descriptor.o avb_sha256.o +obj-$(CONFIG_LIBAVB) += avb_slot_verify.o avb_util.o avb_version.o +obj-$(CONFIG_LIBAVB) += avb_descriptor.o avb_hash_descriptor.o +obj-$(CONFIG_LIBAVB) += avb_kernel_cmdline_descriptor.o avb_rsa.o avb_sha512.o +obj-$(CONFIG_LIBAVB) += avb_sysdeps_posix.o avb_vbmeta_image.o + +ccflags-y = -DAVB_COMPILATION diff --git a/lib/libavb/avb_chain_partition_descriptor.c b/lib/libavb/avb_chain_partition_descriptor.c new file mode 100644 index 0000000000..e299306310 --- /dev/null +++ b/lib/libavb/avb_chain_partition_descriptor.c @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright (C) 2016 The Android Open Source Project + */ + +#include "avb_chain_partition_descriptor.h" +#include "avb_util.h" + +bool avb_chain_partition_descriptor_validate_and_byteswap( + const AvbChainPartitionDescriptor* src, AvbChainPartitionDescriptor* dest) { + uint64_t expected_size; + + avb_memcpy(dest, src, sizeof(AvbChainPartitionDescriptor)); + + if (!avb_descriptor_validate_and_byteswap((const AvbDescriptor*)src, + (AvbDescriptor*)dest)) + return false; + + if (dest->parent_descriptor.tag != AVB_DESCRIPTOR_TAG_CHAIN_PARTITION) { + avb_error("Invalid tag for chain partition descriptor.\n"); + return false; + } + + dest->rollback_index_location = avb_be32toh(dest->rollback_index_location); + dest->partition_name_len = avb_be32toh(dest->partition_name_len); + dest->public_key_len = avb_be32toh(dest->public_key_len); + + if (dest->rollback_index_location < 1) { + avb_error("Invalid rollback index location value.\n"); + return false; + } + + /* Check that partition_name and public_key are fully contained. */ + expected_size = sizeof(AvbChainPartitionDescriptor) - sizeof(AvbDescriptor); + if (!avb_safe_add_to(&expected_size, dest->partition_name_len) || + !avb_safe_add_to(&expected_size, dest->public_key_len)) { + avb_error("Overflow while adding up sizes.\n"); + return false; + } + if (expected_size > dest->parent_descriptor.num_bytes_following) { + avb_error("Descriptor payload size overflow.\n"); + return false; + } + return true; +} diff --git a/lib/libavb/avb_chain_partition_descriptor.h b/lib/libavb/avb_chain_partition_descriptor.h new file mode 100644 index 0000000000..80e2271782 --- /dev/null +++ b/lib/libavb/avb_chain_partition_descriptor.h @@ -0,0 +1,53 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright (C) 2016 The Android Open Source Project + */ + +#if !defined(AVB_INSIDE_LIBAVB_H) && !defined(AVB_COMPILATION) +#error "Never include this file directly, include libavb.h instead." +#endif + +#ifndef AVB_CHAIN_PARTITION_DESCRIPTOR_H_ +#define AVB_CHAIN_PARTITION_DESCRIPTOR_H_ + +#include "avb_descriptor.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* A descriptor containing a pointer to signed integrity data stored + * on another partition. The descriptor contains the partition name in + * question (without the A/B suffix), the public key used to sign the + * integrity data, and rollback index location to use for rollback + * protection. + * + * Following this struct are |partition_name_len| bytes of the + * partition name (UTF-8 encoded) and |public_key_len| bytes of the + * public key. + * + * The |reserved| field is for future expansion and must be set to NUL + * bytes. + */ +typedef struct AvbChainPartitionDescriptor { + AvbDescriptor parent_descriptor; + uint32_t rollback_index_location; + uint32_t partition_name_len; + uint32_t public_key_len; + uint8_t reserved[64]; +} AVB_ATTR_PACKED AvbChainPartitionDescriptor; + +/* Copies |src| to |dest| and validates, byte-swapping fields in the + * process if needed. Returns true if valid, false if invalid. + * + * Data following the struct is not validated nor copied. + */ +bool avb_chain_partition_descriptor_validate_and_byteswap( + const AvbChainPartitionDescriptor* src, + AvbChainPartitionDescriptor* dest) AVB_ATTR_WARN_UNUSED_RESULT; + +#ifdef __cplusplus +} +#endif + +#endif /* AVB_CHAIN_PARTITION_DESCRIPTOR_H_ */ diff --git a/lib/libavb/avb_cmdline.c b/lib/libavb/avb_cmdline.c new file mode 100644 index 0000000000..91a6615c74 --- /dev/null +++ b/lib/libavb/avb_cmdline.c @@ -0,0 +1,421 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright (C) 2016 The Android Open Source Project + */ + +#include "avb_cmdline.h" +#include "avb_sha.h" +#include "avb_util.h" +#include "avb_version.h" + +#define NUM_GUIDS 3 + +/* Substitutes all variables (e.g. $(ANDROID_SYSTEM_PARTUUID)) with + * values. Returns NULL on OOM, otherwise the cmdline with values + * replaced. + */ +char* avb_sub_cmdline(AvbOps* ops, + const char* cmdline, + const char* ab_suffix, + bool using_boot_for_vbmeta, + const AvbCmdlineSubstList* additional_substitutions) { + const char* part_name_str[NUM_GUIDS] = {"system", "boot", "vbmeta"}; + const char* replace_str[NUM_GUIDS] = {"$(ANDROID_SYSTEM_PARTUUID)", + "$(ANDROID_BOOT_PARTUUID)", + "$(ANDROID_VBMETA_PARTUUID)"}; + char* ret = NULL; + AvbIOResult io_ret; + size_t n; + + /* Special-case for when the top-level vbmeta struct is in the boot + * partition. + */ + if (using_boot_for_vbmeta) { + part_name_str[2] = "boot"; + } + + /* Replace unique partition GUIDs */ + for (n = 0; n < NUM_GUIDS; n++) { + char part_name[AVB_PART_NAME_MAX_SIZE]; + char guid_buf[37]; + + if (!avb_str_concat(part_name, + sizeof part_name, + part_name_str[n], + avb_strlen(part_name_str[n]), + ab_suffix, + avb_strlen(ab_suffix))) { + avb_error("Partition name and suffix does not fit.\n"); + goto fail; + } + + io_ret = ops->get_unique_guid_for_partition( + ops, part_name, guid_buf, sizeof guid_buf); + if (io_ret == AVB_IO_RESULT_ERROR_OOM) { + goto fail; + } else if (io_ret != AVB_IO_RESULT_OK) { + avb_error("Error getting unique GUID for partition.\n"); + goto fail; + } + + if (ret == NULL) { + ret = avb_replace(cmdline, replace_str[n], guid_buf); + } else { + char* new_ret = avb_replace(ret, replace_str[n], guid_buf); + avb_free(ret); + ret = new_ret; + } + if (ret == NULL) { + goto fail; + } + } + + avb_assert(ret != NULL); + + /* Replace any additional substitutions. */ + if (additional_substitutions != NULL) { + for (n = 0; n < additional_substitutions->size; ++n) { + char* new_ret = avb_replace(ret, + additional_substitutions->tokens[n], + additional_substitutions->values[n]); + avb_free(ret); + ret = new_ret; + if (ret == NULL) { + goto fail; + } + } + } + + return ret; + +fail: + if (ret != NULL) { + avb_free(ret); + } + return NULL; +} + +static int cmdline_append_option(AvbSlotVerifyData* slot_data, + const char* key, + const char* value) { + size_t offset, key_len, value_len; + char* new_cmdline; + + key_len = avb_strlen(key); + value_len = avb_strlen(value); + + offset = 0; + if (slot_data->cmdline != NULL) { + offset = avb_strlen(slot_data->cmdline); + if (offset > 0) { + offset += 1; + } + } + + new_cmdline = avb_calloc(offset + key_len + value_len + 2); + if (new_cmdline == NULL) { + return 0; + } + if (offset > 0) { + avb_memcpy(new_cmdline, slot_data->cmdline, offset - 1); + new_cmdline[offset - 1] = ' '; + } + avb_memcpy(new_cmdline + offset, key, key_len); + new_cmdline[offset + key_len] = '='; + avb_memcpy(new_cmdline + offset + key_len + 1, value, value_len); + if (slot_data->cmdline != NULL) { + avb_free(slot_data->cmdline); + } + slot_data->cmdline = new_cmdline; + + return 1; +} + +#define AVB_MAX_DIGITS_UINT64 32 + +/* Writes |value| to |digits| in base 10 followed by a NUL byte. + * Returns number of characters written excluding the NUL byte. + */ +static size_t uint64_to_base10(uint64_t value, + char digits[AVB_MAX_DIGITS_UINT64]) { + char rev_digits[AVB_MAX_DIGITS_UINT64]; + size_t n, num_digits; + + for (num_digits = 0; num_digits < AVB_MAX_DIGITS_UINT64 - 1;) { + rev_digits[num_digits++] = avb_div_by_10(&value) + '0'; + if (value == 0) { + break; + } + } + + for (n = 0; n < num_digits; n++) { + digits[n] = rev_digits[num_digits - 1 - n]; + } + digits[n] = '\0'; + return n; +} + +static int cmdline_append_version(AvbSlotVerifyData* slot_data, + const char* key, + uint64_t major_version, + uint64_t minor_version) { + char major_digits[AVB_MAX_DIGITS_UINT64]; + char minor_digits[AVB_MAX_DIGITS_UINT64]; + char combined[AVB_MAX_DIGITS_UINT64 * 2 + 1]; + size_t num_major_digits, num_minor_digits; + + num_major_digits = uint64_to_base10(major_version, major_digits); + num_minor_digits = uint64_to_base10(minor_version, minor_digits); + avb_memcpy(combined, major_digits, num_major_digits); + combined[num_major_digits] = '.'; + avb_memcpy(combined + num_major_digits + 1, minor_digits, num_minor_digits); + combined[num_major_digits + 1 + num_minor_digits] = '\0'; + + return cmdline_append_option(slot_data, key, combined); +} + +static int cmdline_append_uint64_base10(AvbSlotVerifyData* slot_data, + const char* key, + uint64_t value) { + char digits[AVB_MAX_DIGITS_UINT64]; + uint64_to_base10(value, digits); + return cmdline_append_option(slot_data, key, digits); +} + +static int cmdline_append_hex(AvbSlotVerifyData* slot_data, + const char* key, + const uint8_t* data, + size_t data_len) { + int ret; + char* hex_data = avb_bin2hex(data, data_len); + if (hex_data == NULL) { + return 0; + } + ret = cmdline_append_option(slot_data, key, hex_data); + avb_free(hex_data); + return ret; +} + +AvbSlotVerifyResult avb_append_options( + AvbOps* ops, + AvbSlotVerifyData* slot_data, + AvbVBMetaImageHeader* toplevel_vbmeta, + AvbAlgorithmType algorithm_type, + AvbHashtreeErrorMode hashtree_error_mode) { + AvbSlotVerifyResult ret; + const char* verity_mode; + bool is_device_unlocked; + AvbIOResult io_ret; + + /* Add androidboot.vbmeta.device option. */ + if (!cmdline_append_option(slot_data, + "androidboot.vbmeta.device", + "PARTUUID=$(ANDROID_VBMETA_PARTUUID)")) { + ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; + goto out; + } + + /* Add androidboot.vbmeta.avb_version option. */ + if (!cmdline_append_version(slot_data, + "androidboot.vbmeta.avb_version", + AVB_VERSION_MAJOR, + AVB_VERSION_MINOR)) { + ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; + goto out; + } + + /* Set androidboot.avb.device_state to "locked" or "unlocked". */ + io_ret = ops->read_is_device_unlocked(ops, &is_device_unlocked); + if (io_ret == AVB_IO_RESULT_ERROR_OOM) { + ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; + goto out; + } else if (io_ret != AVB_IO_RESULT_OK) { + avb_error("Error getting device state.\n"); + ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO; + goto out; + } + if (!cmdline_append_option(slot_data, + "androidboot.vbmeta.device_state", + is_device_unlocked ? "unlocked" : "locked")) { + ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; + goto out; + } + + /* Set androidboot.vbmeta.{hash_alg, size, digest} - use same hash + * function as is used to sign vbmeta. + */ + switch (algorithm_type) { + /* Explicit fallthrough. */ + case AVB_ALGORITHM_TYPE_NONE: + case AVB_ALGORITHM_TYPE_SHA256_RSA2048: + case AVB_ALGORITHM_TYPE_SHA256_RSA4096: + case AVB_ALGORITHM_TYPE_SHA256_RSA8192: { + size_t n, total_size = 0; + uint8_t vbmeta_digest[AVB_SHA256_DIGEST_SIZE]; + avb_slot_verify_data_calculate_vbmeta_digest( + slot_data, AVB_DIGEST_TYPE_SHA256, vbmeta_digest); + for (n = 0; n < slot_data->num_vbmeta_images; n++) { + total_size += slot_data->vbmeta_images[n].vbmeta_size; + } + if (!cmdline_append_option( + slot_data, "androidboot.vbmeta.hash_alg", "sha256") || + !cmdline_append_uint64_base10( + slot_data, "androidboot.vbmeta.size", total_size) || + !cmdline_append_hex(slot_data, + "androidboot.vbmeta.digest", + vbmeta_digest, + AVB_SHA256_DIGEST_SIZE)) { + ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; + goto out; + } + } break; + /* Explicit fallthrough. */ + case AVB_ALGORITHM_TYPE_SHA512_RSA2048: + case AVB_ALGORITHM_TYPE_SHA512_RSA4096: + case AVB_ALGORITHM_TYPE_SHA512_RSA8192: { + size_t n, total_size = 0; + uint8_t vbmeta_digest[AVB_SHA512_DIGEST_SIZE]; + avb_slot_verify_data_calculate_vbmeta_digest( + slot_data, AVB_DIGEST_TYPE_SHA512, vbmeta_digest); + for (n = 0; n < slot_data->num_vbmeta_images; n++) { + total_size += slot_data->vbmeta_images[n].vbmeta_size; + } + if (!cmdline_append_option( + slot_data, "androidboot.vbmeta.hash_alg", "sha512") || + !cmdline_append_uint64_base10( + slot_data, "androidboot.vbmeta.size", total_size) || + !cmdline_append_hex(slot_data, + "androidboot.vbmeta.digest", + vbmeta_digest, + AVB_SHA512_DIGEST_SIZE)) { + ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; + goto out; + } + } break; + case _AVB_ALGORITHM_NUM_TYPES: + avb_assert_not_reached(); + break; + } + + /* Set androidboot.veritymode and androidboot.vbmeta.invalidate_on_error */ + if (toplevel_vbmeta->flags & AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED) { + verity_mode = "disabled"; + } else { + const char* dm_verity_mode; + char* new_ret; + + switch (hashtree_error_mode) { + case AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE: + if (!cmdline_append_option( + slot_data, "androidboot.vbmeta.invalidate_on_error", "yes")) { + ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; + goto out; + } + verity_mode = "enforcing"; + dm_verity_mode = "restart_on_corruption"; + break; + case AVB_HASHTREE_ERROR_MODE_RESTART: + verity_mode = "enforcing"; + dm_verity_mode = "restart_on_corruption"; + break; + case AVB_HASHTREE_ERROR_MODE_EIO: + verity_mode = "eio"; + /* For now there's no option to specify the EIO mode. So + * just use 'ignore_zero_blocks' since that's already set + * and dm-verity-target.c supports specifying this multiple + * times. + */ + dm_verity_mode = "ignore_zero_blocks"; + break; + case AVB_HASHTREE_ERROR_MODE_LOGGING: + verity_mode = "logging"; + dm_verity_mode = "ignore_corruption"; + break; + } + new_ret = avb_replace( + slot_data->cmdline, "$(ANDROID_VERITY_MODE)", dm_verity_mode); + avb_free(slot_data->cmdline); + slot_data->cmdline = new_ret; + if (slot_data->cmdline == NULL) { + ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; + goto out; + } + } + if (!cmdline_append_option( + slot_data, "androidboot.veritymode", verity_mode)) { + ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; + goto out; + } + + ret = AVB_SLOT_VERIFY_RESULT_OK; + +out: + + return ret; +} + +AvbCmdlineSubstList* avb_new_cmdline_subst_list() { + return (AvbCmdlineSubstList*)avb_calloc(sizeof(AvbCmdlineSubstList)); +} + +void avb_free_cmdline_subst_list(AvbCmdlineSubstList* cmdline_subst) { + size_t i; + for (i = 0; i < cmdline_subst->size; ++i) { + avb_free(cmdline_subst->tokens[i]); + avb_free(cmdline_subst->values[i]); + } + cmdline_subst->size = 0; + avb_free(cmdline_subst); +} + +AvbSlotVerifyResult avb_add_root_digest_substitution( + const char* part_name, + const uint8_t* digest, + size_t digest_size, + AvbCmdlineSubstList* out_cmdline_subst) { + const char* kDigestSubPrefix = "$(AVB_"; + const char* kDigestSubSuffix = "_ROOT_DIGEST)"; + size_t part_name_len = avb_strlen(part_name); + size_t list_index = out_cmdline_subst->size; + + avb_assert(part_name_len < AVB_PART_NAME_MAX_SIZE); + avb_assert(digest_size <= AVB_SHA512_DIGEST_SIZE); + if (part_name_len >= AVB_PART_NAME_MAX_SIZE || + digest_size > AVB_SHA512_DIGEST_SIZE) { + return AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA; + } + + if (out_cmdline_subst->size >= AVB_MAX_NUM_CMDLINE_SUBST) { + /* The list is full. Currently dynamic growth of this list is not supported. + */ + return AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA; + } + + /* Construct the token to replace in the command line based on the partition + * name. For partition 'foo', this will be '$(AVB_FOO_ROOT_DIGEST)'. + */ + out_cmdline_subst->tokens[list_index] = + avb_strdupv(kDigestSubPrefix, part_name, kDigestSubSuffix, NULL); + if (out_cmdline_subst->tokens[list_index] == NULL) { + goto fail; + } + avb_uppercase(out_cmdline_subst->tokens[list_index]); + + /* The digest value is hex encoded when inserted in the command line. */ + out_cmdline_subst->values[list_index] = avb_bin2hex(digest, digest_size); + if (out_cmdline_subst->values[list_index] == NULL) { + goto fail; + } + + out_cmdline_subst->size++; + return AVB_SLOT_VERIFY_RESULT_OK; + +fail: + if (out_cmdline_subst->tokens[list_index]) { + avb_free(out_cmdline_subst->tokens[list_index]); + } + if (out_cmdline_subst->values[list_index]) { + avb_free(out_cmdline_subst->values[list_index]); + } + return AVB_SLOT_VERIFY_RESULT_ERROR_OOM; +} diff --git a/lib/libavb/avb_cmdline.h b/lib/libavb/avb_cmdline.h new file mode 100644 index 0000000000..9af3a99994 --- /dev/null +++ b/lib/libavb/avb_cmdline.h @@ -0,0 +1,71 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright (C) 2016 The Android Open Source Project + */ + +#ifdef AVB_INSIDE_LIBAVB_H +#error "You can't include avb_sha.h in the public header libavb.h." +#endif + +#ifndef AVB_COMPILATION +#error "Never include this file, it may only be used from internal avb code." +#endif + +#ifndef AVB_CMDLINE_H_ +#define AVB_CMDLINE_H_ + +#include "avb_ops.h" +#include "avb_slot_verify.h" + +/* Maximum allow length (in bytes) of a partition name, including + * ab_suffix. + */ +#define AVB_PART_NAME_MAX_SIZE 32 + +#define AVB_MAX_NUM_CMDLINE_SUBST 10 + +/* Holds information about command-line substitutions. */ +typedef struct AvbCmdlineSubstList { + size_t size; + char* tokens[AVB_MAX_NUM_CMDLINE_SUBST]; + char* values[AVB_MAX_NUM_CMDLINE_SUBST]; +} AvbCmdlineSubstList; + +/* Substitutes all variables (e.g. $(ANDROID_SYSTEM_PARTUUID)) with + * values. Returns NULL on OOM, otherwise the cmdline with values + * replaced. + */ +char* avb_sub_cmdline(AvbOps* ops, + const char* cmdline, + const char* ab_suffix, + bool using_boot_for_vbmeta, + const AvbCmdlineSubstList* additional_substitutions); + +AvbSlotVerifyResult avb_append_options( + AvbOps* ops, + AvbSlotVerifyData* slot_data, + AvbVBMetaImageHeader* toplevel_vbmeta, + AvbAlgorithmType algorithm_type, + AvbHashtreeErrorMode hashtree_error_mode); + +/* Allocates and initializes a new command line substitution list. Free with + * |avb_free_cmdline_subst_list|. + */ +AvbCmdlineSubstList* avb_new_cmdline_subst_list(void); + +/* Use this instead of |avb_free| to deallocate a AvbCmdlineSubstList. */ +void avb_free_cmdline_subst_list(AvbCmdlineSubstList* cmdline_subst); + +/* Adds a hashtree root digest to be substituted in $(AVB_*_ROOT_DIGEST) + * variables. The partition name differentiates the variable. For example, if + * |part_name| is "foo" then $(AVB_FOO_ROOT_DIGEST) will be substituted with the + * hex encoding of the digest. The substitution will be added to + * |out_cmdline_subst|. Returns AVB_SLOT_VERIFY_RESULT_OK on success. + */ +AvbSlotVerifyResult avb_add_root_digest_substitution( + const char* part_name, + const uint8_t* digest, + size_t digest_size, + AvbCmdlineSubstList* out_cmdline_subst); + +#endif diff --git a/lib/libavb/avb_crypto.c b/lib/libavb/avb_crypto.c new file mode 100644 index 0000000000..f1836d5fc3 --- /dev/null +++ b/lib/libavb/avb_crypto.c @@ -0,0 +1,353 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright (C) 2016 The Android Open Source Project + */ + +#include "avb_crypto.h" +#include "avb_rsa.h" +#include "avb_sha.h" +#include "avb_util.h" + +/* NOTE: The PKC1-v1.5 padding is a blob of binary DER of ASN.1 and is + * obtained from section 5.2.2 of RFC 4880. + */ + +static const uint8_t + padding_RSA2048_SHA256[AVB_RSA2048_NUM_BYTES - AVB_SHA256_DIGEST_SIZE] = { + 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, + 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20}; + +static const uint8_t + padding_RSA4096_SHA256[AVB_RSA4096_NUM_BYTES - AVB_SHA256_DIGEST_SIZE] = { + 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, + 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20}; + +static const uint8_t + padding_RSA8192_SHA256[AVB_RSA8192_NUM_BYTES - AVB_SHA256_DIGEST_SIZE] = { + 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, + 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20}; + +static const uint8_t + padding_RSA2048_SHA512[AVB_RSA2048_NUM_BYTES - AVB_SHA512_DIGEST_SIZE] = { + 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, + 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40}; + +static const uint8_t + padding_RSA4096_SHA512[AVB_RSA4096_NUM_BYTES - AVB_SHA512_DIGEST_SIZE] = { + 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x30, 0x51, 0x30, + 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, + 0x05, 0x00, 0x04, 0x40}; + +static const uint8_t + padding_RSA8192_SHA512[AVB_RSA8192_NUM_BYTES - AVB_SHA512_DIGEST_SIZE] = { + 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, + 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40}; + +static AvbAlgorithmData algorithm_data[_AVB_ALGORITHM_NUM_TYPES] = { + /* AVB_ALGORITHM_TYPE_NONE */ + {.padding = NULL, .padding_len = 0, .hash_len = 0}, + /* AVB_ALGORITHM_TYPE_SHA256_RSA2048 */ + {.padding = padding_RSA2048_SHA256, + .padding_len = sizeof(padding_RSA2048_SHA256), + .hash_len = AVB_SHA256_DIGEST_SIZE}, + /* AVB_ALGORITHM_TYPE_SHA256_RSA4096 */ + {.padding = padding_RSA4096_SHA256, + .padding_len = sizeof(padding_RSA4096_SHA256), + .hash_len = AVB_SHA256_DIGEST_SIZE}, + /* AVB_ALGORITHM_TYPE_SHA256_RSA8192 */ + {.padding = padding_RSA8192_SHA256, + .padding_len = sizeof(padding_RSA8192_SHA256), + .hash_len = AVB_SHA256_DIGEST_SIZE}, + /* AVB_ALGORITHM_TYPE_SHA512_RSA2048 */ + {.padding = padding_RSA2048_SHA512, + .padding_len = sizeof(padding_RSA2048_SHA512), + .hash_len = AVB_SHA512_DIGEST_SIZE}, + /* AVB_ALGORITHM_TYPE_SHA512_RSA4096 */ + {.padding = padding_RSA4096_SHA512, + .padding_len = sizeof(padding_RSA4096_SHA512), + .hash_len = AVB_SHA512_DIGEST_SIZE}, + /* AVB_ALGORITHM_TYPE_SHA512_RSA8192 */ + {.padding = padding_RSA8192_SHA512, + .padding_len = sizeof(padding_RSA8192_SHA512), + .hash_len = AVB_SHA512_DIGEST_SIZE}, +}; + +const AvbAlgorithmData* avb_get_algorithm_data(AvbAlgorithmType algorithm) { + if ((size_t)algorithm < _AVB_ALGORITHM_NUM_TYPES) { + return &algorithm_data[algorithm]; + } + return NULL; +} + +bool avb_rsa_public_key_header_validate_and_byteswap( + const AvbRSAPublicKeyHeader* src, AvbRSAPublicKeyHeader* dest) { + avb_memcpy(dest, src, sizeof(AvbRSAPublicKeyHeader)); + + dest->key_num_bits = avb_be32toh(dest->key_num_bits); + dest->n0inv = avb_be32toh(dest->n0inv); + + return true; +} diff --git a/lib/libavb/avb_crypto.h b/lib/libavb/avb_crypto.h new file mode 100644 index 0000000000..d8f649b137 --- /dev/null +++ b/lib/libavb/avb_crypto.h @@ -0,0 +1,155 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright (C) 2016 The Android Open Source Project + */ + +#if !defined(AVB_INSIDE_LIBAVB_H) && !defined(AVB_COMPILATION) +#error "Never include this file directly, include libavb.h instead." +#endif + +#ifndef AVB_CRYPTO_H_ +#define AVB_CRYPTO_H_ + +#include "avb_sysdeps.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Size of a RSA-2048 signature. */ +#define AVB_RSA2048_NUM_BYTES 256 + +/* Size of a RSA-4096 signature. */ +#define AVB_RSA4096_NUM_BYTES 512 + +/* Size of a RSA-8192 signature. */ +#define AVB_RSA8192_NUM_BYTES 1024 + +/* Size in bytes of a SHA-1 digest. */ +#define AVB_SHA1_DIGEST_SIZE 20 + +/* Size in bytes of a SHA-256 digest. */ +#define AVB_SHA256_DIGEST_SIZE 32 + +/* Size in bytes of a SHA-512 digest. */ +#define AVB_SHA512_DIGEST_SIZE 64 + +/* Possible digest types supported by libavb routines. */ +typedef enum { + AVB_DIGEST_TYPE_SHA256, + AVB_DIGEST_TYPE_SHA512, +} AvbDigestType; + +/* Algorithms that can be used in the vbmeta image for + * verification. An algorithm consists of a hash type and a signature + * type. + * + * The data used to calculate the hash is the three blocks mentioned + * in the documentation for |AvbVBMetaImageHeader| except for the data + * in the "Authentication data" block. + * + * For signatures with RSA keys, PKCS v1.5 padding is used. The public + * key data is stored in the auxiliary data block, see + * |AvbRSAPublicKeyHeader| for the serialization format. + * + * Each algorithm type is described below: + * + * AVB_ALGORITHM_TYPE_NONE: There is no hash, no signature of the + * data, and no public key. The data cannot be verified. The fields + * |hash_size|, |signature_size|, and |public_key_size| must be zero. + * + * AVB_ALGORITHM_TYPE_SHA256_RSA2048: The hash function used is + * SHA-256, resulting in 32 bytes of hash digest data. This hash is + * signed with a 2048-bit RSA key. The field |hash_size| must be 32, + * |signature_size| must be 256, and the public key data must have + * |key_num_bits| set to 2048. + * + * AVB_ALGORITHM_TYPE_SHA256_RSA4096: Like above, but only with + * a 4096-bit RSA key and |signature_size| set to 512. + * + * AVB_ALGORITHM_TYPE_SHA256_RSA8192: Like above, but only with + * a 8192-bit RSA key and |signature_size| set to 1024. + * + * AVB_ALGORITHM_TYPE_SHA512_RSA2048: The hash function used is + * SHA-512, resulting in 64 bytes of hash digest data. This hash is + * signed with a 2048-bit RSA key. The field |hash_size| must be 64, + * |signature_size| must be 256, and the public key data must have + * |key_num_bits| set to 2048. + * + * AVB_ALGORITHM_TYPE_SHA512_RSA4096: Like above, but only with + * a 4096-bit RSA key and |signature_size| set to 512. + * + * AVB_ALGORITHM_TYPE_SHA512_RSA8192: Like above, but only with + * a 8192-bit RSA key and |signature_size| set to 1024. + */ +typedef enum { + AVB_ALGORITHM_TYPE_NONE, + AVB_ALGORITHM_TYPE_SHA256_RSA2048, + AVB_ALGORITHM_TYPE_SHA256_RSA4096, + AVB_ALGORITHM_TYPE_SHA256_RSA8192, + AVB_ALGORITHM_TYPE_SHA512_RSA2048, + AVB_ALGORITHM_TYPE_SHA512_RSA4096, + AVB_ALGORITHM_TYPE_SHA512_RSA8192, + _AVB_ALGORITHM_NUM_TYPES +} AvbAlgorithmType; + +/* Holds algorithm-specific data. The |padding| is needed by avb_rsa_verify. */ +typedef struct { + const uint8_t* padding; + size_t padding_len; + size_t hash_len; +} AvbAlgorithmData; + +/* Provides algorithm-specific data for a given |algorithm|. Returns NULL if + * |algorithm| is invalid. + */ +const AvbAlgorithmData* avb_get_algorithm_data(AvbAlgorithmType algorithm) + AVB_ATTR_WARN_UNUSED_RESULT; + +/* The header for a serialized RSA public key. + * + * The size of the key is given by |key_num_bits|, for example 2048 + * for a RSA-2048 key. By definition, a RSA public key is the pair (n, + * e) where |n| is the modulus (which can be represented in + * |key_num_bits| bits) and |e| is the public exponent. The exponent + * is not stored since it's assumed to always be 65537. + * + * To optimize verification, the key block includes two precomputed + * values, |n0inv| (fits in 32 bits) and |rr| and can always be + * represented in |key_num_bits|. + + * The value |n0inv| is the value -1/n[0] (mod 2^32). The value |rr| + * is (2^key_num_bits)^2 (mod n). + * + * Following this header is |key_num_bits| bits of |n|, then + * |key_num_bits| bits of |rr|. Both values are stored with most + * significant bit first. Each serialized number takes up + * |key_num_bits|/8 bytes. + * + * All fields in this struct are stored in network byte order when + * serialized. To generate a copy with fields swapped to native byte + * order, use the function avb_rsa_public_key_header_validate_and_byteswap(). + * + * The avb_rsa_verify() function expects a key in this serialized + * format. + * + * The 'avbtool extract_public_key' command can be used to generate a + * serialized RSA public key. + */ +typedef struct AvbRSAPublicKeyHeader { + uint32_t key_num_bits; + uint32_t n0inv; +} AVB_ATTR_PACKED AvbRSAPublicKeyHeader; + +/* Copies |src| to |dest| and validates, byte-swapping fields in the + * process if needed. Returns true if valid, false if invalid. + */ +bool avb_rsa_public_key_header_validate_and_byteswap( + const AvbRSAPublicKeyHeader* src, + AvbRSAPublicKeyHeader* dest) AVB_ATTR_WARN_UNUSED_RESULT; + +#ifdef __cplusplus +} +#endif + +#endif /* AVB_CRYPTO_H_ */ diff --git a/lib/libavb/avb_descriptor.c b/lib/libavb/avb_descriptor.c new file mode 100644 index 0000000000..fb0b305f2c --- /dev/null +++ b/lib/libavb/avb_descriptor.c @@ -0,0 +1,141 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright (C) 2016 The Android Open Source Project + */ + +#include "avb_descriptor.h" +#include "avb_util.h" +#include "avb_vbmeta_image.h" + +bool avb_descriptor_validate_and_byteswap(const AvbDescriptor* src, + AvbDescriptor* dest) { + dest->tag = avb_be64toh(src->tag); + dest->num_bytes_following = avb_be64toh(src->num_bytes_following); + + if ((dest->num_bytes_following & 0x07) != 0) { + avb_error("Descriptor size is not divisible by 8.\n"); + return false; + } + return true; +} + +bool avb_descriptor_foreach(const uint8_t* image_data, + size_t image_size, + AvbDescriptorForeachFunc foreach_func, + void* user_data) { + const AvbVBMetaImageHeader* header = NULL; + bool ret = false; + const uint8_t* image_end; + const uint8_t* desc_start; + const uint8_t* desc_end; + const uint8_t* p; + + if (image_data == NULL) { + avb_error("image_data is NULL\n."); + goto out; + } + + if (foreach_func == NULL) { + avb_error("foreach_func is NULL\n."); + goto out; + } + + if (image_size < sizeof(AvbVBMetaImageHeader)) { + avb_error("Length is smaller than header.\n"); + goto out; + } + + /* Ensure magic is correct. */ + if (avb_memcmp(image_data, AVB_MAGIC, AVB_MAGIC_LEN) != 0) { + avb_error("Magic is incorrect.\n"); + goto out; + } + + /* Careful, not byteswapped - also ensure it's aligned properly. */ + avb_assert_aligned(image_data); + header = (const AvbVBMetaImageHeader*)image_data; + image_end = image_data + image_size; + + desc_start = image_data + sizeof(AvbVBMetaImageHeader) + + avb_be64toh(header->authentication_data_block_size) + + avb_be64toh(header->descriptors_offset); + + desc_end = desc_start + avb_be64toh(header->descriptors_size); + + if (desc_start < image_data || desc_start > image_end || + desc_end < image_data || desc_end > image_end || desc_end < desc_start) { + avb_error("Descriptors not inside passed-in data.\n"); + goto out; + } + + for (p = desc_start; p < desc_end;) { + const AvbDescriptor* dh = (const AvbDescriptor*)p; + avb_assert_aligned(dh); + uint64_t nb_following = avb_be64toh(dh->num_bytes_following); + uint64_t nb_total = sizeof(AvbDescriptor) + nb_following; + + if ((nb_total & 7) != 0) { + avb_error("Invalid descriptor length.\n"); + goto out; + } + + if (nb_total + p < desc_start || nb_total + p > desc_end) { + avb_error("Invalid data in descriptors array.\n"); + goto out; + } + + if (foreach_func(dh, user_data) == 0) { + goto out; + } + + p += nb_total; + } + + ret = true; + +out: + return ret; +} + +static bool count_descriptors(const AvbDescriptor* descriptor, + void* user_data) { + size_t* num_descriptors = user_data; + *num_descriptors += 1; + return true; +} + +typedef struct { + size_t descriptor_number; + const AvbDescriptor** descriptors; +} SetDescriptorData; + +static bool set_descriptors(const AvbDescriptor* descriptor, void* user_data) { + SetDescriptorData* data = user_data; + data->descriptors[data->descriptor_number++] = descriptor; + return true; +} + +const AvbDescriptor** avb_descriptor_get_all(const uint8_t* image_data, + size_t image_size, + size_t* out_num_descriptors) { + size_t num_descriptors = 0; + SetDescriptorData data; + + avb_descriptor_foreach( + image_data, image_size, count_descriptors, &num_descriptors); + + data.descriptor_number = 0; + data.descriptors = + avb_calloc(sizeof(const AvbDescriptor*) * (num_descriptors + 1)); + if (data.descriptors == NULL) { + return NULL; + } + avb_descriptor_foreach(image_data, image_size, set_descriptors, &data); + avb_assert(data.descriptor_number == num_descriptors); + + if (out_num_descriptors != NULL) { + *out_num_descriptors = num_descriptors; + } + + return data.descriptors; +} diff --git a/lib/libavb/avb_descriptor.h b/lib/libavb/avb_descriptor.h new file mode 100644 index 0000000000..d4f42ac964 --- /dev/null +++ b/lib/libavb/avb_descriptor.h @@ -0,0 +1,112 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright (C) 2016 The Android Open Source Project + */ + +#if !defined(AVB_INSIDE_LIBAVB_H) && !defined(AVB_COMPILATION) +#error "Never include this file directly, include libavb.h instead." +#endif + +#ifndef AVB_DESCRIPTOR_H_ +#define AVB_DESCRIPTOR_H_ + +#include "avb_sysdeps.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Well-known descriptor tags. + * + * AVB_DESCRIPTOR_TAG_PROPERTY: see |AvbPropertyDescriptor| struct. + * AVB_DESCRIPTOR_TAG_HASHTREE: see |AvbHashtreeDescriptor| struct. + * AVB_DESCRIPTOR_TAG_HASH: see |AvbHashDescriptor| struct. + * AVB_DESCRIPTOR_TAG_KERNEL_CMDLINE: see |AvbKernelCmdlineDescriptor| struct. + * AVB_DESCRIPTOR_TAG_CHAIN_PARTITION: see |AvbChainPartitionDescriptor| struct. + */ +typedef enum { + AVB_DESCRIPTOR_TAG_PROPERTY, + AVB_DESCRIPTOR_TAG_HASHTREE, + AVB_DESCRIPTOR_TAG_HASH, + AVB_DESCRIPTOR_TAG_KERNEL_CMDLINE, + AVB_DESCRIPTOR_TAG_CHAIN_PARTITION, +} AvbDescriptorTag; + +/* The header for a serialized descriptor. + * + * A descriptor always have two fields, a |tag| (denoting its type, + * see the |AvbDescriptorTag| enumeration) and the size of the bytes + * following, |num_bytes_following|. + * + * For padding, |num_bytes_following| is always a multiple of 8. + */ +typedef struct AvbDescriptor { + uint64_t tag; + uint64_t num_bytes_following; +} AVB_ATTR_PACKED AvbDescriptor; + +/* Copies |src| to |dest| and validates, byte-swapping fields in the + * process if needed. Returns true if valid, false if invalid. + * + * Data following the struct is not validated nor copied. + */ +bool avb_descriptor_validate_and_byteswap( + const AvbDescriptor* src, AvbDescriptor* dest) AVB_ATTR_WARN_UNUSED_RESULT; + +/* Signature for callback function used in avb_descriptor_foreach(). + * The passed in descriptor is given by |descriptor| and the + * |user_data| passed to avb_descriptor_foreach() function is in + * |user_data|. Return true to continue iterating, false to stop + * iterating. + * + * Note that |descriptor| points into the image passed to + * avb_descriptor_foreach() - all fields need to be byteswapped! + */ +typedef bool AvbDescriptorForeachFunc(const AvbDescriptor* descriptor, + void* user_data); + +/* Convenience function to iterate over all descriptors in an vbmeta + * image. + * + * The function given by |foreach_func| will be called for each + * descriptor. The given function should return true to continue + * iterating, false to stop. + * + * The |user_data| parameter will be passed to |foreach_func|. + * + * Returns false if the iteration was short-circuited, that is if + * an invocation of |foreach_func| returned false. + * + * Before using this function, you MUST verify |image_data| with + * avb_vbmeta_image_verify() and reject it unless it's signed by a known + * good public key. Additionally, |image_data| must be word-aligned. + */ +bool avb_descriptor_foreach(const uint8_t* image_data, + size_t image_size, + AvbDescriptorForeachFunc foreach_func, + void* user_data); + +/* Gets all descriptors in a vbmeta image. + * + * The return value is a NULL-pointer terminated array of + * AvbDescriptor pointers. Free with avb_free() when you are done with + * it. If |out_num_descriptors| is non-NULL, the number of descriptors + * will be returned there. + * + * Note that each AvbDescriptor pointer in the array points into + * |image_data| - all fields need to be byteswapped! + * + * Before using this function, you MUST verify |image_data| with + * avb_vbmeta_image_verify() and reject it unless it's signed by a known + * good public key. Additionally, |image_data| must be word-aligned. + */ +const AvbDescriptor** avb_descriptor_get_all(const uint8_t* image_data, + size_t image_size, + size_t* out_num_descriptors) + AVB_ATTR_WARN_UNUSED_RESULT; + +#ifdef __cplusplus +} +#endif + +#endif /* AVB_DESCRIPTOR_H_ */ diff --git a/lib/libavb/avb_footer.c b/lib/libavb/avb_footer.c new file mode 100644 index 0000000000..697a715217 --- /dev/null +++ b/lib/libavb/avb_footer.c @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright (C) 2016 The Android Open Source Project + */ + +#include "avb_footer.h" +#include "avb_util.h" + +bool avb_footer_validate_and_byteswap(const AvbFooter* src, AvbFooter* dest) { + avb_memcpy(dest, src, sizeof(AvbFooter)); + + dest->version_major = avb_be32toh(dest->version_major); + dest->version_minor = avb_be32toh(dest->version_minor); + + dest->original_image_size = avb_be64toh(dest->original_image_size); + dest->vbmeta_offset = avb_be64toh(dest->vbmeta_offset); + dest->vbmeta_size = avb_be64toh(dest->vbmeta_size); + + /* Check that magic is correct. */ + if (avb_safe_memcmp(dest->magic, AVB_FOOTER_MAGIC, AVB_FOOTER_MAGIC_LEN) != + 0) { + avb_error("Footer magic is incorrect.\n"); + return false; + } + + /* Ensure we don't attempt to access any fields if the footer major + * version is not supported. + */ + if (dest->version_major > AVB_FOOTER_VERSION_MAJOR) { + avb_error("No support for footer version.\n"); + return false; + } + + return true; +} diff --git a/lib/libavb/avb_footer.h b/lib/libavb/avb_footer.h new file mode 100644 index 0000000000..62a6e658d1 --- /dev/null +++ b/lib/libavb/avb_footer.h @@ -0,0 +1,67 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright (C) 2016 The Android Open Source Project + */ + +#if !defined(AVB_INSIDE_LIBAVB_H) && !defined(AVB_COMPILATION) +#error "Never include this file directly, include libavb.h instead." +#endif + +#ifndef AVB_FOOTER_H_ +#define AVB_FOOTER_H_ + +#include "avb_sysdeps.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Magic for the footer. */ +#define AVB_FOOTER_MAGIC "AVBf" +#define AVB_FOOTER_MAGIC_LEN 4 + +/* Size of the footer. */ +#define AVB_FOOTER_SIZE 64 + +/* The current footer version used - keep in sync with avbtool. */ +#define AVB_FOOTER_VERSION_MAJOR 1 +#define AVB_FOOTER_VERSION_MINOR 0 + +/* The struct used as a footer used on partitions, used to find the + * AvbVBMetaImageHeader struct. This struct is always stored at the + * end of a partition. + */ +typedef struct AvbFooter { + /* 0: Four bytes equal to "AVBf" (AVB_FOOTER_MAGIC). */ + uint8_t magic[AVB_FOOTER_MAGIC_LEN]; + /* 4: The major version of the footer struct. */ + uint32_t version_major; + /* 8: The minor version of the footer struct. */ + uint32_t version_minor; + + /* 12: The original size of the image on the partition. */ + uint64_t original_image_size; + + /* 20: The offset of the |AvbVBMetaImageHeader| struct. */ + uint64_t vbmeta_offset; + + /* 28: The size of the vbmeta block (header + auth + aux blocks). */ + uint64_t vbmeta_size; + + /* 36: Padding to ensure struct is size AVB_FOOTER_SIZE bytes. This + * must be set to zeroes. + */ + uint8_t reserved[28]; +} AVB_ATTR_PACKED AvbFooter; + +/* Copies |src| to |dest| and validates, byte-swapping fields in the + * process if needed. Returns true if valid, false if invalid. + */ +bool avb_footer_validate_and_byteswap(const AvbFooter* src, AvbFooter* dest) + AVB_ATTR_WARN_UNUSED_RESULT; + +#ifdef __cplusplus +} +#endif + +#endif /* AVB_FOOTER_H_ */ diff --git a/lib/libavb/avb_hash_descriptor.c b/lib/libavb/avb_hash_descriptor.c new file mode 100644 index 0000000000..cd1438e0cd --- /dev/null +++ b/lib/libavb/avb_hash_descriptor.c @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright (C) 2016 The Android Open Source Project + */ + +#include "avb_hash_descriptor.h" +#include "avb_util.h" + +bool avb_hash_descriptor_validate_and_byteswap(const AvbHashDescriptor* src, + AvbHashDescriptor* dest) { + uint64_t expected_size; + + avb_memcpy(dest, src, sizeof(AvbHashDescriptor)); + + if (!avb_descriptor_validate_and_byteswap((const AvbDescriptor*)src, + (AvbDescriptor*)dest)) + return false; + + if (dest->parent_descriptor.tag != AVB_DESCRIPTOR_TAG_HASH) { + avb_error("Invalid tag for hash descriptor.\n"); + return false; + } + + dest->image_size = avb_be64toh(dest->image_size); + dest->partition_name_len = avb_be32toh(dest->partition_name_len); + dest->salt_len = avb_be32toh(dest->salt_len); + dest->digest_len = avb_be32toh(dest->digest_len); + dest->flags = avb_be32toh(dest->flags); + + /* Check that partition_name, salt, and digest are fully contained. */ + expected_size = sizeof(AvbHashDescriptor) - sizeof(AvbDescriptor); + if (!avb_safe_add_to(&expected_size, dest->partition_name_len) || + !avb_safe_add_to(&expected_size, dest->salt_len) || + !avb_safe_add_to(&expected_size, dest->digest_len)) { + avb_error("Overflow while adding up sizes.\n"); + return false; + } + if (expected_size > dest->parent_descriptor.num_bytes_following) { + avb_error("Descriptor payload size overflow.\n"); + return false; + } + return true; +} diff --git a/lib/libavb/avb_hash_descriptor.h b/lib/libavb/avb_hash_descriptor.h new file mode 100644 index 0000000000..bede97f818 --- /dev/null +++ b/lib/libavb/avb_hash_descriptor.h @@ -0,0 +1,69 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright (C) 2016 The Android Open Source Project + */ + +#if !defined(AVB_INSIDE_LIBAVB_H) && !defined(AVB_COMPILATION) +#error "Never include this file directly, include libavb.h instead." +#endif + +#ifndef AVB_HASH_DESCRIPTOR_H_ +#define AVB_HASH_DESCRIPTOR_H_ + +#include "avb_descriptor.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Flags for hash descriptors. + * + * AVB_HASH_DESCRIPTOR_FLAGS_DO_NOT_USE_AB: Do not apply the default A/B + * partition logic to this partition. This is intentionally a negative boolean + * because A/B should be both the default and most used in practice. + */ +typedef enum { + AVB_HASH_DESCRIPTOR_FLAGS_DO_NOT_USE_AB = (1 << 0), +} AvbHashDescriptorFlags; + +/* A descriptor containing information about hash for an image. + * + * This descriptor is typically used for boot partitions to verify the + * entire kernel+initramfs image before executing it. + * + * Following this struct are |partition_name_len| bytes of the + * partition name (UTF-8 encoded), |salt_len| bytes of salt, and then + * |digest_len| bytes of the digest. + * + * The |reserved| field is for future expansion and must be set to NUL + * bytes. + * + * Changes in v1.1: + * - flags field is added which supports AVB_HASH_DESCRIPTOR_FLAGS_USE_AB + * - digest_len may be zero, which indicates the use of a persistent digest + */ +typedef struct AvbHashDescriptor { + AvbDescriptor parent_descriptor; + uint64_t image_size; + uint8_t hash_algorithm[32]; + uint32_t partition_name_len; + uint32_t salt_len; + uint32_t digest_len; + uint32_t flags; + uint8_t reserved[60]; +} AVB_ATTR_PACKED AvbHashDescriptor; + +/* Copies |src| to |dest| and validates, byte-swapping fields in the + * process if needed. Returns true if valid, false if invalid. + * + * Data following the struct is not validated nor copied. + */ +bool avb_hash_descriptor_validate_and_byteswap(const AvbHashDescriptor* src, + AvbHashDescriptor* dest) + AVB_ATTR_WARN_UNUSED_RESULT; + +#ifdef __cplusplus +} +#endif + +#endif /* AVB_HASH_DESCRIPTOR_H_ */ diff --git a/lib/libavb/avb_hashtree_descriptor.c b/lib/libavb/avb_hashtree_descriptor.c new file mode 100644 index 0000000000..2a61b35a8f --- /dev/null +++ b/lib/libavb/avb_hashtree_descriptor.c @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright (C) 2016 The Android Open Source Project + */ + +#include "avb_hashtree_descriptor.h" +#include "avb_util.h" + +bool avb_hashtree_descriptor_validate_and_byteswap( + const AvbHashtreeDescriptor* src, AvbHashtreeDescriptor* dest) { + uint64_t expected_size; + + avb_memcpy(dest, src, sizeof(AvbHashtreeDescriptor)); + + if (!avb_descriptor_validate_and_byteswap((const AvbDescriptor*)src, + (AvbDescriptor*)dest)) + return false; + + if (dest->parent_descriptor.tag != AVB_DESCRIPTOR_TAG_HASHTREE) { + avb_error("Invalid tag for hashtree descriptor.\n"); + return false; + } + + dest->dm_verity_version = avb_be32toh(dest->dm_verity_version); + dest->image_size = avb_be64toh(dest->image_size); + dest->tree_offset = avb_be64toh(dest->tree_offset); + dest->tree_size = avb_be64toh(dest->tree_size); + dest->data_block_size = avb_be32toh(dest->data_block_size); + dest->hash_block_size = avb_be32toh(dest->hash_block_size); + dest->fec_num_roots = avb_be32toh(dest->fec_num_roots); + dest->fec_offset = avb_be64toh(dest->fec_offset); + dest->fec_size = avb_be64toh(dest->fec_size); + dest->partition_name_len = avb_be32toh(dest->partition_name_len); + dest->salt_len = avb_be32toh(dest->salt_len); + dest->root_digest_len = avb_be32toh(dest->root_digest_len); + dest->flags = avb_be32toh(dest->flags); + + /* Check that partition_name, salt, and root_digest are fully contained. */ + expected_size = sizeof(AvbHashtreeDescriptor) - sizeof(AvbDescriptor); + if (!avb_safe_add_to(&expected_size, dest->partition_name_len) || + !avb_safe_add_to(&expected_size, dest->salt_len) || + !avb_safe_add_to(&expected_size, dest->root_digest_len)) { + avb_error("Overflow while adding up sizes.\n"); + return false; + } + if (expected_size > dest->parent_descriptor.num_bytes_following) { + avb_error("Descriptor payload size overflow.\n"); + return false; + } + return true; +} diff --git a/lib/libavb/avb_hashtree_descriptor.h b/lib/libavb/avb_hashtree_descriptor.h new file mode 100644 index 0000000000..d7f3eb501a --- /dev/null +++ b/lib/libavb/avb_hashtree_descriptor.h @@ -0,0 +1,79 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright (C) 2016 The Android Open Source Project + */ + +#if !defined(AVB_INSIDE_LIBAVB_H) && !defined(AVB_COMPILATION) +#error "Never include this file directly, include libavb.h instead." +#endif + +#ifndef AVB_HASHTREE_DESCRIPTOR_H_ +#define AVB_HASHTREE_DESCRIPTOR_H_ + +#include "avb_descriptor.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Flags for hashtree descriptors. + * + * AVB_HASHTREE_DESCRIPTOR_FLAGS_DO_NOT_USE_AB: Do not apply the default A/B + * partition logic to this partition. This is intentionally a negative boolean + * because A/B should be both the default and most used in practice. + */ +typedef enum { + AVB_HASHTREE_DESCRIPTOR_FLAGS_DO_NOT_USE_AB = (1 << 0), +} AvbHashtreeDescriptorFlags; + +/* A descriptor containing information about a dm-verity hashtree. + * + * Hash-trees are used to verify large partitions typically containing + * file systems. See + * https://gitlab.com/cryptsetup/cryptsetup/wikis/DMVerity for more + * information about dm-verity. + * + * Following this struct are |partition_name_len| bytes of the + * partition name (UTF-8 encoded), |salt_len| bytes of salt, and then + * |root_digest_len| bytes of the root digest. + * + * The |reserved| field is for future expansion and must be set to NUL + * bytes. + * + * Changes in v1.1: + * - flags field is added which supports AVB_HASHTREE_DESCRIPTOR_FLAGS_USE_AB + * - digest_len may be zero, which indicates the use of a persistent digest + */ +typedef struct AvbHashtreeDescriptor { + AvbDescriptor parent_descriptor; + uint32_t dm_verity_version; + uint64_t image_size; + uint64_t tree_offset; + uint64_t tree_size; + uint32_t data_block_size; + uint32_t hash_block_size; + uint32_t fec_num_roots; + uint64_t fec_offset; + uint64_t fec_size; + uint8_t hash_algorithm[32]; + uint32_t partition_name_len; + uint32_t salt_len; + uint32_t root_digest_len; + uint32_t flags; + uint8_t reserved[60]; +} AVB_ATTR_PACKED AvbHashtreeDescriptor; + +/* Copies |src| to |dest| and validates, byte-swapping fields in the + * process if needed. Returns true if valid, false if invalid. + * + * Data following the struct is not validated nor copied. + */ +bool avb_hashtree_descriptor_validate_and_byteswap( + const AvbHashtreeDescriptor* src, + AvbHashtreeDescriptor* dest) AVB_ATTR_WARN_UNUSED_RESULT; + +#ifdef __cplusplus +} +#endif + +#endif /* AVB_HASHTREE_DESCRIPTOR_H_ */ diff --git a/lib/libavb/avb_kernel_cmdline_descriptor.c b/lib/libavb/avb_kernel_cmdline_descriptor.c new file mode 100644 index 0000000000..fa3fe4537b --- /dev/null +++ b/lib/libavb/avb_kernel_cmdline_descriptor.c @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright (C) 2016 The Android Open Source Project + */ + +#include "avb_kernel_cmdline_descriptor.h" +#include "avb_util.h" + +bool avb_kernel_cmdline_descriptor_validate_and_byteswap( + const AvbKernelCmdlineDescriptor* src, AvbKernelCmdlineDescriptor* dest) { + uint64_t expected_size; + + avb_memcpy(dest, src, sizeof(AvbKernelCmdlineDescriptor)); + + if (!avb_descriptor_validate_and_byteswap((const AvbDescriptor*)src, + (AvbDescriptor*)dest)) + return false; + + if (dest->parent_descriptor.tag != AVB_DESCRIPTOR_TAG_KERNEL_CMDLINE) { + avb_error("Invalid tag for kernel cmdline descriptor.\n"); + return false; + } + + dest->flags = avb_be32toh(dest->flags); + dest->kernel_cmdline_length = avb_be32toh(dest->kernel_cmdline_length); + + /* Check that kernel_cmdline is fully contained. */ + expected_size = sizeof(AvbKernelCmdlineDescriptor) - sizeof(AvbDescriptor); + if (!avb_safe_add_to(&expected_size, dest->kernel_cmdline_length)) { + avb_error("Overflow while adding up sizes.\n"); + return false; + } + if (expected_size > dest->parent_descriptor.num_bytes_following) { + avb_error("Descriptor payload size overflow.\n"); + return false; + } + + return true; +} diff --git a/lib/libavb/avb_kernel_cmdline_descriptor.h b/lib/libavb/avb_kernel_cmdline_descriptor.h new file mode 100644 index 0000000000..246fbdacf3 --- /dev/null +++ b/lib/libavb/avb_kernel_cmdline_descriptor.h @@ -0,0 +1,62 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright (C) 2016 The Android Open Source Project + */ + +#if !defined(AVB_INSIDE_LIBAVB_H) && !defined(AVB_COMPILATION) +#error "Never include this file directly, include libavb.h instead." +#endif + +#ifndef AVB_KERNEL_CMDLINE_DESCRIPTOR_H_ +#define AVB_KERNEL_CMDLINE_DESCRIPTOR_H_ + +#include "avb_descriptor.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Flags for kernel command-line descriptors. + * + * AVB_KERNEL_CMDLINE_FLAGS_USE_ONLY_IF_HASHTREE_NOT_DISABLED: The + * cmdline will only be applied if hashtree verification is not + * disabled (cf. AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED). + * + * AVB_KERNEL_CMDLINE_FLAGS_USE_ONLY_IF_HASHTREE_DISABLED: The cmdline + * will only be applied if hashtree verification is disabled + * (cf. AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED). + */ +typedef enum { + AVB_KERNEL_CMDLINE_FLAGS_USE_ONLY_IF_HASHTREE_NOT_DISABLED = (1 << 0), + AVB_KERNEL_CMDLINE_FLAGS_USE_ONLY_IF_HASHTREE_DISABLED = (1 << 1) +} AvbKernelCmdlineFlags; + +/* A descriptor containing information to be appended to the kernel + * command-line. + * + * The |flags| field contains flags from the AvbKernelCmdlineFlags + * enumeration. + * + * Following this struct are |kernel_cmdline_len| bytes with the + * kernel command-line (UTF-8 encoded). + */ +typedef struct AvbKernelCmdlineDescriptor { + AvbDescriptor parent_descriptor; + uint32_t flags; + uint32_t kernel_cmdline_length; +} AVB_ATTR_PACKED AvbKernelCmdlineDescriptor; + +/* Copies |src| to |dest| and validates, byte-swapping fields in the + * process if needed. Returns true if valid, false if invalid. + * + * Data following the struct is not validated nor copied. + */ +bool avb_kernel_cmdline_descriptor_validate_and_byteswap( + const AvbKernelCmdlineDescriptor* src, + AvbKernelCmdlineDescriptor* dest) AVB_ATTR_WARN_UNUSED_RESULT; + +#ifdef __cplusplus +} +#endif + +#endif /* AVB_KERNEL_CMDLINE_DESCRIPTOR_H_ */ diff --git a/lib/libavb/avb_ops.h b/lib/libavb/avb_ops.h new file mode 100644 index 0000000000..8bbdc7c31b --- /dev/null +++ b/lib/libavb/avb_ops.h @@ -0,0 +1,292 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright (C) 2016 The Android Open Source Project + */ + +#if !defined(AVB_INSIDE_LIBAVB_H) && !defined(AVB_COMPILATION) +#error "Never include this file directly, include libavb.h instead." +#endif + +#ifndef AVB_OPS_H_ +#define AVB_OPS_H_ + +#include "avb_sysdeps.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Well-known names of named persistent values. */ +#define AVB_NPV_PERSISTENT_DIGEST_PREFIX "avb.persistent_digest." + +/* Return codes used for I/O operations. + * + * AVB_IO_RESULT_OK is returned if the requested operation was + * successful. + * + * AVB_IO_RESULT_ERROR_IO is returned if the underlying hardware (disk + * or other subsystem) encountered an I/O error. + * + * AVB_IO_RESULT_ERROR_OOM is returned if unable to allocate memory. + * + * AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION is returned if the requested + * partition does not exist. + * + * AVB_IO_RESULT_ERROR_RANGE_OUTSIDE_PARTITION is returned if the + * range of bytes requested to be read or written is outside the range + * of the partition. + * + * AVB_IO_RESULT_ERROR_NO_SUCH_VALUE is returned if a named persistent value + * does not exist. + * + * AVB_IO_RESULT_ERROR_INVALID_VALUE_SIZE is returned if a named persistent + * value size is not supported or does not match the expected size. + * + * AVB_IO_RESULT_ERROR_INSUFFICIENT_SPACE is returned if a buffer is too small + * for the requested operation. + */ +typedef enum { + AVB_IO_RESULT_OK, + AVB_IO_RESULT_ERROR_OOM, + AVB_IO_RESULT_ERROR_IO, + AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION, + AVB_IO_RESULT_ERROR_RANGE_OUTSIDE_PARTITION, + AVB_IO_RESULT_ERROR_NO_SUCH_VALUE, + AVB_IO_RESULT_ERROR_INVALID_VALUE_SIZE, + AVB_IO_RESULT_ERROR_INSUFFICIENT_SPACE, +} AvbIOResult; + +struct AvbOps; +typedef struct AvbOps AvbOps; + +/* Forward-declaration of operations in libavb_ab. */ +struct AvbABOps; + +/* Forward-declaration of operations in libavb_atx. */ +struct AvbAtxOps; + +/* High-level operations/functions/methods that are platform + * dependent. + * + * Operations may be added in the future so when implementing it + * always make sure to zero out sizeof(AvbOps) bytes of the struct to + * ensure that unimplemented operations are set to NULL. + */ +struct AvbOps { + /* This pointer can be used by the application/bootloader using + * libavb and is typically used in each operation to get a pointer + * to platform-specific resources. It cannot be used by libraries. + */ + void* user_data; + + /* If libavb_ab is used, this should point to the + * AvbABOps. Otherwise it must be set to NULL. + */ + struct AvbABOps* ab_ops; + + /* If libavb_atx is used, this should point to the + * AvbAtxOps. Otherwise it must be set to NULL. + */ + struct AvbAtxOps* atx_ops; + + /* Reads |num_bytes| from offset |offset| from partition with name + * |partition| (NUL-terminated UTF-8 string). If |offset| is + * negative, its absolute value should be interpreted as the number + * of bytes from the end of the partition. + * + * This function returns AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION if + * there is no partition with the given name, + * AVB_IO_RESULT_ERROR_RANGE_OUTSIDE_PARTITION if the requested + * |offset| is outside the partition, and AVB_IO_RESULT_ERROR_IO if + * there was an I/O error from the underlying I/O subsystem. If the + * operation succeeds as requested AVB_IO_RESULT_OK is returned and + * the data is available in |buffer|. + * + * The only time partial I/O may occur is if reading beyond the end + * of the partition. In this case the value returned in + * |out_num_read| may be smaller than |num_bytes|. + */ + AvbIOResult (*read_from_partition)(AvbOps* ops, + const char* partition, + int64_t offset, + size_t num_bytes, + void* buffer, + size_t* out_num_read); + + /* Gets the starting pointer of a partition that is pre-loaded in memory, and + * save it to |out_pointer|. The preloaded partition is expected to be + * |num_bytes|, where the actual preloaded byte count is returned in + * |out_num_bytes_preloaded|. |out_num_bytes_preloaded| must be no larger than + * |num_bytes|. + * + * This provides an alternative way to access a partition that is preloaded + * into memory without a full memory copy. When this function pointer is not + * set (has value NULL), or when the |out_pointer| is set to NULL as a result, + * |read_from_partition| will be used as the fallback. This function is mainly + * used for accessing the entire partition content to calculate its hash. + * + * Preloaded partition data must outlive the lifespan of the + * |AvbSlotVerifyData| structure that |avb_slot_verify| outputs. + */ + AvbIOResult (*get_preloaded_partition)(AvbOps* ops, + const char* partition, + size_t num_bytes, + uint8_t** out_pointer, + size_t* out_num_bytes_preloaded); + + /* Writes |num_bytes| from |bffer| at offset |offset| to partition + * with name |partition| (NUL-terminated UTF-8 string). If |offset| + * is negative, its absolute value should be interpreted as the + * number of bytes from the end of the partition. + * + * This function returns AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION if + * there is no partition with the given name, + * AVB_IO_RESULT_ERROR_RANGE_OUTSIDE_PARTITION if the requested + * byterange goes outside the partition, and AVB_IO_RESULT_ERROR_IO + * if there was an I/O error from the underlying I/O subsystem. If + * the operation succeeds as requested AVB_IO_RESULT_OK is + * returned. + * + * This function never does any partial I/O, it either transfers all + * of the requested bytes or returns an error. + */ + AvbIOResult (*write_to_partition)(AvbOps* ops, + const char* partition, + int64_t offset, + size_t num_bytes, + const void* buffer); + + /* Checks if the given public key used to sign the 'vbmeta' + * partition is trusted. Boot loaders typically compare this with + * embedded key material generated with 'avbtool + * extract_public_key'. + * + * The public key is in the array pointed to by |public_key_data| + * and is of |public_key_length| bytes. + * + * If there is no public key metadata (set with the avbtool option + * --public_key_metadata) then |public_key_metadata| will be set to + * NULL. Otherwise this field points to the data which is + * |public_key_metadata_length| bytes long. + * + * If AVB_IO_RESULT_OK is returned then |out_is_trusted| is set - + * true if trusted or false if untrusted. + */ + AvbIOResult (*validate_vbmeta_public_key)(AvbOps* ops, + const uint8_t* public_key_data, + size_t public_key_length, + const uint8_t* public_key_metadata, + size_t public_key_metadata_length, + bool* out_is_trusted); + + /* Gets the rollback index corresponding to the location given by + * |rollback_index_location|. The value is returned in + * |out_rollback_index|. Returns AVB_IO_RESULT_OK if the rollback + * index was retrieved, otherwise an error code. + * + * A device may have a limited amount of rollback index locations (say, + * one or four) so may error out if |rollback_index_location| exceeds + * this number. + */ + AvbIOResult (*read_rollback_index)(AvbOps* ops, + size_t rollback_index_location, + uint64_t* out_rollback_index); + + /* Sets the rollback index corresponding to the location given by + * |rollback_index_location| to |rollback_index|. Returns + * AVB_IO_RESULT_OK if the rollback index was set, otherwise an + * error code. + * + * A device may have a limited amount of rollback index locations (say, + * one or four) so may error out if |rollback_index_location| exceeds + * this number. + */ + AvbIOResult (*write_rollback_index)(AvbOps* ops, + size_t rollback_index_location, + uint64_t rollback_index); + + /* Gets whether the device is unlocked. The value is returned in + * |out_is_unlocked| (true if unlocked, false otherwise). Returns + * AVB_IO_RESULT_OK if the state was retrieved, otherwise an error + * code. + */ + AvbIOResult (*read_is_device_unlocked)(AvbOps* ops, bool* out_is_unlocked); + + /* Gets the unique partition GUID for a partition with name in + * |partition| (NUL-terminated UTF-8 string). The GUID is copied as + * a string into |guid_buf| of size |guid_buf_size| and will be NUL + * terminated. The string must be lower-case and properly + * hyphenated. For example: + * + * 527c1c6d-6361-4593-8842-3c78fcd39219 + * + * Returns AVB_IO_RESULT_OK on success, otherwise an error code. + */ + AvbIOResult (*get_unique_guid_for_partition)(AvbOps* ops, + const char* partition, + char* guid_buf, + size_t guid_buf_size); + + /* Gets the size of a partition with the name in |partition| + * (NUL-terminated UTF-8 string). Returns the value in + * |out_size_num_bytes|. + * + * Returns AVB_IO_RESULT_OK on success, otherwise an error code. + */ + AvbIOResult (*get_size_of_partition)(AvbOps* ops, + const char* partition, + uint64_t* out_size_num_bytes); + + /* Reads a persistent value corresponding to the given |name|. The value is + * returned in |out_buffer| which must point to |buffer_size| bytes. On + * success |out_num_bytes_read| contains the number of bytes read into + * |out_buffer|. If AVB_IO_RESULT_ERROR_INSUFFICIENT_SPACE is returned, + * |out_num_bytes_read| contains the number of bytes that would have been read + * which can be used to allocate a buffer. + * + * The |buffer_size| may be zero and the |out_buffer| may be NULL, but if + * |out_buffer| is NULL then |buffer_size| *must* be zero. + * + * Returns AVB_IO_RESULT_OK on success, otherwise an error code. + * + * If the value does not exist, is not supported, or is not populated, returns + * AVB_IO_RESULT_ERROR_NO_SUCH_VALUE. If |buffer_size| is smaller than the + * size of the stored value, returns AVB_IO_RESULT_ERROR_INSUFFICIENT_SPACE. + * + * This operation is currently only used to support persistent digests. If a + * device does not use persistent digests this function pointer can be set to + * NULL. + */ + AvbIOResult (*read_persistent_value)(AvbOps* ops, + const char* name, + size_t buffer_size, + uint8_t* out_buffer, + size_t* out_num_bytes_read); + + /* Writes a persistent value corresponding to the given |name|. The value is + * supplied in |value| which must point to |value_size| bytes. Any existing + * value with the same name is overwritten. If |value_size| is zero, future + * calls to |read_persistent_value| will return + * AVB_IO_RESULT_ERROR_NO_SUCH_VALUE. + * + * Returns AVB_IO_RESULT_OK on success, otherwise an error code. + * + * If the value |name| is not supported, returns + * AVB_IO_RESULT_ERROR_NO_SUCH_VALUE. If the |value_size| is not supported, + * returns AVB_IO_RESULT_ERROR_INVALID_VALUE_SIZE. + * + * This operation is currently only used to support persistent digests. If a + * device does not use persistent digests this function pointer can be set to + * NULL. + */ + AvbIOResult (*write_persistent_value)(AvbOps* ops, + const char* name, + size_t value_size, + const uint8_t* value); +}; + +#ifdef __cplusplus +} +#endif + +#endif /* AVB_OPS_H_ */ diff --git a/lib/libavb/avb_property_descriptor.c b/lib/libavb/avb_property_descriptor.c new file mode 100644 index 0000000000..589c96310a --- /dev/null +++ b/lib/libavb/avb_property_descriptor.c @@ -0,0 +1,166 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright (C) 2016 The Android Open Source Project + */ + +#include "avb_property_descriptor.h" +#include "avb_util.h" + +bool avb_property_descriptor_validate_and_byteswap( + const AvbPropertyDescriptor* src, AvbPropertyDescriptor* dest) { + uint64_t expected_size; + + avb_memcpy(dest, src, sizeof(AvbPropertyDescriptor)); + + if (!avb_descriptor_validate_and_byteswap((const AvbDescriptor*)src, + (AvbDescriptor*)dest)) + return false; + + if (dest->parent_descriptor.tag != AVB_DESCRIPTOR_TAG_PROPERTY) { + avb_error("Invalid tag for property descriptor.\n"); + return false; + } + + dest->key_num_bytes = avb_be64toh(dest->key_num_bytes); + dest->value_num_bytes = avb_be64toh(dest->value_num_bytes); + + /* Check that key and value are fully contained. */ + expected_size = sizeof(AvbPropertyDescriptor) - sizeof(AvbDescriptor) + 2; + if (!avb_safe_add_to(&expected_size, dest->key_num_bytes) || + !avb_safe_add_to(&expected_size, dest->value_num_bytes)) { + avb_error("Overflow while adding up sizes.\n"); + return false; + } + if (expected_size > dest->parent_descriptor.num_bytes_following) { + avb_error("Descriptor payload size overflow.\n"); + return false; + } + + return true; +} + +typedef struct { + const char* key; + size_t key_size; + const char* ret_value; + size_t ret_value_size; +} PropertyIteratorData; + +static bool property_lookup_desc_foreach(const AvbDescriptor* header, + void* user_data) { + PropertyIteratorData* data = (PropertyIteratorData*)user_data; + AvbPropertyDescriptor prop_desc; + const uint8_t* p; + bool ret = true; + + if (header->tag != AVB_DESCRIPTOR_TAG_PROPERTY) { + goto out; + } + + if (!avb_property_descriptor_validate_and_byteswap( + (const AvbPropertyDescriptor*)header, &prop_desc)) { + goto out; + } + + p = (const uint8_t*)header; + if (p[sizeof(AvbPropertyDescriptor) + prop_desc.key_num_bytes] != 0) { + avb_error("No terminating NUL byte in key.\n"); + goto out; + } + + if (data->key_size == prop_desc.key_num_bytes) { + if (avb_memcmp(p + sizeof(AvbPropertyDescriptor), + data->key, + data->key_size) == 0) { + data->ret_value = (const char*)(p + sizeof(AvbPropertyDescriptor) + + prop_desc.key_num_bytes + 1); + data->ret_value_size = prop_desc.value_num_bytes; + /* Stop iterating. */ + ret = false; + goto out; + } + } + +out: + return ret; +} + +const char* avb_property_lookup(const uint8_t* image_data, + size_t image_size, + const char* key, + size_t key_size, + size_t* out_value_size) { + PropertyIteratorData data; + + if (key_size == 0) { + key_size = avb_strlen(key); + } + + data.key = key; + data.key_size = key_size; + + if (avb_descriptor_foreach( + image_data, image_size, property_lookup_desc_foreach, &data) == 0) { + if (out_value_size != NULL) { + *out_value_size = data.ret_value_size; + } + return data.ret_value; + } + + if (out_value_size != NULL) { + *out_value_size = 0; + } + return NULL; +} + +bool avb_property_lookup_uint64(const uint8_t* image_data, + size_t image_size, + const char* key, + size_t key_size, + uint64_t* out_value) { + const char* value; + bool ret = false; + uint64_t parsed_val; + int base; + int n; + + value = avb_property_lookup(image_data, image_size, key, key_size, NULL); + if (value == NULL) { + goto out; + } + + base = 10; + if (avb_memcmp(value, "0x", 2) == 0) { + base = 16; + value += 2; + } + + parsed_val = 0; + for (n = 0; value[n] != '\0'; n++) { + int c = value[n]; + int digit; + + parsed_val *= base; + + if (c >= '0' && c <= '9') { + digit = c - '0'; + } else if (base == 16 && c >= 'a' && c <= 'f') { + digit = c - 'a' + 10; + } else if (base == 16 && c >= 'A' && c <= 'F') { + digit = c - 'A' + 10; + } else { + avb_error("Invalid digit.\n"); + goto out; + } + + parsed_val += digit; + } + + ret = true; + if (out_value != NULL) { + *out_value = parsed_val; + } + +out: + return ret; +} diff --git a/lib/libavb/avb_property_descriptor.h b/lib/libavb/avb_property_descriptor.h new file mode 100644 index 0000000000..917c58f9fe --- /dev/null +++ b/lib/libavb/avb_property_descriptor.h @@ -0,0 +1,88 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright (C) 2016 The Android Open Source Project + */ + +#if !defined(AVB_INSIDE_LIBAVB_H) && !defined(AVB_COMPILATION) +#error "Never include this file directly, include libavb.h instead." +#endif + +#ifndef AVB_PROPERTY_DESCRIPTOR_H_ +#define AVB_PROPERTY_DESCRIPTOR_H_ + +#include "avb_descriptor.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* A descriptor for properties (free-form key/value pairs). + * + * Following this struct are |key_num_bytes| bytes of key data, + * followed by a NUL byte, then |value_num_bytes| bytes of value data, + * followed by a NUL byte and then enough padding to make the combined + * size a multiple of 8. + */ +typedef struct AvbPropertyDescriptor { + AvbDescriptor parent_descriptor; + uint64_t key_num_bytes; + uint64_t value_num_bytes; +} AVB_ATTR_PACKED AvbPropertyDescriptor; + +/* Copies |src| to |dest| and validates, byte-swapping fields in the + * process if needed. Returns true if valid, false if invalid. + * + * Data following the struct is not validated nor copied. + */ +bool avb_property_descriptor_validate_and_byteswap( + const AvbPropertyDescriptor* src, + AvbPropertyDescriptor* dest) AVB_ATTR_WARN_UNUSED_RESULT; + +/* Convenience function for looking up the value for a property with + * name |key| in a vbmeta image. If |key_size| is 0, |key| must be + * NUL-terminated. + * + * The |image_data| parameter must be a pointer to a vbmeta image of + * size |image_size|. + * + * This function returns a pointer to the value inside the passed-in + * image or NULL if not found. Note that the value is always + * guaranteed to be followed by a NUL byte. + * + * If the value was found and |out_value_size| is not NULL, the size + * of the value is returned there. + * + * This function is O(n) in number of descriptors so if you need to + * look up a lot of values, you may want to build a more efficient + * lookup-table by manually walking all descriptors using + * avb_descriptor_foreach(). + * + * Before using this function, you MUST verify |image_data| with + * avb_vbmeta_image_verify() and reject it unless it's signed by a + * known good public key. + */ +const char* avb_property_lookup(const uint8_t* image_data, + size_t image_size, + const char* key, + size_t key_size, + size_t* out_value_size) + AVB_ATTR_WARN_UNUSED_RESULT; + +/* Like avb_property_lookup() but parses the intial portions of the + * value as an unsigned 64-bit integer. Both decimal and hexadecimal + * representations (e.g. "0x2a") are supported. Returns false on + * failure and true on success. On success, the parsed value is + * returned in |out_value|. + */ +bool avb_property_lookup_uint64(const uint8_t* image_data, + size_t image_size, + const char* key, + size_t key_size, + uint64_t* out_value) + AVB_ATTR_WARN_UNUSED_RESULT; + +#ifdef __cplusplus +} +#endif + +#endif /* AVB_PROPERTY_DESCRIPTOR_H_ */ diff --git a/lib/libavb/avb_rsa.c b/lib/libavb/avb_rsa.c new file mode 100644 index 0000000000..bbf15626b8 --- /dev/null +++ b/lib/libavb/avb_rsa.c @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: MIT OR BSD-3-Clause +/* + * Copyright (C) 2016 The Android Open Source Project + */ + +/* Implementation of RSA signature verification which uses a pre-processed + * key for computation. The code extends libmincrypt RSA verification code to + * support multiple RSA key lengths and hash digest algorithms. + */ + +#include "avb_rsa.h" +#include "avb_sha.h" +#include "avb_util.h" +#include "avb_vbmeta_image.h" + +typedef struct IAvbKey { + unsigned int len; /* Length of n[] in number of uint32_t */ + uint32_t n0inv; /* -1 / n[0] mod 2^32 */ + uint32_t* n; /* modulus as array (host-byte order) */ + uint32_t* rr; /* R^2 as array (host-byte order) */ +} IAvbKey; + +static IAvbKey* iavb_parse_key_data(const uint8_t* data, size_t length) { + AvbRSAPublicKeyHeader h; + IAvbKey* key = NULL; + size_t expected_length; + unsigned int i; + const uint8_t* n; + const uint8_t* rr; + + if (!avb_rsa_public_key_header_validate_and_byteswap( + (const AvbRSAPublicKeyHeader*)data, &h)) { + avb_error("Invalid key.\n"); + goto fail; + } + + if (!(h.key_num_bits == 2048 || h.key_num_bits == 4096 || + h.key_num_bits == 8192)) { + avb_error("Unexpected key length.\n"); + goto fail; + } + + expected_length = sizeof(AvbRSAPublicKeyHeader) + 2 * h.key_num_bits / 8; + if (length != expected_length) { + avb_error("Key does not match expected length.\n"); + goto fail; + } + + n = data + sizeof(AvbRSAPublicKeyHeader); + rr = data + sizeof(AvbRSAPublicKeyHeader) + h.key_num_bits / 8; + + /* Store n and rr following the key header so we only have to do one + * allocation. + */ + key = (IAvbKey*)(avb_malloc(sizeof(IAvbKey) + 2 * h.key_num_bits / 8)); + if (key == NULL) { + goto fail; + } + + key->len = h.key_num_bits / 32; + key->n0inv = h.n0inv; + key->n = (uint32_t*)(key + 1); /* Skip ahead sizeof(IAvbKey) bytes. */ + key->rr = key->n + key->len; + + /* Crypto-code below (modpowF4() and friends) expects the key in + * little-endian format (rather than the format we're storing the + * key in), so convert it. + */ + for (i = 0; i < key->len; i++) { + key->n[i] = avb_be32toh(((uint32_t*)n)[key->len - i - 1]); + key->rr[i] = avb_be32toh(((uint32_t*)rr)[key->len - i - 1]); + } + return key; + +fail: + if (key != NULL) { + avb_free(key); + } + return NULL; +} + +static void iavb_free_parsed_key(IAvbKey* key) { + avb_free(key); +} + +/* a[] -= mod */ +static void subM(const IAvbKey* key, uint32_t* a) { + int64_t A = 0; + uint32_t i; + for (i = 0; i < key->len; ++i) { + A += (uint64_t)a[i] - key->n[i]; + a[i] = (uint32_t)A; + A >>= 32; + } +} + +/* return a[] >= mod */ +static int geM(const IAvbKey* key, uint32_t* a) { + uint32_t i; + for (i = key->len; i;) { + --i; + if (a[i] < key->n[i]) { + return 0; + } + if (a[i] > key->n[i]) { + return 1; + } + } + return 1; /* equal */ +} + +/* montgomery c[] += a * b[] / R % mod */ +static void montMulAdd(const IAvbKey* key, + uint32_t* c, + const uint32_t a, + const uint32_t* b) { + uint64_t A = (uint64_t)a * b[0] + c[0]; + uint32_t d0 = (uint32_t)A * key->n0inv; + uint64_t B = (uint64_t)d0 * key->n[0] + (uint32_t)A; + uint32_t i; + + for (i = 1; i < key->len; ++i) { + A = (A >> 32) + (uint64_t)a * b[i] + c[i]; + B = (B >> 32) + (uint64_t)d0 * key->n[i] + (uint32_t)A; + c[i - 1] = (uint32_t)B; + } + + A = (A >> 32) + (B >> 32); + + c[i - 1] = (uint32_t)A; + + if (A >> 32) { + subM(key, c); + } +} + +/* montgomery c[] = a[] * b[] / R % mod */ +static void montMul(const IAvbKey* key, uint32_t* c, uint32_t* a, uint32_t* b) { + uint32_t i; + for (i = 0; i < key->len; ++i) { + c[i] = 0; + } + for (i = 0; i < key->len; ++i) { + montMulAdd(key, c, a[i], b); + } +} + +/* In-place public exponentiation. (65537} + * Input and output big-endian byte array in inout. + */ +static void modpowF4(const IAvbKey* key, uint8_t* inout) { + uint32_t* a = (uint32_t*)avb_malloc(key->len * sizeof(uint32_t)); + uint32_t* aR = (uint32_t*)avb_malloc(key->len * sizeof(uint32_t)); + uint32_t* aaR = (uint32_t*)avb_malloc(key->len * sizeof(uint32_t)); + if (a == NULL || aR == NULL || aaR == NULL) { + goto out; + } + + uint32_t* aaa = aaR; /* Re-use location. */ + int i; + + /* Convert from big endian byte array to little endian word array. */ + for (i = 0; i < (int)key->len; ++i) { + uint32_t tmp = (inout[((key->len - 1 - i) * 4) + 0] << 24) | + (inout[((key->len - 1 - i) * 4) + 1] << 16) | + (inout[((key->len - 1 - i) * 4) + 2] << 8) | + (inout[((key->len - 1 - i) * 4) + 3] << 0); + a[i] = tmp; + } + + montMul(key, aR, a, key->rr); /* aR = a * RR / R mod M */ + for (i = 0; i < 16; i += 2) { + montMul(key, aaR, aR, aR); /* aaR = aR * aR / R mod M */ + montMul(key, aR, aaR, aaR); /* aR = aaR * aaR / R mod M */ + } + montMul(key, aaa, aR, a); /* aaa = aR * a / R mod M */ + + /* Make sure aaa < mod; aaa is at most 1x mod too large. */ + if (geM(key, aaa)) { + subM(key, aaa); + } + + /* Convert to bigendian byte array */ + for (i = (int)key->len - 1; i >= 0; --i) { + uint32_t tmp = aaa[i]; + *inout++ = (uint8_t)(tmp >> 24); + *inout++ = (uint8_t)(tmp >> 16); + *inout++ = (uint8_t)(tmp >> 8); + *inout++ = (uint8_t)(tmp >> 0); + } + +out: + if (a != NULL) { + avb_free(a); + } + if (aR != NULL) { + avb_free(aR); + } + if (aaR != NULL) { + avb_free(aaR); + } +} + +/* Verify a RSA PKCS1.5 signature against an expected hash. + * Returns false on failure, true on success. + */ +bool avb_rsa_verify(const uint8_t* key, + size_t key_num_bytes, + const uint8_t* sig, + size_t sig_num_bytes, + const uint8_t* hash, + size_t hash_num_bytes, + const uint8_t* padding, + size_t padding_num_bytes) { + uint8_t* buf = NULL; + IAvbKey* parsed_key = NULL; + bool success = false; + + if (key == NULL || sig == NULL || hash == NULL || padding == NULL) { + avb_error("Invalid input.\n"); + goto out; + } + + parsed_key = iavb_parse_key_data(key, key_num_bytes); + if (parsed_key == NULL) { + avb_error("Error parsing key.\n"); + goto out; + } + + if (sig_num_bytes != (parsed_key->len * sizeof(uint32_t))) { + avb_error("Signature length does not match key length.\n"); + goto out; + } + + if (padding_num_bytes != sig_num_bytes - hash_num_bytes) { + avb_error("Padding length does not match hash and signature lengths.\n"); + goto out; + } + + buf = (uint8_t*)avb_malloc(sig_num_bytes); + if (buf == NULL) { + avb_error("Error allocating memory.\n"); + goto out; + } + avb_memcpy(buf, sig, sig_num_bytes); + + modpowF4(parsed_key, buf); + + /* Check padding bytes. + * + * Even though there are probably no timing issues here, we use + * avb_safe_memcmp() just to be on the safe side. + */ + if (avb_safe_memcmp(buf, padding, padding_num_bytes)) { + avb_error("Padding check failed.\n"); + goto out; + } + + /* Check hash. */ + if (avb_safe_memcmp(buf + padding_num_bytes, hash, hash_num_bytes)) { + avb_error("Hash check failed.\n"); + goto out; + } + + success = true; + +out: + if (parsed_key != NULL) { + iavb_free_parsed_key(parsed_key); + } + if (buf != NULL) { + avb_free(buf); + } + return success; +} diff --git a/lib/libavb/avb_rsa.h b/lib/libavb/avb_rsa.h new file mode 100644 index 0000000000..8741790e09 --- /dev/null +++ b/lib/libavb/avb_rsa.h @@ -0,0 +1,54 @@ +/* SPDX-License-Identifier: MIT OR BSD-3-Clause */ +/* + * Copyright (C) 2016 The Android Open Source Project + */ + +/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifdef AVB_INSIDE_LIBAVB_H +#error "You can't include avb_rsa.h in the public header libavb.h." +#endif + +#ifndef AVB_COMPILATION +#error "Never include this file, it may only be used from internal avb code." +#endif + +#ifndef AVB_RSA_H_ +#define AVB_RSA_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "avb_crypto.h" +#include "avb_sysdeps.h" + +/* Using the key given by |key|, verify a RSA signature |sig| of + * length |sig_num_bytes| against an expected |hash| of length + * |hash_num_bytes|. The padding to expect must be passed in using + * |padding| of length |padding_num_bytes|. + * + * The data in |key| must match the format defined in + * |AvbRSAPublicKeyHeader|, including the two large numbers + * following. The |key_num_bytes| must be the size of the entire + * serialized key. + * + * Returns false if verification fails, true otherwise. + */ +bool avb_rsa_verify(const uint8_t* key, + size_t key_num_bytes, + const uint8_t* sig, + size_t sig_num_bytes, + const uint8_t* hash, + size_t hash_num_bytes, + const uint8_t* padding, + size_t padding_num_bytes) AVB_ATTR_WARN_UNUSED_RESULT; + +#ifdef __cplusplus +} +#endif + +#endif /* AVB_RSA_H_ */ diff --git a/lib/libavb/avb_sha.h b/lib/libavb/avb_sha.h new file mode 100644 index 0000000000..365aaadc2f --- /dev/null +++ b/lib/libavb/avb_sha.h @@ -0,0 +1,71 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright (C) 2016 The Android Open Source Project + */ + +#ifdef AVB_INSIDE_LIBAVB_H +#error "You can't include avb_sha.h in the public header libavb.h." +#endif + +#ifndef AVB_COMPILATION +#error "Never include this file, it may only be used from internal avb code." +#endif + +#ifndef AVB_SHA_H_ +#define AVB_SHA_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "avb_crypto.h" +#include "avb_sysdeps.h" + +/* Block size in bytes of a SHA-256 digest. */ +#define AVB_SHA256_BLOCK_SIZE 64 + + +/* Block size in bytes of a SHA-512 digest. */ +#define AVB_SHA512_BLOCK_SIZE 128 + +/* Data structure used for SHA-256. */ +typedef struct { + uint32_t h[8]; + uint32_t tot_len; + uint32_t len; + uint8_t block[2 * AVB_SHA256_BLOCK_SIZE]; + uint8_t buf[AVB_SHA256_DIGEST_SIZE]; /* Used for storing the final digest. */ +} AvbSHA256Ctx; + +/* Data structure used for SHA-512. */ +typedef struct { + uint64_t h[8]; + uint32_t tot_len; + uint32_t len; + uint8_t block[2 * AVB_SHA512_BLOCK_SIZE]; + uint8_t buf[AVB_SHA512_DIGEST_SIZE]; /* Used for storing the final digest. */ +} AvbSHA512Ctx; + +/* Initializes the SHA-256 context. */ +void avb_sha256_init(AvbSHA256Ctx* ctx); + +/* Updates the SHA-256 context with |len| bytes from |data|. */ +void avb_sha256_update(AvbSHA256Ctx* ctx, const uint8_t* data, uint32_t len); + +/* Returns the SHA-256 digest. */ +uint8_t* avb_sha256_final(AvbSHA256Ctx* ctx) AVB_ATTR_WARN_UNUSED_RESULT; + +/* Initializes the SHA-512 context. */ +void avb_sha512_init(AvbSHA512Ctx* ctx); + +/* Updates the SHA-512 context with |len| bytes from |data|. */ +void avb_sha512_update(AvbSHA512Ctx* ctx, const uint8_t* data, uint32_t len); + +/* Returns the SHA-512 digest. */ +uint8_t* avb_sha512_final(AvbSHA512Ctx* ctx) AVB_ATTR_WARN_UNUSED_RESULT; + +#ifdef __cplusplus +} +#endif + +#endif /* AVB_SHA_H_ */ diff --git a/lib/libavb/avb_sha256.c b/lib/libavb/avb_sha256.c new file mode 100644 index 0000000000..d24c7015f6 --- /dev/null +++ b/lib/libavb/avb_sha256.c @@ -0,0 +1,363 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (C) 2005, 2007 Olivier Gay <olivier.gay@a3.epfl.ch> + * All rights reserved. + * + * FIPS 180-2 SHA-224/256/384/512 implementation + * Last update: 02/02/2007 + * Issue date: 04/30/2005 + */ + +#include "avb_sha.h" + +#define SHFR(x, n) (x >> n) +#define ROTR(x, n) ((x >> n) | (x << ((sizeof(x) << 3) - n))) +#define ROTL(x, n) ((x << n) | (x >> ((sizeof(x) << 3) - n))) +#define CH(x, y, z) ((x & y) ^ (~x & z)) +#define MAJ(x, y, z) ((x & y) ^ (x & z) ^ (y & z)) + +#define SHA256_F1(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22)) +#define SHA256_F2(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25)) +#define SHA256_F3(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHFR(x, 3)) +#define SHA256_F4(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHFR(x, 10)) + +#define UNPACK32(x, str) \ + { \ + *((str) + 3) = (uint8_t)((x)); \ + *((str) + 2) = (uint8_t)((x) >> 8); \ + *((str) + 1) = (uint8_t)((x) >> 16); \ + *((str) + 0) = (uint8_t)((x) >> 24); \ + } + +#define PACK32(str, x) \ + { \ + *(x) = ((uint32_t) * ((str) + 3)) | ((uint32_t) * ((str) + 2) << 8) | \ + ((uint32_t) * ((str) + 1) << 16) | \ + ((uint32_t) * ((str) + 0) << 24); \ + } + +/* Macros used for loops unrolling */ + +#define SHA256_SCR(i) \ + { w[i] = SHA256_F4(w[i - 2]) + w[i - 7] + SHA256_F3(w[i - 15]) + w[i - 16]; } + +#define SHA256_EXP(a, b, c, d, e, f, g, h, j) \ + { \ + t1 = wv[h] + SHA256_F2(wv[e]) + CH(wv[e], wv[f], wv[g]) + sha256_k[j] + \ + w[j]; \ + t2 = SHA256_F1(wv[a]) + MAJ(wv[a], wv[b], wv[c]); \ + wv[d] += t1; \ + wv[h] = t1 + t2; \ + } + +static const uint32_t sha256_h0[8] = {0x6a09e667, + 0xbb67ae85, + 0x3c6ef372, + 0xa54ff53a, + 0x510e527f, + 0x9b05688c, + 0x1f83d9ab, + 0x5be0cd19}; + +static const uint32_t sha256_k[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, + 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, + 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, + 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, + 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, + 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2}; + +/* SHA-256 implementation */ +void avb_sha256_init(AvbSHA256Ctx* ctx) { +#ifndef UNROLL_LOOPS + int i; + for (i = 0; i < 8; i++) { + ctx->h[i] = sha256_h0[i]; + } +#else + ctx->h[0] = sha256_h0[0]; + ctx->h[1] = sha256_h0[1]; + ctx->h[2] = sha256_h0[2]; + ctx->h[3] = sha256_h0[3]; + ctx->h[4] = sha256_h0[4]; + ctx->h[5] = sha256_h0[5]; + ctx->h[6] = sha256_h0[6]; + ctx->h[7] = sha256_h0[7]; +#endif /* !UNROLL_LOOPS */ + + ctx->len = 0; + ctx->tot_len = 0; +} + +static void SHA256_transform(AvbSHA256Ctx* ctx, + const uint8_t* message, + unsigned int block_nb) { + uint32_t w[64]; + uint32_t wv[8]; + uint32_t t1, t2; + const unsigned char* sub_block; + int i; + +#ifndef UNROLL_LOOPS + int j; +#endif + + for (i = 0; i < (int)block_nb; i++) { + sub_block = message + (i << 6); + +#ifndef UNROLL_LOOPS + for (j = 0; j < 16; j++) { + PACK32(&sub_block[j << 2], &w[j]); + } + + for (j = 16; j < 64; j++) { + SHA256_SCR(j); + } + + for (j = 0; j < 8; j++) { + wv[j] = ctx->h[j]; + } + + for (j = 0; j < 64; j++) { + t1 = wv[7] + SHA256_F2(wv[4]) + CH(wv[4], wv[5], wv[6]) + sha256_k[j] + + w[j]; + t2 = SHA256_F1(wv[0]) + MAJ(wv[0], wv[1], wv[2]); + wv[7] = wv[6]; + wv[6] = wv[5]; + wv[5] = wv[4]; + wv[4] = wv[3] + t1; + wv[3] = wv[2]; + wv[2] = wv[1]; + wv[1] = wv[0]; + wv[0] = t1 + t2; + } + + for (j = 0; j < 8; j++) { + ctx->h[j] += wv[j]; + } +#else + PACK32(&sub_block[0], &w[0]); + PACK32(&sub_block[4], &w[1]); + PACK32(&sub_block[8], &w[2]); + PACK32(&sub_block[12], &w[3]); + PACK32(&sub_block[16], &w[4]); + PACK32(&sub_block[20], &w[5]); + PACK32(&sub_block[24], &w[6]); + PACK32(&sub_block[28], &w[7]); + PACK32(&sub_block[32], &w[8]); + PACK32(&sub_block[36], &w[9]); + PACK32(&sub_block[40], &w[10]); + PACK32(&sub_block[44], &w[11]); + PACK32(&sub_block[48], &w[12]); + PACK32(&sub_block[52], &w[13]); + PACK32(&sub_block[56], &w[14]); + PACK32(&sub_block[60], &w[15]); + + SHA256_SCR(16); + SHA256_SCR(17); + SHA256_SCR(18); + SHA256_SCR(19); + SHA256_SCR(20); + SHA256_SCR(21); + SHA256_SCR(22); + SHA256_SCR(23); + SHA256_SCR(24); + SHA256_SCR(25); + SHA256_SCR(26); + SHA256_SCR(27); + SHA256_SCR(28); + SHA256_SCR(29); + SHA256_SCR(30); + SHA256_SCR(31); + SHA256_SCR(32); + SHA256_SCR(33); + SHA256_SCR(34); + SHA256_SCR(35); + SHA256_SCR(36); + SHA256_SCR(37); + SHA256_SCR(38); + SHA256_SCR(39); + SHA256_SCR(40); + SHA256_SCR(41); + SHA256_SCR(42); + SHA256_SCR(43); + SHA256_SCR(44); + SHA256_SCR(45); + SHA256_SCR(46); + SHA256_SCR(47); + SHA256_SCR(48); + SHA256_SCR(49); + SHA256_SCR(50); + SHA256_SCR(51); + SHA256_SCR(52); + SHA256_SCR(53); + SHA256_SCR(54); + SHA256_SCR(55); + SHA256_SCR(56); + SHA256_SCR(57); + SHA256_SCR(58); + SHA256_SCR(59); + SHA256_SCR(60); + SHA256_SCR(61); + SHA256_SCR(62); + SHA256_SCR(63); + + wv[0] = ctx->h[0]; + wv[1] = ctx->h[1]; + wv[2] = ctx->h[2]; + wv[3] = ctx->h[3]; + wv[4] = ctx->h[4]; + wv[5] = ctx->h[5]; + wv[6] = ctx->h[6]; + wv[7] = ctx->h[7]; + + SHA256_EXP(0, 1, 2, 3, 4, 5, 6, 7, 0); + SHA256_EXP(7, 0, 1, 2, 3, 4, 5, 6, 1); + SHA256_EXP(6, 7, 0, 1, 2, 3, 4, 5, 2); + SHA256_EXP(5, 6, 7, 0, 1, 2, 3, 4, 3); + SHA256_EXP(4, 5, 6, 7, 0, 1, 2, 3, 4); + SHA256_EXP(3, 4, 5, 6, 7, 0, 1, 2, 5); + SHA256_EXP(2, 3, 4, 5, 6, 7, 0, 1, 6); + SHA256_EXP(1, 2, 3, 4, 5, 6, 7, 0, 7); + SHA256_EXP(0, 1, 2, 3, 4, 5, 6, 7, 8); + SHA256_EXP(7, 0, 1, 2, 3, 4, 5, 6, 9); + SHA256_EXP(6, 7, 0, 1, 2, 3, 4, 5, 10); + SHA256_EXP(5, 6, 7, 0, 1, 2, 3, 4, 11); + SHA256_EXP(4, 5, 6, 7, 0, 1, 2, 3, 12); + SHA256_EXP(3, 4, 5, 6, 7, 0, 1, 2, 13); + SHA256_EXP(2, 3, 4, 5, 6, 7, 0, 1, 14); + SHA256_EXP(1, 2, 3, 4, 5, 6, 7, 0, 15); + SHA256_EXP(0, 1, 2, 3, 4, 5, 6, 7, 16); + SHA256_EXP(7, 0, 1, 2, 3, 4, 5, 6, 17); + SHA256_EXP(6, 7, 0, 1, 2, 3, 4, 5, 18); + SHA256_EXP(5, 6, 7, 0, 1, 2, 3, 4, 19); + SHA256_EXP(4, 5, 6, 7, 0, 1, 2, 3, 20); + SHA256_EXP(3, 4, 5, 6, 7, 0, 1, 2, 21); + SHA256_EXP(2, 3, 4, 5, 6, 7, 0, 1, 22); + SHA256_EXP(1, 2, 3, 4, 5, 6, 7, 0, 23); + SHA256_EXP(0, 1, 2, 3, 4, 5, 6, 7, 24); + SHA256_EXP(7, 0, 1, 2, 3, 4, 5, 6, 25); + SHA256_EXP(6, 7, 0, 1, 2, 3, 4, 5, 26); + SHA256_EXP(5, 6, 7, 0, 1, 2, 3, 4, 27); + SHA256_EXP(4, 5, 6, 7, 0, 1, 2, 3, 28); + SHA256_EXP(3, 4, 5, 6, 7, 0, 1, 2, 29); + SHA256_EXP(2, 3, 4, 5, 6, 7, 0, 1, 30); + SHA256_EXP(1, 2, 3, 4, 5, 6, 7, 0, 31); + SHA256_EXP(0, 1, 2, 3, 4, 5, 6, 7, 32); + SHA256_EXP(7, 0, 1, 2, 3, 4, 5, 6, 33); + SHA256_EXP(6, 7, 0, 1, 2, 3, 4, 5, 34); + SHA256_EXP(5, 6, 7, 0, 1, 2, 3, 4, 35); + SHA256_EXP(4, 5, 6, 7, 0, 1, 2, 3, 36); + SHA256_EXP(3, 4, 5, 6, 7, 0, 1, 2, 37); + SHA256_EXP(2, 3, 4, 5, 6, 7, 0, 1, 38); + SHA256_EXP(1, 2, 3, 4, 5, 6, 7, 0, 39); + SHA256_EXP(0, 1, 2, 3, 4, 5, 6, 7, 40); + SHA256_EXP(7, 0, 1, 2, 3, 4, 5, 6, 41); + SHA256_EXP(6, 7, 0, 1, 2, 3, 4, 5, 42); + SHA256_EXP(5, 6, 7, 0, 1, 2, 3, 4, 43); + SHA256_EXP(4, 5, 6, 7, 0, 1, 2, 3, 44); + SHA256_EXP(3, 4, 5, 6, 7, 0, 1, 2, 45); + SHA256_EXP(2, 3, 4, 5, 6, 7, 0, 1, 46); + SHA256_EXP(1, 2, 3, 4, 5, 6, 7, 0, 47); + SHA256_EXP(0, 1, 2, 3, 4, 5, 6, 7, 48); + SHA256_EXP(7, 0, 1, 2, 3, 4, 5, 6, 49); + SHA256_EXP(6, 7, 0, 1, 2, 3, 4, 5, 50); + SHA256_EXP(5, 6, 7, 0, 1, 2, 3, 4, 51); + SHA256_EXP(4, 5, 6, 7, 0, 1, 2, 3, 52); + SHA256_EXP(3, 4, 5, 6, 7, 0, 1, 2, 53); + SHA256_EXP(2, 3, 4, 5, 6, 7, 0, 1, 54); + SHA256_EXP(1, 2, 3, 4, 5, 6, 7, 0, 55); + SHA256_EXP(0, 1, 2, 3, 4, 5, 6, 7, 56); + SHA256_EXP(7, 0, 1, 2, 3, 4, 5, 6, 57); + SHA256_EXP(6, 7, 0, 1, 2, 3, 4, 5, 58); + SHA256_EXP(5, 6, 7, 0, 1, 2, 3, 4, 59); + SHA256_EXP(4, 5, 6, 7, 0, 1, 2, 3, 60); + SHA256_EXP(3, 4, 5, 6, 7, 0, 1, 2, 61); + SHA256_EXP(2, 3, 4, 5, 6, 7, 0, 1, 62); + SHA256_EXP(1, 2, 3, 4, 5, 6, 7, 0, 63); + + ctx->h[0] += wv[0]; + ctx->h[1] += wv[1]; + ctx->h[2] += wv[2]; + ctx->h[3] += wv[3]; + ctx->h[4] += wv[4]; + ctx->h[5] += wv[5]; + ctx->h[6] += wv[6]; + ctx->h[7] += wv[7]; +#endif /* !UNROLL_LOOPS */ + } +} + +void avb_sha256_update(AvbSHA256Ctx* ctx, const uint8_t* data, uint32_t len) { + unsigned int block_nb; + unsigned int new_len, rem_len, tmp_len; + const uint8_t* shifted_data; + + tmp_len = AVB_SHA256_BLOCK_SIZE - ctx->len; + rem_len = len < tmp_len ? len : tmp_len; + + avb_memcpy(&ctx->block[ctx->len], data, rem_len); + + if (ctx->len + len < AVB_SHA256_BLOCK_SIZE) { + ctx->len += len; + return; + } + + new_len = len - rem_len; + block_nb = new_len / AVB_SHA256_BLOCK_SIZE; + + shifted_data = data + rem_len; + + SHA256_transform(ctx, ctx->block, 1); + SHA256_transform(ctx, shifted_data, block_nb); + + rem_len = new_len % AVB_SHA256_BLOCK_SIZE; + + avb_memcpy(ctx->block, &shifted_data[block_nb << 6], rem_len); + + ctx->len = rem_len; + ctx->tot_len += (block_nb + 1) << 6; +} + +uint8_t* avb_sha256_final(AvbSHA256Ctx* ctx) { + unsigned int block_nb; + unsigned int pm_len; + unsigned int len_b; +#ifndef UNROLL_LOOPS + int i; +#endif + + block_nb = + (1 + ((AVB_SHA256_BLOCK_SIZE - 9) < (ctx->len % AVB_SHA256_BLOCK_SIZE))); + + len_b = (ctx->tot_len + ctx->len) << 3; + pm_len = block_nb << 6; + + avb_memset(ctx->block + ctx->len, 0, pm_len - ctx->len); + ctx->block[ctx->len] = 0x80; + UNPACK32(len_b, ctx->block + pm_len - 4); + + SHA256_transform(ctx, ctx->block, block_nb); + +#ifndef UNROLL_LOOPS + for (i = 0; i < 8; i++) { + UNPACK32(ctx->h[i], &ctx->buf[i << 2]); + } +#else + UNPACK32(ctx->h[0], &ctx->buf[0]); + UNPACK32(ctx->h[1], &ctx->buf[4]); + UNPACK32(ctx->h[2], &ctx->buf[8]); + UNPACK32(ctx->h[3], &ctx->buf[12]); + UNPACK32(ctx->h[4], &ctx->buf[16]); + UNPACK32(ctx->h[5], &ctx->buf[20]); + UNPACK32(ctx->h[6], &ctx->buf[24]); + UNPACK32(ctx->h[7], &ctx->buf[28]); +#endif /* !UNROLL_LOOPS */ + + return ctx->buf; +} diff --git a/lib/libavb/avb_sha512.c b/lib/libavb/avb_sha512.c new file mode 100644 index 0000000000..a5e7297aa7 --- /dev/null +++ b/lib/libavb/avb_sha512.c @@ -0,0 +1,361 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (C) 2005, 2007 Olivier Gay <olivier.gay@a3.epfl.ch> + * All rights reserved. + * + * FIPS 180-2 SHA-224/256/384/512 implementation + * Last update: 02/02/2007 + * Issue date: 04/30/2005 + */ + +#include "avb_sha.h" + +#define SHFR(x, n) (x >> n) +#define ROTR(x, n) ((x >> n) | (x << ((sizeof(x) << 3) - n))) +#define ROTL(x, n) ((x << n) | (x >> ((sizeof(x) << 3) - n))) +#define CH(x, y, z) ((x & y) ^ (~x & z)) +#define MAJ(x, y, z) ((x & y) ^ (x & z) ^ (y & z)) + +#define SHA512_F1(x) (ROTR(x, 28) ^ ROTR(x, 34) ^ ROTR(x, 39)) +#define SHA512_F2(x) (ROTR(x, 14) ^ ROTR(x, 18) ^ ROTR(x, 41)) +#define SHA512_F3(x) (ROTR(x, 1) ^ ROTR(x, 8) ^ SHFR(x, 7)) +#define SHA512_F4(x) (ROTR(x, 19) ^ ROTR(x, 61) ^ SHFR(x, 6)) + +#define UNPACK32(x, str) \ + { \ + *((str) + 3) = (uint8_t)((x)); \ + *((str) + 2) = (uint8_t)((x) >> 8); \ + *((str) + 1) = (uint8_t)((x) >> 16); \ + *((str) + 0) = (uint8_t)((x) >> 24); \ + } + +#define UNPACK64(x, str) \ + { \ + *((str) + 7) = (uint8_t)x; \ + *((str) + 6) = (uint8_t)((uint64_t)x >> 8); \ + *((str) + 5) = (uint8_t)((uint64_t)x >> 16); \ + *((str) + 4) = (uint8_t)((uint64_t)x >> 24); \ + *((str) + 3) = (uint8_t)((uint64_t)x >> 32); \ + *((str) + 2) = (uint8_t)((uint64_t)x >> 40); \ + *((str) + 1) = (uint8_t)((uint64_t)x >> 48); \ + *((str) + 0) = (uint8_t)((uint64_t)x >> 56); \ + } + +#define PACK64(str, x) \ + { \ + *(x) = \ + ((uint64_t) * ((str) + 7)) | ((uint64_t) * ((str) + 6) << 8) | \ + ((uint64_t) * ((str) + 5) << 16) | ((uint64_t) * ((str) + 4) << 24) | \ + ((uint64_t) * ((str) + 3) << 32) | ((uint64_t) * ((str) + 2) << 40) | \ + ((uint64_t) * ((str) + 1) << 48) | ((uint64_t) * ((str) + 0) << 56); \ + } + +/* Macros used for loops unrolling */ + +#define SHA512_SCR(i) \ + { w[i] = SHA512_F4(w[i - 2]) + w[i - 7] + SHA512_F3(w[i - 15]) + w[i - 16]; } + +#define SHA512_EXP(a, b, c, d, e, f, g, h, j) \ + { \ + t1 = wv[h] + SHA512_F2(wv[e]) + CH(wv[e], wv[f], wv[g]) + sha512_k[j] + \ + w[j]; \ + t2 = SHA512_F1(wv[a]) + MAJ(wv[a], wv[b], wv[c]); \ + wv[d] += t1; \ + wv[h] = t1 + t2; \ + } + +static const uint64_t sha512_h0[8] = {0x6a09e667f3bcc908ULL, + 0xbb67ae8584caa73bULL, + 0x3c6ef372fe94f82bULL, + 0xa54ff53a5f1d36f1ULL, + 0x510e527fade682d1ULL, + 0x9b05688c2b3e6c1fULL, + 0x1f83d9abfb41bd6bULL, + 0x5be0cd19137e2179ULL}; + +static const uint64_t sha512_k[80] = { + 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL, + 0xe9b5dba58189dbbcULL, 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, + 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, 0xd807aa98a3030242ULL, + 0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, + 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL, + 0xc19bf174cf692694ULL, 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, + 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, 0x2de92c6f592b0275ULL, + 0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL, + 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL, + 0xbf597fc7beef0ee4ULL, 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, + 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, 0x27b70a8546d22ffcULL, + 0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL, + 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL, + 0x92722c851482353bULL, 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, + 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, 0xd192e819d6ef5218ULL, + 0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL, + 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL, + 0x34b0bcb5e19b48a8ULL, 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, + 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, 0x748f82ee5defb2fcULL, + 0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL, + 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL, + 0xc67178f2e372532bULL, 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, + 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, 0x06f067aa72176fbaULL, + 0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL, + 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL, + 0x431d67c49c100d4cULL, 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, + 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL}; + +/* SHA-512 implementation */ + +void avb_sha512_init(AvbSHA512Ctx* ctx) { +#ifdef UNROLL_LOOPS_SHA512 + ctx->h[0] = sha512_h0[0]; + ctx->h[1] = sha512_h0[1]; + ctx->h[2] = sha512_h0[2]; + ctx->h[3] = sha512_h0[3]; + ctx->h[4] = sha512_h0[4]; + ctx->h[5] = sha512_h0[5]; + ctx->h[6] = sha512_h0[6]; + ctx->h[7] = sha512_h0[7]; +#else + int i; + + for (i = 0; i < 8; i++) + ctx->h[i] = sha512_h0[i]; +#endif /* UNROLL_LOOPS_SHA512 */ + + ctx->len = 0; + ctx->tot_len = 0; +} + +static void SHA512_transform(AvbSHA512Ctx* ctx, + const uint8_t* message, + unsigned int block_nb) { + uint64_t w[80]; + uint64_t wv[8]; + uint64_t t1, t2; + const uint8_t* sub_block; + int i, j; + + for (i = 0; i < (int)block_nb; i++) { + sub_block = message + (i << 7); + +#ifdef UNROLL_LOOPS_SHA512 + PACK64(&sub_block[0], &w[0]); + PACK64(&sub_block[8], &w[1]); + PACK64(&sub_block[16], &w[2]); + PACK64(&sub_block[24], &w[3]); + PACK64(&sub_block[32], &w[4]); + PACK64(&sub_block[40], &w[5]); + PACK64(&sub_block[48], &w[6]); + PACK64(&sub_block[56], &w[7]); + PACK64(&sub_block[64], &w[8]); + PACK64(&sub_block[72], &w[9]); + PACK64(&sub_block[80], &w[10]); + PACK64(&sub_block[88], &w[11]); + PACK64(&sub_block[96], &w[12]); + PACK64(&sub_block[104], &w[13]); + PACK64(&sub_block[112], &w[14]); + PACK64(&sub_block[120], &w[15]); + + SHA512_SCR(16); + SHA512_SCR(17); + SHA512_SCR(18); + SHA512_SCR(19); + SHA512_SCR(20); + SHA512_SCR(21); + SHA512_SCR(22); + SHA512_SCR(23); + SHA512_SCR(24); + SHA512_SCR(25); + SHA512_SCR(26); + SHA512_SCR(27); + SHA512_SCR(28); + SHA512_SCR(29); + SHA512_SCR(30); + SHA512_SCR(31); + SHA512_SCR(32); + SHA512_SCR(33); + SHA512_SCR(34); + SHA512_SCR(35); + SHA512_SCR(36); + SHA512_SCR(37); + SHA512_SCR(38); + SHA512_SCR(39); + SHA512_SCR(40); + SHA512_SCR(41); + SHA512_SCR(42); + SHA512_SCR(43); + SHA512_SCR(44); + SHA512_SCR(45); + SHA512_SCR(46); + SHA512_SCR(47); + SHA512_SCR(48); + SHA512_SCR(49); + SHA512_SCR(50); + SHA512_SCR(51); + SHA512_SCR(52); + SHA512_SCR(53); + SHA512_SCR(54); + SHA512_SCR(55); + SHA512_SCR(56); + SHA512_SCR(57); + SHA512_SCR(58); + SHA512_SCR(59); + SHA512_SCR(60); + SHA512_SCR(61); + SHA512_SCR(62); + SHA512_SCR(63); + SHA512_SCR(64); + SHA512_SCR(65); + SHA512_SCR(66); + SHA512_SCR(67); + SHA512_SCR(68); + SHA512_SCR(69); + SHA512_SCR(70); + SHA512_SCR(71); + SHA512_SCR(72); + SHA512_SCR(73); + SHA512_SCR(74); + SHA512_SCR(75); + SHA512_SCR(76); + SHA512_SCR(77); + SHA512_SCR(78); + SHA512_SCR(79); + + wv[0] = ctx->h[0]; + wv[1] = ctx->h[1]; + wv[2] = ctx->h[2]; + wv[3] = ctx->h[3]; + wv[4] = ctx->h[4]; + wv[5] = ctx->h[5]; + wv[6] = ctx->h[6]; + wv[7] = ctx->h[7]; + + j = 0; + + do { + SHA512_EXP(0, 1, 2, 3, 4, 5, 6, 7, j); + j++; + SHA512_EXP(7, 0, 1, 2, 3, 4, 5, 6, j); + j++; + SHA512_EXP(6, 7, 0, 1, 2, 3, 4, 5, j); + j++; + SHA512_EXP(5, 6, 7, 0, 1, 2, 3, 4, j); + j++; + SHA512_EXP(4, 5, 6, 7, 0, 1, 2, 3, j); + j++; + SHA512_EXP(3, 4, 5, 6, 7, 0, 1, 2, j); + j++; + SHA512_EXP(2, 3, 4, 5, 6, 7, 0, 1, j); + j++; + SHA512_EXP(1, 2, 3, 4, 5, 6, 7, 0, j); + j++; + } while (j < 80); + + ctx->h[0] += wv[0]; + ctx->h[1] += wv[1]; + ctx->h[2] += wv[2]; + ctx->h[3] += wv[3]; + ctx->h[4] += wv[4]; + ctx->h[5] += wv[5]; + ctx->h[6] += wv[6]; + ctx->h[7] += wv[7]; +#else + for (j = 0; j < 16; j++) { + PACK64(&sub_block[j << 3], &w[j]); + } + + for (j = 16; j < 80; j++) { + SHA512_SCR(j); + } + + for (j = 0; j < 8; j++) { + wv[j] = ctx->h[j]; + } + + for (j = 0; j < 80; j++) { + t1 = wv[7] + SHA512_F2(wv[4]) + CH(wv[4], wv[5], wv[6]) + sha512_k[j] + + w[j]; + t2 = SHA512_F1(wv[0]) + MAJ(wv[0], wv[1], wv[2]); + wv[7] = wv[6]; + wv[6] = wv[5]; + wv[5] = wv[4]; + wv[4] = wv[3] + t1; + wv[3] = wv[2]; + wv[2] = wv[1]; + wv[1] = wv[0]; + wv[0] = t1 + t2; + } + + for (j = 0; j < 8; j++) + ctx->h[j] += wv[j]; +#endif /* UNROLL_LOOPS_SHA512 */ + } +} + +void avb_sha512_update(AvbSHA512Ctx* ctx, const uint8_t* data, uint32_t len) { + unsigned int block_nb; + unsigned int new_len, rem_len, tmp_len; + const uint8_t* shifted_data; + + tmp_len = AVB_SHA512_BLOCK_SIZE - ctx->len; + rem_len = len < tmp_len ? len : tmp_len; + + avb_memcpy(&ctx->block[ctx->len], data, rem_len); + + if (ctx->len + len < AVB_SHA512_BLOCK_SIZE) { + ctx->len += len; + return; + } + + new_len = len - rem_len; + block_nb = new_len / AVB_SHA512_BLOCK_SIZE; + + shifted_data = data + rem_len; + + SHA512_transform(ctx, ctx->block, 1); + SHA512_transform(ctx, shifted_data, block_nb); + + rem_len = new_len % AVB_SHA512_BLOCK_SIZE; + + avb_memcpy(ctx->block, &shifted_data[block_nb << 7], rem_len); + + ctx->len = rem_len; + ctx->tot_len += (block_nb + 1) << 7; +} + +uint8_t* avb_sha512_final(AvbSHA512Ctx* ctx) { + unsigned int block_nb; + unsigned int pm_len; + unsigned int len_b; + +#ifndef UNROLL_LOOPS_SHA512 + int i; +#endif + + block_nb = + 1 + ((AVB_SHA512_BLOCK_SIZE - 17) < (ctx->len % AVB_SHA512_BLOCK_SIZE)); + + len_b = (ctx->tot_len + ctx->len) << 3; + pm_len = block_nb << 7; + + avb_memset(ctx->block + ctx->len, 0, pm_len - ctx->len); + ctx->block[ctx->len] = 0x80; + UNPACK32(len_b, ctx->block + pm_len - 4); + + SHA512_transform(ctx, ctx->block, block_nb); + +#ifdef UNROLL_LOOPS_SHA512 + UNPACK64(ctx->h[0], &ctx->buf[0]); + UNPACK64(ctx->h[1], &ctx->buf[8]); + UNPACK64(ctx->h[2], &ctx->buf[16]); + UNPACK64(ctx->h[3], &ctx->buf[24]); + UNPACK64(ctx->h[4], &ctx->buf[32]); + UNPACK64(ctx->h[5], &ctx->buf[40]); + UNPACK64(ctx->h[6], &ctx->buf[48]); + UNPACK64(ctx->h[7], &ctx->buf[56]); +#else + for (i = 0; i < 8; i++) + UNPACK64(ctx->h[i], &ctx->buf[i << 3]); +#endif /* UNROLL_LOOPS_SHA512 */ + + return ctx->buf; +} diff --git a/lib/libavb/avb_slot_verify.c b/lib/libavb/avb_slot_verify.c new file mode 100644 index 0000000000..a941850d93 --- /dev/null +++ b/lib/libavb/avb_slot_verify.c @@ -0,0 +1,1366 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright (C) 2016 The Android Open Source Project + */ + +#include "avb_slot_verify.h" +#include "avb_chain_partition_descriptor.h" +#include "avb_cmdline.h" +#include "avb_footer.h" +#include "avb_hash_descriptor.h" +#include "avb_hashtree_descriptor.h" +#include "avb_kernel_cmdline_descriptor.h" +#include "avb_sha.h" +#include "avb_util.h" +#include "avb_vbmeta_image.h" +#include "avb_version.h" + +/* Maximum number of partitions that can be loaded with avb_slot_verify(). */ +#define MAX_NUMBER_OF_LOADED_PARTITIONS 32 + +/* Maximum number of vbmeta images that can be loaded with avb_slot_verify(). */ +#define MAX_NUMBER_OF_VBMETA_IMAGES 32 + +/* Maximum size of a vbmeta image - 64 KiB. */ +#define VBMETA_MAX_SIZE (64 * 1024) + +/* Helper function to see if we should continue with verification in + * allow_verification_error=true mode if something goes wrong. See the + * comments for the avb_slot_verify() function for more information. + */ +static inline bool result_should_continue(AvbSlotVerifyResult result) { + switch (result) { + case AVB_SLOT_VERIFY_RESULT_ERROR_OOM: + case AVB_SLOT_VERIFY_RESULT_ERROR_IO: + case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA: + case AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION: + case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT: + return false; + + case AVB_SLOT_VERIFY_RESULT_OK: + case AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION: + case AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX: + case AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED: + return true; + } + + return false; +} + +static AvbSlotVerifyResult load_full_partition(AvbOps* ops, + const char* part_name, + uint64_t image_size, + uint8_t** out_image_buf, + bool* out_image_preloaded) { + size_t part_num_read; + AvbIOResult io_ret; + + /* Make sure that we do not overwrite existing data. */ + avb_assert(*out_image_buf == NULL); + avb_assert(!*out_image_preloaded); + + /* We are going to implicitly cast image_size from uint64_t to size_t in the + * following code, so we need to make sure that the cast is safe. */ + if (image_size != (size_t)(image_size)) { + avb_errorv(part_name, ": Partition size too large to load.\n", NULL); + return AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA; + } + + /* Try use a preloaded one. */ + if (ops->get_preloaded_partition != NULL) { + io_ret = ops->get_preloaded_partition( + ops, part_name, image_size, out_image_buf, &part_num_read); + if (io_ret == AVB_IO_RESULT_ERROR_OOM) { + return AVB_SLOT_VERIFY_RESULT_ERROR_OOM; + } else if (io_ret != AVB_IO_RESULT_OK) { + avb_errorv(part_name, ": Error loading data from partition.\n", NULL); + return AVB_SLOT_VERIFY_RESULT_ERROR_IO; + } + + if (*out_image_buf != NULL) { + if (part_num_read != image_size) { + avb_errorv(part_name, ": Read incorrect number of bytes.\n", NULL); + return AVB_SLOT_VERIFY_RESULT_ERROR_IO; + } + *out_image_preloaded = true; + } + } + + /* Allocate and copy the partition. */ + if (!*out_image_preloaded) { + *out_image_buf = avb_malloc(image_size); + if (*out_image_buf == NULL) { + return AVB_SLOT_VERIFY_RESULT_ERROR_OOM; + } + + io_ret = ops->read_from_partition(ops, + part_name, + 0 /* offset */, + image_size, + *out_image_buf, + &part_num_read); + if (io_ret == AVB_IO_RESULT_ERROR_OOM) { + return AVB_SLOT_VERIFY_RESULT_ERROR_OOM; + } else if (io_ret != AVB_IO_RESULT_OK) { + avb_errorv(part_name, ": Error loading data from partition.\n", NULL); + return AVB_SLOT_VERIFY_RESULT_ERROR_IO; + } + if (part_num_read != image_size) { + avb_errorv(part_name, ": Read incorrect number of bytes.\n", NULL); + return AVB_SLOT_VERIFY_RESULT_ERROR_IO; + } + } + + return AVB_SLOT_VERIFY_RESULT_OK; +} + +static AvbSlotVerifyResult read_persistent_digest(AvbOps* ops, + const char* part_name, + size_t expected_digest_size, + uint8_t* out_digest) { + char* persistent_value_name = NULL; + AvbIOResult io_ret = AVB_IO_RESULT_OK; + size_t stored_digest_size = 0; + + if (ops->read_persistent_value == NULL) { + avb_errorv(part_name, ": Persistent values are not implemented.\n", NULL); + return AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA; + } + persistent_value_name = + avb_strdupv(AVB_NPV_PERSISTENT_DIGEST_PREFIX, part_name, NULL); + if (persistent_value_name == NULL) { + return AVB_SLOT_VERIFY_RESULT_ERROR_OOM; + } + io_ret = ops->read_persistent_value(ops, + persistent_value_name, + expected_digest_size, + out_digest, + &stored_digest_size); + avb_free(persistent_value_name); + if (io_ret == AVB_IO_RESULT_ERROR_OOM) { + return AVB_SLOT_VERIFY_RESULT_ERROR_OOM; + } else if (io_ret == AVB_IO_RESULT_ERROR_NO_SUCH_VALUE) { + avb_errorv(part_name, ": Persistent digest does not exist.\n", NULL); + return AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA; + } else if (io_ret == AVB_IO_RESULT_ERROR_INVALID_VALUE_SIZE || + io_ret == AVB_IO_RESULT_ERROR_INSUFFICIENT_SPACE || + expected_digest_size != stored_digest_size) { + avb_errorv( + part_name, ": Persistent digest is not of expected size.\n", NULL); + return AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA; + } else if (io_ret != AVB_IO_RESULT_OK) { + avb_errorv(part_name, ": Error reading persistent digest.\n", NULL); + return AVB_SLOT_VERIFY_RESULT_ERROR_IO; + } + return AVB_SLOT_VERIFY_RESULT_OK; +} + +static AvbSlotVerifyResult load_and_verify_hash_partition( + AvbOps* ops, + const char* const* requested_partitions, + const char* ab_suffix, + bool allow_verification_error, + const AvbDescriptor* descriptor, + AvbSlotVerifyData* slot_data) { + AvbHashDescriptor hash_desc; + const uint8_t* desc_partition_name = NULL; + const uint8_t* desc_salt; + const uint8_t* desc_digest; + char part_name[AVB_PART_NAME_MAX_SIZE]; + AvbSlotVerifyResult ret; + AvbIOResult io_ret; + uint8_t* image_buf = NULL; + bool image_preloaded = false; + uint8_t* digest; + size_t digest_len; + const char* found; + uint64_t image_size; + size_t expected_digest_len = 0; + uint8_t expected_digest_buf[AVB_SHA512_DIGEST_SIZE]; + const uint8_t* expected_digest = NULL; + + if (!avb_hash_descriptor_validate_and_byteswap( + (const AvbHashDescriptor*)descriptor, &hash_desc)) { + ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA; + goto out; + } + + desc_partition_name = + ((const uint8_t*)descriptor) + sizeof(AvbHashDescriptor); + desc_salt = desc_partition_name + hash_desc.partition_name_len; + desc_digest = desc_salt + hash_desc.salt_len; + + if (!avb_validate_utf8(desc_partition_name, hash_desc.partition_name_len)) { + avb_error("Partition name is not valid UTF-8.\n"); + ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA; + goto out; + } + + /* Don't bother loading or validating unless the partition was + * requested in the first place. + */ + found = avb_strv_find_str(requested_partitions, + (const char*)desc_partition_name, + hash_desc.partition_name_len); + if (found == NULL) { + ret = AVB_SLOT_VERIFY_RESULT_OK; + goto out; + } + + if ((hash_desc.flags & AVB_HASH_DESCRIPTOR_FLAGS_DO_NOT_USE_AB) != 0) { + /* No ab_suffix, just copy the partition name as is. */ + if (hash_desc.partition_name_len >= AVB_PART_NAME_MAX_SIZE) { + avb_error("Partition name does not fit.\n"); + ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA; + goto out; + } + avb_memcpy(part_name, desc_partition_name, hash_desc.partition_name_len); + part_name[hash_desc.partition_name_len] = '\0'; + } else if (hash_desc.digest_len == 0 && avb_strlen(ab_suffix) != 0) { + /* No ab_suffix allowed for partitions without a digest in the descriptor + * because these partitions hold data unique to this device and are not + * updated using an A/B scheme. + */ + avb_error("Cannot use A/B with a persistent digest.\n"); + ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA; + goto out; + } else { + /* Add ab_suffix to the partition name. */ + if (!avb_str_concat(part_name, + sizeof part_name, + (const char*)desc_partition_name, + hash_desc.partition_name_len, + ab_suffix, + avb_strlen(ab_suffix))) { + avb_error("Partition name and suffix does not fit.\n"); + ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA; + goto out; + } + } + + /* If we're allowing verification errors then hash_desc.image_size + * may no longer match what's in the partition... so in this case + * just load the entire partition. + * + * For example, this can happen if a developer does 'fastboot flash + * boot /path/to/new/and/bigger/boot.img'. We want this to work + * since it's such a common workflow. + */ + image_size = hash_desc.image_size; + if (allow_verification_error) { + if (ops->get_size_of_partition == NULL) { + avb_errorv(part_name, + ": The get_size_of_partition() operation is " + "not implemented so we may not load the entire partition. " + "Please implement.", + NULL); + } else { + io_ret = ops->get_size_of_partition(ops, part_name, &image_size); + if (io_ret == AVB_IO_RESULT_ERROR_OOM) { + ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; + goto out; + } else if (io_ret != AVB_IO_RESULT_OK) { + avb_errorv(part_name, ": Error determining partition size.\n", NULL); + ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO; + goto out; + } + avb_debugv(part_name, ": Loading entire partition.\n", NULL); + } + } + + ret = load_full_partition( + ops, part_name, image_size, &image_buf, &image_preloaded); + if (ret != AVB_SLOT_VERIFY_RESULT_OK) { + goto out; + } + + if (avb_strcmp((const char*)hash_desc.hash_algorithm, "sha256") == 0) { + AvbSHA256Ctx sha256_ctx; + avb_sha256_init(&sha256_ctx); + avb_sha256_update(&sha256_ctx, desc_salt, hash_desc.salt_len); + avb_sha256_update(&sha256_ctx, image_buf, hash_desc.image_size); + digest = avb_sha256_final(&sha256_ctx); + digest_len = AVB_SHA256_DIGEST_SIZE; + } else if (avb_strcmp((const char*)hash_desc.hash_algorithm, "sha512") == 0) { + AvbSHA512Ctx sha512_ctx; + avb_sha512_init(&sha512_ctx); + avb_sha512_update(&sha512_ctx, desc_salt, hash_desc.salt_len); + avb_sha512_update(&sha512_ctx, image_buf, hash_desc.image_size); + digest = avb_sha512_final(&sha512_ctx); + digest_len = AVB_SHA512_DIGEST_SIZE; + } else { + avb_errorv(part_name, ": Unsupported hash algorithm.\n", NULL); + ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA; + goto out; + } + + if (hash_desc.digest_len == 0) { + // Expect a match to a persistent digest. + avb_debugv(part_name, ": No digest, using persistent digest.\n", NULL); + expected_digest_len = digest_len; + expected_digest = expected_digest_buf; + avb_assert(expected_digest_len <= sizeof(expected_digest_buf)); + ret = + read_persistent_digest(ops, part_name, digest_len, expected_digest_buf); + if (ret != AVB_SLOT_VERIFY_RESULT_OK) { + goto out; + } + } else { + // Expect a match to the digest in the descriptor. + expected_digest_len = hash_desc.digest_len; + expected_digest = desc_digest; + } + + if (digest_len != expected_digest_len) { + avb_errorv( + part_name, ": Digest in descriptor not of expected size.\n", NULL); + ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA; + goto out; + } + + if (avb_safe_memcmp(digest, expected_digest, digest_len) != 0) { + avb_errorv(part_name, + ": Hash of data does not match digest in descriptor.\n", + NULL); + ret = AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION; + goto out; + } + + ret = AVB_SLOT_VERIFY_RESULT_OK; + +out: + + /* If it worked and something was loaded, copy to slot_data. */ + if ((ret == AVB_SLOT_VERIFY_RESULT_OK || result_should_continue(ret)) && + image_buf != NULL) { + AvbPartitionData* loaded_partition; + if (slot_data->num_loaded_partitions == MAX_NUMBER_OF_LOADED_PARTITIONS) { + avb_errorv(part_name, ": Too many loaded partitions.\n", NULL); + ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; + goto fail; + } + loaded_partition = + &slot_data->loaded_partitions[slot_data->num_loaded_partitions++]; + loaded_partition->partition_name = avb_strdup(found); + loaded_partition->data_size = image_size; + loaded_partition->data = image_buf; + loaded_partition->preloaded = image_preloaded; + image_buf = NULL; + } + +fail: + if (image_buf != NULL && !image_preloaded) { + avb_free(image_buf); + } + return ret; +} + +static AvbSlotVerifyResult load_requested_partitions( + AvbOps* ops, + const char* const* requested_partitions, + const char* ab_suffix, + AvbSlotVerifyData* slot_data) { + AvbSlotVerifyResult ret; + uint8_t* image_buf = NULL; + bool image_preloaded = false; + size_t n; + + if (ops->get_size_of_partition == NULL) { + avb_error("get_size_of_partition() not implemented.\n"); + ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT; + goto out; + } + + for (n = 0; requested_partitions[n] != NULL; n++) { + char part_name[AVB_PART_NAME_MAX_SIZE]; + AvbIOResult io_ret; + uint64_t image_size; + AvbPartitionData* loaded_partition; + + if (!avb_str_concat(part_name, + sizeof part_name, + requested_partitions[n], + avb_strlen(requested_partitions[n]), + ab_suffix, + avb_strlen(ab_suffix))) { + avb_error("Partition name and suffix does not fit.\n"); + ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA; + goto out; + } + + io_ret = ops->get_size_of_partition(ops, part_name, &image_size); + if (io_ret == AVB_IO_RESULT_ERROR_OOM) { + ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; + goto out; + } else if (io_ret != AVB_IO_RESULT_OK) { + avb_errorv(part_name, ": Error determining partition size.\n", NULL); + ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO; + goto out; + } + avb_debugv(part_name, ": Loading entire partition.\n", NULL); + + ret = load_full_partition( + ops, part_name, image_size, &image_buf, &image_preloaded); + if (ret != AVB_SLOT_VERIFY_RESULT_OK) { + goto out; + } + + /* Move to slot_data. */ + if (slot_data->num_loaded_partitions == MAX_NUMBER_OF_LOADED_PARTITIONS) { + avb_errorv(part_name, ": Too many loaded partitions.\n", NULL); + ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; + goto out; + } + loaded_partition = + &slot_data->loaded_partitions[slot_data->num_loaded_partitions++]; + loaded_partition->partition_name = avb_strdup(requested_partitions[n]); + if (loaded_partition->partition_name == NULL) { + ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; + goto out; + } + loaded_partition->data_size = image_size; + loaded_partition->data = image_buf; /* Transferring the owner. */ + loaded_partition->preloaded = image_preloaded; + image_buf = NULL; + image_preloaded = false; + } + + ret = AVB_SLOT_VERIFY_RESULT_OK; + +out: + /* Free the current buffer if any. */ + if (image_buf != NULL && !image_preloaded) { + avb_free(image_buf); + } + /* Buffers that are already saved in slot_data will be handled by the caller + * even on failure. */ + return ret; +} + +static AvbSlotVerifyResult load_and_verify_vbmeta( + AvbOps* ops, + const char* const* requested_partitions, + const char* ab_suffix, + bool allow_verification_error, + AvbVBMetaImageFlags toplevel_vbmeta_flags, + int rollback_index_location, + const char* partition_name, + size_t partition_name_len, + const uint8_t* expected_public_key, + size_t expected_public_key_length, + AvbSlotVerifyData* slot_data, + AvbAlgorithmType* out_algorithm_type, + AvbCmdlineSubstList* out_additional_cmdline_subst) { + char full_partition_name[AVB_PART_NAME_MAX_SIZE]; + AvbSlotVerifyResult ret; + AvbIOResult io_ret; + size_t vbmeta_offset; + size_t vbmeta_size; + uint8_t* vbmeta_buf = NULL; + size_t vbmeta_num_read; + AvbVBMetaVerifyResult vbmeta_ret; + const uint8_t* pk_data; + size_t pk_len; + AvbVBMetaImageHeader vbmeta_header; + uint64_t stored_rollback_index; + const AvbDescriptor** descriptors = NULL; + size_t num_descriptors; + size_t n; + bool is_main_vbmeta; + bool is_vbmeta_partition; + AvbVBMetaData* vbmeta_image_data = NULL; + + ret = AVB_SLOT_VERIFY_RESULT_OK; + + avb_assert(slot_data != NULL); + + /* Since we allow top-level vbmeta in 'boot', use + * rollback_index_location to determine whether we're the main + * vbmeta struct. + */ + is_main_vbmeta = (rollback_index_location == 0); + is_vbmeta_partition = (avb_strcmp(partition_name, "vbmeta") == 0); + + if (!avb_validate_utf8((const uint8_t*)partition_name, partition_name_len)) { + avb_error("Partition name is not valid UTF-8.\n"); + ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA; + goto out; + } + + /* Construct full partition name. */ + if (!avb_str_concat(full_partition_name, + sizeof full_partition_name, + partition_name, + partition_name_len, + ab_suffix, + avb_strlen(ab_suffix))) { + avb_error("Partition name and suffix does not fit.\n"); + ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA; + goto out; + } + + avb_debugv("Loading vbmeta struct from partition '", + full_partition_name, + "'.\n", + NULL); + + /* If we're loading from the main vbmeta partition, the vbmeta + * struct is in the beginning. Otherwise we have to locate it via a + * footer. + */ + if (is_vbmeta_partition) { + vbmeta_offset = 0; + vbmeta_size = VBMETA_MAX_SIZE; + } else { + uint8_t footer_buf[AVB_FOOTER_SIZE]; + size_t footer_num_read; + AvbFooter footer; + + io_ret = ops->read_from_partition(ops, + full_partition_name, + -AVB_FOOTER_SIZE, + AVB_FOOTER_SIZE, + footer_buf, + &footer_num_read); + if (io_ret == AVB_IO_RESULT_ERROR_OOM) { + ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; + goto out; + } else if (io_ret != AVB_IO_RESULT_OK) { + avb_errorv(full_partition_name, ": Error loading footer.\n", NULL); + ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO; + goto out; + } + avb_assert(footer_num_read == AVB_FOOTER_SIZE); + + if (!avb_footer_validate_and_byteswap((const AvbFooter*)footer_buf, + &footer)) { + avb_errorv(full_partition_name, ": Error validating footer.\n", NULL); + ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA; + goto out; + } + + /* Basic footer sanity check since the data is untrusted. */ + if (footer.vbmeta_size > VBMETA_MAX_SIZE) { + avb_errorv( + full_partition_name, ": Invalid vbmeta size in footer.\n", NULL); + ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA; + goto out; + } + + vbmeta_offset = footer.vbmeta_offset; + vbmeta_size = footer.vbmeta_size; + } + + vbmeta_buf = avb_malloc(vbmeta_size); + if (vbmeta_buf == NULL) { + ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; + goto out; + } + + io_ret = ops->read_from_partition(ops, + full_partition_name, + vbmeta_offset, + vbmeta_size, + vbmeta_buf, + &vbmeta_num_read); + if (io_ret == AVB_IO_RESULT_ERROR_OOM) { + ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; + goto out; + } else if (io_ret != AVB_IO_RESULT_OK) { + /* If we're looking for 'vbmeta' but there is no such partition, + * go try to get it from the boot partition instead. + */ + if (is_main_vbmeta && io_ret == AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION && + is_vbmeta_partition) { + avb_debugv(full_partition_name, + ": No such partition. Trying 'boot' instead.\n", + NULL); + ret = load_and_verify_vbmeta(ops, + requested_partitions, + ab_suffix, + allow_verification_error, + 0 /* toplevel_vbmeta_flags */, + 0 /* rollback_index_location */, + "boot", + avb_strlen("boot"), + NULL /* expected_public_key */, + 0 /* expected_public_key_length */, + slot_data, + out_algorithm_type, + out_additional_cmdline_subst); + goto out; + } else { + avb_errorv(full_partition_name, ": Error loading vbmeta data.\n", NULL); + ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO; + goto out; + } + } + avb_assert(vbmeta_num_read <= vbmeta_size); + + /* Check if the image is properly signed and get the public key used + * to sign the image. + */ + vbmeta_ret = + avb_vbmeta_image_verify(vbmeta_buf, vbmeta_num_read, &pk_data, &pk_len); + switch (vbmeta_ret) { + case AVB_VBMETA_VERIFY_RESULT_OK: + avb_assert(pk_data != NULL && pk_len > 0); + break; + + case AVB_VBMETA_VERIFY_RESULT_OK_NOT_SIGNED: + case AVB_VBMETA_VERIFY_RESULT_HASH_MISMATCH: + case AVB_VBMETA_VERIFY_RESULT_SIGNATURE_MISMATCH: + ret = AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION; + avb_errorv(full_partition_name, + ": Error verifying vbmeta image: ", + avb_vbmeta_verify_result_to_string(vbmeta_ret), + "\n", + NULL); + if (!allow_verification_error) { + goto out; + } + break; + + case AVB_VBMETA_VERIFY_RESULT_INVALID_VBMETA_HEADER: + /* No way to continue this case. */ + ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA; + avb_errorv(full_partition_name, + ": Error verifying vbmeta image: invalid vbmeta header\n", + NULL); + goto out; + + case AVB_VBMETA_VERIFY_RESULT_UNSUPPORTED_VERSION: + /* No way to continue this case. */ + ret = AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION; + avb_errorv(full_partition_name, + ": Error verifying vbmeta image: unsupported AVB version\n", + NULL); + goto out; + } + + /* Byteswap the header. */ + avb_vbmeta_image_header_to_host_byte_order((AvbVBMetaImageHeader*)vbmeta_buf, + &vbmeta_header); + + /* If we're the toplevel, assign flags so they'll be passed down. */ + if (is_main_vbmeta) { + toplevel_vbmeta_flags = (AvbVBMetaImageFlags)vbmeta_header.flags; + } else { + if (vbmeta_header.flags != 0) { + ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA; + avb_errorv(full_partition_name, + ": chained vbmeta image has non-zero flags\n", + NULL); + goto out; + } + } + + /* Check if key used to make signature matches what is expected. */ + if (pk_data != NULL) { + if (expected_public_key != NULL) { + avb_assert(!is_main_vbmeta); + if (expected_public_key_length != pk_len || + avb_safe_memcmp(expected_public_key, pk_data, pk_len) != 0) { + avb_errorv(full_partition_name, + ": Public key used to sign data does not match key in chain " + "partition descriptor.\n", + NULL); + ret = AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED; + if (!allow_verification_error) { + goto out; + } + } + } else { + bool key_is_trusted = false; + const uint8_t* pk_metadata = NULL; + size_t pk_metadata_len = 0; + + if (vbmeta_header.public_key_metadata_size > 0) { + pk_metadata = vbmeta_buf + sizeof(AvbVBMetaImageHeader) + + vbmeta_header.authentication_data_block_size + + vbmeta_header.public_key_metadata_offset; + pk_metadata_len = vbmeta_header.public_key_metadata_size; + } + + avb_assert(is_main_vbmeta); + io_ret = ops->validate_vbmeta_public_key( + ops, pk_data, pk_len, pk_metadata, pk_metadata_len, &key_is_trusted); + if (io_ret == AVB_IO_RESULT_ERROR_OOM) { + ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; + goto out; + } else if (io_ret != AVB_IO_RESULT_OK) { + avb_errorv(full_partition_name, + ": Error while checking public key used to sign data.\n", + NULL); + ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO; + goto out; + } + if (!key_is_trusted) { + avb_errorv(full_partition_name, + ": Public key used to sign data rejected.\n", + NULL); + ret = AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED; + if (!allow_verification_error) { + goto out; + } + } + } + } + + /* Check rollback index. */ + io_ret = ops->read_rollback_index( + ops, rollback_index_location, &stored_rollback_index); + if (io_ret == AVB_IO_RESULT_ERROR_OOM) { + ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; + goto out; + } else if (io_ret != AVB_IO_RESULT_OK) { + avb_errorv(full_partition_name, + ": Error getting rollback index for location.\n", + NULL); + ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO; + goto out; + } + if (vbmeta_header.rollback_index < stored_rollback_index) { + avb_errorv( + full_partition_name, + ": Image rollback index is less than the stored rollback index.\n", + NULL); + ret = AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX; + if (!allow_verification_error) { + goto out; + } + } + + /* Copy vbmeta to vbmeta_images before recursing. */ + if (is_main_vbmeta) { + avb_assert(slot_data->num_vbmeta_images == 0); + } else { + avb_assert(slot_data->num_vbmeta_images > 0); + } + if (slot_data->num_vbmeta_images == MAX_NUMBER_OF_VBMETA_IMAGES) { + avb_errorv(full_partition_name, ": Too many vbmeta images.\n", NULL); + ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; + goto out; + } + vbmeta_image_data = &slot_data->vbmeta_images[slot_data->num_vbmeta_images++]; + vbmeta_image_data->partition_name = avb_strdup(partition_name); + vbmeta_image_data->vbmeta_data = vbmeta_buf; + /* Note that |vbmeta_buf| is actually |vbmeta_num_read| bytes long + * and this includes data past the end of the image. Pass the + * actual size of the vbmeta image. Also, no need to use + * avb_safe_add() since the header has already been verified. + */ + vbmeta_image_data->vbmeta_size = + sizeof(AvbVBMetaImageHeader) + + vbmeta_header.authentication_data_block_size + + vbmeta_header.auxiliary_data_block_size; + vbmeta_image_data->verify_result = vbmeta_ret; + + /* If verification has been disabled by setting a bit in the image, + * we're done... except that we need to load the entirety of the + * requested partitions. + */ + if (vbmeta_header.flags & AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED) { + AvbSlotVerifyResult sub_ret; + avb_debugv( + full_partition_name, ": VERIFICATION_DISABLED bit is set.\n", NULL); + /* If load_requested_partitions() fail it is always a fatal + * failure (e.g. ERROR_INVALID_ARGUMENT, ERROR_OOM, etc.) rather + * than recoverable (e.g. one where result_should_continue() + * returns true) and we want to convey that error. + */ + sub_ret = load_requested_partitions( + ops, requested_partitions, ab_suffix, slot_data); + if (sub_ret != AVB_SLOT_VERIFY_RESULT_OK) { + ret = sub_ret; + } + goto out; + } + + /* Now go through all descriptors and take the appropriate action: + * + * - hash descriptor: Load data from partition, calculate hash, and + * checks that it matches what's in the hash descriptor. + * + * - hashtree descriptor: Do nothing since verification happens + * on-the-fly from within the OS. (Unless the descriptor uses a + * persistent digest, in which case we need to find it). + * + * - chained partition descriptor: Load the footer, load the vbmeta + * image, verify vbmeta image (includes rollback checks, hash + * checks, bail on chained partitions). + */ + descriptors = + avb_descriptor_get_all(vbmeta_buf, vbmeta_num_read, &num_descriptors); + for (n = 0; n < num_descriptors; n++) { + AvbDescriptor desc; + + if (!avb_descriptor_validate_and_byteswap(descriptors[n], &desc)) { + avb_errorv(full_partition_name, ": Descriptor is invalid.\n", NULL); + ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA; + goto out; + } + + switch (desc.tag) { + case AVB_DESCRIPTOR_TAG_HASH: { + AvbSlotVerifyResult sub_ret; + sub_ret = load_and_verify_hash_partition(ops, + requested_partitions, + ab_suffix, + allow_verification_error, + descriptors[n], + slot_data); + if (sub_ret != AVB_SLOT_VERIFY_RESULT_OK) { + ret = sub_ret; + if (!allow_verification_error || !result_should_continue(ret)) { + goto out; + } + } + } break; + + case AVB_DESCRIPTOR_TAG_CHAIN_PARTITION: { + AvbSlotVerifyResult sub_ret; + AvbChainPartitionDescriptor chain_desc; + const uint8_t* chain_partition_name; + const uint8_t* chain_public_key; + + /* Only allow CHAIN_PARTITION descriptors in the main vbmeta image. */ + if (!is_main_vbmeta) { + avb_errorv(full_partition_name, + ": Encountered chain descriptor not in main image.\n", + NULL); + ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA; + goto out; + } + + if (!avb_chain_partition_descriptor_validate_and_byteswap( + (AvbChainPartitionDescriptor*)descriptors[n], &chain_desc)) { + avb_errorv(full_partition_name, + ": Chain partition descriptor is invalid.\n", + NULL); + ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA; + goto out; + } + + if (chain_desc.rollback_index_location == 0) { + avb_errorv(full_partition_name, + ": Chain partition has invalid " + "rollback_index_location field.\n", + NULL); + ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA; + goto out; + } + + chain_partition_name = ((const uint8_t*)descriptors[n]) + + sizeof(AvbChainPartitionDescriptor); + chain_public_key = chain_partition_name + chain_desc.partition_name_len; + + sub_ret = + load_and_verify_vbmeta(ops, + requested_partitions, + ab_suffix, + allow_verification_error, + toplevel_vbmeta_flags, + chain_desc.rollback_index_location, + (const char*)chain_partition_name, + chain_desc.partition_name_len, + chain_public_key, + chain_desc.public_key_len, + slot_data, + NULL, /* out_algorithm_type */ + NULL /* out_additional_cmdline_subst */); + if (sub_ret != AVB_SLOT_VERIFY_RESULT_OK) { + ret = sub_ret; + if (!result_should_continue(ret)) { + goto out; + } + } + } break; + + case AVB_DESCRIPTOR_TAG_KERNEL_CMDLINE: { + const uint8_t* kernel_cmdline; + AvbKernelCmdlineDescriptor kernel_cmdline_desc; + bool apply_cmdline; + + if (!avb_kernel_cmdline_descriptor_validate_and_byteswap( + (AvbKernelCmdlineDescriptor*)descriptors[n], + &kernel_cmdline_desc)) { + avb_errorv(full_partition_name, + ": Kernel cmdline descriptor is invalid.\n", + NULL); + ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA; + goto out; + } + + kernel_cmdline = ((const uint8_t*)descriptors[n]) + + sizeof(AvbKernelCmdlineDescriptor); + + if (!avb_validate_utf8(kernel_cmdline, + kernel_cmdline_desc.kernel_cmdline_length)) { + avb_errorv(full_partition_name, + ": Kernel cmdline is not valid UTF-8.\n", + NULL); + ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA; + goto out; + } + + /* Compare the flags for top-level VBMeta struct with flags in + * the command-line descriptor so command-line snippets only + * intended for a certain mode (dm-verity enabled/disabled) + * are skipped if applicable. + */ + apply_cmdline = true; + if (toplevel_vbmeta_flags & AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED) { + if (kernel_cmdline_desc.flags & + AVB_KERNEL_CMDLINE_FLAGS_USE_ONLY_IF_HASHTREE_NOT_DISABLED) { + apply_cmdline = false; + } + } else { + if (kernel_cmdline_desc.flags & + AVB_KERNEL_CMDLINE_FLAGS_USE_ONLY_IF_HASHTREE_DISABLED) { + apply_cmdline = false; + } + } + + if (apply_cmdline) { + if (slot_data->cmdline == NULL) { + slot_data->cmdline = + avb_calloc(kernel_cmdline_desc.kernel_cmdline_length + 1); + if (slot_data->cmdline == NULL) { + ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; + goto out; + } + avb_memcpy(slot_data->cmdline, + kernel_cmdline, + kernel_cmdline_desc.kernel_cmdline_length); + } else { + /* new cmdline is: <existing_cmdline> + ' ' + <newcmdline> + '\0' */ + size_t orig_size = avb_strlen(slot_data->cmdline); + size_t new_size = + orig_size + 1 + kernel_cmdline_desc.kernel_cmdline_length + 1; + char* new_cmdline = avb_calloc(new_size); + if (new_cmdline == NULL) { + ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; + goto out; + } + avb_memcpy(new_cmdline, slot_data->cmdline, orig_size); + new_cmdline[orig_size] = ' '; + avb_memcpy(new_cmdline + orig_size + 1, + kernel_cmdline, + kernel_cmdline_desc.kernel_cmdline_length); + avb_free(slot_data->cmdline); + slot_data->cmdline = new_cmdline; + } + } + } break; + + case AVB_DESCRIPTOR_TAG_HASHTREE: { + AvbHashtreeDescriptor hashtree_desc; + + if (!avb_hashtree_descriptor_validate_and_byteswap( + (AvbHashtreeDescriptor*)descriptors[n], &hashtree_desc)) { + avb_errorv( + full_partition_name, ": Hashtree descriptor is invalid.\n", NULL); + ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA; + goto out; + } + + /* We only need to continue when there is no digest in the descriptor. + * This is because the only processing here is to find the digest and + * make it available on the kernel command line. + */ + if (hashtree_desc.root_digest_len == 0) { + char part_name[AVB_PART_NAME_MAX_SIZE]; + size_t digest_len = 0; + uint8_t digest_buf[AVB_SHA512_DIGEST_SIZE]; + const uint8_t* desc_partition_name = + ((const uint8_t*)descriptors[n]) + sizeof(AvbHashtreeDescriptor); + + if (!avb_validate_utf8(desc_partition_name, + hashtree_desc.partition_name_len)) { + avb_error("Partition name is not valid UTF-8.\n"); + ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA; + goto out; + } + + /* No ab_suffix for partitions without a digest in the descriptor + * because these partitions hold data unique to this device and are + * not updated using an A/B scheme. + */ + if ((hashtree_desc.flags & + AVB_HASHTREE_DESCRIPTOR_FLAGS_DO_NOT_USE_AB) == 0 && + avb_strlen(ab_suffix) != 0) { + avb_error("Cannot use A/B with a persistent root digest.\n"); + ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA; + goto out; + } + if (hashtree_desc.partition_name_len >= AVB_PART_NAME_MAX_SIZE) { + avb_error("Partition name does not fit.\n"); + ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA; + goto out; + } + avb_memcpy( + part_name, desc_partition_name, hashtree_desc.partition_name_len); + part_name[hashtree_desc.partition_name_len] = '\0'; + + /* Determine the expected digest size from the hash algorithm. */ + if (avb_strcmp((const char*)hashtree_desc.hash_algorithm, "sha1") == + 0) { + digest_len = AVB_SHA1_DIGEST_SIZE; + } else if (avb_strcmp((const char*)hashtree_desc.hash_algorithm, + "sha256") == 0) { + digest_len = AVB_SHA256_DIGEST_SIZE; + } else if (avb_strcmp((const char*)hashtree_desc.hash_algorithm, + "sha512") == 0) { + digest_len = AVB_SHA512_DIGEST_SIZE; + } else { + avb_errorv(part_name, ": Unsupported hash algorithm.\n", NULL); + ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA; + goto out; + } + + ret = read_persistent_digest(ops, part_name, digest_len, digest_buf); + if (ret != AVB_SLOT_VERIFY_RESULT_OK) { + goto out; + } + + if (out_additional_cmdline_subst) { + ret = + avb_add_root_digest_substitution(part_name, + digest_buf, + digest_len, + out_additional_cmdline_subst); + if (ret != AVB_SLOT_VERIFY_RESULT_OK) { + goto out; + } + } + } + } break; + + case AVB_DESCRIPTOR_TAG_PROPERTY: + /* Do nothing. */ + break; + } + } + + if (rollback_index_location >= AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_LOCATIONS) { + avb_errorv( + full_partition_name, ": Invalid rollback_index_location.\n", NULL); + ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA; + goto out; + } + + slot_data->rollback_indexes[rollback_index_location] = + vbmeta_header.rollback_index; + + if (out_algorithm_type != NULL) { + *out_algorithm_type = (AvbAlgorithmType)vbmeta_header.algorithm_type; + } + +out: + /* If |vbmeta_image_data| isn't NULL it means that it adopted + * |vbmeta_buf| so in that case don't free it here. + */ + if (vbmeta_image_data == NULL) { + if (vbmeta_buf != NULL) { + avb_free(vbmeta_buf); + } + } + if (descriptors != NULL) { + avb_free(descriptors); + } + return ret; +} + +AvbSlotVerifyResult avb_slot_verify(AvbOps* ops, + const char* const* requested_partitions, + const char* ab_suffix, + AvbSlotVerifyFlags flags, + AvbHashtreeErrorMode hashtree_error_mode, + AvbSlotVerifyData** out_data) { + AvbSlotVerifyResult ret; + AvbSlotVerifyData* slot_data = NULL; + AvbAlgorithmType algorithm_type = AVB_ALGORITHM_TYPE_NONE; + bool using_boot_for_vbmeta = false; + AvbVBMetaImageHeader toplevel_vbmeta; + bool allow_verification_error = + (flags & AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR); + AvbCmdlineSubstList* additional_cmdline_subst = NULL; + + /* Fail early if we're missing the AvbOps needed for slot verification. + * + * For now, handle get_size_of_partition() not being implemented. In + * a later release we may change that. + */ + avb_assert(ops->read_is_device_unlocked != NULL); + avb_assert(ops->read_from_partition != NULL); + avb_assert(ops->validate_vbmeta_public_key != NULL); + avb_assert(ops->read_rollback_index != NULL); + avb_assert(ops->get_unique_guid_for_partition != NULL); + + if (out_data != NULL) { + *out_data = NULL; + } + + /* Allowing dm-verity errors defeats the purpose of verified boot so + * only allow this if set up to allow verification errors + * (e.g. typically only UNLOCKED mode). + */ + if (hashtree_error_mode == AVB_HASHTREE_ERROR_MODE_LOGGING && + !allow_verification_error) { + ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT; + goto fail; + } + + slot_data = avb_calloc(sizeof(AvbSlotVerifyData)); + if (slot_data == NULL) { + ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; + goto fail; + } + slot_data->vbmeta_images = + avb_calloc(sizeof(AvbVBMetaData) * MAX_NUMBER_OF_VBMETA_IMAGES); + if (slot_data->vbmeta_images == NULL) { + ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; + goto fail; + } + slot_data->loaded_partitions = + avb_calloc(sizeof(AvbPartitionData) * MAX_NUMBER_OF_LOADED_PARTITIONS); + if (slot_data->loaded_partitions == NULL) { + ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; + goto fail; + } + + additional_cmdline_subst = avb_new_cmdline_subst_list(); + if (additional_cmdline_subst == NULL) { + ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; + goto fail; + } + + ret = load_and_verify_vbmeta(ops, + requested_partitions, + ab_suffix, + allow_verification_error, + 0 /* toplevel_vbmeta_flags */, + 0 /* rollback_index_location */, + "vbmeta", + avb_strlen("vbmeta"), + NULL /* expected_public_key */, + 0 /* expected_public_key_length */, + slot_data, + &algorithm_type, + additional_cmdline_subst); + if (!allow_verification_error && ret != AVB_SLOT_VERIFY_RESULT_OK) { + goto fail; + } + + /* If things check out, mangle the kernel command-line as needed. */ + if (result_should_continue(ret)) { + if (avb_strcmp(slot_data->vbmeta_images[0].partition_name, "vbmeta") != 0) { + avb_assert( + avb_strcmp(slot_data->vbmeta_images[0].partition_name, "boot") == 0); + using_boot_for_vbmeta = true; + } + + /* Byteswap top-level vbmeta header since we'll need it below. */ + avb_vbmeta_image_header_to_host_byte_order( + (const AvbVBMetaImageHeader*)slot_data->vbmeta_images[0].vbmeta_data, + &toplevel_vbmeta); + + /* Fill in |ab_suffix| field. */ + slot_data->ab_suffix = avb_strdup(ab_suffix); + if (slot_data->ab_suffix == NULL) { + ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; + goto fail; + } + + /* If verification is disabled, we are done ... we specifically + * don't want to add any androidboot.* options since verification + * is disabled. + */ + if (toplevel_vbmeta.flags & AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED) { + /* Since verification is disabled we didn't process any + * descriptors and thus there's no cmdline... so set root= such + * that the system partition is mounted. + */ + avb_assert(slot_data->cmdline == NULL); + slot_data->cmdline = + avb_strdup("root=PARTUUID=$(ANDROID_SYSTEM_PARTUUID)"); + if (slot_data->cmdline == NULL) { + ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; + goto fail; + } + } else { + /* Add options - any failure in avb_append_options() is either an + * I/O or OOM error. + */ + AvbSlotVerifyResult sub_ret = avb_append_options(ops, + slot_data, + &toplevel_vbmeta, + algorithm_type, + hashtree_error_mode); + if (sub_ret != AVB_SLOT_VERIFY_RESULT_OK) { + ret = sub_ret; + goto fail; + } + } + + /* Substitute $(ANDROID_SYSTEM_PARTUUID) and friends. */ + if (slot_data->cmdline != NULL) { + char* new_cmdline; + new_cmdline = avb_sub_cmdline(ops, + slot_data->cmdline, + ab_suffix, + using_boot_for_vbmeta, + additional_cmdline_subst); + if (new_cmdline != slot_data->cmdline) { + if (new_cmdline == NULL) { + ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; + goto fail; + } + avb_free(slot_data->cmdline); + slot_data->cmdline = new_cmdline; + } + } + + if (out_data != NULL) { + *out_data = slot_data; + } else { + avb_slot_verify_data_free(slot_data); + } + } + + avb_free_cmdline_subst_list(additional_cmdline_subst); + additional_cmdline_subst = NULL; + + if (!allow_verification_error) { + avb_assert(ret == AVB_SLOT_VERIFY_RESULT_OK); + } + + return ret; + +fail: + if (slot_data != NULL) { + avb_slot_verify_data_free(slot_data); + } + if (additional_cmdline_subst != NULL) { + avb_free_cmdline_subst_list(additional_cmdline_subst); + } + return ret; +} + +void avb_slot_verify_data_free(AvbSlotVerifyData* data) { + if (data->ab_suffix != NULL) { + avb_free(data->ab_suffix); + } + if (data->cmdline != NULL) { + avb_free(data->cmdline); + } + if (data->vbmeta_images != NULL) { + size_t n; + for (n = 0; n < data->num_vbmeta_images; n++) { + AvbVBMetaData* vbmeta_image = &data->vbmeta_images[n]; + if (vbmeta_image->partition_name != NULL) { + avb_free(vbmeta_image->partition_name); + } + if (vbmeta_image->vbmeta_data != NULL) { + avb_free(vbmeta_image->vbmeta_data); + } + } + avb_free(data->vbmeta_images); + } + if (data->loaded_partitions != NULL) { + size_t n; + for (n = 0; n < data->num_loaded_partitions; n++) { + AvbPartitionData* loaded_partition = &data->loaded_partitions[n]; + if (loaded_partition->partition_name != NULL) { + avb_free(loaded_partition->partition_name); + } + if (loaded_partition->data != NULL && !loaded_partition->preloaded) { + avb_free(loaded_partition->data); + } + } + avb_free(data->loaded_partitions); + } + avb_free(data); +} + +const char* avb_slot_verify_result_to_string(AvbSlotVerifyResult result) { + const char* ret = NULL; + + switch (result) { + case AVB_SLOT_VERIFY_RESULT_OK: + ret = "OK"; + break; + case AVB_SLOT_VERIFY_RESULT_ERROR_OOM: + ret = "ERROR_OOM"; + break; + case AVB_SLOT_VERIFY_RESULT_ERROR_IO: + ret = "ERROR_IO"; + break; + case AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION: + ret = "ERROR_VERIFICATION"; + break; + case AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX: + ret = "ERROR_ROLLBACK_INDEX"; + break; + case AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED: + ret = "ERROR_PUBLIC_KEY_REJECTED"; + break; + case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA: + ret = "ERROR_INVALID_METADATA"; + break; + case AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION: + ret = "ERROR_UNSUPPORTED_VERSION"; + break; + case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT: + ret = "ERROR_INVALID_ARGUMENT"; + break; + /* Do not add a 'default:' case here because of -Wswitch. */ + } + + if (ret == NULL) { + avb_error("Unknown AvbSlotVerifyResult value.\n"); + ret = "(unknown)"; + } + + return ret; +} + +void avb_slot_verify_data_calculate_vbmeta_digest(AvbSlotVerifyData* data, + AvbDigestType digest_type, + uint8_t* out_digest) { + bool ret = false; + size_t n; + + switch (digest_type) { + case AVB_DIGEST_TYPE_SHA256: { + AvbSHA256Ctx ctx; + avb_sha256_init(&ctx); + for (n = 0; n < data->num_vbmeta_images; n++) { + avb_sha256_update(&ctx, + data->vbmeta_images[n].vbmeta_data, + data->vbmeta_images[n].vbmeta_size); + } + avb_memcpy(out_digest, avb_sha256_final(&ctx), AVB_SHA256_DIGEST_SIZE); + ret = true; + } break; + + case AVB_DIGEST_TYPE_SHA512: { + AvbSHA512Ctx ctx; + avb_sha512_init(&ctx); + for (n = 0; n < data->num_vbmeta_images; n++) { + avb_sha512_update(&ctx, + data->vbmeta_images[n].vbmeta_data, + data->vbmeta_images[n].vbmeta_size); + } + avb_memcpy(out_digest, avb_sha512_final(&ctx), AVB_SHA512_DIGEST_SIZE); + ret = true; + } break; + + /* Do not add a 'default:' case here because of -Wswitch. */ + } + + if (!ret) { + avb_fatal("Unknown digest type"); + } +} diff --git a/lib/libavb/avb_slot_verify.h b/lib/libavb/avb_slot_verify.h new file mode 100644 index 0000000000..73fd70d4ce --- /dev/null +++ b/lib/libavb/avb_slot_verify.h @@ -0,0 +1,340 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright (C) 2016 The Android Open Source Project + */ + +#if !defined(AVB_INSIDE_LIBAVB_H) && !defined(AVB_COMPILATION) +#error "Never include this file directly, include libavb.h instead." +#endif + +#ifndef AVB_SLOT_VERIFY_H_ +#define AVB_SLOT_VERIFY_H_ + +#include "avb_ops.h" +#include "avb_vbmeta_image.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Return codes used in avb_slot_verify(), see that function for + * documentation for each field. + * + * Use avb_slot_verify_result_to_string() to get a textual + * representation usable for error/debug output. + */ +typedef enum { + AVB_SLOT_VERIFY_RESULT_OK, + AVB_SLOT_VERIFY_RESULT_ERROR_OOM, + AVB_SLOT_VERIFY_RESULT_ERROR_IO, + AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION, + AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX, + AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED, + AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA, + AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION, + AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT +} AvbSlotVerifyResult; + +/* Various error handling modes for when verification fails using a + * hashtree at runtime inside the HLOS. + * + * AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE means that the OS + * will invalidate the current slot and restart. + * + * AVB_HASHTREE_ERROR_MODE_RESTART means that the OS will restart. + * + * AVB_HASHTREE_ERROR_MODE_EIO means that an EIO error will be + * returned to applications. + * + * AVB_HASHTREE_ERROR_MODE_LOGGING means that errors will be logged + * and corrupt data may be returned to applications. This mode should + * be used ONLY for diagnostics and debugging. It cannot be used + * unless AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR is also + * used. + */ +typedef enum { + AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE, + AVB_HASHTREE_ERROR_MODE_RESTART, + AVB_HASHTREE_ERROR_MODE_EIO, + AVB_HASHTREE_ERROR_MODE_LOGGING +} AvbHashtreeErrorMode; + +/* Flags that influence how avb_slot_verify() works. + * + * If AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR is NOT set then + * avb_slot_verify() will bail out as soon as an error is encountered + * and |out_data| is set only if AVB_SLOT_VERIFY_RESULT_OK is + * returned. + * + * Otherwise if AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR is set + * avb_slot_verify() will continue verification efforts and |out_data| + * is also set if AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED, + * AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION, or + * AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX is returned. It is + * undefined which error is returned if more than one distinct error + * is encountered. It is guaranteed that AVB_SLOT_VERIFY_RESULT_OK is + * returned if, and only if, there are no errors. This mode is needed + * to boot valid but unverified slots when the device is unlocked. + * + * Also, if AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR is set the + * contents loaded from |requested_partition| will be the contents of + * the entire partition instead of just the size specified in the hash + * descriptor. + */ +typedef enum { + AVB_SLOT_VERIFY_FLAGS_NONE = 0, + AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR = (1 << 0) +} AvbSlotVerifyFlags; + +/* Get a textual representation of |result|. */ +const char* avb_slot_verify_result_to_string(AvbSlotVerifyResult result); + +/* Maximum number of rollback index locations supported. */ +#define AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_LOCATIONS 32 + +/* AvbPartitionData contains data loaded from partitions when using + * avb_slot_verify(). The |partition_name| field contains the name of + * the partition (without A/B suffix), |data| points to the loaded + * data which is |data_size| bytes long. If |preloaded| is set to true, + * this structure dose not own |data|. The caller of |avb_slot_verify| + * needs to make sure that the preloaded data outlives this + * |AvbPartitionData| structure. + * + * Note that this is strictly less than the partition size - it's only + * the image stored there, not the entire partition nor any of the + * metadata. + */ +typedef struct { + char* partition_name; + uint8_t* data; + size_t data_size; + bool preloaded; +} AvbPartitionData; + +/* AvbVBMetaData contains a vbmeta struct loaded from a partition when + * using avb_slot_verify(). The |partition_name| field contains the + * name of the partition (without A/B suffix), |vbmeta_data| points to + * the loaded data which is |vbmeta_size| bytes long. + * + * The |verify_result| field contains the result of + * avb_vbmeta_image_verify() on the data. This is guaranteed to be + * AVB_VBMETA_VERIFY_RESULT_OK for all vbmeta images if + * avb_slot_verify() returns AVB_SLOT_VERIFY_RESULT_OK. + * + * You can use avb_descriptor_get_all(), avb_descriptor_foreach(), and + * avb_vbmeta_image_header_to_host_byte_order() with this data. + */ +typedef struct { + char* partition_name; + uint8_t* vbmeta_data; + size_t vbmeta_size; + AvbVBMetaVerifyResult verify_result; +} AvbVBMetaData; + +/* AvbSlotVerifyData contains data needed to boot a particular slot + * and is returned by avb_slot_verify() if partitions in a slot are + * successfully verified. + * + * All data pointed to by this struct - including data in each item in + * the |partitions| array - will be freed when the + * avb_slot_verify_data_free() function is called. + * + * The |ab_suffix| field is the copy of the of |ab_suffix| field + * passed to avb_slot_verify(). It is the A/B suffix of the slot. This + * value includes the leading underscore - typical values are "" (if + * no slots are in use), "_a" (for the first slot), and "_b" (for the + * second slot). + * + * The VBMeta images that were checked are available in the + * |vbmeta_images| field. The field |num_vbmeta_images| contains the + * number of elements in this array. The first element - + * vbmeta_images[0] - is guaranteed to be from the partition with the + * top-level vbmeta struct. This is usually the "vbmeta" partition in + * the requested slot but if there is no "vbmeta" partition it can + * also be the "boot" partition. + * + * The partitions loaded and verified from from the slot are + * accessible in the |loaded_partitions| array. The field + * |num_loaded_partitions| contains the number of elements in this + * array. The order of partitions in this array may not necessarily be + * the same order as in the passed-in |requested_partitions| array. + * + * Rollback indexes for the verified slot are stored in the + * |rollback_indexes| field. Note that avb_slot_verify() will NEVER + * modify stored_rollback_index[n] locations e.g. it will never use + * the write_rollback_index() AvbOps operation. Instead it is the job + * of the caller of avb_slot_verify() to do this based on e.g. A/B + * policy and other factors. See libavb_ab/avb_ab_flow.c for an + * example of how to do this. + * + * The |cmdline| field is a NUL-terminated string in UTF-8 resulting + * from concatenating all |AvbKernelCmdlineDescriptor| and then + * performing proper substitution of the variables + * $(ANDROID_SYSTEM_PARTUUID), $(ANDROID_BOOT_PARTUUID), and + * $(ANDROID_VBMETA_PARTUUID) using the + * get_unique_guid_for_partition() operation in |AvbOps|. Additionally + * $(ANDROID_VERITY_MODE) will be replaced with the proper dm-verity + * option depending on the value of |hashtree_error_mode|. + * + * Additionally, the |cmdline| field will have the following kernel + * command-line options set (unless verification is disabled, see + * below): + * + * androidboot.veritymode: This is set to 'disabled' if the + * AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED flag is set in top-level + * vbmeta struct. Otherwise it is set to 'enforcing' if the + * passed-in hashtree error mode is AVB_HASHTREE_ERROR_MODE_RESTART + * or AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE, 'eio' if it's + * set to AVB_HASHTREE_ERROR_MODE_EIO, and 'logging' if it's set to + * AVB_HASHTREE_ERROR_MODE_LOGGING. + * + * androidboot.vbmeta.invalidate_on_error: This is set to 'yes' only + * if hashtree validation isn't disabled and the passed-in hashtree + * error mode is AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE. + * + * androidboot.vbmeta.device_state: set to "locked" or "unlocked" + * depending on the result of the result of AvbOps's + * read_is_unlocked() function. + * + * androidboot.vbmeta.{hash_alg, size, digest}: Will be set to + * the digest of all images in |vbmeta_images|. + * + * androidboot.vbmeta.device: This is set to the value + * PARTUUID=$(ANDROID_VBMETA_PARTUUID) before substitution so it + * will end up pointing to the vbmeta partition for the verified + * slot. If there is no vbmeta partition it will point to the boot + * partition of the verified slot. + * + * androidboot.vbmeta.avb_version: This is set to the decimal value + * of AVB_VERSION_MAJOR followed by a dot followed by the decimal + * value of AVB_VERSION_MINOR, for example "1.0" or "1.4". This + * version number represents the vbmeta file format version + * supported by libavb copy used in the boot loader. This is not + * necessarily the same version number of the on-disk metadata for + * the slot that was verified. + * + * Note that androidboot.slot_suffix is not set in the |cmdline| field + * in |AvbSlotVerifyData| - you will have to set this yourself. + * + * If the |AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED| flag is set + * in the top-level vbmeta struct then only the top-level vbmeta + * struct is verified and descriptors will not processed. The return + * value will be set accordingly (if this flag is set via 'avbctl + * disable-verification' then the return value will be + * |AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION|) and + * |AvbSlotVerifyData| is returned. Additionally all partitions in the + * |requested_partitions| are loaded and the |cmdline| field is set to + * "root=PARTUUID=$(ANDROID_SYSTEM_PARTUUID)" and the GUID for the + * appropriate system partition is substituted in. Note that none of + * the androidboot.* options mentioned above will be set. + * + * This struct may grow in the future without it being considered an + * ABI break. + */ +typedef struct { + char* ab_suffix; + AvbVBMetaData* vbmeta_images; + size_t num_vbmeta_images; + AvbPartitionData* loaded_partitions; + size_t num_loaded_partitions; + char* cmdline; + uint64_t rollback_indexes[AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_LOCATIONS]; +} AvbSlotVerifyData; + +/* Calculates a digest of all vbmeta images in |data| using + * the digest indicated by |digest_type|. Stores the result + * in |out_digest| which must be large enough to hold a digest + * of the requested type. + */ +void avb_slot_verify_data_calculate_vbmeta_digest(AvbSlotVerifyData* data, + AvbDigestType digest_type, + uint8_t* out_digest); + +/* Frees a |AvbSlotVerifyData| including all data it points to. */ +void avb_slot_verify_data_free(AvbSlotVerifyData* data); + +/* Performs a full verification of the slot identified by |ab_suffix| + * and load and verify the contents of the partitions whose name is in + * the NULL-terminated string array |requested_partitions| (each + * partition must use hash verification). If not using A/B, pass an + * empty string (e.g. "", not NULL) for |ab_suffix|. This parameter + * must include the leading underscore, for example "_a" should be + * used to refer to the first slot. + * + * Typically the |requested_partitions| array only contains a single + * item for the boot partition, 'boot'. + * + * Verification includes loading and verifying data from the 'vbmeta', + * the requested hash partitions, and possibly other partitions (with + * |ab_suffix| appended), inspecting rollback indexes, and checking if + * the public key used to sign the data is acceptable. The functions + * in |ops| will be used to do this. + * + * If |out_data| is not NULL, it will be set to a newly allocated + * |AvbSlotVerifyData| struct containing all the data needed to + * actually boot the slot. This data structure should be freed with + * avb_slot_verify_data_free() when you are done with it. See below + * for when this is returned. + * + * The |flags| parameter is used to influence the semantics of + * avb_slot_verify() - for example the + * AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR flag can be used to + * ignore verification errors which is something needed in the + * UNLOCKED state. See the AvbSlotVerifyFlags enumeration for details. + * + * The |hashtree_error_mode| parameter should be set to the desired + * error handling mode when hashtree validation fails inside the + * HLOS. This value isn't used by libavb per se - it is forwarded to + * the HLOS through the androidboot.veritymode and + * androidboot.vbmeta.invalidate_on_error cmdline parameters. See the + * AvbHashtreeErrorMode enumeration for details. + * + * Also note that |out_data| is never set if + * AVB_SLOT_VERIFY_RESULT_ERROR_OOM, AVB_SLOT_VERIFY_RESULT_ERROR_IO, + * or AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA is returned. + * + * AVB_SLOT_VERIFY_RESULT_OK is returned if everything is verified + * correctly and all public keys are accepted. + * + * AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED is returned if + * everything is verified correctly out but one or more public keys + * are not accepted. This includes the case where integrity data is + * not signed. + * + * AVB_SLOT_VERIFY_RESULT_ERROR_OOM is returned if unable to + * allocate memory. + * + * AVB_SLOT_VERIFY_RESULT_ERROR_IO is returned if an I/O error + * occurred while trying to load data or get a rollback index. + * + * AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION is returned if the data + * did not verify, e.g. the digest didn't match or signature checks + * failed. + * + * AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX is returned if a + * rollback index was less than its stored value. + * + * AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA is returned if some + * of the metadata is invalid or inconsistent. + * + * AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION is returned if + * some of the metadata requires a newer version of libavb than what + * is in use. + * + * AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT is returned if the + * caller passed invalid parameters, for example trying to use + * AVB_HASHTREE_ERROR_MODE_LOGGING without + * AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR. + */ +AvbSlotVerifyResult avb_slot_verify(AvbOps* ops, + const char* const* requested_partitions, + const char* ab_suffix, + AvbSlotVerifyFlags flags, + AvbHashtreeErrorMode hashtree_error_mode, + AvbSlotVerifyData** out_data); + +#ifdef __cplusplus +} +#endif + +#endif /* AVB_SLOT_VERIFY_H_ */ diff --git a/lib/libavb/avb_sysdeps.h b/lib/libavb/avb_sysdeps.h new file mode 100644 index 0000000000..f032de4a2e --- /dev/null +++ b/lib/libavb/avb_sysdeps.h @@ -0,0 +1,100 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright (C) 2016 The Android Open Source Project + */ + +#if !defined(AVB_INSIDE_LIBAVB_H) && !defined(AVB_COMPILATION) +#error "Never include this file directly, include libavb.h instead." +#endif + +#ifndef AVB_SYSDEPS_H_ +#define AVB_SYSDEPS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Change these includes to match your platform to bring in the + * equivalent types available in a normal C runtime. At least things + * like uint8_t, uint64_t, and bool (with |false|, |true| keywords) + * must be present. + */ +#include <common.h> + +/* If you don't have gcc or clang, these attribute macros may need to + * be adjusted. + */ +#define AVB_ATTR_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) +#define AVB_ATTR_PACKED __attribute__((packed)) +#define AVB_ATTR_NO_RETURN __attribute__((noreturn)) +#define AVB_ATTR_SENTINEL __attribute__((__sentinel__)) + +/* Size in bytes used for alignment. */ +#ifdef __LP64__ +#define AVB_ALIGNMENT_SIZE 8 +#else +#define AVB_ALIGNMENT_SIZE 4 +#endif + +/* Compare |n| bytes in |src1| and |src2|. + * + * Returns an integer less than, equal to, or greater than zero if the + * first |n| bytes of |src1| is found, respectively, to be less than, + * to match, or be greater than the first |n| bytes of |src2|. */ +int avb_memcmp(const void* src1, + const void* src2, + size_t n) AVB_ATTR_WARN_UNUSED_RESULT; + +/* Compare two strings. + * + * Return an integer less than, equal to, or greater than zero if |s1| + * is found, respectively, to be less than, to match, or be greater + * than |s2|. + */ +int avb_strcmp(const char* s1, const char* s2); + +/* Copy |n| bytes from |src| to |dest|. */ +void* avb_memcpy(void* dest, const void* src, size_t n); + +/* Set |n| bytes starting at |s| to |c|. Returns |dest|. */ +void* avb_memset(void* dest, const int c, size_t n); + +/* Prints out a message. The string passed must be a NUL-terminated + * UTF-8 string. + */ +void avb_print(const char* message); + +/* Prints out a vector of strings. Each argument must point to a + * NUL-terminated UTF-8 string and NULL should be the last argument. + */ +void avb_printv(const char* message, ...) AVB_ATTR_SENTINEL; + +/* Aborts the program or reboots the device. */ +void avb_abort(void) AVB_ATTR_NO_RETURN; + +/* Allocates |size| bytes. Returns NULL if no memory is available, + * otherwise a pointer to the allocated memory. + * + * The memory is not initialized. + * + * The pointer returned is guaranteed to be word-aligned. + * + * The memory should be freed with avb_free() when you are done with it. + */ +void* avb_malloc_(size_t size) AVB_ATTR_WARN_UNUSED_RESULT; + +/* Frees memory previously allocated with avb_malloc(). */ +void avb_free(void* ptr); + +/* Returns the lenght of |str|, excluding the terminating NUL-byte. */ +size_t avb_strlen(const char* str) AVB_ATTR_WARN_UNUSED_RESULT; + +/* Divide the |dividend| by 10 and saves back to the pointer. Return the + * remainder. */ +uint32_t avb_div_by_10(uint64_t* dividend); + +#ifdef __cplusplus +} +#endif + +#endif /* AVB_SYSDEPS_H_ */ diff --git a/lib/libavb/avb_sysdeps_posix.c b/lib/libavb/avb_sysdeps_posix.c new file mode 100644 index 0000000000..e9addc1c87 --- /dev/null +++ b/lib/libavb/avb_sysdeps_posix.c @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright (C) 2016 The Android Open Source Project + */ + +#include <stdarg.h> +#include <stdlib.h> + +#include "avb_sysdeps.h" + +int avb_memcmp(const void* src1, const void* src2, size_t n) { + return memcmp(src1, src2, n); +} + +void* avb_memcpy(void* dest, const void* src, size_t n) { + return memcpy(dest, src, n); +} + +void* avb_memset(void* dest, const int c, size_t n) { + return memset(dest, c, n); +} + +int avb_strcmp(const char* s1, const char* s2) { + return strcmp(s1, s2); +} + +size_t avb_strlen(const char* str) { + return strlen(str); +} + +uint32_t avb_div_by_10(uint64_t* dividend) { + uint32_t rem = (uint32_t)(*dividend % 10); + *dividend /= 10; + return rem; +} + +void avb_abort(void) { + hang(); +} + +void avb_print(const char* message) { + printf("%s", message); +} + +void avb_printv(const char* message, ...) { + va_list ap; + const char* m; + + va_start(ap, message); + for (m = message; m != NULL; m = va_arg(ap, const char*)) { + printf("%s", m); + } + va_end(ap); +} + +void* avb_malloc_(size_t size) { + return malloc(size); +} + +void avb_free(void* ptr) { + free(ptr); +} diff --git a/lib/libavb/avb_util.c b/lib/libavb/avb_util.c new file mode 100644 index 0000000000..405d625351 --- /dev/null +++ b/lib/libavb/avb_util.c @@ -0,0 +1,411 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright (C) 2016 The Android Open Source Project + */ + +#include "avb_util.h" + +#include <stdarg.h> + +uint32_t avb_be32toh(uint32_t in) { + uint8_t* d = (uint8_t*)∈ + uint32_t ret; + ret = ((uint32_t)d[0]) << 24; + ret |= ((uint32_t)d[1]) << 16; + ret |= ((uint32_t)d[2]) << 8; + ret |= ((uint32_t)d[3]); + return ret; +} + +uint64_t avb_be64toh(uint64_t in) { + uint8_t* d = (uint8_t*)∈ + uint64_t ret; + ret = ((uint64_t)d[0]) << 56; + ret |= ((uint64_t)d[1]) << 48; + ret |= ((uint64_t)d[2]) << 40; + ret |= ((uint64_t)d[3]) << 32; + ret |= ((uint64_t)d[4]) << 24; + ret |= ((uint64_t)d[5]) << 16; + ret |= ((uint64_t)d[6]) << 8; + ret |= ((uint64_t)d[7]); + return ret; +} + +/* Converts a 32-bit unsigned integer from host to big-endian byte order. */ +uint32_t avb_htobe32(uint32_t in) { + union { + uint32_t word; + uint8_t bytes[4]; + } ret; + ret.bytes[0] = (in >> 24) & 0xff; + ret.bytes[1] = (in >> 16) & 0xff; + ret.bytes[2] = (in >> 8) & 0xff; + ret.bytes[3] = in & 0xff; + return ret.word; +} + +/* Converts a 64-bit unsigned integer from host to big-endian byte order. */ +uint64_t avb_htobe64(uint64_t in) { + union { + uint64_t word; + uint8_t bytes[8]; + } ret; + ret.bytes[0] = (in >> 56) & 0xff; + ret.bytes[1] = (in >> 48) & 0xff; + ret.bytes[2] = (in >> 40) & 0xff; + ret.bytes[3] = (in >> 32) & 0xff; + ret.bytes[4] = (in >> 24) & 0xff; + ret.bytes[5] = (in >> 16) & 0xff; + ret.bytes[6] = (in >> 8) & 0xff; + ret.bytes[7] = in & 0xff; + return ret.word; +} + +int avb_safe_memcmp(const void* s1, const void* s2, size_t n) { + const unsigned char* us1 = s1; + const unsigned char* us2 = s2; + int result = 0; + + if (0 == n) { + return 0; + } + + /* + * Code snippet without data-dependent branch due to Nate Lawson + * (nate@root.org) of Root Labs. + */ + while (n--) { + result |= *us1++ ^ *us2++; + } + + return result != 0; +} + +bool avb_safe_add_to(uint64_t* value, uint64_t value_to_add) { + uint64_t original_value; + + avb_assert(value != NULL); + + original_value = *value; + + *value += value_to_add; + if (*value < original_value) { + avb_error("Overflow when adding values.\n"); + return false; + } + + return true; +} + +bool avb_safe_add(uint64_t* out_result, uint64_t a, uint64_t b) { + uint64_t dummy; + if (out_result == NULL) { + out_result = &dummy; + } + *out_result = a; + return avb_safe_add_to(out_result, b); +} + +bool avb_validate_utf8(const uint8_t* data, size_t num_bytes) { + size_t n; + unsigned int num_cc; + + for (n = 0, num_cc = 0; n < num_bytes; n++) { + uint8_t c = data[n]; + + if (num_cc > 0) { + if ((c & (0x80 | 0x40)) == 0x80) { + /* 10xx xxxx */ + } else { + goto fail; + } + num_cc--; + } else { + if (c < 0x80) { + num_cc = 0; + } else if ((c & (0x80 | 0x40 | 0x20)) == (0x80 | 0x40)) { + /* 110x xxxx */ + num_cc = 1; + } else if ((c & (0x80 | 0x40 | 0x20 | 0x10)) == (0x80 | 0x40 | 0x20)) { + /* 1110 xxxx */ + num_cc = 2; + } else if ((c & (0x80 | 0x40 | 0x20 | 0x10 | 0x08)) == + (0x80 | 0x40 | 0x20 | 0x10)) { + /* 1111 0xxx */ + num_cc = 3; + } else { + goto fail; + } + } + } + + if (num_cc != 0) { + goto fail; + } + + return true; + +fail: + return false; +} + +bool avb_str_concat(char* buf, + size_t buf_size, + const char* str1, + size_t str1_len, + const char* str2, + size_t str2_len) { + uint64_t combined_len; + + if (!avb_safe_add(&combined_len, str1_len, str2_len)) { + avb_error("Overflow when adding string sizes.\n"); + return false; + } + + if (combined_len > buf_size - 1) { + avb_error("Insufficient buffer space.\n"); + return false; + } + + avb_memcpy(buf, str1, str1_len); + avb_memcpy(buf + str1_len, str2, str2_len); + buf[combined_len] = '\0'; + + return true; +} + +void* avb_malloc(size_t size) { + void* ret = avb_malloc_(size); + if (ret == NULL) { + avb_error("Failed to allocate memory.\n"); + return NULL; + } + return ret; +} + +void* avb_calloc(size_t size) { + void* ret = avb_malloc(size); + if (ret == NULL) { + return NULL; + } + + avb_memset(ret, '\0', size); + return ret; +} + +char* avb_strdup(const char* str) { + size_t len = avb_strlen(str); + char* ret = avb_malloc(len + 1); + if (ret == NULL) { + return NULL; + } + + avb_memcpy(ret, str, len); + ret[len] = '\0'; + + return ret; +} + +const char* avb_strstr(const char* haystack, const char* needle) { + size_t n, m; + + /* Look through |haystack| and check if the first character of + * |needle| matches. If so, check the rest of |needle|. + */ + for (n = 0; haystack[n] != '\0'; n++) { + if (haystack[n] != needle[0]) { + continue; + } + + for (m = 1;; m++) { + if (needle[m] == '\0') { + return haystack + n; + } + + if (haystack[n + m] != needle[m]) { + break; + } + } + } + + return NULL; +} + +const char* avb_strv_find_str(const char* const* strings, + const char* str, + size_t str_size) { + size_t n; + for (n = 0; strings[n] != NULL; n++) { + if (avb_strlen(strings[n]) == str_size && + avb_memcmp(strings[n], str, str_size) == 0) { + return strings[n]; + } + } + return NULL; +} + +char* avb_replace(const char* str, const char* search, const char* replace) { + char* ret = NULL; + size_t ret_len = 0; + size_t search_len, replace_len; + const char* str_after_last_replace; + + search_len = avb_strlen(search); + replace_len = avb_strlen(replace); + + str_after_last_replace = str; + while (*str != '\0') { + const char* s; + size_t num_before; + size_t num_new; + + s = avb_strstr(str, search); + if (s == NULL) { + break; + } + + num_before = s - str; + + if (ret == NULL) { + num_new = num_before + replace_len + 1; + ret = avb_malloc(num_new); + if (ret == NULL) { + goto out; + } + avb_memcpy(ret, str, num_before); + avb_memcpy(ret + num_before, replace, replace_len); + ret[num_new - 1] = '\0'; + ret_len = num_new - 1; + } else { + char* new_str; + num_new = ret_len + num_before + replace_len + 1; + new_str = avb_malloc(num_new); + if (new_str == NULL) { + goto out; + } + avb_memcpy(new_str, ret, ret_len); + avb_memcpy(new_str + ret_len, str, num_before); + avb_memcpy(new_str + ret_len + num_before, replace, replace_len); + new_str[num_new - 1] = '\0'; + avb_free(ret); + ret = new_str; + ret_len = num_new - 1; + } + + str = s + search_len; + str_after_last_replace = str; + } + + if (ret == NULL) { + ret = avb_strdup(str_after_last_replace); + if (ret == NULL) { + goto out; + } + } else { + size_t num_remaining = avb_strlen(str_after_last_replace); + size_t num_new = ret_len + num_remaining + 1; + char* new_str = avb_malloc(num_new); + if (new_str == NULL) { + goto out; + } + avb_memcpy(new_str, ret, ret_len); + avb_memcpy(new_str + ret_len, str_after_last_replace, num_remaining); + new_str[num_new - 1] = '\0'; + avb_free(ret); + ret = new_str; + ret_len = num_new - 1; + } + +out: + return ret; +} + +/* We only support a limited amount of strings in avb_strdupv(). */ +#define AVB_STRDUPV_MAX_NUM_STRINGS 32 + +char* avb_strdupv(const char* str, ...) { + va_list ap; + const char* strings[AVB_STRDUPV_MAX_NUM_STRINGS]; + size_t lengths[AVB_STRDUPV_MAX_NUM_STRINGS]; + size_t num_strings, n; + uint64_t total_length; + char *ret = NULL, *dest; + + num_strings = 0; + total_length = 0; + va_start(ap, str); + do { + size_t str_len = avb_strlen(str); + strings[num_strings] = str; + lengths[num_strings] = str_len; + if (!avb_safe_add_to(&total_length, str_len)) { + avb_fatal("Overflow while determining total length.\n"); + break; + } + num_strings++; + if (num_strings == AVB_STRDUPV_MAX_NUM_STRINGS) { + avb_fatal("Too many strings passed.\n"); + break; + } + str = va_arg(ap, const char*); + } while (str != NULL); + va_end(ap); + + ret = avb_malloc(total_length + 1); + if (ret == NULL) { + goto out; + } + + dest = ret; + for (n = 0; n < num_strings; n++) { + avb_memcpy(dest, strings[n], lengths[n]); + dest += lengths[n]; + } + *dest = '\0'; + avb_assert(dest == ret + total_length); + +out: + return ret; +} + +const char* avb_basename(const char* str) { + int64_t n; + size_t len; + + len = avb_strlen(str); + if (len >= 2) { + for (n = len - 2; n >= 0; n--) { + if (str[n] == '/') { + return str + n + 1; + } + } + } + return str; +} + +void avb_uppercase(char* str) { + size_t i; + for (i = 0; str[i] != '\0'; ++i) { + if (str[i] <= 0x7A && str[i] >= 0x61) { + str[i] -= 0x20; + } + } +} + +char* avb_bin2hex(const uint8_t* data, size_t data_len) { + const char hex_digits[17] = "0123456789abcdef"; + char* hex_data; + size_t n; + + hex_data = avb_malloc(data_len * 2 + 1); + if (hex_data == NULL) { + return NULL; + } + + for (n = 0; n < data_len; n++) { + hex_data[n * 2] = hex_digits[data[n] >> 4]; + hex_data[n * 2 + 1] = hex_digits[data[n] & 0x0f]; + } + hex_data[n * 2] = '\0'; + return hex_data; +} diff --git a/lib/libavb/avb_util.h b/lib/libavb/avb_util.h new file mode 100644 index 0000000000..26dc6b045a --- /dev/null +++ b/lib/libavb/avb_util.h @@ -0,0 +1,268 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright (C) 2016 The Android Open Source Project + */ + +#if !defined(AVB_INSIDE_LIBAVB_H) && !defined(AVB_COMPILATION) +#error "Never include this file directly, include libavb.h instead." +#endif + +#ifndef AVB_UTIL_H_ +#define AVB_UTIL_H_ + +#include "avb_sysdeps.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define AVB_STRINGIFY(x) #x +#define AVB_TO_STRING(x) AVB_STRINGIFY(x) + +#ifdef AVB_ENABLE_DEBUG +/* Aborts the program if |expr| is false. + * + * This has no effect unless AVB_ENABLE_DEBUG is defined. + */ +#define avb_assert(expr) \ + do { \ + if (!(expr)) { \ + avb_fatal("assert fail: " #expr "\n"); \ + } \ + } while (0) +#else +#define avb_assert(expr) +#endif + +/* Aborts the program if reached. + * + * This has no effect unless AVB_ENABLE_DEBUG is defined. + */ +#ifdef AVB_ENABLE_DEBUG +#define avb_assert_not_reached() \ + do { \ + avb_fatal("assert_not_reached()\n"); \ + } while (0) +#else +#define avb_assert_not_reached() +#endif + +/* Aborts the program if |addr| is not word-aligned. + * + * This has no effect unless AVB_ENABLE_DEBUG is defined. + */ +#define avb_assert_aligned(addr) \ + avb_assert((((uintptr_t)addr) & (AVB_ALIGNMENT_SIZE - 1)) == 0) + +#ifdef AVB_ENABLE_DEBUG +/* Print functions, used for diagnostics. + * + * These have no effect unless AVB_ENABLE_DEBUG is defined. + */ +#define avb_debug(message) \ + do { \ + avb_printv(avb_basename(__FILE__), \ + ":", \ + AVB_TO_STRING(__LINE__), \ + ": DEBUG: ", \ + message, \ + NULL); \ + } while (0) +#define avb_debugv(message, ...) \ + do { \ + avb_printv(avb_basename(__FILE__), \ + ":", \ + AVB_TO_STRING(__LINE__), \ + ": DEBUG: ", \ + message, \ + ##__VA_ARGS__); \ + } while (0) +#else +#define avb_debug(message) +#define avb_debugv(message, ...) +#endif + +/* Prints out a message. This is typically used if a runtime-error + * occurs. + */ +#define avb_error(message) \ + do { \ + avb_printv(avb_basename(__FILE__), \ + ":", \ + AVB_TO_STRING(__LINE__), \ + ": ERROR: ", \ + message, \ + NULL); \ + } while (0) +#define avb_errorv(message, ...) \ + do { \ + avb_printv(avb_basename(__FILE__), \ + ":", \ + AVB_TO_STRING(__LINE__), \ + ": ERROR: ", \ + message, \ + ##__VA_ARGS__); \ + } while (0) + +/* Prints out a message and calls avb_abort(). + */ +#define avb_fatal(message) \ + do { \ + avb_printv(avb_basename(__FILE__), \ + ":", \ + AVB_TO_STRING(__LINE__), \ + ": FATAL: ", \ + message, \ + NULL); \ + avb_abort(); \ + } while (0) +#define avb_fatalv(message, ...) \ + do { \ + avb_printv(avb_basename(__FILE__), \ + ":", \ + AVB_TO_STRING(__LINE__), \ + ": FATAL: ", \ + message, \ + ##__VA_ARGS__); \ + avb_abort(); \ + } while (0) + +/* Converts a 32-bit unsigned integer from big-endian to host byte order. */ +uint32_t avb_be32toh(uint32_t in) AVB_ATTR_WARN_UNUSED_RESULT; + +/* Converts a 64-bit unsigned integer from big-endian to host byte order. */ +uint64_t avb_be64toh(uint64_t in) AVB_ATTR_WARN_UNUSED_RESULT; + +/* Converts a 32-bit unsigned integer from host to big-endian byte order. */ +uint32_t avb_htobe32(uint32_t in) AVB_ATTR_WARN_UNUSED_RESULT; + +/* Converts a 64-bit unsigned integer from host to big-endian byte order. */ +uint64_t avb_htobe64(uint64_t in) AVB_ATTR_WARN_UNUSED_RESULT; + +/* Compare |n| bytes starting at |s1| with |s2| and return 0 if they + * match, 1 if they don't. Returns 0 if |n|==0, since no bytes + * mismatched. + * + * Time taken to perform the comparison is only dependent on |n| and + * not on the relationship of the match between |s1| and |s2|. + * + * Note that unlike avb_memcmp(), this only indicates inequality, not + * whether |s1| is less than or greater than |s2|. + */ +int avb_safe_memcmp(const void* s1, + const void* s2, + size_t n) AVB_ATTR_WARN_UNUSED_RESULT; + +/* Adds |value_to_add| to |value| with overflow protection. + * + * Returns false if the addition overflows, true otherwise. In either + * case, |value| is always modified. + */ +bool avb_safe_add_to(uint64_t* value, + uint64_t value_to_add) AVB_ATTR_WARN_UNUSED_RESULT; + +/* Adds |a| and |b| with overflow protection, returning the value in + * |out_result|. + * + * It's permissible to pass NULL for |out_result| if you just want to + * check that the addition would not overflow. + * + * Returns false if the addition overflows, true otherwise. + */ +bool avb_safe_add(uint64_t* out_result, + uint64_t a, + uint64_t b) AVB_ATTR_WARN_UNUSED_RESULT; + +/* Checks if |num_bytes| data at |data| is a valid UTF-8 + * string. Returns true if valid UTF-8, false otherwise. + */ +bool avb_validate_utf8(const uint8_t* data, + size_t num_bytes) AVB_ATTR_WARN_UNUSED_RESULT; + +/* Concatenates |str1| (of |str1_len| bytes) and |str2| (of |str2_len| + * bytes) and puts the result in |buf| which holds |buf_size| + * bytes. The result is also guaranteed to be NUL terminated. Fail if + * there is not enough room in |buf| for the resulting string plus + * terminating NUL byte. + * + * Returns true if the operation succeeds, false otherwise. + */ +bool avb_str_concat(char* buf, + size_t buf_size, + const char* str1, + size_t str1_len, + const char* str2, + size_t str2_len); + +/* Like avb_malloc_() but prints a error using avb_error() if memory + * allocation fails. + */ +void* avb_malloc(size_t size) AVB_ATTR_WARN_UNUSED_RESULT; + +/* Like avb_malloc() but sets the memory with zeroes. */ +void* avb_calloc(size_t size) AVB_ATTR_WARN_UNUSED_RESULT; + +/* Duplicates a NUL-terminated string. Returns NULL on OOM. */ +char* avb_strdup(const char* str) AVB_ATTR_WARN_UNUSED_RESULT; + +/* Duplicates a NULL-terminated array of NUL-terminated strings by + * concatenating them. The returned string will be + * NUL-terminated. Returns NULL on OOM. + */ +char* avb_strdupv(const char* str, + ...) AVB_ATTR_WARN_UNUSED_RESULT AVB_ATTR_SENTINEL; + +/* Finds the first occurrence of |needle| in the string |haystack| + * where both strings are NUL-terminated strings. The terminating NUL + * bytes are not compared. + * + * Returns NULL if not found, otherwise points into |haystack| for the + * first occurrence of |needle|. + */ +const char* avb_strstr(const char* haystack, + const char* needle) AVB_ATTR_WARN_UNUSED_RESULT; + +/* Finds the first occurrence of |str| in the NULL-terminated string + * array |strings|. Each element in |strings| must be + * NUL-terminated. The string given by |str| need not be + * NUL-terminated but its size must be given in |str_size|. + * + * Returns NULL if not found, otherwise points into |strings| for the + * first occurrence of |str|. + */ +const char* avb_strv_find_str(const char* const* strings, + const char* str, + size_t str_size); + +/* Replaces all occurrences of |search| with |replace| in |str|. + * + * Returns a newly allocated string or NULL if out of memory. + */ +char* avb_replace(const char* str, + const char* search, + const char* replace) AVB_ATTR_WARN_UNUSED_RESULT; + +/* Calculates the CRC-32 for data in |buf| of size |buf_size|. */ +uint32_t avb_crc32(const uint8_t* buf, size_t buf_size); + +/* Returns the basename of |str|. This is defined as the last path + * component, assuming the normal POSIX separator '/'. If there are no + * separators, returns |str|. + */ +const char* avb_basename(const char* str); + +/* Converts any ascii lowercase characters in |str| to uppercase in-place. + * |str| must be NUL-terminated and valid UTF-8. + */ +void avb_uppercase(char* str); + +/* Converts |data_len| bytes of |data| to hex and returns the result. Returns + * NULL on OOM. Caller must free the returned string with avb_free. + */ +char* avb_bin2hex(const uint8_t* data, size_t data_len); + +#ifdef __cplusplus +} +#endif + +#endif /* AVB_UTIL_H_ */ diff --git a/lib/libavb/avb_vbmeta_image.c b/lib/libavb/avb_vbmeta_image.c new file mode 100644 index 0000000000..a7e2322b9e --- /dev/null +++ b/lib/libavb/avb_vbmeta_image.c @@ -0,0 +1,289 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright (C) 2016 The Android Open Source Project + */ + +#include "avb_vbmeta_image.h" +#include "avb_crypto.h" +#include "avb_rsa.h" +#include "avb_sha.h" +#include "avb_util.h" +#include "avb_version.h" + +AvbVBMetaVerifyResult avb_vbmeta_image_verify( + const uint8_t* data, + size_t length, + const uint8_t** out_public_key_data, + size_t* out_public_key_length) { + AvbVBMetaVerifyResult ret; + AvbVBMetaImageHeader h; + uint8_t* computed_hash; + const AvbAlgorithmData* algorithm; + AvbSHA256Ctx sha256_ctx; + AvbSHA512Ctx sha512_ctx; + const uint8_t* header_block; + const uint8_t* authentication_block; + const uint8_t* auxiliary_block; + int verification_result; + + ret = AVB_VBMETA_VERIFY_RESULT_INVALID_VBMETA_HEADER; + + if (out_public_key_data != NULL) { + *out_public_key_data = NULL; + } + if (out_public_key_length != NULL) { + *out_public_key_length = 0; + } + + /* Ensure magic is correct. */ + if (avb_safe_memcmp(data, AVB_MAGIC, AVB_MAGIC_LEN) != 0) { + avb_error("Magic is incorrect.\n"); + goto out; + } + + /* Before we byteswap, ensure length is long enough. */ + if (length < sizeof(AvbVBMetaImageHeader)) { + avb_error("Length is smaller than header.\n"); + goto out; + } + avb_vbmeta_image_header_to_host_byte_order((const AvbVBMetaImageHeader*)data, + &h); + + /* Ensure we don't attempt to access any fields if we do not meet + * the specified minimum version of libavb. + */ + if ((h.required_libavb_version_major != AVB_VERSION_MAJOR) || + (h.required_libavb_version_minor > AVB_VERSION_MINOR)) { + avb_error("Mismatch between image version and libavb version.\n"); + ret = AVB_VBMETA_VERIFY_RESULT_UNSUPPORTED_VERSION; + goto out; + } + + /* Ensure |release_string| ends with a NUL byte. */ + if (h.release_string[AVB_RELEASE_STRING_SIZE - 1] != '\0') { + avb_error("Release string does not end with a NUL byte.\n"); + goto out; + } + + /* Ensure inner block sizes are multiple of 64. */ + if ((h.authentication_data_block_size & 0x3f) != 0 || + (h.auxiliary_data_block_size & 0x3f) != 0) { + avb_error("Block size is not a multiple of 64.\n"); + goto out; + } + + /* Ensure block sizes all add up to at most |length|. */ + uint64_t block_total = sizeof(AvbVBMetaImageHeader); + if (!avb_safe_add_to(&block_total, h.authentication_data_block_size) || + !avb_safe_add_to(&block_total, h.auxiliary_data_block_size)) { + avb_error("Overflow while computing size of boot image.\n"); + goto out; + } + if (block_total > length) { + avb_error("Block sizes add up to more than given length.\n"); + goto out; + } + + uintptr_t data_ptr = (uintptr_t)data; + /* Ensure passed in memory doesn't wrap. */ + if (!avb_safe_add(NULL, (uint64_t)data_ptr, length)) { + avb_error("Boot image location and length mismatch.\n"); + goto out; + } + + /* Ensure hash and signature are entirely in the Authentication data block. */ + uint64_t hash_end; + if (!avb_safe_add(&hash_end, h.hash_offset, h.hash_size) || + hash_end > h.authentication_data_block_size) { + avb_error("Hash is not entirely in its block.\n"); + goto out; + } + uint64_t signature_end; + if (!avb_safe_add(&signature_end, h.signature_offset, h.signature_size) || + signature_end > h.authentication_data_block_size) { + avb_error("Signature is not entirely in its block.\n"); + goto out; + } + + /* Ensure public key is entirely in the Auxiliary data block. */ + uint64_t pubkey_end; + if (!avb_safe_add(&pubkey_end, h.public_key_offset, h.public_key_size) || + pubkey_end > h.auxiliary_data_block_size) { + avb_error("Public key is not entirely in its block.\n"); + goto out; + } + + /* Ensure public key metadata (if set) is entirely in the Auxiliary + * data block. */ + if (h.public_key_metadata_size > 0) { + uint64_t pubkey_md_end; + if (!avb_safe_add(&pubkey_md_end, + h.public_key_metadata_offset, + h.public_key_metadata_size) || + pubkey_md_end > h.auxiliary_data_block_size) { + avb_error("Public key metadata is not entirely in its block.\n"); + goto out; + } + } + + /* Bail early if there's no hash or signature. */ + if (h.algorithm_type == AVB_ALGORITHM_TYPE_NONE) { + ret = AVB_VBMETA_VERIFY_RESULT_OK_NOT_SIGNED; + goto out; + } + + /* Ensure algorithm field is supported. */ + algorithm = avb_get_algorithm_data(h.algorithm_type); + if (!algorithm) { + avb_error("Invalid or unknown algorithm.\n"); + goto out; + } + + /* Bail if the embedded hash size doesn't match the chosen algorithm. */ + if (h.hash_size != algorithm->hash_len) { + avb_error("Embedded hash has wrong size.\n"); + goto out; + } + + /* No overflow checks needed from here-on after since all block + * sizes and offsets have been verified above. + */ + + header_block = data; + authentication_block = header_block + sizeof(AvbVBMetaImageHeader); + auxiliary_block = authentication_block + h.authentication_data_block_size; + + switch (h.algorithm_type) { + /* Explicit fall-through: */ + case AVB_ALGORITHM_TYPE_SHA256_RSA2048: + case AVB_ALGORITHM_TYPE_SHA256_RSA4096: + case AVB_ALGORITHM_TYPE_SHA256_RSA8192: + avb_sha256_init(&sha256_ctx); + avb_sha256_update( + &sha256_ctx, header_block, sizeof(AvbVBMetaImageHeader)); + avb_sha256_update( + &sha256_ctx, auxiliary_block, h.auxiliary_data_block_size); + computed_hash = avb_sha256_final(&sha256_ctx); + break; + /* Explicit fall-through: */ + case AVB_ALGORITHM_TYPE_SHA512_RSA2048: + case AVB_ALGORITHM_TYPE_SHA512_RSA4096: + case AVB_ALGORITHM_TYPE_SHA512_RSA8192: + avb_sha512_init(&sha512_ctx); + avb_sha512_update( + &sha512_ctx, header_block, sizeof(AvbVBMetaImageHeader)); + avb_sha512_update( + &sha512_ctx, auxiliary_block, h.auxiliary_data_block_size); + computed_hash = avb_sha512_final(&sha512_ctx); + break; + default: + avb_error("Unknown algorithm.\n"); + goto out; + } + + if (avb_safe_memcmp(authentication_block + h.hash_offset, + computed_hash, + h.hash_size) != 0) { + avb_error("Hash does not match!\n"); + ret = AVB_VBMETA_VERIFY_RESULT_HASH_MISMATCH; + goto out; + } + + verification_result = + avb_rsa_verify(auxiliary_block + h.public_key_offset, + h.public_key_size, + authentication_block + h.signature_offset, + h.signature_size, + authentication_block + h.hash_offset, + h.hash_size, + algorithm->padding, + algorithm->padding_len); + + if (verification_result == 0) { + ret = AVB_VBMETA_VERIFY_RESULT_SIGNATURE_MISMATCH; + goto out; + } + + if (h.public_key_size > 0) { + if (out_public_key_data != NULL) { + *out_public_key_data = auxiliary_block + h.public_key_offset; + } + if (out_public_key_length != NULL) { + *out_public_key_length = h.public_key_size; + } + } + + ret = AVB_VBMETA_VERIFY_RESULT_OK; + +out: + return ret; +} + +void avb_vbmeta_image_header_to_host_byte_order(const AvbVBMetaImageHeader* src, + AvbVBMetaImageHeader* dest) { + avb_memcpy(dest, src, sizeof(AvbVBMetaImageHeader)); + + dest->required_libavb_version_major = + avb_be32toh(dest->required_libavb_version_major); + dest->required_libavb_version_minor = + avb_be32toh(dest->required_libavb_version_minor); + + dest->authentication_data_block_size = + avb_be64toh(dest->authentication_data_block_size); + dest->auxiliary_data_block_size = + avb_be64toh(dest->auxiliary_data_block_size); + + dest->algorithm_type = avb_be32toh(dest->algorithm_type); + + dest->hash_offset = avb_be64toh(dest->hash_offset); + dest->hash_size = avb_be64toh(dest->hash_size); + + dest->signature_offset = avb_be64toh(dest->signature_offset); + dest->signature_size = avb_be64toh(dest->signature_size); + + dest->public_key_offset = avb_be64toh(dest->public_key_offset); + dest->public_key_size = avb_be64toh(dest->public_key_size); + + dest->public_key_metadata_offset = + avb_be64toh(dest->public_key_metadata_offset); + dest->public_key_metadata_size = avb_be64toh(dest->public_key_metadata_size); + + dest->descriptors_offset = avb_be64toh(dest->descriptors_offset); + dest->descriptors_size = avb_be64toh(dest->descriptors_size); + + dest->rollback_index = avb_be64toh(dest->rollback_index); + dest->flags = avb_be32toh(dest->flags); +} + +const char* avb_vbmeta_verify_result_to_string(AvbVBMetaVerifyResult result) { + const char* ret = NULL; + + switch (result) { + case AVB_VBMETA_VERIFY_RESULT_OK: + ret = "OK"; + break; + case AVB_VBMETA_VERIFY_RESULT_OK_NOT_SIGNED: + ret = "OK_NOT_SIGNED"; + break; + case AVB_VBMETA_VERIFY_RESULT_INVALID_VBMETA_HEADER: + ret = "INVALID_VBMETA_HEADER"; + break; + case AVB_VBMETA_VERIFY_RESULT_UNSUPPORTED_VERSION: + ret = "UNSUPPORTED_VERSION"; + break; + case AVB_VBMETA_VERIFY_RESULT_HASH_MISMATCH: + ret = "HASH_MISMATCH"; + break; + case AVB_VBMETA_VERIFY_RESULT_SIGNATURE_MISMATCH: + ret = "SIGNATURE_MISMATCH"; + break; + /* Do not add a 'default:' case here because of -Wswitch. */ + } + + if (ret == NULL) { + avb_error("Unknown AvbVBMetaVerifyResult value.\n"); + ret = "(unknown)"; + } + + return ret; +} diff --git a/lib/libavb/avb_vbmeta_image.h b/lib/libavb/avb_vbmeta_image.h new file mode 100644 index 0000000000..24f8519ff6 --- /dev/null +++ b/lib/libavb/avb_vbmeta_image.h @@ -0,0 +1,275 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright (C) 2016 The Android Open Source Project + */ + +#if !defined(AVB_INSIDE_LIBAVB_H) && !defined(AVB_COMPILATION) +#error "Never include this file directly, include libavb.h instead." +#endif + +#ifndef AVB_VBMETA_IMAGE_H_ +#define AVB_VBMETA_IMAGE_H_ + +#include "avb_sysdeps.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#include "avb_crypto.h" +#include "avb_descriptor.h" + +/* Size of the vbmeta image header. */ +#define AVB_VBMETA_IMAGE_HEADER_SIZE 256 + +/* Magic for the vbmeta image header. */ +#define AVB_MAGIC "AVB0" +#define AVB_MAGIC_LEN 4 + +/* Maximum size of the release string including the terminating NUL byte. */ +#define AVB_RELEASE_STRING_SIZE 48 + +/* Flags for the vbmeta image. + * + * AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED: If this flag is set, + * hashtree image verification will be disabled. + * + * AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED: If this flag is set, + * verification will be disabled and descriptors will not be parsed. + */ +typedef enum { + AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED = (1 << 0), + AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED = (1 << 1) +} AvbVBMetaImageFlags; + +/* Binary format for header of the vbmeta image. + * + * The vbmeta image consists of three blocks: + * + * +-----------------------------------------+ + * | Header data - fixed size | + * +-----------------------------------------+ + * | Authentication data - variable size | + * +-----------------------------------------+ + * | Auxiliary data - variable size | + * +-----------------------------------------+ + * + * The "Header data" block is described by this struct and is always + * |AVB_VBMETA_IMAGE_HEADER_SIZE| bytes long. + * + * The "Authentication data" block is |authentication_data_block_size| + * bytes long and contains the hash and signature used to authenticate + * the vbmeta image. The type of the hash and signature is defined by + * the |algorithm_type| field. + * + * The "Auxiliary data" is |auxiliary_data_block_size| bytes long and + * contains the auxiliary data including the public key used to make + * the signature and descriptors. + * + * The public key is at offset |public_key_offset| with size + * |public_key_size| in this block. The size of the public key data is + * defined by the |algorithm_type| field. The format of the public key + * data is described in the |AvbRSAPublicKeyHeader| struct. + * + * The descriptors starts at |descriptors_offset| from the beginning + * of the "Auxiliary Data" block and take up |descriptors_size| + * bytes. Each descriptor is stored as a |AvbDescriptor| with tag and + * number of bytes following. The number of descriptors can be + * determined by walking this data until |descriptors_size| is + * exhausted. + * + * The size of each of the "Authentication data" and "Auxiliary data" + * blocks must be divisible by 64. This is to ensure proper alignment. + * + * Descriptors are free-form blocks stored in a part of the vbmeta + * image subject to the same integrity checks as the rest of the + * image. See the documentation for |AvbDescriptor| for well-known + * descriptors. See avb_descriptor_foreach() for a convenience + * function to iterate over descriptors. + * + * This struct is versioned, see the |required_libavb_version_major| + * and |required_libavb_version_minor| fields. This represents the + * minimum version of libavb required to verify the header and depends + * on the features (e.g. algorithms, descriptors) used. Note that this + * may be 1.0 even if generated by an avbtool from 1.4 but where no + * features introduced after 1.0 has been used. See the "Versioning + * and compatibility" section in the README.md file for more details. + * + * All fields are stored in network byte order when serialized. To + * generate a copy with fields swapped to native byte order, use the + * function avb_vbmeta_image_header_to_host_byte_order(). + * + * Before reading and/or using any of this data, you MUST verify it + * using avb_vbmeta_image_verify() and reject it unless it's signed by + * a known good public key. + */ +typedef struct AvbVBMetaImageHeader { + /* 0: Four bytes equal to "AVB0" (AVB_MAGIC). */ + uint8_t magic[AVB_MAGIC_LEN]; + + /* 4: The major version of libavb required for this header. */ + uint32_t required_libavb_version_major; + /* 8: The minor version of libavb required for this header. */ + uint32_t required_libavb_version_minor; + + /* 12: The size of the signature block. */ + uint64_t authentication_data_block_size; + /* 20: The size of the auxiliary data block. */ + uint64_t auxiliary_data_block_size; + + /* 28: The verification algorithm used, see |AvbAlgorithmType| enum. */ + uint32_t algorithm_type; + + /* 32: Offset into the "Authentication data" block of hash data. */ + uint64_t hash_offset; + /* 40: Length of the hash data. */ + uint64_t hash_size; + + /* 48: Offset into the "Authentication data" block of signature data. */ + uint64_t signature_offset; + /* 56: Length of the signature data. */ + uint64_t signature_size; + + /* 64: Offset into the "Auxiliary data" block of public key data. */ + uint64_t public_key_offset; + /* 72: Length of the public key data. */ + uint64_t public_key_size; + + /* 80: Offset into the "Auxiliary data" block of public key metadata. */ + uint64_t public_key_metadata_offset; + /* 88: Length of the public key metadata. Must be set to zero if there + * is no public key metadata. + */ + uint64_t public_key_metadata_size; + + /* 96: Offset into the "Auxiliary data" block of descriptor data. */ + uint64_t descriptors_offset; + /* 104: Length of descriptor data. */ + uint64_t descriptors_size; + + /* 112: The rollback index which can be used to prevent rollback to + * older versions. + */ + uint64_t rollback_index; + + /* 120: Flags from the AvbVBMetaImageFlags enumeration. This must be + * set to zero if the vbmeta image is not a top-level image. + */ + uint32_t flags; + + /* 124: Reserved to ensure |release_string| start on a 16-byte + * boundary. Must be set to zeroes. + */ + uint8_t reserved0[4]; + + /* 128: The release string from avbtool, e.g. "avbtool 1.0.0" or + * "avbtool 1.0.0 xyz_board Git-234abde89". Is guaranteed to be NUL + * terminated. Applications must not make assumptions about how this + * string is formatted. + */ + uint8_t release_string[AVB_RELEASE_STRING_SIZE]; + + /* 176: Padding to ensure struct is size AVB_VBMETA_IMAGE_HEADER_SIZE + * bytes. This must be set to zeroes. + */ + uint8_t reserved[80]; +} AVB_ATTR_PACKED AvbVBMetaImageHeader; + +/* Copies |src| to |dest|, byte-swapping fields in the process. + * + * Make sure you've verified |src| using avb_vbmeta_image_verify() + * before accessing the data and/or using this function. + */ +void avb_vbmeta_image_header_to_host_byte_order(const AvbVBMetaImageHeader* src, + AvbVBMetaImageHeader* dest); + +/* Return codes used in avb_vbmeta_image_verify(). + * + * AVB_VBMETA_VERIFY_RESULT_OK is returned if the vbmeta image header + * is valid, the hash is correct and the signature is correct. Keep in + * mind that you still need to check that you know the public key used + * to sign the image, see avb_vbmeta_image_verify() for details. + * + * AVB_VBMETA_VERIFY_RESULT_OK_NOT_SIGNED is returned if the vbmeta + * image header is valid but there is no signature or hash. + * + * AVB_VBMETA_VERIFY_RESULT_INVALID_VBMETA_HEADER is returned if the + * header of the vbmeta image is invalid, for example, invalid magic + * or inconsistent data. + * + * AVB_VBMETA_VERIFY_RESULT_UNSUPPORTED_VERSION is returned if a) the + * vbmeta image requires a minimum version of libavb which exceeds the + * version of libavb used; or b) the vbmeta image major version + * differs from the major version of libavb in use. + * + * AVB_VBMETA_VERIFY_RESULT_HASH_MISMATCH is returned if the hash + * stored in the "Authentication data" block does not match the + * calculated hash. + * + * AVB_VBMETA_VERIFY_RESULT_SIGNATURE_MISMATCH is returned if the + * signature stored in the "Authentication data" block is invalid or + * doesn't match the public key stored in the vbmeta image. + */ +typedef enum { + AVB_VBMETA_VERIFY_RESULT_OK, + AVB_VBMETA_VERIFY_RESULT_OK_NOT_SIGNED, + AVB_VBMETA_VERIFY_RESULT_INVALID_VBMETA_HEADER, + AVB_VBMETA_VERIFY_RESULT_UNSUPPORTED_VERSION, + AVB_VBMETA_VERIFY_RESULT_HASH_MISMATCH, + AVB_VBMETA_VERIFY_RESULT_SIGNATURE_MISMATCH, +} AvbVBMetaVerifyResult; + +/* Get a textual representation of |result|. */ +const char* avb_vbmeta_verify_result_to_string(AvbVBMetaVerifyResult result); + +/* Checks that vbmeta image at |data| of size |length| is a valid + * vbmeta image. The complete contents of the vbmeta image must be + * passed in. It's fine if |length| is bigger than the actual image, + * typically callers of this function will load the entire contents of + * the 'vbmeta_a' or 'vbmeta_b' partition and pass in its length (for + * example, 1 MiB). + * + * See the |AvbVBMetaImageHeader| struct for information about the + * three blocks (header, authentication, auxiliary) that make up a + * vbmeta image. + * + * If the function returns |AVB_VBMETA_VERIFY_RESULT_OK| and + * |out_public_key_data| is non-NULL, it will be set to point inside + * |data| for where the serialized public key data is stored and + * |out_public_key_length|, if non-NULL, will be set to the length of + * the public key data. If there is no public key in the metadata then + * |out_public_key_data| is set to NULL. + * + * See the |AvbVBMetaVerifyResult| enum for possible return values. + * + * VERY IMPORTANT: + * + * 1. Even if |AVB_VBMETA_VERIFY_RESULT_OK| is returned, you still + * need to check that the public key embedded in the image + * matches a known key! You can use 'avbtool extract_public_key' + * to extract the key (at build time, then store it along your + * code) and compare it to what is returned in + * |out_public_key_data|. + * + * 2. You need to check the |rollback_index| field against a stored + * value in NVRAM and reject the vbmeta image if the value in + * NVRAM is bigger than |rollback_index|. You must also update + * the value stored in NVRAM to the smallest value of + * |rollback_index| field from boot images in all bootable and + * authentic slots marked as GOOD. + * + * This is a low-level function to only verify the vbmeta data - you + * are likely looking for avb_slot_verify() instead for verifying + * integrity data for a whole set of partitions. + */ +AvbVBMetaVerifyResult avb_vbmeta_image_verify( + const uint8_t* data, + size_t length, + const uint8_t** out_public_key_data, + size_t* out_public_key_length) AVB_ATTR_WARN_UNUSED_RESULT; + +#ifdef __cplusplus +} +#endif + +#endif /* AVB_VBMETA_IMAGE_H_ */ diff --git a/lib/libavb/avb_version.c b/lib/libavb/avb_version.c new file mode 100644 index 0000000000..1f20722e6c --- /dev/null +++ b/lib/libavb/avb_version.c @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright (C) 2017 The Android Open Source Project + */ + +#include "avb_version.h" + +#define AVB_QUOTE(str) #str +#define AVB_EXPAND_AND_QUOTE(str) AVB_QUOTE(str) + +/* Keep in sync with get_release_string() in avbtool. */ +const char* avb_version_string(void) { + return AVB_EXPAND_AND_QUOTE(AVB_VERSION_MAJOR) "." AVB_EXPAND_AND_QUOTE( + AVB_VERSION_MINOR) "." AVB_EXPAND_AND_QUOTE(AVB_VERSION_SUB); +} diff --git a/lib/libavb/avb_version.h b/lib/libavb/avb_version.h new file mode 100644 index 0000000000..57c6ece851 --- /dev/null +++ b/lib/libavb/avb_version.h @@ -0,0 +1,40 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright (C) 2017 The Android Open Source Project + */ + +#if !defined(AVB_INSIDE_LIBAVB_H) && !defined(AVB_COMPILATION) +#error "Never include this file directly, include libavb.h instead." +#endif + +#ifndef AVB_VERSION_H_ +#define AVB_VERSION_H_ + +#include "avb_sysdeps.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* The version number of AVB - keep in sync with avbtool. */ +#define AVB_VERSION_MAJOR 1 +#define AVB_VERSION_MINOR 1 +#define AVB_VERSION_SUB 0 + +/* Returns a NUL-terminated string for the libavb version in use. The + * returned string usually looks like "%d.%d.%d". Applications must + * not make assumptions about the content of this string. + * + * Boot loaders should display this string in debug/diagnostics output + * to aid with debugging. + * + * This is similar to the string put in the |release_string| string + * field in the VBMeta struct by avbtool. + */ +const char* avb_version_string(void); + +#ifdef __cplusplus +} +#endif + +#endif /* AVB_VERSION_H_ */ diff --git a/lib/libavb/libavb.h b/lib/libavb/libavb.h new file mode 100644 index 0000000000..ac92a2bcb8 --- /dev/null +++ b/lib/libavb/libavb.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright (C) 2016 The Android Open Source Project + */ + +#ifndef LIBAVB_H_ +#define LIBAVB_H_ + +/* The AVB_INSIDE_LIBAVB_H preprocessor symbol is used to enforce + * library users to include only this file. All public interfaces, and + * only public interfaces, must be included here. + */ + +#define AVB_INSIDE_LIBAVB_H +#include "avb_chain_partition_descriptor.h" +#include "avb_crypto.h" +#include "avb_descriptor.h" +#include "avb_footer.h" +#include "avb_hash_descriptor.h" +#include "avb_hashtree_descriptor.h" +#include "avb_kernel_cmdline_descriptor.h" +#include "avb_ops.h" +#include "avb_property_descriptor.h" +#include "avb_slot_verify.h" +#include "avb_sysdeps.h" +#include "avb_util.h" +#include "avb_vbmeta_image.h" +#include "avb_version.h" +#undef AVB_INSIDE_LIBAVB_H + +#endif /* LIBAVB_H_ */ diff --git a/lib/rsa/rsa-sign.c b/lib/rsa/rsa-sign.c index d2788bf79a..cfe09cc94c 100644 --- a/lib/rsa/rsa-sign.c +++ b/lib/rsa/rsa-sign.c @@ -635,6 +635,15 @@ static int fdt_add_bignum(void *blob, int noffset, const char *prop_name, big2 = BN_new(); big32 = BN_new(); big2_32 = BN_new(); + + /* + * Note: This code assumes that all of the above succeed, or all fail. + * In practice memory allocations generally do not fail (unless the + * process is killed), so it does not seem worth handling each of these + * as a separate case. Technicaly this could leak memory on failure, + * but a) it won't happen in practice, and b) it doesn't matter as we + * will immediately exit with a failure code. + */ if (!tmp || !big2 || !big32 || !big2_32) { fprintf(stderr, "Out of memory (bignum)\n"); return -ENOMEM; @@ -667,15 +676,13 @@ static int fdt_add_bignum(void *blob, int noffset, const char *prop_name, * might fail several times */ ret = fdt_setprop(blob, noffset, prop_name, buf, size); - if (ret) - return -FDT_ERR_NOSPACE; free(buf); BN_free(tmp); BN_free(big2); BN_free(big32); BN_free(big2_32); - return ret; + return ret ? -FDT_ERR_NOSPACE : 0; } int rsa_add_verify_data(struct image_sign_info *info, void *keydest) diff --git a/test/py/tests/test_avb.py b/test/py/tests/test_avb.py new file mode 100644 index 0000000000..7996e4845d --- /dev/null +++ b/test/py/tests/test_avb.py @@ -0,0 +1,116 @@ +# Copyright (c) 2018, Linaro Limited +# +# SPDX-License-Identifier: GPL-2.0+ +# +# Android Verified Boot 2.0 Test + +""" +This tests Android Verified Boot 2.0 support in U-boot: + +For additional details about how to build proper vbmeta partition +check doc/README.avb2 + +For configuration verification: +- Corrupt boot partition and check for failure +- Corrupt vbmeta partition and check for failure +""" + +import pytest +import u_boot_utils as util + +# defauld mmc id +mmc_dev = 1 +temp_addr = 0x90000000 +temp_addr2 = 0x90002000 + +@pytest.mark.buildconfigspec('cmd_avb') +def test_avb_verify(u_boot_console): + """Run AVB 2.0 boot verification chain with avb subset of commands + """ + + success_str = "Verification passed successfully" + + response = u_boot_console.run_command('avb init %s' %str(mmc_dev)) + assert response == '' + response = u_boot_console.run_command('avb verify') + assert response.find(success_str) + + +@pytest.mark.buildconfigspec('cmd_avb') +def test_avb_mmc_uuid(u_boot_console): + """Check if 'avb get_uuid' works, compare results with + 'part list mmc 1' output + """ + + response = u_boot_console.run_command('avb init %s' % str(mmc_dev)) + assert response == '' + + response = u_boot_console.run_command('mmc rescan; mmc dev %s' % + str(mmc_dev)) + assert response.find('is current device') + + part_lines = u_boot_console.run_command('mmc part').splitlines() + part_list = {} + cur_partname = "" + + for line in part_lines: + if "\"" in line: + start_pt = line.find("\"") + end_pt = line.find("\"", start_pt + 1) + cur_partname = line[start_pt + 1: end_pt] + + if "guid:" in line: + guid_to_check = line.split("guid:\t") + part_list[cur_partname] = guid_to_check[1] + + # lets check all guids with avb get_guid + for part, guid in part_list.iteritems(): + avb_guid_resp = u_boot_console.run_command('avb get_uuid %s' % part) + assert guid == avb_guid_resp.split("UUID: ")[1] + + +@pytest.mark.buildconfigspec('cmd_avb') +def test_avb_read_rb(u_boot_console): + """Test reading rollback indexes + """ + + response = u_boot_console.run_command('avb init %s' % str(mmc_dev)) + assert response == '' + + response = u_boot_console.run_command('avb read_rb 1') + + +@pytest.mark.buildconfigspec('cmd_avb') +def test_avb_is_unlocked(u_boot_console): + """Test if device is in the unlocked state + """ + + response = u_boot_console.run_command('avb init %s' % str(mmc_dev)) + assert response == '' + + response = u_boot_console.run_command('avb is_unlocked') + + +@pytest.mark.buildconfigspec('cmd_avb') +def test_avb_mmc_read(u_boot_console): + """Test mmc read operation + """ + + response = u_boot_console.run_command('mmc rescan; mmc dev %s 0' % + str(mmc_dev)) + assert response.find('is current device') + + response = u_boot_console.run_command('mmc read 0x%x 0x100 0x1' % temp_addr) + assert response.find('read: OK') + + response = u_boot_console.run_command('avb init %s' % str(mmc_dev)) + assert response == '' + + response = u_boot_console.run_command('avb read_part xloader 0 100 0x%x' % + temp_addr2) + assert response.find('Read 512 bytes') + + # Now lets compare two buffers + response = u_boot_console.run_command('cmp 0x%x 0x%x 40' % + (temp_addr, temp_addr2)) + assert response.find('64 word') diff --git a/tools/fdtgrep.c b/tools/fdtgrep.c index f2b8b71ed7..8f44f599c1 100644 --- a/tools/fdtgrep.c +++ b/tools/fdtgrep.c @@ -133,11 +133,11 @@ static int value_add(struct display_info *disp, struct value_node **headp, } str = strdup(str); + if (!str) + goto err_mem; node = malloc(sizeof(*node)); - if (!str || !node) { - fprintf(stderr, "Out of memory\n"); - return -1; - } + if (!node) + goto err_mem; node->next = *headp; node->type = type; node->include = include; @@ -145,6 +145,9 @@ static int value_add(struct display_info *disp, struct value_node **headp, *headp = node; return 0; +err_mem: + fprintf(stderr, "Out of memory\n"); + return -1; } static bool util_is_printable_string(const void *data, int len) @@ -773,7 +776,7 @@ char *utilfdt_read(const char *filename) */ static int do_fdtgrep(struct display_info *disp, const char *filename) { - struct fdt_region *region; + struct fdt_region *region = NULL; int max_regions; int count = 100; char path[1024]; @@ -801,7 +804,7 @@ static int do_fdtgrep(struct display_info *disp, const char *filename) * The first pass will count the regions, but if it is too many, * we do another pass to actually record them. */ - for (i = 0; i < 3; i++) { + for (i = 0; i < 2; i++) { region = malloc(count * sizeof(struct fdt_region)); if (!region) { fprintf(stderr, "Out of memory for %d regions\n", @@ -815,11 +818,14 @@ static int do_fdtgrep(struct display_info *disp, const char *filename) disp->flags); if (count < 0) { report_error("fdt_find_regions", count); + free(region); return -1; } if (count <= max_regions) break; free(region); + fprintf(stderr, "Internal error with fdtgrep_find_region)(\n"); + return -1; } /* Optionally print a list of regions */ |