Patrick Rudolph has uploaded this change for review.

View Change

devicetree: Check destination size while flattening

* Check that destination buffer doesn't overflow while flattening
* Add 128 bytes to the requested space for the FDT in fit_payload.c

Change-Id: Ia8300df1abd012d286c10d12cc99bdc05c2710d8
Signed-off-by: Patrick Rudolph <siro@das-labor.org>
---
M src/include/device_tree.h
M src/lib/device_tree.c
M src/lib/fit_payload.c
M src/mainboard/sifive/hifive-unleashed/fixup_fdt.c
4 files changed, 25 insertions(+), 6 deletions(-)

git pull ssh://review.coreboot.org:29418/coreboot refs/changes/01/41201/1
diff --git a/src/include/device_tree.h b/src/include/device_tree.h
index bd0d151..ddfb6e5 100644
--- a/src/include/device_tree.h
+++ b/src/include/device_tree.h
@@ -116,8 +116,8 @@

/* Figure out how big a device tree would be if it were flattened. */
uint32_t dt_flat_size(const struct device_tree *tree);
-/* Flatten a device tree into the buffer pointed to by dest. */
-void dt_flatten(const struct device_tree *tree, void *dest);
+/* Flatten a device tree into the buffer with size len pointed to by dest. */
+void dt_flatten(const struct device_tree *tree, void *dest, size_t len);
void dt_print_node(const struct device_tree_node *node);
/* Read #address-cells and #size-cells properties from a node. */
void dt_read_cell_props(const struct device_tree_node *node, u32 *addrcp,
diff --git a/src/lib/device_tree.c b/src/lib/device_tree.c
index cb81d32..5d4b2b0 100644
--- a/src/lib/device_tree.c
+++ b/src/lib/device_tree.c
@@ -421,14 +421,21 @@
*strings_start = dstrings;
}

-void dt_flatten(const struct device_tree *tree, void *start_dest)
+void dt_flatten(const struct device_tree *tree, void *start_dest, size_t len)
{
uint8_t *dest = (uint8_t *)start_dest;
+ uint8_t *dest_max = ((uint8_t *)start_dest) + len;
+
+ if ((dest + tree->header_size) > dest_max)
+ goto err;

memcpy(dest, tree->header, tree->header_size);
struct fdt_header *header = (struct fdt_header *)dest;
dest += tree->header_size;

+ if ((dest + sizeof(uint64_t) * 2) > dest_max)
+ goto err;
+
struct device_tree_reserve_map_entry *entry;
list_for_each(entry, tree->reserve_map, list_node)
dt_flatten_map_entry(entry, (void **)&dest);
@@ -439,6 +446,9 @@
uint32_t strings_size = 0;
dt_flat_node_size(tree->root, &struct_size, &strings_size);

+ if ((dest + struct_size) > dest_max)
+ goto err;
+
uint8_t *struct_start = dest;
header->structure_offset = htobe32(dest - (uint8_t *)start_dest);
header->structure_size = htobe32(struct_size);
@@ -447,6 +457,9 @@
*((uint32_t *)dest) = htobe32(FDT_TOKEN_END);
dest += sizeof(uint32_t);

+ if ((dest + strings_size) > dest_max)
+ goto err;
+
uint8_t *strings_start = dest;
header->strings_offset = htobe32(dest - (uint8_t *)start_dest);
header->strings_size = htobe32(strings_size);
@@ -456,6 +469,11 @@
(void **)&strings_start);

header->totalsize = htobe32(dest - (uint8_t *)start_dest);
+
+ return;
+err:
+ printk(BIOS_CRIT, "%s: Buffer overflowed (used %d, max %zd) while flattening devicetree\n",
+ __func__, (dest - (uint8_t *)start_dest), len);
}


diff --git a/src/lib/fit_payload.c b/src/lib/fit_payload.c
index 9cf1542..1b97ad9 100644
--- a/src/lib/fit_payload.c
+++ b/src/lib/fit_payload.c
@@ -23,7 +23,7 @@
printk(BIOS_INFO, "FIT: Flattening FDT to %p\n",
(void *)fdt->offset);

- dt_flatten(dt, (void *)fdt->offset);
+ dt_flatten(dt, (void *)fdt->offset, fdt->size);
prog_segment_loaded(fdt->offset, fdt->size, 0);
}

@@ -219,7 +219,8 @@

/* Collect infos for fit_payload_arch */
kernel.size = config->kernel->size;
- fdt.size = dt_flat_size(dt);
+ /* Add additional space for fit_add_ramdisk() */
+ fdt.size = dt_flat_size(dt) + 128;
initrd.size = config->ramdisk ? config->ramdisk->size : 0;

/* Invoke arch specific payload placement and fixups */
diff --git a/src/mainboard/sifive/hifive-unleashed/fixup_fdt.c b/src/mainboard/sifive/hifive-unleashed/fixup_fdt.c
index c270857..3cffb97 100644
--- a/src/mainboard/sifive/hifive-unleashed/fixup_fdt.c
+++ b/src/mainboard/sifive/hifive-unleashed/fixup_fdt.c
@@ -96,7 +96,7 @@
return;
}

- dt_flatten(tree, dt);
+ dt_flatten(tree, dt, dt_flat_size(tree));

/* update HLS */
for (int i = 0; i < CONFIG_MAX_CPUS; i++)

To view, visit change 41201. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-Change-Id: Ia8300df1abd012d286c10d12cc99bdc05c2710d8
Gerrit-Change-Number: 41201
Gerrit-PatchSet: 1
Gerrit-Owner: Patrick Rudolph <siro@das-labor.org>
Gerrit-Reviewer: Philipp Hug <philipp@hug.cx>
Gerrit-Reviewer: ron minnich <rminnich@gmail.com>
Gerrit-MessageType: newchange