diff --git a/src/arch/riscv/prefix/sbiprefix.S b/src/arch/riscv/prefix/sbiprefix.S index a39d37cb1..e8ef40b6d 100644 --- a/src/arch/riscv/prefix/sbiprefix.S +++ b/src/arch/riscv/prefix/sbiprefix.S @@ -123,6 +123,7 @@ _sbi_start: /* Register device tree */ la a0, sysfdt mv a1, s1 + li a2, -1 call fdt_parse /* Call main program */ diff --git a/src/core/fdt.c b/src/core/fdt.c index e2ce055eb..9c2880c84 100644 --- a/src/core/fdt.c +++ b/src/core/fdt.c @@ -82,7 +82,7 @@ static int fdt_traverse ( struct fdt *fdt, size_t len; /* Sanity checks */ - assert ( pos->offset < fdt->len ); + assert ( pos->offset <= fdt->len ); assert ( ( pos->offset & ( FDT_STRUCTURE_ALIGN - 1 ) ) == 0 ); /* Clear descriptor */ @@ -453,14 +453,28 @@ int fdt_mac ( struct fdt *fdt, unsigned int offset, * * @v fdt Device tree * @v hdr Device tree header + * @v max_len Maximum device tree length * @ret rc Return status code */ -int fdt_parse ( struct fdt *fdt, const struct fdt_header *hdr ) { +int fdt_parse ( struct fdt *fdt, const struct fdt_header *hdr, + size_t max_len ) { const uint8_t *end; + /* Sanity check */ + if ( sizeof ( fdt ) > max_len ) { + DBGC ( fdt, "FDT length %#zx too short for header\n", + max_len ); + goto err; + } + /* Record device tree location */ fdt->hdr = hdr; fdt->len = be32_to_cpu ( hdr->totalsize ); + if ( fdt->len > max_len ) { + DBGC ( fdt, "FDT has invalid length %#zx / %#zx\n", + fdt->len, max_len ); + goto err; + } DBGC ( fdt, "FDT version %d at %p+%#04zx\n", be32_to_cpu ( hdr->version ), fdt->hdr, fdt->len ); diff --git a/src/include/ipxe/fdt.h b/src/include/ipxe/fdt.h index 04201ce9b..70dc01790 100644 --- a/src/include/ipxe/fdt.h +++ b/src/include/ipxe/fdt.h @@ -107,6 +107,7 @@ extern int fdt_u64 ( struct fdt *fdt, unsigned int offset, const char *name, uint64_t *value ); extern int fdt_mac ( struct fdt *fdt, unsigned int offset, struct net_device *netdev ); -extern int fdt_parse ( struct fdt *fdt, const struct fdt_header *hdr ); +extern int fdt_parse ( struct fdt *fdt, const struct fdt_header *hdr, + size_t max_len ); #endif /* _IPXE_FDT_H */ diff --git a/src/interface/efi/efi_fdt.c b/src/interface/efi/efi_fdt.c index f81e6ad63..e207f7e6d 100644 --- a/src/interface/efi/efi_fdt.c +++ b/src/interface/efi/efi_fdt.c @@ -54,7 +54,7 @@ static void efi_fdt_init ( void ) { DBGC ( &efi_fdt, "EFIFDT configuration table at %p\n", efi_fdt ); /* Parse as system device tree */ - if ( ( rc = fdt_parse ( &sysfdt, efi_fdt ) ) != 0 ) { + if ( ( rc = fdt_parse ( &sysfdt, efi_fdt, -1UL ) ) != 0 ) { DBGC ( &efi_fdt, "EFIFDT could not parse: %s\n", strerror ( rc ) ); return;