diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2022-03-14 19:09:33 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2022-03-14 19:09:33 +0000 |
commit | 448b9be27dee5474282650db65f859cdb9b1dd63 (patch) | |
tree | 5ada0fb68cf6ca5dc0c1f3550cb63759943e249a /sys/arch/arm64/stand/efiboot/fdt.c | |
parent | b7f324b229c712cdb6d90b6346dcda5d734ac3a9 (diff) |
The current FDT code we use in the bootloader is buggy and will write into
memory beyond the actual FDT data structure when adding information to the
device tree. This is especially problematic on ACPI systems where we add
lots of information to the device tree based on ACPI tables. Fix the FDT
code to never write beyond the end of the data structure and panic if we
run out of free space. Raise the amount of free space frm 4K to 16K for
the proto-FDT we use on ACPI systems. Bump the version number of the
arm64 bootloader.
ok visa@, patrick@
Diffstat (limited to 'sys/arch/arm64/stand/efiboot/fdt.c')
-rw-r--r-- | sys/arch/arm64/stand/efiboot/fdt.c | 47 |
1 files changed, 22 insertions, 25 deletions
diff --git a/sys/arch/arm64/stand/efiboot/fdt.c b/sys/arch/arm64/stand/efiboot/fdt.c index 48b4ba8f178..e2c3a8a2393 100644 --- a/sys/arch/arm64/stand/efiboot/fdt.c +++ b/sys/arch/arm64/stand/efiboot/fdt.c @@ -1,4 +1,4 @@ -/* $OpenBSD: fdt.c,v 1.5 2021/03/11 11:16:56 jsg Exp $ */ +/* $OpenBSD: fdt.c,v 1.6 2022/03/14 19:09:32 kettenis Exp $ */ /* * Copyright (c) 2009 Dariusz Swiderski <sfires@sfires.net> @@ -141,13 +141,10 @@ fdt_add_str(char *name) size_t len = roundup(strlen(name) + 1, sizeof(uint32_t)); char *end = tree.strings + tree.strings_size; - memmove(end + len, end, tree.end - end); + if (end + len > tree.end) + panic("FDT overflow"); + tree.strings_size += len; - if (tree.tree > tree.strings) - tree.tree += len; - if (tree.memory > tree.strings) - tree.memory += len; - tree.end += len; memset(end, 0, len); memcpy(end, name, strlen(name)); @@ -222,6 +219,7 @@ fdt_node_property(void *node, char *name, char **out) int fdt_node_set_property(void *node, char *name, void *data, int len) { + char *end = tree.strings + tree.strings_size; uint32_t *ptr, *next; uint32_t nameid; uint32_t curlen; @@ -246,14 +244,13 @@ fdt_node_set_property(void *node, char *name, void *data, int len) curlen = betoh32(*(ptr + 1)); delta = roundup(len, sizeof(uint32_t)) - roundup(curlen, sizeof(uint32_t)); + if (end + delta > tree.end) + panic("FDT overflow"); + memmove((char *)next + delta, next, - tree.end - (char *)next); + end - (char *)next); tree.struct_size += delta; - if (tree.strings > tree.tree) - tree.strings += delta; - if (tree.memory > tree.tree) - tree.memory += delta; - tree.end += delta; + tree.strings += delta; *(ptr + 1) = htobe32(len); memcpy(ptr + 3, data, len); return 1; @@ -266,6 +263,7 @@ fdt_node_set_property(void *node, char *name, void *data, int len) int fdt_node_add_property(void *node, char *name, void *data, int len) { + char *end = tree.strings + tree.strings_size; char *dummy; if (!tree_inited) @@ -277,15 +275,14 @@ fdt_node_add_property(void *node, char *name, void *data, int len) if (betoh32(*ptr) != FDT_NODE_BEGIN) return 0; + if (end + 3 * sizeof(uint32_t) > tree.end) + panic("FDT overflow"); + ptr = skip_node_name(ptr + 1); - memmove(ptr + 3, ptr, tree.end - (char *)ptr); + memmove(ptr + 3, ptr, end - (char *)ptr); tree.struct_size += 3 * sizeof(uint32_t); - if (tree.strings > tree.tree) - tree.strings += 3 * sizeof(uint32_t); - if (tree.memory > tree.tree) - tree.memory += 3 * sizeof(uint32_t); - tree.end += 3 * sizeof(uint32_t); + tree.strings += 3 * sizeof(uint32_t); *ptr++ = htobe32(FDT_PROPERTY); *ptr++ = htobe32(0); *ptr++ = htobe32(fdt_add_str(name)); @@ -298,6 +295,7 @@ int fdt_node_add_node(void *node, char *name, void **child) { size_t len = roundup(strlen(name) + 1, sizeof(uint32_t)) + 8; + char *end = tree.strings + tree.strings_size; uint32_t *ptr = (uint32_t *)node; if (!tree_inited) @@ -306,6 +304,9 @@ fdt_node_add_node(void *node, char *name, void **child) if (betoh32(*ptr) != FDT_NODE_BEGIN) return 0; + if (end + len > tree.end) + panic("FDT overflow"); + ptr = skip_node_name(ptr + 1); ptr = skip_props(ptr); @@ -313,13 +314,9 @@ fdt_node_add_node(void *node, char *name, void **child) while (betoh32(*ptr) == FDT_NODE_BEGIN) ptr = skip_node(ptr); - memmove((char *)ptr + len, ptr, tree.end - (char *)ptr); + memmove((char *)ptr + len, ptr, end - (char *)ptr); tree.struct_size += len; - if (tree.strings > tree.tree) - tree.strings += len; - if (tree.memory > tree.tree) - tree.memory += len; - tree.end += len; + tree.strings += len; *child = ptr; *ptr++ = htobe32(FDT_NODE_BEGIN); |