diff --git a/Kconfig b/Kconfig index 2cc272b..e332245 100644 --- a/Kconfig +++ b/Kconfig
@@ -275,10 +275,20 @@ SHA256 variant is supported: SHA512 and others are not currently supported in U-Boot. +config FIT_FULL_CHECK + bool "Do a full check of the FIT before using it" + default y + help + Enable this do a full check of the FIT to make sure it is valid. This + helps to protect against carefully crafted FITs which take advantage + of bugs or omissions in the code. This includes a bad structure, + multiple root nodes and the like. + config FIT_SIGNATURE bool "Enable signature verification of FIT uImages" depends on DM select HASH + select FIT_FULL_CHECK select RSA help This option enables signature verification of FIT uImages, @@ -355,11 +365,21 @@ help Support printing the content of the fitImage in a verbose manner in SPL. +config SPL_FIT_FULL_CHECK + bool "Do a full check of the FIT before using it" + help + Enable this do a full check of the FIT to make sure it is valid. This + helps to protect against carefully crafted FITs which take advantage + of bugs or omissions in the code. This includes a bad structure, + multiple root nodes and the like. + + config SPL_FIT_SIGNATURE bool "Enable signature verification of FIT firmware within SPL" depends on SPL_DM select SPL_FIT select SPL_RSA + select SPL_FIT_FULL_CHECK config SPL_LOAD_FIT bool "Enable SPL loading U-Boot as a FIT"
diff --git a/arch/arm/cpu/armv8/sec_firmware.c b/arch/arm/cpu/armv8/sec_firmware.c index 8dc0ac9..3c52495 100644 --- a/arch/arm/cpu/armv8/sec_firmware.c +++ b/arch/arm/cpu/armv8/sec_firmware.c
@@ -310,7 +310,7 @@ return false; } - if (!fit_check_format(sec_firmware_img)) { + if (fit_check_format(sec_firmware_img, IMAGE_SIZE_INVAL)) { printf("SEC Firmware: Bad firmware image (bad FIT header)\n"); return false; }
diff --git a/board/amlogic/defconfigs/s4_t211_defconfig b/board/amlogic/defconfigs/s4_t211_defconfig index bc8f787..053a994 100644 --- a/board/amlogic/defconfigs/s4_t211_defconfig +++ b/board/amlogic/defconfigs/s4_t211_defconfig
@@ -12,7 +12,7 @@ CONFIG_DEBUG_UART=y CONFIG_OF_BOARD_SETUP=y CONFIG_BOOTDELAY=-2 -CONFIG_BOOTCOMMAND="run storeboot" +CONFIG_BOOTCOMMAND="run storeboot ; reboot" CONFIG_BOARD_LATE_INIT=y # CONFIG_DISPLAY_CPUINFO is not set # CONFIG_DISPLAY_BOARDINFO is not set @@ -111,3 +111,5 @@ CONFIG_MD5=y CONFIG_OF_LIBFDT_OVERLAY=y CONFIG_CHROMECAST=y +CONFIG_AML_DISABLE_DEV_CMDS=y +# CONFIG_USB_STORAGE is not set
diff --git a/cmd/amlogic/cmd_avb.c b/cmd/amlogic/cmd_avb.c index 948f7ed..df1b861 100644 --- a/cmd/amlogic/cmd_avb.c +++ b/cmd/amlogic/cmd_avb.c
@@ -381,13 +381,10 @@ printf("ab_suffix is %s\n", ab_suffix); AvbSlotVerifyFlags flags = AVB_SLOT_VERIFY_FLAGS_NONE; - char *upgradestep = NULL; avb_init(); - upgradestep = env_get("upgrade_step"); - - if (is_device_unlocked() || !strcmp(upgradestep, "3")) + if (is_device_unlocked()) flags |= AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR; if (!strcmp(ab_suffix, "")) { @@ -412,9 +409,6 @@ flags, AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE, out_data); - if (!strcmp(upgradestep, "3")) - result = AVB_SLOT_VERIFY_RESULT_OK; - return result; }
diff --git a/cmd/amlogic/cmd_bcb.c b/cmd/amlogic/cmd_bcb.c index 7315dda..bbe12bf 100644 --- a/cmd/amlogic/cmd_bcb.c +++ b/cmd/amlogic/cmd_bcb.c
@@ -44,21 +44,6 @@ char reserved[192]; }; - -static int clear_misc_partition(char *clearbuf, int size) -{ - char *partition = "misc"; - - memset(clearbuf, 0, size); - if (store_write((const char *)partition, - 0, size, (unsigned char *)clearbuf) < 0) { - printf("failed to clear %s.\n", partition); - return -1; - } - - return 0; -} - static int do_RunBcbCommand( cmd_tbl_t * cmdtp, int flag, @@ -174,25 +159,6 @@ return 0; } - if (!memcmp(command_mark, command, strlen(command_mark))) { - printf("%s\n", recovery); - if (run_command((char *)recovery, 0) < 0) { - printf("run_command for cmd:%s failed.\n", recovery); - goto ERR; - } - printf("run command successful.\n"); - - if (clear_misc_partition(clearbuf, sizeof(clearbuf)) < 0) { - printf("clear misc partition failed.\n"); - goto ERR; - } else { - printf("clear misc partition successful.\n"); - } - } else { - printf("command mark(%s) not match %s,don't execute.\n", - command_mark, command); - } - return 0; ERR:
diff --git a/cmd/bootm.c b/cmd/bootm.c index e58a595..e712302 100644 --- a/cmd/bootm.c +++ b/cmd/bootm.c
@@ -416,7 +416,7 @@ case IMAGE_FORMAT_FIT: puts(" FIT image found\n"); - if (!fit_check_format(hdr)) { + if (fit_check_format(hdr, IMAGE_SIZE_INVAL)) { puts("Bad FIT image format!\n"); return 1; } @@ -489,7 +489,7 @@ #endif #if defined(CONFIG_FIT) case IMAGE_FORMAT_FIT: - if (!fit_check_format(hdr)) + if (fit_check_format(hdr, IMAGE_SIZE_INVAL)) goto next_sector; printf("FIT Image at %08lX:\n", (ulong)hdr); @@ -569,7 +569,7 @@ return ret; } - if (!fit_check_format(imgdata)) { + if (fit_check_format(imgdata, IMAGE_SIZE_INVAL)) { free(imgdata); return 0; }
diff --git a/cmd/disk.c b/cmd/disk.c index dcc36a6..294fc11 100644 --- a/cmd/disk.c +++ b/cmd/disk.c
@@ -110,7 +110,7 @@ /* This cannot be done earlier, * we need complete FIT image in RAM first */ if (genimg_get_format((void *) addr) == IMAGE_FORMAT_FIT) { - if (!fit_check_format(fit_hdr)) { + if (fit_check_format(fit_hdr, IMAGE_SIZE_INVAL)) { bootstage_error(BOOTSTAGE_ID_IDE_FIT_READ); puts("** Bad FIT image format\n"); return 1;
diff --git a/cmd/fpga.c b/cmd/fpga.c index 88a8e3f..9093026 100644 --- a/cmd/fpga.c +++ b/cmd/fpga.c
@@ -325,7 +325,7 @@ return CMD_RET_FAILURE; } - if (!fit_check_format(fit_hdr)) { + if (fit_check_format(fit_hdr, IMAGE_SIZE_INVAL)) { puts("Bad FIT image format\n"); return CMD_RET_FAILURE; }
diff --git a/cmd/nand.c b/cmd/nand.c index 22a534d..069da99 100644 --- a/cmd/nand.c +++ b/cmd/nand.c
@@ -928,7 +928,7 @@ #if defined(CONFIG_FIT) /* This cannot be done earlier, we need complete FIT image in RAM first */ if (genimg_get_format ((void *)addr) == IMAGE_FORMAT_FIT) { - if (!fit_check_format (fit_hdr)) { + if (fit_check_format(fit_hdr, IMAGE_SIZE_INVAL)) { bootstage_error(BOOTSTAGE_ID_NAND_FIT_READ); puts ("** Bad FIT image format\n"); return 1;
diff --git a/cmd/source.c b/cmd/source.c index 6d98a1c..897b970 100644 --- a/cmd/source.c +++ b/cmd/source.c
@@ -106,7 +106,7 @@ #if defined(CONFIG_FIT) case IMAGE_FORMAT_FIT: fit_hdr = buf; - if (!fit_check_format (fit_hdr)) { + if (fit_check_format(fit_hdr, IMAGE_SIZE_INVAL)) { puts ("Bad FIT image format\n"); return 1; }
diff --git a/cmd/ximg.c b/cmd/ximg.c index 6880c74..4fd1b26 100644 --- a/cmd/ximg.c +++ b/cmd/ximg.c
@@ -131,7 +131,7 @@ "at %08lx ...\n", uname, addr); fit_hdr = (const void *)addr; - if (!fit_check_format(fit_hdr)) { + if (fit_check_format(fit_hdr, IMAGE_SIZE_INVAL)) { puts("Bad FIT image format\n"); return 1; }
diff --git a/common/bootm.c b/common/bootm.c index 85532c7..0fef966 100644 --- a/common/bootm.c +++ b/common/bootm.c
@@ -1279,7 +1279,8 @@ memmove(to, from, len); } -static int bootm_host_load_image(const void *fit, int req_image_type) +static int bootm_host_load_image(const void *fit, int req_image_type, + int cfg_noffset) { const char *fit_uname_config = NULL; ulong data, len; @@ -1291,6 +1292,7 @@ void *load_buf; int ret; + fit_uname_config = fdt_get_name(fit, cfg_noffset, NULL); memset(&images, '\0', sizeof(images)); images.verify = 1; noffset = fit_image_load(&images, (ulong)fit, @@ -1335,7 +1337,7 @@ for (i = 0; i < ARRAY_SIZE(image_types); i++) { int ret; - ret = bootm_host_load_image(fit, image_types[i]); + ret = bootm_host_load_image(fit, image_types[i], cfg_noffset); if (!err && ret && ret != -ENOENT) err = ret; }
diff --git a/common/image-fdt.c b/common/image-fdt.c index aaf0f22..b72b2bf 100644 --- a/common/image-fdt.c +++ b/common/image-fdt.c
@@ -363,7 +363,7 @@ */ #if CONFIG_IS_ENABLED(FIT) /* check FDT blob vs FIT blob */ - if (fit_check_format(buf)) { + if (!fit_check_format(buf, IMAGE_SIZE_INVAL)) { ulong load, len; fdt_noffset = boot_get_fdt_fit(images,
diff --git a/common/image-fit.c b/common/image-fit.c index 95b5723..3b0f19c 100644 --- a/common/image-fit.c +++ b/common/image-fit.c
@@ -8,12 +8,14 @@ * Wolfgang Denk, DENX Software Engineering, wd@denx.de. */ +#define LOG_CATEGORY LOGC_BOOT + #ifdef USE_HOSTCC #include "mkimage.h" #include <time.h> +#include <linux/libfdt.h> #else #include <linux/compiler.h> -#include <linux/kconfig.h> #include <common.h> #include <errno.h> #include <mapmem.h> @@ -24,6 +26,7 @@ #include <image.h> #include <bootstage.h> +#include <linux/kconfig.h> #include <u-boot/crc.h> #include <u-boot/md5.h> #include <u-boot/sha1.h> @@ -166,7 +169,7 @@ int value_len; char *algo; const char *padding; - int required; + bool required; int ret, i; debug("%s %s node: '%s'\n", p, type, @@ -177,8 +180,8 @@ return; } printf("%s", algo); - keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL); - required = fdt_getprop(fit, noffset, "required", NULL) != NULL; + keyname = fdt_getprop(fit, noffset, FIT_KEY_HINT, NULL); + required = fdt_getprop(fit, noffset, FIT_KEY_REQUIRED, NULL) != (void *)NULL; if (keyname) printf(":%s", keyname); if (required) @@ -1287,21 +1290,31 @@ */ int fit_image_verify(const void *fit, int image_noffset) { + const char *name = fit_get_name(fit, image_noffset, NULL); const void *data; size_t size; - int noffset = 0; char *err_msg = ""; + if (strchr(name, '@')) { + /* + * We don't support this since libfdt considers names with the + * name root but different @ suffix to be equal + */ + err_msg = "Node name contains @"; + goto err; + } /* Get image data and data length */ if (fit_image_get_data_and_size(fit, image_noffset, &data, &size)) { err_msg = "Can't get image data/size"; - printf("error!\n%s for '%s' hash node in '%s' image node\n", - err_msg, fit_get_name(fit, noffset, NULL), - fit_get_name(fit, image_noffset, NULL)); - return 0; + goto err; } return fit_image_verify_with_data(fit, image_noffset, data, size); + +err: + printf("error!\n%s in '%s' image node\n", err_msg, + fit_get_name(fit, image_noffset, NULL)); + return 0; } /** @@ -1452,42 +1465,100 @@ } /** - * fit_check_format - sanity check FIT image format - * @fit: pointer to the FIT format image header + * fdt_check_no_at() - Check for nodes whose names contain '@' * - * fit_check_format() runs a basic sanity FIT image verification. - * Routine checks for mandatory properties, nodes, etc. + * This checks the parent node and all subnodes recursively * - * returns: - * 1, on success - * 0, on failure + * @fit: FIT to check + * @parent: Parent node to check + * @return 0 if OK, -EADDRNOTAVAIL is a node has a name containing '@' */ -int fit_check_format(const void *fit) +static int fdt_check_no_at(const void *fit, int parent) { + const char *name; + int node; + int ret; + + name = fdt_get_name(fit, parent, NULL); + if (!name || strchr(name, '@')) + return -EADDRNOTAVAIL; + + fdt_for_each_subnode(node, fit, parent) { + ret = fdt_check_no_at(fit, node); + if (ret) + return ret; + } + + return 0; +} + +int fit_check_format(const void *fit, ulong size) +{ + int ret; + + /* A FIT image must be a valid FDT */ + ret = fdt_check_header(fit); + if (ret) { + log_debug("Wrong FIT format: not a flattened device tree (err=%d)\n", + ret); + return -ENOEXEC; + } + + if (CONFIG_IS_ENABLED(FIT_FULL_CHECK)) { + /* + * If we are not given the size, make do with calculating it. + * This is not as secure, so we should consider a flag to + * control this. + */ + if (size == IMAGE_SIZE_INVAL) + size = fdt_totalsize(fit); + ret = fdt_check_full(fit, size); + if (ret) + ret = -EINVAL; + + /* + * U-Boot stopped using unit addressed in 2017. Since libfdt + * can match nodes ignoring any unit address, signature + * verification can see the wrong node if one is inserted with + * the same name as a valid node but with a unit address + * attached. Protect against this by disallowing unit addresses. + */ + if (!ret && CONFIG_IS_ENABLED(FIT_SIGNATURE)) { + ret = fdt_check_no_at(fit, 0); + + if (ret) { + log_debug("FIT check error %d\n", ret); + return ret; + } + } + if (ret) { + log_debug("FIT check error %d\n", ret); + return ret; + } + } /* mandatory / node 'description' property */ - if (fdt_getprop(fit, 0, FIT_DESC_PROP, NULL) == NULL) { - debug("Wrong FIT format: no description\n"); - return 0; + if (!fdt_getprop(fit, 0, FIT_DESC_PROP, NULL)) { + log_debug("Wrong FIT format: no description\n"); + return -ENOMSG; } if (IMAGE_ENABLE_TIMESTAMP) { /* mandatory / node 'timestamp' property */ - if (fdt_getprop(fit, 0, FIT_TIMESTAMP_PROP, NULL) == NULL) { - debug("Wrong FIT format: no timestamp\n"); - return 0; + if (!fdt_getprop(fit, 0, FIT_TIMESTAMP_PROP, NULL)) { + log_debug("Wrong FIT format: no timestamp\n"); + return -ENODATA; } } /* mandatory subimages parent '/images' node */ if (fdt_path_offset(fit, FIT_IMAGES_PATH) < 0) { - debug("Wrong FIT format: no images parent node\n"); - return 0; + log_debug("Wrong FIT format: no images parent node\n"); + return -ENOENT; } - return 1; + return 0; } - /** * fit_conf_find_compat * @fit: pointer to the FIT format image header @@ -1816,10 +1887,13 @@ printf("## Loading %s from FIT Image at %08lx ...\n", prop_name, addr); bootstage_mark(bootstage_id + BOOTSTAGE_SUB_FORMAT); - if (!fit_check_format(fit)) { - printf("Bad FIT %s image format!\n", prop_name); + ret = fit_check_format(fit, IMAGE_SIZE_INVAL); + if (ret) { + printf("Bad FIT %s image format! (err=%d)\n", prop_name, ret); + if (CONFIG_IS_ENABLED(FIT_SIGNATURE) && ret == -EADDRNOTAVAIL) + printf("Signature checking prevents use of unit addresses (@) in nodes\n"); bootstage_error(bootstage_id + BOOTSTAGE_SUB_FORMAT); - return -ENOEXEC; + return ret; } bootstage_mark(bootstage_id + BOOTSTAGE_SUB_FORMAT_OK); if (fit_uname) { @@ -1870,7 +1944,7 @@ fit_uname = fit_get_name(fit, noffset, NULL); } if (noffset < 0) { - puts("Could not find subimage node\n"); + printf("Could not find subimage node type '%s'\n", prop_name); bootstage_error(bootstage_id + BOOTSTAGE_SUB_SUBNODE); return -ENOENT; }
diff --git a/common/image-sig.c b/common/image-sig.c index 4f6b4ec..b757641 100644 --- a/common/image-sig.c +++ b/common/image-sig.c
@@ -200,7 +200,7 @@ padding_name = RSA_DEFAULT_PADDING_NAME; memset(info, '\0', sizeof(*info)); - info->keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL); + info->keyname = fdt_getprop(fit, noffset, FIT_KEY_HINT, NULL); info->fit = (void *)fit; info->node_offset = noffset; info->name = algo_name; @@ -311,7 +311,7 @@ const char *required; int ret; - required = fdt_getprop(sig_blob, noffset, "required", NULL); + required = fdt_getprop(sig_blob, noffset, FIT_KEY_REQUIRED, NULL); if (!required || strcmp(required, "image")) continue; ret = fit_image_verify_sig(fit, image_noffset, data, size, @@ -330,20 +330,39 @@ return 0; } -int fit_config_check_sig(const void *fit, int noffset, int required_keynode, - char **err_msgp) +/** + * fit_config_check_sig() - Check the signature of a config + * + * @fit: FIT to check + * @noffset: Offset of configuration node (e.g. /configurations/conf-1) + * @required_keynode: Offset in the control FDT of the required key node, + * if any. If this is given, then the configuration wil not + * pass verification unless that key is used. If this is + * -1 then any signature will do. + * @conf_noffset: Offset of the configuration subnode being checked (e.g. + * /configurations/conf-1/kernel) + * @err_msgp: In the event of an error, this will be pointed to a + * help error string to display to the user. + * @return 0 if all verified ok, <0 on error + */ +static int fit_config_check_sig(const void *fit, int noffset, + int required_keynode, int conf_noffset, + char **err_msgp) { char * const exc_prop[] = {"data"}; const char *prop, *end, *name; struct image_sign_info info; const uint32_t *strings; + const char *config_name; uint8_t *fit_value; int fit_value_len; + bool found_config; int max_regions; int i, prop_len; char path[200]; int count; + config_name = fit_get_name(fit, conf_noffset, NULL); debug("%s: fdt=%p, conf='%s', sig='%s'\n", __func__, gd_fdt_blob(), fit_get_name(fit, noffset, NULL), fit_get_name(gd_fdt_blob(), required_keynode, NULL)); @@ -384,9 +403,20 @@ char *node_inc[count]; debug("Hash nodes (%d):\n", count); + found_config = false; for (name = prop, i = 0; name < end; name += strlen(name) + 1, i++) { debug(" '%s'\n", name); node_inc[i] = (char *)name; + if (!strncmp(FIT_CONFS_PATH, name, strlen(FIT_CONFS_PATH)) && + name[sizeof(FIT_CONFS_PATH) - 1] == '/' && + !strcmp(name + sizeof(FIT_CONFS_PATH), config_name)) { + debug(" (found config node %s)", config_name); + found_config = true; + } + } + if (!found_config) { + *err_msgp = "Selected config not in hashed nodes"; + return -1; } /* @@ -454,7 +484,7 @@ if (!strncmp(name, FIT_SIG_NODENAME, strlen(FIT_SIG_NODENAME))) { ret = fit_config_check_sig(fit, noffset, sig_offset, - &err_msg); + conf_noffset, &err_msg); if (ret) { puts("- "); } else { @@ -470,13 +500,14 @@ goto error; } - return verified ? 0 : -EPERM; + if (verified) + return 0; error: printf(" error!\n%s for '%s' hash node in '%s' config node\n", err_msg, fit_get_name(fit, noffset, NULL), fit_get_name(fit, conf_noffset, NULL)); - return -1; + return -EPERM; } int fit_config_verify_required_sigs(const void *fit, int conf_noffset, @@ -497,7 +528,7 @@ const char *required; int ret; - required = fdt_getprop(sig_blob, noffset, "required", NULL); + required = fdt_getprop(sig_blob, noffset, FIT_KEY_REQUIRED, NULL); if (!required || strcmp(required, "conf")) continue; ret = fit_config_verify_sig(fit, conf_noffset, sig_blob,
diff --git a/common/splash_source.c b/common/splash_source.c index 62763b9..9467def 100644 --- a/common/splash_source.c +++ b/common/splash_source.c
@@ -329,10 +329,10 @@ if (res < 0) return res; - res = fit_check_format(fit_header); - if (!res) { + res = fit_check_format(fit_header, IMAGE_SIZE_INVAL); + if (res) { debug("Could not find valid FIT image\n"); - return -EINVAL; + return res; } node_offset = fit_image_get_node(fit_header, location->name);
diff --git a/common/update.c b/common/update.c index f237ea5..42950ed 100644 --- a/common/update.c +++ b/common/update.c
@@ -280,7 +280,7 @@ got_update_file: fit = (void *)addr; - if (!fit_check_format((void *)fit)) { + if (fit_check_format((void *)fit, IMAGE_SIZE_INVAL)) { printf("Bad FIT format of the update file, aborting " "auto-update\n"); return 1;
diff --git a/disk/part_dos.c b/disk/part_dos.c index c25c3f0..b26a33b 100644 --- a/disk/part_dos.c +++ b/disk/part_dos.c
@@ -23,6 +23,11 @@ #define DOS_PART_DEFAULT_SECTOR 512 +/* should this be configurable? It looks like it's not very common at all + * to use large numbers of partitions + */ +#define MAX_EXT_PARTS 256 + /* Convert char[4] in little endian format to the host format integer */ static inline unsigned int le32_to_int(unsigned char *le32) @@ -127,6 +132,12 @@ dos_partition_t *pt; int i; + /* set a maximum recursion level */ + if (part_num > MAX_EXT_PARTS) { + printf("** Nested DOS partitions detected, stopping **\n"); + return; + } + if (blk_dread(dev_desc, ext_part_sector, 1, (ulong *)buffer) != 1) { printf ("** Can't read partition table on %d:" LBAFU " **\n", dev_desc->devnum, ext_part_sector); @@ -192,6 +203,12 @@ int i; int dos_type; + /* set a maximum recursion level */ + if (part_num > MAX_EXT_PARTS) { + printf("** Nested DOS partitions detected, stopping **\n"); + return -1; + } + if (blk_dread(dev_desc, ext_part_sector, 1, (ulong *)buffer) != 1) { printf ("** Can't read partition table on %d:" LBAFU " **\n", dev_desc->devnum, ext_part_sector);
diff --git a/drivers/amlogic/media/vout/hdmitx/hdmitx20/hdmitx_drv.c b/drivers/amlogic/media/vout/hdmitx/hdmitx20/hdmitx_drv.c index 5323753..49e80c5 100644 --- a/drivers/amlogic/media/vout/hdmitx/hdmitx20/hdmitx_drv.c +++ b/drivers/amlogic/media/vout/hdmitx/hdmitx20/hdmitx_drv.c
@@ -964,6 +964,12 @@ hdmitx_wr_reg(HDMITX_DWC_FC_AVICONF1, 0x8); hdmitx_wr_reg(HDMITX_DWC_FC_AVICONF2, 0); + /* refer to 861-H, Page 83, A Source shall always explicitly signal + * the RGB Quantization Range as either Limited Range (Q=1)or Full + * Range (Q=2). + */ + if (output_color_format == HDMI_COLOR_FORMAT_RGB) + hdmitx_set_reg_bits(HDMITX_DWC_FC_AVICONF2, 1, 2, 2); /* set Aspect Ratio in AVIInfo */ switch (para->vic) {
diff --git a/drivers/fastboot/fb_getvar.c b/drivers/fastboot/fb_getvar.c index 3b5a24e..90ee314 100644 --- a/drivers/fastboot/fb_getvar.c +++ b/drivers/fastboot/fb_getvar.c
@@ -253,23 +253,10 @@ static void getvar_super_partition_name(char *var_parameter, char *response) { - char *slot_name; - slot_name = env_get("slot-suffixes"); - char name[64]; - if (has_boot_slot == 0) { - strncpy(name, "super-partition-name: super", 64); - } else { - printf("slot-suffixes: %s\n", slot_name); - if (strcmp(slot_name, "0") == 0) { - strncpy(name, "super-partition-name: super_a", 64); - } else if (strcmp(slot_name, "1") == 0) { - strncpy(name, "super-partition-name: super_b", 64); - } - } if (busy_flag == 1) - fastboot_busy(name, response); + fastboot_busy("super-partition-name: super", response); else - fastboot_okay(name, response); + fastboot_okay("super", response); } static void getvar_is_logical(char *var_parameter, char *response)
diff --git a/drivers/net/fsl-mc/mc.c b/drivers/net/fsl-mc/mc.c index b245fbc..87dfddb 100644 --- a/drivers/net/fsl-mc/mc.c +++ b/drivers/net/fsl-mc/mc.c
@@ -129,7 +129,7 @@ return -EINVAL; } - if (!fit_check_format(fit_hdr)) { + if (fit_check_format(fit_hdr, IMAGE_SIZE_INVAL)) { printf("fsl-mc: ERR: Bad firmware image (bad FIT header)\n"); return -EINVAL; }
diff --git a/drivers/net/pfe_eth/pfe_firmware.c b/drivers/net/pfe_eth/pfe_firmware.c index adb2d06..7b930ec 100644 --- a/drivers/net/pfe_eth/pfe_firmware.c +++ b/drivers/net/pfe_eth/pfe_firmware.c
@@ -150,7 +150,7 @@ return ret; } - if (!fit_check_format(pfe_fit_addr)) { + if (fit_check_format(pfe_fit_addr, IMAGE_SIZE_INVAL)) { printf("PFE Firmware: Bad firmware image (bad FIT header)\n"); ret = -1; return ret;
diff --git a/fs/ext4/ext4_common.c b/fs/ext4/ext4_common.c index 67e2471..1d70444 100644 --- a/fs/ext4/ext4_common.c +++ b/fs/ext4/ext4_common.c
@@ -510,7 +510,8 @@ restart_read: /* read the block no allocated to a file */ - first_block_no_of_root = read_allocated_block(g_parent_inode, blk_idx); + first_block_no_of_root = read_allocated_block(g_parent_inode, blk_idx, + NULL); if (first_block_no_of_root <= 0) goto fail; @@ -646,7 +647,7 @@ /* get the block no allocated to a file */ for (blk_idx = 0; blk_idx < directory_blocks; blk_idx++) { - blknr = read_allocated_block(parent_inode, blk_idx); + blknr = read_allocated_block(parent_inode, blk_idx, NULL); if (blknr <= 0) goto fail; @@ -943,7 +944,7 @@ /* read the block no allocated to a file */ for (blk_idx = 0; blk_idx < directory_blocks; blk_idx++) { - blknr = read_allocated_block(g_parent_inode, blk_idx); + blknr = read_allocated_block(g_parent_inode, blk_idx, NULL); if (blknr <= 0) break; inodeno = unlink_filename(filename, blknr); @@ -1522,7 +1523,7 @@ #endif static struct ext4_extent_header *ext4fs_get_extent_block - (struct ext2_data *data, char *buf, + (struct ext2_data *data, struct ext_block_cache *cache, struct ext4_extent_header *ext_block, uint32_t fileblock, int log2_blksz) { @@ -1551,12 +1552,10 @@ block = le16_to_cpu(index[i].ei_leaf_hi); block = (block << 32) + le32_to_cpu(index[i].ei_leaf_lo); - - if (ext4fs_devread((lbaint_t)block << log2_blksz, 0, blksz, - buf)) - ext_block = (struct ext4_extent_header *)buf; - else + block <<= log2_blksz; + if (!ext_cache_read(cache, (lbaint_t)block, blksz)) return NULL; + ext_block = (struct ext4_extent_header *)cache->buf; } } @@ -1584,7 +1583,7 @@ int ext4fs_read_inode(struct ext2_data *data, int ino, struct ext2_inode *inode) { - struct ext2_block_group blkgrp; + struct ext2_block_group *blkgrp; struct ext2_sblock *sblock = &data->sblock; struct ext_filesystem *fs = get_fs(); int log2blksz = get_fs()->dev_desc->log2blksz; @@ -1592,17 +1591,28 @@ long int blkno; unsigned int blkoff; + /* Allocate blkgrp based on gdsize (for 64-bit support). */ + blkgrp = zalloc(get_fs()->gdsize); + if (!blkgrp) + return 0; + /* It is easier to calculate if the first inode is 0. */ ino--; status = ext4fs_blockgroup(data, ino / le32_to_cpu - (sblock->inodes_per_group), &blkgrp); - if (status == 0) + (sblock->inodes_per_group), blkgrp); + if (status == 0) { + free(blkgrp); return 0; + } inodes_per_block = EXT2_BLOCK_SIZE(data) / fs->inodesz; - blkno = ext4fs_bg_get_inode_table_id(&blkgrp, fs) + + blkno = ext4fs_bg_get_inode_table_id(blkgrp, fs) + (ino % le32_to_cpu(sblock->inodes_per_group)) / inodes_per_block; blkoff = (ino % inodes_per_block) * fs->inodesz; + + /* Free blkgrp as it is no longer required. */ + free(blkgrp); + /* Read the inode. */ status = ext4fs_devread((lbaint_t)blkno << (LOG2_BLOCK_SIZE(data) - log2blksz), blkoff, @@ -1613,7 +1623,8 @@ return 1; } -long int read_allocated_block(struct ext2_inode *inode, int fileblock) +long int read_allocated_block(struct ext2_inode *inode, int fileblock, + struct ext_block_cache *cache) { long int blknr; int blksz; @@ -1630,20 +1641,26 @@ if (le32_to_cpu(inode->flags) & EXT4_EXTENTS_FL) { long int startblock, endblock; - char *buf = zalloc(blksz); - if (!buf) - return -ENOMEM; + struct ext_block_cache *c, cd; struct ext4_extent_header *ext_block; struct ext4_extent *extent; int i; + + if (cache) { + c = cache; + } else { + c = &cd; + ext_cache_init(c); + } ext_block = - ext4fs_get_extent_block(ext4fs_root, buf, + ext4fs_get_extent_block(ext4fs_root, c, (struct ext4_extent_header *) inode->b.blocks.dir_blocks, fileblock, log2_blksz); if (!ext_block) { printf("invalid extent block\n"); - free(buf); + if (!cache) + ext_cache_fini(c); return -EINVAL; } @@ -1655,19 +1672,22 @@ if (startblock > fileblock) { /* Sparse file */ - free(buf); + if (!cache) + ext_cache_fini(c); return 0; } else if (fileblock < endblock) { start = le16_to_cpu(extent[i].ee_start_hi); start = (start << 32) + le32_to_cpu(extent[i].ee_start_lo); - free(buf); + if (!cache) + ext_cache_fini(c); return (fileblock - startblock) + start; } } - free(buf); + if (!cache) + ext_cache_fini(c); return 0; }
diff --git a/fs/ext4/ext4_journal.c b/fs/ext4/ext4_journal.c index 148593d..6adbab9 100644 --- a/fs/ext4/ext4_journal.c +++ b/fs/ext4/ext4_journal.c
@@ -347,7 +347,7 @@ ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, (struct ext2_inode *)&inode_journal); blknr = read_allocated_block((struct ext2_inode *) - &inode_journal, i); + &inode_journal, i, NULL); ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0, fs->blksz, temp_buff); p_jdb = (char *)temp_buff; @@ -372,7 +372,7 @@ be32_to_cpu(jdb->h_sequence)) == 0) continue; } - blknr = read_allocated_block(&inode_journal, i); + blknr = read_allocated_block(&inode_journal, i, NULL); ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0, fs->blksz, metadata_buff); put_ext4((uint64_t)((uint64_t)be32_to_cpu(tag->block) * (uint64_t)fs->blksz), @@ -419,7 +419,8 @@ } ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal); - blknr = read_allocated_block(&inode_journal, EXT2_JOURNAL_SUPERBLOCK); + blknr = read_allocated_block(&inode_journal, EXT2_JOURNAL_SUPERBLOCK, + NULL); ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0, fs->blksz, temp_buff); jsb = (struct journal_superblock_t *) temp_buff; @@ -443,7 +444,7 @@ i = be32_to_cpu(jsb->s_first); while (1) { - blknr = read_allocated_block(&inode_journal, i); + blknr = read_allocated_block(&inode_journal, i, NULL); memset(temp_buff1, '\0', fs->blksz); ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0, fs->blksz, temp_buff1); @@ -537,7 +538,7 @@ ext4_read_superblock((char *)fs->sb); blknr = read_allocated_block(&inode_journal, - EXT2_JOURNAL_SUPERBLOCK); + EXT2_JOURNAL_SUPERBLOCK, NULL); put_ext4((uint64_t) ((uint64_t)blknr * (uint64_t)fs->blksz), (struct journal_superblock_t *)temp_buff, (uint32_t) fs->blksz); @@ -566,7 +567,7 @@ ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal); jsb_blknr = read_allocated_block(&inode_journal, - EXT2_JOURNAL_SUPERBLOCK); + EXT2_JOURNAL_SUPERBLOCK, NULL); ext4fs_devread((lbaint_t)jsb_blknr * fs->sect_perblk, 0, fs->blksz, temp_buff); jsb = (struct journal_superblock_t *) temp_buff; @@ -618,7 +619,7 @@ ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal); jsb_blknr = read_allocated_block(&inode_journal, - EXT2_JOURNAL_SUPERBLOCK); + EXT2_JOURNAL_SUPERBLOCK, NULL); ext4fs_devread((lbaint_t)jsb_blknr * fs->sect_perblk, 0, fs->blksz, temp_buff); jsb = (struct journal_superblock_t *) temp_buff; @@ -645,16 +646,17 @@ long int blknr; int i; ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal); - blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++); + blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++, NULL); update_descriptor_block(blknr); for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) { if (journal_ptr[i]->blknr == -1) break; - blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++); + blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++, + NULL); put_ext4((uint64_t) ((uint64_t)blknr * (uint64_t)fs->blksz), journal_ptr[i]->buf, fs->blksz); } - blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++); + blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++, NULL); update_commit_block(blknr); printf("update journal finished\n"); }
diff --git a/fs/ext4/ext4_write.c b/fs/ext4/ext4_write.c index a7f543f..8615689 100644 --- a/fs/ext4/ext4_write.c +++ b/fs/ext4/ext4_write.c
@@ -479,7 +479,7 @@ /* release data blocks */ for (i = 0; i < no_blocks; i++) { - blknr = read_allocated_block(&inode, i); + blknr = read_allocated_block(&inode, i, NULL); if (blknr == 0) continue; if (blknr < 0) @@ -695,7 +695,7 @@ ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal); blknr = read_allocated_block(&inode_journal, - EXT2_JOURNAL_SUPERBLOCK); + EXT2_JOURNAL_SUPERBLOCK, NULL); ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0, fs->blksz, temp_buff); jsb = (struct journal_superblock_t *)temp_buff; @@ -776,7 +776,7 @@ long int blknr; int blockend = fs->blksz; int skipfirst = 0; - blknr = read_allocated_block(file_inode, i); + blknr = read_allocated_block(file_inode, i, NULL); if (blknr <= 0) return -1;
diff --git a/fs/ext4/ext4fs.c b/fs/ext4/ext4fs.c index 2a28031..4624042 100644 --- a/fs/ext4/ext4fs.c +++ b/fs/ext4/ext4fs.c
@@ -61,15 +61,21 @@ lbaint_t delayed_skipfirst = 0; lbaint_t delayed_next = 0; char *delayed_buf = NULL; + char *start_buf = buf; short status; + struct ext_block_cache cache; - if (blocksize <= 0) - return -1; + ext_cache_init(&cache); /* Adjust len so it we can't read past the end of the file. */ if (len + pos > filesize) len = (filesize - pos); + if (blocksize <= 0 || len <= 0) { + ext_cache_fini(&cache); + return -1; + } + blockcnt = lldiv(((len + pos) + blocksize - 1), blocksize); for (i = lldiv(pos, blocksize); i < blockcnt; i++) { @@ -77,9 +83,11 @@ int blockoff = pos - (blocksize * i); int blockend = blocksize; int skipfirst = 0; - blknr = read_allocated_block(&(node->inode), i); - if (blknr < 0) + blknr = read_allocated_block(&node->inode, i, &cache); + if (blknr < 0) { + ext_cache_fini(&cache); return -1; + } blknr = blknr << log2_fs_blocksize; @@ -109,8 +117,10 @@ delayed_skipfirst, delayed_extent, delayed_buf); - if (status == 0) + if (status == 0) { + ext_cache_fini(&cache); return -1; + } previous_block_number = blknr; delayed_start = blknr; delayed_extent = blockend; @@ -130,20 +140,24 @@ } } else { int n; + int n_left; if (previous_block_number != -1) { /* spill */ status = ext4fs_devread(delayed_start, delayed_skipfirst, delayed_extent, delayed_buf); - if (status == 0) + if (status == 0) { + ext_cache_fini(&cache); return -1; + } previous_block_number = -1; } /* Zero no more than `len' bytes. */ n = blocksize - skipfirst; - if (n > len) - n = len; + n_left = len - (buf - start_buf); + if (n > n_left) + n = n_left; memset(buf, 0, n); } buf += blocksize - skipfirst; @@ -153,12 +167,15 @@ status = ext4fs_devread(delayed_start, delayed_skipfirst, delayed_extent, delayed_buf); - if (status == 0) + if (status == 0) { + ext_cache_fini(&cache); return -1; + } previous_block_number = -1; } *actread = len; + ext_cache_fini(&cache); return 0; } @@ -252,3 +269,32 @@ return -ENOSYS; #endif } + +void ext_cache_init(struct ext_block_cache *cache) +{ + memset(cache, 0, sizeof(*cache)); +} + +void ext_cache_fini(struct ext_block_cache *cache) +{ + free(cache->buf); + ext_cache_init(cache); +} + +int ext_cache_read(struct ext_block_cache *cache, lbaint_t block, int size) +{ + /* This could be more lenient, but this is simple and enough for now */ + if (cache->buf && cache->block == block && cache->size == size) + return 1; + ext_cache_fini(cache); + cache->buf = malloc(size); + if (!cache->buf) + return 0; + if (!ext4fs_devread(block, 0, size, cache->buf)) { + free(cache->buf); + return 0; + } + cache->block = block; + cache->size = size; + return 1; +}
diff --git a/fs/fs.c b/fs/fs.c index cb26517..7fd2210 100644 --- a/fs/fs.c +++ b/fs/fs.c
@@ -429,13 +429,57 @@ return ret; } -int fs_read(const char *filename, ulong addr, loff_t offset, loff_t len, - loff_t *actread) +#ifdef CONFIG_LMB +/* Check if a file may be read to the given address */ +static int fs_read_lmb_check(const char *filename, ulong addr, loff_t offset, + loff_t len, struct fstype_info *info) +{ + struct lmb lmb; + int ret; + loff_t size; + loff_t read_len; + + /* get the actual size of the file */ + ret = info->size(filename, &size); + if (ret) + return ret; + if (offset >= size) { + /* offset >= EOF, no bytes will be written */ + return 0; + } + read_len = size - offset; + + /* limit to 'len' if it is smaller */ + if (len && len < read_len) + read_len = len; + + lmb_init_and_reserve(&lmb, gd->bd->bi_dram[0].start, + gd->bd->bi_dram[0].size, (void *)gd->fdt_blob); + lmb_dump_all(&lmb); + + if (lmb_alloc_addr(&lmb, addr, read_len) == addr) + return 0; + + printf("** Reading file would overwrite reserved memory **\n"); + return -ENOSPC; +} +#endif + +static int _fs_read(const char *filename, ulong addr, loff_t offset, loff_t len, + int do_lmb_check, loff_t *actread) { struct fstype_info *info = fs_get_info(fs_type); void *buf; int ret; +#ifdef CONFIG_LMB + if (do_lmb_check) { + ret = fs_read_lmb_check(filename, addr, offset, len, info); + if (ret) + return ret; + } +#endif + /* * We don't actually know how many bytes are being read, since len==0 * means read the whole file. @@ -452,6 +496,12 @@ return ret; } +int fs_read(const char *filename, ulong addr, loff_t offset, loff_t len, + loff_t *actread) +{ + return _fs_read(filename, addr, offset, len, 0, actread); +} + int fs_write(const char *filename, ulong addr, loff_t offset, loff_t len, loff_t *actwrite) { @@ -622,7 +672,7 @@ pos = 0; time = get_timer(0); - ret = fs_read(filename, addr, pos, bytes, &len_read); + ret = _fs_read(filename, addr, pos, bytes, 1, &len_read); time = get_timer(time); if (ret < 0) return 1;
diff --git a/include/ext4fs.h b/include/ext4fs.h index bb55639..bed4bee 100644 --- a/include/ext4fs.h +++ b/include/ext4fs.h
@@ -116,6 +116,12 @@ struct blk_desc *dev_desc; }; +struct ext_block_cache { + char *buf; + lbaint_t block; + int size; +}; + extern struct ext2_data *ext4fs_root; extern struct ext2fs_node *ext4fs_file; @@ -145,11 +151,15 @@ void ext4fs_free_node(struct ext2fs_node *node, struct ext2fs_node *currroot); int ext4fs_devread(lbaint_t sector, int byte_offset, int byte_len, char *buf); void ext4fs_set_blk_dev(struct blk_desc *rbdd, disk_partition_t *info); -long int read_allocated_block(struct ext2_inode *inode, int fileblock); +long int read_allocated_block(struct ext2_inode *inode, int fileblock, + struct ext_block_cache *cache); int ext4fs_probe(struct blk_desc *fs_dev_desc, disk_partition_t *fs_partition); int ext4_read_file(const char *filename, void *buf, loff_t offset, loff_t len, loff_t *actread); int ext4_read_superblock(char *buffer); int ext4fs_uuid(char *uuid_str); +void ext_cache_init(struct ext_block_cache *cache); +void ext_cache_fini(struct ext_block_cache *cache); +int ext_cache_read(struct ext_block_cache *cache, lbaint_t block, int size); #endif
diff --git a/include/image.h b/include/image.h index 2027f01..43de407 100644 --- a/include/image.h +++ b/include/image.h
@@ -113,6 +113,9 @@ # define IMAGE_OF_SYSTEM_SETUP 0 #endif +/* An invalid size, meaning that the image size is not known */ +#define IMAGE_SIZE_INVAL (-1UL) + enum ih_category { IH_ARCH, IH_COMP, @@ -909,6 +912,8 @@ #define FIT_VALUE_PROP "value" #define FIT_IGNORE_PROP "uboot-ignore" #define FIT_SIG_NODENAME "signature" +#define FIT_KEY_REQUIRED "required" +#define FIT_KEY_HINT "key-name-hint" /* image node */ #define FIT_DATA_PROP "data" @@ -1042,7 +1047,23 @@ int fit_image_check_arch(const void *fit, int noffset, uint8_t arch); int fit_image_check_type(const void *fit, int noffset, uint8_t type); int fit_image_check_comp(const void *fit, int noffset, uint8_t comp); -int fit_check_format(const void *fit); + +/** + * fit_check_format() - Check that the FIT is valid + * + * This performs various checks on the FIT to make sure it is suitable for + * use, looking for mandatory properties, nodes, etc. + * + * If FIT_FULL_CHECK is enabled, it also runs it through libfdt to make + * sure that there are no strange tags or broken nodes in the FIT. + * + * @fit: pointer to the FIT format image header + * @return 0 if OK, -ENOEXEC if not an FDT file, -EINVAL if the full FDT check + * failed (e.g. due to bad structure), -ENOMSG if the description is + * missing, -ENODATA if the timestamp is missing, -ENOENT if the /images + * path is missing + */ +int fit_check_format(const void *fit, ulong size); int fit_conf_find_compat(const void *fit, const void *fdt); int fit_conf_get_node(const void *fit, const char *conf_uname);
diff --git a/include/lmb.h b/include/lmb.h index f04d058..c97210d 100644 --- a/include/lmb.h +++ b/include/lmb.h
@@ -31,6 +31,8 @@ extern struct lmb lmb; extern void lmb_init(struct lmb *lmb); +extern void lmb_init_and_reserve(struct lmb *lmb, phys_addr_t base, + phys_size_t size, void *fdt_blob); extern long lmb_add(struct lmb *lmb, phys_addr_t base, phys_size_t size); extern long lmb_reserve(struct lmb *lmb, phys_addr_t base, phys_size_t size); extern phys_addr_t lmb_alloc(struct lmb *lmb, phys_size_t size, ulong align); @@ -52,6 +54,8 @@ void board_lmb_reserve(struct lmb *lmb); void arch_lmb_reserve(struct lmb *lmb); +phys_addr_t lmb_alloc_addr(struct lmb *lmb, phys_addr_t base, phys_size_t size); + #endif /* __KERNEL__ */ #endif /* _LINUX_LMB_H */
diff --git a/lib/libfdt/fdt_region.c b/lib/libfdt/fdt_region.c index 7e9fa92..d52facc 100644 --- a/lib/libfdt/fdt_region.c +++ b/lib/libfdt/fdt_region.c
@@ -13,6 +13,7 @@ #else #include "fdt_host.h" #endif +#include <linux/kconfig.h> #define FDT_MAX_DEPTH 32 @@ -41,6 +42,7 @@ int depth = -1; int want = 0; int base = fdt_off_dt_struct(fdt); + int expect_end = 0; end = path; *end = '\0'; @@ -57,6 +59,10 @@ tag = fdt_next_tag(fdt, offset, &nextoffset); stop_at = nextoffset; + /* If we see two root nodes, something is wrong */ + if (expect_end && tag != FDT_END) + return -FDT_ERR_BADLAYOUT; + switch (tag) { case FDT_PROP: include = want >= 2; @@ -77,6 +83,10 @@ if (depth == FDT_MAX_DEPTH) return -FDT_ERR_BADSTRUCTURE; name = fdt_get_name(fdt, offset, &len); + + /* The root node must have an empty name */ + if (!depth && *name) + return -FDT_ERR_BADLAYOUT; if (end - path + 2 + len >= path_len) return -FDT_ERR_NOSPACE; if (end != path + 1) @@ -104,6 +114,8 @@ while (end > path && *--end != '/') ; *end = '\0'; + if (depth == -1) + expect_end = 1; break; case FDT_END:
diff --git a/lib/lmb.c b/lib/lmb.c index 1705417..cb247f6 100644 --- a/lib/lmb.c +++ b/lib/lmb.c
@@ -104,6 +104,19 @@ lmb->reserved.size = 0; } +/* Initialize the struct, add memory and call arch/board reserve functions */ +void lmb_init_and_reserve(struct lmb *lmb, phys_addr_t base, phys_size_t size, + void *fdt_blob) +{ + lmb_init(lmb); + lmb_add(lmb, base, size); + arch_lmb_reserve(lmb); + board_lmb_reserve(lmb); + + if (IMAGE_ENABLE_OF_LIBFDT && fdt_blob) + boot_fdt_add_mem_rsv_regions(lmb, fdt_blob); +} + /* This routine called with relocation disabled. */ static long lmb_add_region(struct lmb_region *rgn, phys_addr_t base, phys_size_t size) { @@ -343,3 +356,29 @@ { /* please define platform specific arch_lmb_reserve() */ } + +/* + * Try to allocate a specific address range: must be in defined memory but not + * reserved + */ +phys_addr_t lmb_alloc_addr(struct lmb *lmb, phys_addr_t base, phys_size_t size) +{ + long rgn; + + /* Check if the requested address is in one of the memory regions */ + rgn = lmb_overlaps_region(&lmb->memory, base, size); + if (rgn >= 0) { + /* + * Check if the requested end address is in the same memory + * region we found. + */ + if (lmb_addrs_overlap(lmb->memory.region[rgn].base, + lmb->memory.region[rgn].size, + base + size - 1, 1)) { + /* ok, reserve the memory */ + if (lmb_reserve(lmb, base, size) >= 0) + return base; + } + } + return 0; +}
diff --git a/lib/rsa/rsa-sign.c b/lib/rsa/rsa-sign.c index fb5e07b..8af2c8b 100644 --- a/lib/rsa/rsa-sign.c +++ b/lib/rsa/rsa-sign.c
@@ -773,7 +773,7 @@ } if (!ret) { - ret = fdt_setprop_string(keydest, node, "key-name-hint", + ret = fdt_setprop_string(keydest, node, FIT_KEY_HINT, info->keyname); } if (!ret) @@ -796,7 +796,7 @@ info->name); } if (!ret && info->require_keys) { - ret = fdt_setprop_string(keydest, node, "required", + ret = fdt_setprop_string(keydest, node, FIT_KEY_REQUIRED, info->require_keys); } done:
diff --git a/lib/uuid.c b/lib/uuid.c index d1bd330..468d807 100644 --- a/lib/uuid.c +++ b/lib/uuid.c
@@ -239,6 +239,8 @@ unsigned int *ptr = (unsigned int *)&uuid; int i; + srand(get_ticks() + rand()); + /* Set all fields randomly */ for (i = 0; i < sizeof(struct uuid) / sizeof(*ptr); i++) *(ptr + i) = cpu_to_be32(rand());
diff --git a/net/net.c b/net/net.c index 644c550..5e2d39d 100644 --- a/net/net.c +++ b/net/net.c
@@ -1269,6 +1269,9 @@ return; } + if (ntohs(ip->udp_len) < UDP_HDR_SIZE || ntohs(ip->udp_len) > ntohs(ip->ip_len)) + return; + debug_cond(DEBUG_DEV_PKT, "received UDP (to=%pI4, from=%pI4, len=%d)\n", &dst_ip, &src_ip, len);
diff --git a/scripts/dtc/libfdt/fdt_ro.c b/scripts/dtc/libfdt/fdt_ro.c index dfb3236..971bbe3 100644 --- a/scripts/dtc/libfdt/fdt_ro.c +++ b/scripts/dtc/libfdt/fdt_ro.c
@@ -140,6 +140,10 @@ do { tag = fdt_next_tag(fdt, offset, &nextoffset); + /* If we see two root nodes, something is wrong */ + if (expect_end && tag != FDT_END) + return -FDT_ERR_BADLAYOUT; + switch (tag) { case FDT_END: if (nextoffset >= 0)
diff --git a/scripts/dtc/libfdt/libfdt.h b/scripts/dtc/libfdt/libfdt.h index fd73688..6b4ebd4 100644 --- a/scripts/dtc/libfdt/libfdt.h +++ b/scripts/dtc/libfdt/libfdt.h
@@ -280,6 +280,8 @@ */ int fdt_move(const void *fdt, void *buf, int bufsize); +int fdt_check_full(const void *fdt, size_t bufsize); + /**********************************************************************/ /* Read-only functions */ /**********************************************************************/
diff --git a/test/py/tests/test_fit.py b/test/py/tests/test_fit.py index 49d6fea..839dcf9 100755 --- a/test/py/tests/test_fit.py +++ b/test/py/tests/test_fit.py
@@ -19,7 +19,7 @@ #address-cells = <1>; images { - kernel@1 { + kernel-1 { data = /incbin/("%(kernel)s"); type = "kernel"; arch = "sandbox"; @@ -28,7 +28,7 @@ load = <0x40000>; entry = <0x8>; }; - kernel@2 { + kernel-2 { data = /incbin/("%(loadables1)s"); type = "kernel"; arch = "sandbox"; @@ -37,19 +37,19 @@ %(loadables1_load)s entry = <0x0>; }; - fdt@1 { + fdt-1 { description = "snow"; data = /incbin/("u-boot.dtb"); type = "flat_dt"; arch = "sandbox"; %(fdt_load)s compression = "none"; - signature@1 { + signature-1 { algo = "sha1,rsa2048"; key-name-hint = "dev"; }; }; - ramdisk@1 { + ramdisk-1 { description = "snow"; data = /incbin/("%(ramdisk)s"); type = "ramdisk"; @@ -58,7 +58,7 @@ %(ramdisk_load)s compression = "none"; }; - ramdisk@2 { + ramdisk-2 { description = "snow"; data = /incbin/("%(loadables2)s"); type = "ramdisk"; @@ -69,10 +69,10 @@ }; }; configurations { - default = "conf@1"; - conf@1 { - kernel = "kernel@1"; - fdt = "fdt@1"; + default = "conf-1"; + conf-1 { + kernel = "kernel-1"; + fdt = "fdt-1"; %(ramdisk_config)s %(loadables_config)s }; @@ -395,7 +395,7 @@ # Try a ramdisk with cons.log.section('Kernel + FDT + Ramdisk load'): - params['ramdisk_config'] = 'ramdisk = "ramdisk@1";' + params['ramdisk_config'] = 'ramdisk = "ramdisk-1";' params['ramdisk_load'] = 'load = <%#x>;' % params['ramdisk_addr'] fit = make_fit(mkimage, params) cons.restart_uboot() @@ -404,7 +404,7 @@ # Configuration with some Loadables with cons.log.section('Kernel + FDT + Ramdisk load + Loadables'): - params['loadables_config'] = 'loadables = "kernel@2", "ramdisk@2";' + params['loadables_config'] = 'loadables = "kernel-2", "ramdisk-2";' params['loadables1_load'] = ('load = <%#x>;' % params['loadables1_addr']) params['loadables2_load'] = ('load = <%#x>;' %
diff --git a/test/py/tests/test_vboot.py b/test/py/tests/test_vboot.py index 4627ceb..fb47441 100644 --- a/test/py/tests/test_vboot.py +++ b/test/py/tests/test_vboot.py
@@ -24,10 +24,28 @@ Tests run with both SHA1 and SHA256 hashing. """ + +import shutil import pytest import sys import struct import u_boot_utils as util +import vboot_evil + +# Only run the full suite on a few combinations, since it doesn't add any more +# test coverage. +TESTDATA = [ + ['sha1', '', None, False, True], + ['sha1', '', '-E -p 0x10000', False, False], + ['sha1', '-pss', None, False, False], + ['sha1', '-pss', '-E -p 0x10000', False, False], + ['sha256', '', None, False, False], + ['sha256', '', '-E -p 0x10000', False, False], + ['sha256', '-pss', None, False, False], + ['sha256', '-pss', '-E -p 0x10000', False, False], + ['sha256', '-pss', None, True, False], + ['sha256', '-pss', '-E -p 0x10000', True, True], +] @pytest.mark.boardspec('sandbox') @pytest.mark.buildconfigspec('fit_signature') @@ -57,7 +75,7 @@ util.run_and_log(cons, 'dtc %s %s%s -O dtb ' '-o %s%s' % (dtc_args, datadir, dts, tmpdir, dtb)) - def run_bootm(sha_algo, test_type, expect_string, boots): + def run_bootm(sha_algo, test_type, expect_string, boots, fit=None): """Run a 'bootm' command U-Boot. This always starts a fresh U-Boot instance since the device tree may
diff --git a/tools/fdt_host.h b/tools/fdt_host.h index 99b009b..15c07c7 100644 --- a/tools/fdt_host.h +++ b/tools/fdt_host.h
@@ -27,6 +27,7 @@ */ int fdt_remove_unused_strings(const void *old, void *new); -int fit_check_sign(const void *working_fdt, const void *key); +int fit_check_sign(const void *fit, const void *key, + const char *fit_uname_config); #endif /* __FDT_HOST_H__ */
diff --git a/tools/fit_check_sign.c b/tools/fit_check_sign.c index 62adc75..303e878 100644 --- a/tools/fit_check_sign.c +++ b/tools/fit_check_sign.c
@@ -41,6 +41,7 @@ void *fit_blob; char *fdtfile = NULL; char *keyfile = NULL; + char *config_name = NULL; char cmdname[256]; int ret; void *key_blob; @@ -48,7 +49,7 @@ strncpy(cmdname, *argv, sizeof(cmdname) - 1); cmdname[sizeof(cmdname) - 1] = '\0'; - while ((c = getopt(argc, argv, "f:k:")) != -1) + while ((c = getopt(argc, argv, "f:k:c:")) != -1) switch (c) { case 'f': fdtfile = optarg; @@ -56,6 +57,9 @@ case 'k': keyfile = optarg; break; + case 'c': + config_name = optarg; + break; default: usage(cmdname); break; @@ -78,7 +82,7 @@ return EXIT_FAILURE; image_set_host_blob(key_blob); - ret = fit_check_sign(fit_blob, key_blob); + ret = fit_check_sign(fit_blob, key_blob, config_name); if (!ret) { ret = EXIT_SUCCESS; fprintf(stderr, "Signature check OK\n");
diff --git a/tools/fit_common.c b/tools/fit_common.c index d96085e..5e85ca2 100644 --- a/tools/fit_common.c +++ b/tools/fit_common.c
@@ -26,7 +26,11 @@ int fit_verify_header(unsigned char *ptr, int image_size, struct image_tool_params *params) { - return fdt_check_header(ptr); + if (fdt_check_header(ptr) != EXIT_SUCCESS || + fit_check_format(ptr, IMAGE_SIZE_INVAL)) + return EXIT_FAILURE; + + return EXIT_SUCCESS; } int fit_check_image_types(uint8_t type)
diff --git a/tools/fit_image.c b/tools/fit_image.c index 4b62635..f7ee947 100644 --- a/tools/fit_image.c +++ b/tools/fit_image.c
@@ -763,7 +763,7 @@ /* Indent string is defined in header image.h */ p = IMAGE_INDENT_STRING; - if (!fit_check_format(fit)) { + if (fit_check_format(fit, IMAGE_SIZE_INVAL)) { printf("Bad FIT image format\n"); return -1; }
diff --git a/tools/image-host.c b/tools/image-host.c index 88b3295..3396d82 100644 --- a/tools/image-host.c +++ b/tools/image-host.c
@@ -170,7 +170,7 @@ memset(info, '\0', sizeof(*info)); info->keydir = keydir; - info->keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL); + info->keyname = fdt_getprop(fit, noffset, FIT_KEY_HINT, NULL); info->fit = fit; info->node_offset = noffset; info->name = strdup(algo_name); @@ -249,7 +249,7 @@ free(value); /* Get keyname again, as FDT has changed and invalidated our pointer */ - info.keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL); + info.keyname = fdt_getprop(fit, noffset, FIT_KEY_HINT, NULL); /* * Write the public key into the supplied FDT file; this might fail @@ -630,7 +630,7 @@ free(region_prop); /* Get keyname again, as FDT has changed and invalidated our pointer */ - info.keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL); + info.keyname = fdt_getprop(fit, noffset, FIT_KEY_HINT, NULL); /* Write the public key into the supplied FDT file */ if (keydest) { @@ -734,19 +734,22 @@ } #ifdef CONFIG_FIT_SIGNATURE -int fit_check_sign(const void *fit, const void *key) +int fit_check_sign(const void *fit, const void *key, + const char *fit_uname_config) { int cfg_noffset; int ret; - cfg_noffset = fit_conf_get_node(fit, NULL); + cfg_noffset = fit_conf_get_node(fit, fit_uname_config); if (!cfg_noffset) return -1; - printf("Verifying Hash Integrity ... "); + printf("Verifying Hash Integrity for node '%s'... ", + fdt_get_name(fit, cfg_noffset, NULL)); ret = fit_config_verify(fit, cfg_noffset); if (ret) return ret; + printf("Verified OK, loading images\n"); ret = bootm_host_load_images(fit, cfg_noffset); return ret;
diff --git a/tools/mkimage.h b/tools/mkimage.h index 0254af5..d32625f 100644 --- a/tools/mkimage.h +++ b/tools/mkimage.h
@@ -29,6 +29,8 @@ #define debug(fmt,args...) #endif /* MKIMAGE_DEBUG */ +#define log_debug(fmt, args...) debug(fmt, ##args) + static inline void *map_sysmem(ulong paddr, unsigned long len) { return (void *)(uintptr_t)paddr;