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.c101
1 files changed, 93 insertions, 8 deletions
diff --git a/tools/fit_image.c b/tools/fit_image.c
index 1dbc14c63e4..5831b07c090 100644
--- a/tools/fit_image.c
+++ b/tools/fit_image.c
@@ -40,10 +40,10 @@ static int fit_estimate_hash_sig_size(struct image_tool_params *params, const ch
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.
+ * Walk the FIT image, looking for nodes named hash*,
+ * signature*, and dm-verity. 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
@@ -55,6 +55,10 @@ static int fit_estimate_hash_sig_size(struct image_tool_params *params, const ch
* account for fdt overhead and the various other properties
* (hashed-nodes etc.) that will also be filled in.
*
+ * For a dm-verity node the small metadata properties (digest,
+ * salt, two u32s and a temp-file path) are written into the
+ * FDT by fit_image_process_verity().
+ *
* 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,
@@ -76,6 +80,18 @@ static int fit_estimate_hash_sig_size(struct image_tool_params *params, const ch
if (signing && !strncmp(name, FIT_SIG_NODENAME, strlen(FIT_SIG_NODENAME)))
estimate += 1024;
+
+ if (!strcmp(name, FIT_VERITY_NODENAME)) {
+ if (!params->external_data) {
+ fprintf(stderr,
+ "%s: dm-verity requires external data (-E)\n",
+ params->cmdname);
+ munmap(fdt, sbuf.st_size);
+ close(fd);
+ return -EINVAL;
+ }
+ estimate += 256;
+ }
}
munmap(fdt, sbuf.st_size);
@@ -265,8 +281,14 @@ static void get_basename(char *str, int size, const char *fname)
*/
p = strrchr(fname, '/');
start = p ? p + 1 : fname;
- p = strrchr(fname, '.');
- end = p ? p : fname + strlen(fname);
+ /*
+ * Search for the extension dot only within the basename. Searching
+ * the whole path would let a dot in the directory part (for example
+ * "./mydt" or "a.b/c") place 'end' before 'start' and produce a
+ * negative length, which the size check below does not catch.
+ */
+ p = strrchr(start, '.');
+ end = p ? p : start + strlen(start);
len = end - start;
if (len >= size)
len = size - 1;
@@ -471,6 +493,41 @@ static int fit_write_images(struct image_tool_params *params, char *fdt)
}
/**
+ * fit_copy_image_data() - copy image data, using cached verity expansion
+ * @fdt: FIT blob
+ * @node: image node offset
+ * @buf: destination buffer
+ * @buf_ptr: write offset within @buf
+ * @data: embedded image data (used when no dm-verity expansion exists)
+ * @lenp: in/out: on entry, length of @data; on exit, bytes written
+ *
+ * When fit_image_process_verity() has run, the expanded image data
+ * (original + hash tree) is cached in memory. Look it up by image name
+ * and copy from the cached buffer rather than the embedded ``data``
+ * property; fall back to @data otherwise.
+ *
+ * Return: 0 on success
+ */
+static int fit_copy_image_data(void *fdt, int node, void *buf,
+ int buf_ptr, const void *data, int *lenp)
+{
+ const char *image_name = fdt_get_name(fdt, node, NULL);
+ const void *vdata;
+ size_t vsize;
+
+ if (image_name &&
+ !fit_verity_get_expanded(image_name, &vdata, &vsize)) {
+ memcpy(buf + buf_ptr, vdata, vsize);
+ *lenp = vsize;
+ return 0;
+ }
+
+ memcpy(buf + buf_ptr, data, *lenp);
+
+ return 0;
+}
+
+/**
* fit_write_configs() - Write out a list of configurations to the FIT
*
* If there are device tree files, we include a configuration for each, which
@@ -653,6 +710,8 @@ static int fit_extract_data(struct image_tool_params *params, const char *fname)
int node;
int align_size = 0;
int len = 0;
+ int verity_extra = 0;
+ int orig_len;
fd = mmap_fdt(params->cmdname, fname, 0, &fdt, &sbuf, false, false);
if (fd < 0)
@@ -687,10 +746,33 @@ static int fit_extract_data(struct image_tool_params *params, const char *fname)
}
/*
+ * When dm-verity is active the external data for an image is
+ * larger than the embedded data property (original + hash tree).
+ * Walk images once more and consult the in-memory cache for the
+ * actual expanded size.
+ */
+ fdt_for_each_subnode(node, fdt, images) {
+ const char *image_name;
+ const void *vdata;
+ size_t vsize;
+
+ orig_len = 0;
+ if (fdt_subnode_offset(fdt, node, FIT_VERITY_NODENAME) < 0)
+ continue;
+ image_name = fdt_get_name(fdt, node, NULL);
+ if (!image_name ||
+ fit_verity_get_expanded(image_name, &vdata, &vsize))
+ continue;
+ fdt_getprop(fdt, node, FIT_DATA_PROP, &orig_len);
+ if ((int)vsize > orig_len)
+ verity_extra += (int)vsize - orig_len;
+ }
+
+ /*
* Allocate space to hold the image data we will extract,
* extral space allocate for image alignment to prevent overflow.
*/
- buf = calloc(1, fit_size + align_size);
+ buf = calloc(1, fit_size + align_size + verity_extra);
if (!buf) {
ret = -ENOMEM;
goto err_munmap;
@@ -721,7 +803,10 @@ static int fit_extract_data(struct image_tool_params *params, const char *fname)
data = fdt_getprop(fdt, node, FIT_DATA_PROP, &len);
if (!data)
continue;
- memcpy(buf + buf_ptr, data, len);
+
+ ret = fit_copy_image_data(fdt, node, buf, buf_ptr, data, &len);
+ if (ret)
+ goto err_munmap;
debug("Extracting data size %x\n", len);
ret = fdt_delprop(fdt, node, FIT_DATA_PROP);