diff options
Diffstat (limited to 'tools/fit_image.c')
-rw-r--r-- | tools/fit_image.c | 122 |
1 files changed, 110 insertions, 12 deletions
diff --git a/tools/fit_image.c b/tools/fit_image.c index caed8d5f901..8717dc9a3b1 100644 --- a/tools/fit_image.c +++ b/tools/fit_image.c @@ -24,6 +24,65 @@ static struct legacy_img_hdr header; +static int fit_estimate_hash_sig_size(struct image_tool_params *params, const char *fname) +{ + bool signing = IMAGE_ENABLE_SIGN && (params->keydir || params->keyfile); + struct stat sbuf; + void *fdt; + int fd; + int estimate = 0; + int depth, noffset; + const char *name; + + fd = mmap_fdt(params->cmdname, fname, 0, &fdt, &sbuf, false, true); + if (fd < 0) + return -EIO; + + /* + * Walk the FIT image, looking for nodes named hash* and + * signature*. Since the interesting nodes are subnodes of an + * image or configuration node, we are only interested in + * those at depth exactly 3. + * + * The estimate for a hash node is based on a sha512 digest + * being 64 bytes, with another 64 bytes added to account for + * fdt structure overhead (the tags and the name of the + * "value" property). + * + * The estimate for a signature node is based on an rsa4096 + * signature being 512 bytes, with another 512 bytes to + * account for fdt overhead and the various other properties + * (hashed-nodes etc.) that will also be filled in. + * + * One could try to be more precise in the estimates by + * looking at the "algo" property and, in the case of + * configuration signatures, the sign-images property. Also, + * when signing an already created FIT image, the hash nodes + * already have properly sized value properties, so one could + * also take pre-existence of "value" properties in hash nodes + * into account. But this rather simple approach should work + * well enough in practice. + */ + for (depth = 0, noffset = fdt_next_node(fdt, 0, &depth); + noffset >= 0 && depth > 0; + noffset = fdt_next_node(fdt, noffset, &depth)) { + if (depth != 3) + continue; + + name = fdt_get_name(fdt, noffset, NULL); + if (!strncmp(name, FIT_HASH_NODENAME, strlen(FIT_HASH_NODENAME))) + estimate += 128; + + if (signing && !strncmp(name, FIT_SIG_NODENAME, strlen(FIT_SIG_NODENAME))) + estimate += 1024; + } + + munmap(fdt, sbuf.st_size); + close(fd); + + return estimate; +} + static int fit_add_file_data(struct image_tool_params *params, size_t size_inc, const char *tmpfile) { @@ -627,6 +686,7 @@ static int fit_import_data(struct image_tool_params *params, const char *fname) struct stat sbuf; int ret; int images; + int confs; int node; fd = mmap_fdt(params->cmdname, fname, 0, &old_fdt, &sbuf, false, false); @@ -695,6 +755,43 @@ static int fit_import_data(struct image_tool_params *params, const char *fname) } } + confs = fdt_path_offset(fdt, FIT_CONFS_PATH); + static const char * const props[] = { FIT_KERNEL_PROP, + FIT_RAMDISK_PROP, + FIT_FDT_PROP, + FIT_LOADABLE_PROP, + FIT_FPGA_PROP, + FIT_FIRMWARE_PROP, + FIT_SCRIPT_PROP}; + + fdt_for_each_subnode(node, fdt, confs) { + const char *conf_name = fdt_get_name(fdt, node, NULL); + + for (int i = 0; i < ARRAY_SIZE(props); i++) { + int count = fdt_stringlist_count(fdt, node, props[i]); + + if (count < 0) + continue; + + for (int j = 0; j < count; j++) { + const char *img_name = + fdt_stringlist_get(fdt, node, props[i], j, NULL); + if (!img_name || !*img_name) + continue; + + int img = fdt_subnode_offset(fdt, images, img_name); + + if (img < 0) { + fprintf(stderr, + "Error: configuration '%s' references undefined image '%s' in property '%s'\n", + conf_name, img_name, props[i]); + ret = FDT_ERR_NOTFOUND; + goto err_munmap; + } + } + } + } + munmap(old_fdt, sbuf.st_size); /* Close the old fd so we can re-use it. */ @@ -750,7 +847,7 @@ static int fit_handle_file(struct image_tool_params *params) char bakfile[MKIMAGE_MAX_TMPFILE_LEN + 4] = {0}; char cmd[MKIMAGE_MAX_DTC_CMDLINE_LEN]; size_t size_inc; - int ret; + int ret = EXIT_FAILURE; /* Flattened Image Tree (FIT) format handling */ debug ("FIT format handling\n"); @@ -806,16 +903,16 @@ static int fit_handle_file(struct image_tool_params *params) rename(tmpfile, bakfile); /* - * Set hashes for images in the blob. Unfortunately we may need more - * space in either FDT, so keep trying until we succeed. - * - * Note: this is pretty inefficient for signing, since we must - * calculate the signature every time. It would be better to calculate - * all the data and then store it in a separate step. However, this - * would be considerably more complex to implement. Generally a few - * steps of this loop is enough to sign with several keys. + * Set hashes for images in the blob and compute + * signatures. We do an attempt at estimating the expected + * extra size, but just in case that is not sufficient, keep + * trying adding 1K, with a reasonable upper bound of 64K + * total, until we succeed. */ - for (size_inc = 0; size_inc < 64 * 1024; size_inc += 1024) { + size_inc = fit_estimate_hash_sig_size(params, bakfile); + if (size_inc < 0) + goto err_system; + do { if (copyfile(bakfile, tmpfile) < 0) { printf("Can't copy %s to %s\n", bakfile, tmpfile); ret = -EIO; @@ -824,7 +921,8 @@ static int fit_handle_file(struct image_tool_params *params) ret = fit_add_file_data(params, size_inc, tmpfile); if (!ret || ret != -ENOSPC) break; - } + size_inc += 1024; + } while (size_inc < 64 * 1024); if (ret) { fprintf(stderr, "%s Can't add hashes to FIT blob: %d\n", @@ -854,7 +952,7 @@ static int fit_handle_file(struct image_tool_params *params) err_system: unlink(tmpfile); unlink(bakfile); - return -1; + return ret; } /** |