diff options
Diffstat (limited to 'common/image-fit.c')
-rw-r--r-- | common/image-fit.c | 154 |
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); } |