libfdt: Fix bugs with unchecked usage of fdt_num_mem_rsv()
Some checks failed
Build test / build-make (alpine) (push) Has been cancelled
Build test / build-make (archlinux) (push) Has been cancelled
Build test / build-make (fedora) (push) Has been cancelled
Build test / build-make (ubuntu) (push) Has been cancelled
Build test / build-meson (alpine) (push) Has been cancelled
Build test / build-meson (archlinux) (push) Has been cancelled
Build test / build-meson (fedora) (push) Has been cancelled
Build test / build-meson (ubuntu) (push) Has been cancelled
Build test / clang64 (push) Has been cancelled
Build test / mingw32 (push) Has been cancelled
Build test / mingw64 (push) Has been cancelled
Build test / ucrt64 (push) Has been cancelled

fdt_num_mem_rsv() can return an error if the memory reservation block
is not properly terminated with a (0, 0) entry.  However several other
places in libfdt called it without checking for error returns, and could
therefore return strange results, or in the case of fdt_open_into()
crash.

Fix this by always checking the return value.  Add some addition tests to
catch this bug.

Reported-by: Moshe Strauss <moshestrauss10@gmail.com>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
This commit is contained in:
David Gibson 2026-04-17 20:36:42 +10:00
parent f551be7b39
commit 47d7c01ba8
11 changed files with 127 additions and 9 deletions

View file

@ -191,6 +191,8 @@ int fdt_num_mem_rsv(const void *fdt)
int i;
const struct fdt_reserve_entry *re;
FDT_RO_PROBE(fdt);
for (i = 0; (re = fdt_mem_rsv(fdt, i)) != NULL; i++) {
if (fdt64_ld_(&re->size) == 0)
return i;

View file

@ -166,7 +166,11 @@ int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size)
FDT_RW_PROBE(fdt);
re = fdt_mem_rsv_w_(fdt, fdt_num_mem_rsv(fdt));
err = fdt_num_mem_rsv(fdt);
if (err < 0)
return err;
re = fdt_mem_rsv_w_(fdt, err);
err = fdt_splice_mem_rsv_(fdt, re, 0, 1);
if (err)
return err;
@ -179,10 +183,15 @@ int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size)
int fdt_del_mem_rsv(void *fdt, int n)
{
struct fdt_reserve_entry *re = fdt_mem_rsv_w_(fdt, n);
int num;
FDT_RW_PROBE(fdt);
if (n >= fdt_num_mem_rsv(fdt))
num = fdt_num_mem_rsv(fdt);
if (num < 0)
return num;
if (n >= num)
return -FDT_ERR_NOTFOUND;
return fdt_splice_mem_rsv_(fdt, re, 1, 0);
@ -439,8 +448,10 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize)
FDT_RO_PROBE(fdt);
mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
* sizeof(struct fdt_reserve_entry);
err = fdt_num_mem_rsv(fdt);
if (err < 0)
return err;
mem_rsv_size = (err + 1) * sizeof(struct fdt_reserve_entry);
if (can_assume(LATEST) || fdt_version(fdt) >= 17) {
struct_size = fdt_size_dt_struct(fdt);
@ -498,12 +509,14 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize)
int fdt_pack(void *fdt)
{
int mem_rsv_size;
int err, mem_rsv_size;
FDT_RW_PROBE(fdt);
mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
* sizeof(struct fdt_reserve_entry);
err = fdt_num_mem_rsv(fdt);
if (err < 0)
return err;
mem_rsv_size = (err+1) * sizeof(struct fdt_reserve_entry);
fdt_packblocks_(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt),
fdt_size_dt_strings(fdt));
fdt_set_totalsize(fdt, fdt_data_size_(fdt));

View file

@ -475,7 +475,12 @@ int fdt_generate_phandle(const void *fdt, uint32_t *phandle);
* or any other (0,0) entries reserved for expansion.
*
* returns:
* the number of entries
* the number of entries, on success
* -FDT_ERR_ALIGNMENT,
* -FDT_ERR_BADMAGIC,
* -FDT_ERR_BADVERSION,
* -FDT_ERR_BADSTATE,
* -FDT_ERR_TRUNCATED, standard meanings
*/
int fdt_num_mem_rsv(const void *fdt);