boot: fit: cover the dm-verity roothash with the config signature
A dm-verity protected filesystem image is not hashed by U-Boot when it is loaded; its integrity is delegated to the kernel, which validates the filesystem on the fly against the roothash taken from the FIT dm-verity subnode. The roothash is therefore the sole integrity anchor for the filesystem, yet fit_config_add_hash() only adds the image node, its hash subnodes and its cipher subnode to the signed region, leaving the dm-verity subnode (roothash, salt and block parameters) unsigned. An attacker able to rewrite the boot medium could then replace both the filesystem and the roothash, recompute a matching dm-verity tree and keep the configuration signature valid, defeating verified boot for the root filesystem. Add the dm-verity subnode to the list of nodes covered by the configuration signature, both when signing (tools/image-host.c) and when verifying (boot/image-fit-sig.c), so the roothash and salt are authenticated together with the rest of the configuration. Signed-off-by: Daniel Golle <daniel@makrotopia.org> Reviewed-by: Tom Rini <trini@konsulko.com> Reviewed-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
+19
-4
@@ -264,8 +264,8 @@ static int fit_config_add_node(const void *fit, int noffset, char **node_inc,
|
||||
/**
|
||||
* fit_config_add_hash() - Add hash nodes for one image to the node list
|
||||
*
|
||||
* Adds the image path, all its hash-* subnode paths, and its cipher
|
||||
* subnode path (if present) to the packed buffer.
|
||||
* Adds the image path, all its hash-* subnode paths, and its cipher and
|
||||
* dm-verity subnode paths (each if present) to the packed buffer.
|
||||
*
|
||||
* @fit: FIT blob
|
||||
* @image_noffset: Image node offset (e.g. /images/kernel-1)
|
||||
@@ -322,6 +322,21 @@ static int fit_config_add_hash(const void *fit, int image_noffset,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add this image's dm-verity node if present. Its roothash is the
|
||||
* only integrity anchor for a dm-verity filesystem image, so it must
|
||||
* be covered by the configuration signature.
|
||||
*/
|
||||
noffset = fdt_subnode_offset(fit, image_noffset, FIT_VERITY_NODENAME);
|
||||
if (noffset != -FDT_ERR_NOTFOUND) {
|
||||
if (noffset < 0)
|
||||
return -EIO;
|
||||
ret = fit_config_add_node(fit, noffset, node_inc, count,
|
||||
max_nodes, buf, buf_used, buf_len);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -329,8 +344,8 @@ static int fit_config_add_hash(const void *fit, int image_noffset,
|
||||
* fit_config_get_hash_list() - Build the list of nodes to hash
|
||||
*
|
||||
* Works through every image referenced by the configuration and collects the
|
||||
* node paths: root + config + all referenced images with their hash and
|
||||
* cipher subnodes.
|
||||
* node paths: root + config + all referenced images with their hash,
|
||||
* cipher and dm-verity subnodes.
|
||||
*
|
||||
* Properties known not to be image references (description, compatible,
|
||||
* default, load-only) are skipped, so any new image type is covered by default.
|
||||
|
||||
@@ -209,6 +209,11 @@ typically be obtained from its output.
|
||||
The ``digest`` and ``salt`` byte arrays correspond to the hex-encoded
|
||||
``Root hash`` and ``Salt`` printed by ``veritysetup format``.
|
||||
|
||||
When the configuration is signed, ``digest`` and ``salt`` are covered by
|
||||
the configuration signature (see :doc:`signature`), so the roothash
|
||||
cannot be swapped out for a matching one without invalidating the
|
||||
signature.
|
||||
|
||||
Optional boolean properties (when present, they are collected and appended
|
||||
as dm-verity optional parameters with hyphens converted to underscores):
|
||||
|
||||
|
||||
@@ -359,7 +359,7 @@ however, U-Boot does not read 'hashed-nodes'. Instead it rebuilds the node
|
||||
list from the configuration's own image references (kernel, fdt, ramdisk,
|
||||
etc.), since 'hashed-nodes' is not itself covered by the signature. The
|
||||
rebuilt list always includes the root node, the configuration node, each
|
||||
referenced image node and its hash/cipher subnodes.
|
||||
referenced image node and its hash, cipher and dm-verity subnodes.
|
||||
|
||||
The image is walked in order and each tag processed as follows:
|
||||
|
||||
|
||||
@@ -1287,6 +1287,27 @@ static int fit_config_add_hash(const void *fit, int image_noffset,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add this image's dm-verity node if present. Its roothash is the
|
||||
* only integrity anchor for a dm-verity filesystem image, so it must
|
||||
* be covered by the configuration signature.
|
||||
*/
|
||||
noffset = fdt_subnode_offset(fit, image_noffset,
|
||||
FIT_VERITY_NODENAME);
|
||||
if (noffset != -FDT_ERR_NOTFOUND) {
|
||||
if (noffset < 0) {
|
||||
fprintf(stderr,
|
||||
"Failed to get dm-verity node in configuration '%s/%s' image '%s': %s\n",
|
||||
conf_name, sig_name, iname,
|
||||
fdt_strerror(noffset));
|
||||
return -EIO;
|
||||
}
|
||||
ret = fit_config_add_node(fit, noffset, node_inc, conf_name,
|
||||
sig_name, iname);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user