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
