summaryrefslogtreecommitdiff
path: root/sys/arch/arm64/stand/efiboot/fdt.c
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2022-03-14 19:09:33 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2022-03-14 19:09:33 +0000
commit448b9be27dee5474282650db65f859cdb9b1dd63 (patch)
tree5ada0fb68cf6ca5dc0c1f3550cb63759943e249a /sys/arch/arm64/stand/efiboot/fdt.c
parentb7f324b229c712cdb6d90b6346dcda5d734ac3a9 (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.c47
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);