summaryrefslogtreecommitdiff
path: root/tools/fit_image.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/fit_image.c')
-rw-r--r--tools/fit_image.c122
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;
}
/**