summaryrefslogtreecommitdiffstats
path: root/common/image-fit.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/image-fit.c')
-rw-r--r--common/image-fit.c154
1 files changed, 129 insertions, 25 deletions
diff --git a/common/image-fit.c b/common/image-fit.c
index a410632d70..251fda97b3 100644
--- a/common/image-fit.c
+++ b/common/image-fit.c
@@ -21,6 +21,7 @@
#include <linux/err.h>
#include <stringlist.h>
#include <rsa.h>
+#include <uncompress.h>
#include <image-fit.h>
#define FDT_MAX_DEPTH 32
@@ -263,7 +264,7 @@ static int fit_check_rsa_signature(struct device_node *sig_node,
sig_value = of_get_property(sig_node, "value", &sig_len);
if (!sig_value) {
- pr_err("signature value not found in %s\n", sig_node->full_name);
+ pr_err("signature value not found in %pOF\n", sig_node);
return -EINVAL;
}
@@ -309,12 +310,12 @@ static int fit_verify_signature(struct device_node *sig_node, const void *fit)
if (of_property_read_u32_index(sig_node, "hashed-strings", 0,
&hashed_strings_start)) {
- pr_err("hashed-strings start not found in %s\n", sig_node->full_name);
+ pr_err("hashed-strings start not found in %pOF\n", sig_node);
return -EINVAL;
}
if (of_property_read_u32_index(sig_node, "hashed-strings", 1,
&hashed_strings_size)) {
- pr_err("hashed-strings size not found in %s\n", sig_node->full_name);
+ pr_err("hashed-strings size not found in %pOF\n", sig_node);
return -EINVAL;
}
@@ -322,7 +323,7 @@ static int fit_verify_signature(struct device_node *sig_node, const void *fit)
string_list_init(&exc_props);
if (of_read_string_list(sig_node, "hashed-nodes", &inc_nodes)) {
- pr_err("hashed-nodes property not found in %s\n", sig_node->full_name);
+ pr_err("hashed-nodes property not found in %pOF\n", sig_node);
ret = -EINVAL;
goto out_sl;
}
@@ -380,30 +381,29 @@ static int fit_verify_hash(struct fit_handle *handle, struct device_node *image,
hash = of_get_child_by_name(image, "hash@1");
if (!hash) {
if (ret)
- pr_err("image %s does not have hashes\n",
- image->full_name);
+ pr_err("image %pOF does not have hashes\n", image);
return ret;
}
value_read = of_get_property(hash, "value", &hash_len);
if (!value_read) {
- pr_err("%s: \"value\" property not found\n", hash->full_name);
+ pr_err("%pOF: \"value\" property not found\n", hash);
return -EINVAL;
}
if (of_property_read_string(hash, "algo", &algo)) {
- pr_err("%s: \"algo\" property not found\n", hash->full_name);
+ pr_err("%pOF: \"algo\" property not found\n", hash);
return -EINVAL;
}
d = digest_alloc(algo);
if (!d) {
- pr_err("%s: unsupported algo %s\n", hash->full_name, algo);
+ pr_err("%pOF: unsupported algo %s\n", hash, algo);
return -EINVAL;
}
if (hash_len != digest_length(d)) {
- pr_err("%s: invalid hash length %d\n", hash->full_name, hash_len);
+ pr_err("%pOF: invalid hash length %d\n", hash, hash_len);
ret = -EINVAL;
goto err_digest_free;
}
@@ -412,10 +412,10 @@ static int fit_verify_hash(struct fit_handle *handle, struct device_node *image,
digest_update(d, data, data_len);
if (digest_verify(d, value_read)) {
- pr_info("%s: hash BAD\n", hash->full_name);
+ pr_info("%pOF: hash BAD\n", hash);
ret = -EBADMSG;
} else {
- pr_info("%s: hash OK\n", hash->full_name);
+ pr_info("%pOF: hash OK\n", hash);
ret = 0;
}
@@ -452,7 +452,7 @@ static int fit_image_verify_signature(struct fit_handle *handle,
if (!sig_node)
sig_node = of_get_child_by_name(image, "signature@1");
if (!sig_node) {
- pr_err("Image %s has no signature\n", image->full_name);
+ pr_err("Image %pOF has no signature\n", image);
return ret;
}
@@ -545,6 +545,7 @@ int fit_get_image_address(struct fit_handle *handle, void *configuration,
{
struct device_node *image;
const char *unit = name;
+ const char *type;
int ret;
if (!address || !property || !name)
@@ -554,11 +555,62 @@ int fit_get_image_address(struct fit_handle *handle, void *configuration,
if (ret)
return ret;
+ /* Treat type = "kernel_noload" as if entry/load address is missing */
+ ret = of_property_read_string(image, "type", &type);
+ if (!ret && !strcmp(type, "kernel_noload"))
+ return -ENOENT;
+
ret = fit_get_address(image, property, address);
return ret;
}
+static void fit_uncompress_error_fn(char *x)
+{
+ pr_err("%s\n", x);
+}
+
+static int fit_handle_decompression(struct device_node *image,
+ const char *type,
+ const void **data,
+ int *data_len)
+{
+ const char *compression = NULL;
+ void *uc_data;
+ int ret;
+
+ of_property_read_string(image, "compression", &compression);
+ if (!compression || !strcmp(compression, "none"))
+ return 0;
+
+ if (!strcmp(type, "ramdisk")) {
+ pr_warn("compression != \"none\" for ramdisks is deprecated,"
+ " please fix your .its file!\n");
+ return 0;
+ }
+
+ if (!IS_ENABLED(CONFIG_UNCOMPRESS)) {
+ pr_err("image has compression = \"%s\", but support not compiled in\n",
+ compression);
+ return -ENOSYS;
+ }
+
+ ret = uncompress_buf_to_buf(*data, *data_len, &uc_data,
+ fit_uncompress_error_fn);
+ if (ret < 0) {
+ pr_err("data couldn't be decompressed\n");
+ return ret;
+ }
+
+ *data = uc_data;
+ *data_len = ret;
+
+ /* associate buffer with FIT, so it's not leaked */
+ __of_new_property(image, "uncompressed-data", uc_data, *data_len);
+
+ return 0;
+}
+
/**
* fit_open_image - Open an image in a FIT image
* @handle: The FIT image handle
@@ -595,7 +647,7 @@ int fit_open_image(struct fit_handle *handle, void *configuration,
of_property_read_string(image, "type", &type);
if (!type) {
- pr_err("No \"type\" property found in %s\n", image->full_name);
+ pr_err("No \"type\" property found in %pOF\n", image);
return -EINVAL;
}
@@ -613,6 +665,10 @@ int fit_open_image(struct fit_handle *handle, void *configuration,
if (ret < 0)
return ret;
+ ret = fit_handle_decompression(image, type, &data, &data_len);
+ if (ret)
+ return ret;
+
*outdata = data;
*outsize = data_len;
@@ -640,27 +696,32 @@ static int fit_config_verify_signature(struct fit_handle *handle, struct device_
}
for_each_child_of_node(conf_node, sig_node) {
+ if (!of_node_has_prefix(sig_node, "signature"))
+ continue;
+
if (handle->verbose)
- of_print_nodes(sig_node, 0);
+ of_print_nodes(sig_node, 0, ~0);
+
ret = fit_verify_signature(sig_node, handle->fit);
if (ret < 0)
return ret;
}
if (ret < 0) {
- pr_err("configuration '%s' does not have a signature\n",
- conf_node->full_name);
+ pr_err("configuration '%pOF' does not have a signature\n", conf_node);
return ret;
}
return ret;
}
-static int fit_find_compatible_unit(struct device_node *conf_node,
+static int fit_find_compatible_unit(struct fit_handle *handle,
+ struct device_node *conf_node,
const char **unit)
{
struct device_node *child = NULL;
struct device_node *barebox_root;
+ int best_score = 0;
const char *machine;
int ret;
@@ -673,13 +734,55 @@ static int fit_find_compatible_unit(struct device_node *conf_node,
return -ENOENT;
for_each_child_of_node(conf_node, child) {
- if (of_device_is_compatible(child, machine)) {
+ int score = of_device_is_compatible(child, machine);
+
+ if (!score && !of_property_present(child, "compatible") &&
+ of_property_present(child, "fdt")) {
+ struct device_node *image;
+ const char *unit = "fdt";
+ int data_len;
+ const void *data;
+ int ret;
+
+ ret = fit_get_image(handle, child, &unit, &image);
+ if (ret)
+ goto next;
+
+ data = of_get_property(image, "data", &data_len);
+ if (!data) {
+ ret = -EINVAL;
+ goto next;
+ }
+
+ ret = fit_handle_decompression(image, "fdt", &data, &data_len);
+ if (ret) {
+ ret = -EILSEQ;
+ goto next;
+ }
+
+ score = fdt_machine_is_compatible(data, data_len, machine);
+
+ of_delete_property_by_name(image, "uncompressed-data");
+next:
+ if (ret)
+ pr_warn("skipping malformed configuration: %pOF (%pe)\n",
+ child, ERR_PTR(ret));
+ }
+
+ if (score > best_score) {
+ best_score = score;
*unit = child->name;
- pr_info("matching unit '%s' found\n", *unit);
- return 0;
+
+ if (score == OF_DEVICE_COMPATIBLE_MAX_SCORE)
+ break;
}
}
+ if (best_score) {
+ pr_info("matching unit '%s' found\n", *unit);
+ return 0;
+ }
+
default_unit:
pr_info("No match found. Trying default.\n");
if (of_property_read_string(conf_node, "default", unit) == 0)
@@ -711,7 +814,7 @@ void *fit_open_configuration(struct fit_handle *handle, const char *name)
if (name) {
unit = name;
} else {
- ret = fit_find_compatible_unit(conf_node, &unit);
+ ret = fit_find_compatible_unit(handle, conf_node, &unit);
if (ret) {
pr_info("Couldn't get a valid configuration. Aborting.\n");
return ERR_PTR(ret);
@@ -797,6 +900,7 @@ struct fit_handle *fit_open_buf(const void *buf, size_t size, bool verbose,
* @filename: The filename of the FIT image
* @verbose: If true, be more verbose
* @verify: The verify mode
+ * @max_size: maximum length to read from file
*
* This opens a FIT image found in @filename. The returned handle is used as
* context for the other FIT functions.
@@ -804,7 +908,7 @@ struct fit_handle *fit_open_buf(const void *buf, size_t size, bool verbose,
* Return: A handle to a FIT image or a ERR_PTR
*/
struct fit_handle *fit_open(const char *filename, bool verbose,
- enum bootm_verify verify)
+ enum bootm_verify verify, loff_t max_size)
{
struct fit_handle *handle;
int ret;
@@ -815,8 +919,8 @@ struct fit_handle *fit_open(const char *filename, bool verbose,
handle->verify = verify;
ret = read_file_2(filename, &handle->size, &handle->fit_alloc,
- FILESIZE_MAX);
- if (ret) {
+ max_size);
+ if (ret && ret != -EFBIG) {
pr_err("unable to read %s: %s\n", filename, strerror(-ret));
return ERR_PTR(ret);
}