The generic ebl_set_initial_registers_sample() implementation used a
fixed-size Dwarf_Word dwarf_regs[64] buffer while operating on
ebl->frame_nregs entries. The only bound check was an assert:

assert (ebl->frame_nregs < 64);

which is compiled out in release builds.

Several architectures using the generic implementation have
frame_nregs values greater than 64 (for example ppc64=145,
sparc=103 and riscv=66). As a result, the initialization loop can
write beyond the end of the stack buffer, and subsequent register
mapping may perform additional out-of-bounds writes.

Replace the fixed-size array with a dynamically allocated buffer sized
to ebl->frame_nregs using calloc(). Free the buffer after setfunc()
returns.

* libebl/eblinitreg_sample.c (ebl_set_initial_registers_sample):
Allocate dwarf_regs dynamically based on frame_nregs.
Remove the fixed-size buffer and debug-only assert.
Free the allocated buffer before returning.

Signed-off-by: Sayed Kaif <[email protected]>
---
 libebl/eblinitreg_sample.c | 26 +++++++++++++++++---------
 1 file changed, 17 insertions(+), 9 deletions(-)

diff --git a/libebl/eblinitreg_sample.c b/libebl/eblinitreg_sample.c
index feba2c64..ec4a2587 100644
--- a/libebl/eblinitreg_sample.c
+++ b/libebl/eblinitreg_sample.c
@@ -63,21 +63,29 @@ ebl_set_initial_registers_sample (Ebl *ebl,
 
   /* If set_initial_registers_sample is unspecified, then it is safe
      to use the following generic code to populate a contiguous array
-     of dwarf_regs:  */
-  Dwarf_Word dwarf_regs[64];
-  assert (ebl->frame_nregs < 64);
-  size_t i;
-  for (i = 0; i < ebl->frame_nregs; i++)
-    dwarf_regs[i] = 0x0;
-  for (i = 0; i < n_regs; i++)
+     of dwarf_regs.  The array must be sized to the architecture's full
+     register count (ebl->frame_nregs).  For several backends (e.g. ppc,
+     ppc64, sparc, riscv, mips, arc, loongarch) frame_nregs exceeds 64,
+     so this must not live in a fixed-size stack buffer: setfunc reads
+     ebl->frame_nregs words from it, and regs_mapping[] entries (bounded
+     only by frame_nregs) are used as write indices.  */
+  size_t nregs = ebl->frame_nregs;
+  if (nregs == 0)
+    return false;
+  Dwarf_Word *dwarf_regs = calloc (nregs, sizeof (Dwarf_Word));
+  if (dwarf_regs == NULL)
+    return false;
+  for (size_t i = 0; i < n_regs; i++)
     {
       if (i >= n_regs_mapping)
        break;
-      if (regs_mapping[i] < 0 || regs_mapping[i] >= (int)ebl->frame_nregs)
+      if (regs_mapping[i] < 0 || regs_mapping[i] >= (int) nregs)
        continue;
       dwarf_regs[regs_mapping[i]] = regs[i];
     }
-  return setfunc (0, ebl->frame_nregs, dwarf_regs, arg);
+  bool ok = setfunc (0, nregs, dwarf_regs, arg);
+  free (dwarf_regs);
+  return ok;
 }
 
 bool
-- 
2.52.0.windows.1

Reply via email to