4ca61f84dc
At present it is possible to have two root nodes and even access nodes in the 'second' root. Such trees should not be considered valid. This was discovered as part of a security investigation into U-Boot verified boot. Add a check for this to fdt_check_full(). Signed-off-by: Simon Glass <sjg@chromium.org> Reported-by: Arie Haenel <arie.haenel@intel.com> Reported-by: Julien Lenoir <julien.lenoir@intel.com> Message-Id: <20210323000926.3210733-1-sjg@chromium.org> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
83 lines
1.6 KiB
C
83 lines
1.6 KiB
C
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
|
|
/*
|
|
* libfdt - Flat Device Tree manipulation
|
|
* Copyright (C) 2006 David Gibson, IBM Corporation.
|
|
*/
|
|
#include "libfdt_env.h"
|
|
|
|
#include <fdt.h>
|
|
#include <libfdt.h>
|
|
|
|
#include "libfdt_internal.h"
|
|
|
|
int fdt_check_full(const void *fdt, size_t bufsize)
|
|
{
|
|
int err;
|
|
int num_memrsv;
|
|
int offset, nextoffset = 0;
|
|
uint32_t tag;
|
|
unsigned int depth = 0;
|
|
const void *prop;
|
|
const char *propname;
|
|
bool expect_end = false;
|
|
|
|
if (bufsize < FDT_V1_SIZE)
|
|
return -FDT_ERR_TRUNCATED;
|
|
if (bufsize < fdt_header_size(fdt))
|
|
return -FDT_ERR_TRUNCATED;
|
|
err = fdt_check_header(fdt);
|
|
if (err != 0)
|
|
return err;
|
|
if (bufsize < fdt_totalsize(fdt))
|
|
return -FDT_ERR_TRUNCATED;
|
|
|
|
num_memrsv = fdt_num_mem_rsv(fdt);
|
|
if (num_memrsv < 0)
|
|
return num_memrsv;
|
|
|
|
while (1) {
|
|
offset = nextoffset;
|
|
tag = fdt_next_tag(fdt, offset, &nextoffset);
|
|
|
|
if (nextoffset < 0)
|
|
return nextoffset;
|
|
|
|
/* If we see two root nodes, something is wrong */
|
|
if (expect_end && tag != FDT_END)
|
|
return -FDT_ERR_BADSTRUCTURE;
|
|
|
|
switch (tag) {
|
|
case FDT_NOP:
|
|
break;
|
|
|
|
case FDT_END:
|
|
if (depth != 0)
|
|
return -FDT_ERR_BADSTRUCTURE;
|
|
return 0;
|
|
|
|
case FDT_BEGIN_NODE:
|
|
depth++;
|
|
if (depth > INT_MAX)
|
|
return -FDT_ERR_BADSTRUCTURE;
|
|
break;
|
|
|
|
case FDT_END_NODE:
|
|
if (depth == 0)
|
|
return -FDT_ERR_BADSTRUCTURE;
|
|
depth--;
|
|
if (depth == 0)
|
|
expect_end = true;
|
|
break;
|
|
|
|
case FDT_PROP:
|
|
prop = fdt_getprop_by_offset(fdt, offset, &propname,
|
|
&err);
|
|
if (!prop)
|
|
return err;
|
|
break;
|
|
|
|
default:
|
|
return -FDT_ERR_INTERNAL;
|
|
}
|
|
}
|
|
}
|