diff options
Diffstat (limited to 'drivers/remoteproc')
-rw-r--r-- | drivers/remoteproc/remoteproc_core.c | 35 |
1 files changed, 30 insertions, 5 deletions
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index 080c0569ef38..f2354cee42bf 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c | |||
@@ -191,6 +191,7 @@ static void *rproc_da_to_va(struct rproc *rproc, u64 da, int len) | |||
191 | * rproc_load_segments() - load firmware segments to memory | 191 | * rproc_load_segments() - load firmware segments to memory |
192 | * @rproc: remote processor which will be booted using these fw segments | 192 | * @rproc: remote processor which will be booted using these fw segments |
193 | * @elf_data: the content of the ELF firmware image | 193 | * @elf_data: the content of the ELF firmware image |
194 | * @len: firmware size (in bytes) | ||
194 | * | 195 | * |
195 | * This function loads the firmware segments to memory, where the remote | 196 | * This function loads the firmware segments to memory, where the remote |
196 | * processor expects them. | 197 | * processor expects them. |
@@ -211,7 +212,8 @@ static void *rproc_da_to_va(struct rproc *rproc, u64 da, int len) | |||
211 | * directly allocate memory for every segment/resource. This is not yet | 212 | * directly allocate memory for every segment/resource. This is not yet |
212 | * supported, though. | 213 | * supported, though. |
213 | */ | 214 | */ |
214 | static int rproc_load_segments(struct rproc *rproc, const u8 *elf_data) | 215 | static int |
216 | rproc_load_segments(struct rproc *rproc, const u8 *elf_data, size_t len) | ||
215 | { | 217 | { |
216 | struct device *dev = rproc->dev; | 218 | struct device *dev = rproc->dev; |
217 | struct elf32_hdr *ehdr; | 219 | struct elf32_hdr *ehdr; |
@@ -226,6 +228,7 @@ static int rproc_load_segments(struct rproc *rproc, const u8 *elf_data) | |||
226 | u32 da = phdr->p_paddr; | 228 | u32 da = phdr->p_paddr; |
227 | u32 memsz = phdr->p_memsz; | 229 | u32 memsz = phdr->p_memsz; |
228 | u32 filesz = phdr->p_filesz; | 230 | u32 filesz = phdr->p_filesz; |
231 | u32 offset = phdr->p_offset; | ||
229 | void *ptr; | 232 | void *ptr; |
230 | 233 | ||
231 | if (phdr->p_type != PT_LOAD) | 234 | if (phdr->p_type != PT_LOAD) |
@@ -241,6 +244,13 @@ static int rproc_load_segments(struct rproc *rproc, const u8 *elf_data) | |||
241 | break; | 244 | break; |
242 | } | 245 | } |
243 | 246 | ||
247 | if (offset + filesz > len) { | ||
248 | dev_err(dev, "truncated fw: need 0x%x avail 0x%x\n", | ||
249 | offset + filesz, len); | ||
250 | ret = -EINVAL; | ||
251 | break; | ||
252 | } | ||
253 | |||
244 | /* grab the kernel address for this device address */ | 254 | /* grab the kernel address for this device address */ |
245 | ptr = rproc_da_to_va(rproc, da, memsz); | 255 | ptr = rproc_da_to_va(rproc, da, memsz); |
246 | if (!ptr) { | 256 | if (!ptr) { |
@@ -712,6 +722,7 @@ rproc_handle_virtio_rsc(struct rproc *rproc, struct fw_resource *rsc, int len) | |||
712 | * rproc_handle_resources() - find and handle the resource table | 722 | * rproc_handle_resources() - find and handle the resource table |
713 | * @rproc: the rproc handle | 723 | * @rproc: the rproc handle |
714 | * @elf_data: the content of the ELF firmware image | 724 | * @elf_data: the content of the ELF firmware image |
725 | * @len: firmware size (in bytes) | ||
715 | * @handler: function that should be used to handle the resource table | 726 | * @handler: function that should be used to handle the resource table |
716 | * | 727 | * |
717 | * This function finds the resource table inside the remote processor's | 728 | * This function finds the resource table inside the remote processor's |
@@ -725,7 +736,7 @@ rproc_handle_virtio_rsc(struct rproc *rproc, struct fw_resource *rsc, int len) | |||
725 | * processors that don't need a resource table. | 736 | * processors that don't need a resource table. |
726 | */ | 737 | */ |
727 | static int rproc_handle_resources(struct rproc *rproc, const u8 *elf_data, | 738 | static int rproc_handle_resources(struct rproc *rproc, const u8 *elf_data, |
728 | rproc_handle_resources_t handler) | 739 | size_t len, rproc_handle_resources_t handler) |
729 | 740 | ||
730 | { | 741 | { |
731 | struct elf32_hdr *ehdr; | 742 | struct elf32_hdr *ehdr; |
@@ -743,6 +754,13 @@ static int rproc_handle_resources(struct rproc *rproc, const u8 *elf_data, | |||
743 | struct fw_resource *table = (struct fw_resource *) | 754 | struct fw_resource *table = (struct fw_resource *) |
744 | (elf_data + shdr->sh_offset); | 755 | (elf_data + shdr->sh_offset); |
745 | 756 | ||
757 | if (shdr->sh_offset + shdr->sh_size > len) { | ||
758 | dev_err(rproc->dev, | ||
759 | "truncated fw: need 0x%x avail 0x%x\n", | ||
760 | shdr->sh_offset + shdr->sh_size, len); | ||
761 | ret = -EINVAL; | ||
762 | } | ||
763 | |||
746 | ret = handler(rproc, table, shdr->sh_size); | 764 | ret = handler(rproc, table, shdr->sh_size); |
747 | 765 | ||
748 | break; | 766 | break; |
@@ -833,6 +851,11 @@ static int rproc_fw_sanity_check(struct rproc *rproc, const struct firmware *fw) | |||
833 | 851 | ||
834 | ehdr = (struct elf32_hdr *)fw->data; | 852 | ehdr = (struct elf32_hdr *)fw->data; |
835 | 853 | ||
854 | if (fw->size < ehdr->e_shoff + sizeof(struct elf32_shdr)) { | ||
855 | dev_err(dev, "Image is too small\n"); | ||
856 | return -EINVAL; | ||
857 | } | ||
858 | |||
836 | if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) { | 859 | if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) { |
837 | dev_err(dev, "Image is corrupted (bad magic)\n"); | 860 | dev_err(dev, "Image is corrupted (bad magic)\n"); |
838 | return -EINVAL; | 861 | return -EINVAL; |
@@ -887,14 +910,15 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw) | |||
887 | rproc->bootaddr = ehdr->e_entry; | 910 | rproc->bootaddr = ehdr->e_entry; |
888 | 911 | ||
889 | /* handle fw resources which are required to boot rproc */ | 912 | /* handle fw resources which are required to boot rproc */ |
890 | ret = rproc_handle_resources(rproc, fw->data, rproc_handle_boot_rsc); | 913 | ret = rproc_handle_resources(rproc, fw->data, fw->size, |
914 | rproc_handle_boot_rsc); | ||
891 | if (ret) { | 915 | if (ret) { |
892 | dev_err(dev, "Failed to process resources: %d\n", ret); | 916 | dev_err(dev, "Failed to process resources: %d\n", ret); |
893 | goto clean_up; | 917 | goto clean_up; |
894 | } | 918 | } |
895 | 919 | ||
896 | /* load the ELF segments to memory */ | 920 | /* load the ELF segments to memory */ |
897 | ret = rproc_load_segments(rproc, fw->data); | 921 | ret = rproc_load_segments(rproc, fw->data, fw->size); |
898 | if (ret) { | 922 | if (ret) { |
899 | dev_err(dev, "Failed to load program segments: %d\n", ret); | 923 | dev_err(dev, "Failed to load program segments: %d\n", ret); |
900 | goto clean_up; | 924 | goto clean_up; |
@@ -937,7 +961,8 @@ static void rproc_fw_config_virtio(const struct firmware *fw, void *context) | |||
937 | goto out; | 961 | goto out; |
938 | 962 | ||
939 | /* does the fw supports any virtio devices ? */ | 963 | /* does the fw supports any virtio devices ? */ |
940 | ret = rproc_handle_resources(rproc, fw->data, rproc_handle_virtio_rsc); | 964 | ret = rproc_handle_resources(rproc, fw->data, fw->size, |
965 | rproc_handle_virtio_rsc); | ||
941 | if (ret) { | 966 | if (ret) { |
942 | dev_info(dev, "No fw virtio device was found\n"); | 967 | dev_info(dev, "No fw virtio device was found\n"); |
943 | goto out; | 968 | goto out; |