]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[fdt] Allow for parsing device trees where the length is known in advance
authorMichael Brown <mcb30@ipxe.org>
Fri, 28 Mar 2025 14:08:18 +0000 (14:08 +0000)
committerMichael Brown <mcb30@ipxe.org>
Fri, 28 Mar 2025 15:11:39 +0000 (15:11 +0000)
Allow for parsing device trees where an external factor (such as a
downloaded image length) determines the maximum length, which must be
validated against the length within the device tree header.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/arch/riscv/prefix/sbiprefix.S
src/core/fdt.c
src/include/ipxe/fdt.h
src/interface/efi/efi_fdt.c

index a39d37cb1d5ccd54b1cf458e758e6be1d87ebead..e8ef40b6def730f7e727945680a0a844224a5af2 100644 (file)
@@ -123,6 +123,7 @@ _sbi_start:
        /* Register device tree */
        la      a0, sysfdt
        mv      a1, s1
+       li      a2, -1
        call    fdt_parse
 
        /* Call main program */
index e2ce055ebfb3287038c79c39f96d1a7a0da9f84e..9c2880c843ef49bbd33fa2729731e3bc8ca00490 100644 (file)
@@ -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 );
 
index 04201ce9b9e58c24a9bb6ee4e45c7802488e156e..70dc017909f9e733e1679c9154a55aca6fed33f7 100644 (file)
@@ -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 */
index f81e6ad63da344b13dd604dca632ad14d47d0c6e..e207f7e6d6930d67570d2bb9150dc1935a07d97b 100644 (file)
@@ -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;