x86_sample_perf_regs_mapping initialized perf_to_regs[] only up to the
highest set bit of perf_regs_mask, but indexed it with dwarf_to_perf[i]
values up to PERF_REG_X86_64_MAX-1. For a sample carrying only the base
GP registers the upper slots stay uninitialized, and the resulting index
j was used unchecked to write cached_regs_mapping[j], a count-element
calloc buffer. Initialize the whole perf_to_regs[] array to -1, bounds-
check j before the write, and check calloc for failure.

        * backends/x86_initreg_sample.c (x86_sample_perf_regs_mapping):
        Initialize full perf_to_regs array, bounds-check index, check
        calloc result.

Signed-off-by: Sayed Kaif <[email protected]>

Signed-off-by: Sayed Kaif <[email protected]>
---
 backends/x86_initreg_sample.c | 18 ++++++++++++------
 1 file changed, 12 insertions(+), 6 deletions(-)

diff --git a/backends/x86_initreg_sample.c b/backends/x86_initreg_sample.c
index fe870e61..07f0f563 100644
--- a/backends/x86_initreg_sample.c
+++ b/backends/x86_initreg_sample.c
@@ -65,25 +65,31 @@ x86_sample_perf_regs_mapping (Ebl *ebl,
   const int *dwarf_to_perf = is_abi32 ? regs_i386 : regs_x86_64;
 
   /* Count bits and allocate regs_mapping:  */
-  int j, k, kmax, count; uint64_t bit;
-  for (k = 0, kmax = -1, count = 0, bit = 1;
+  int j, k, count; uint64_t bit;
+  for (k = 0, count = 0, bit = 1;
        k < PERF_REG_X86_64_MAX; k++, bit <<= 1)
     {
       if ((bit & perf_regs_mask)) {
        count++;
-       kmax = k;
       }
     }
   ebl->cached_perf_regs_mask = perf_regs_mask;
   ebl->cached_regs_mapping = (int *)calloc (count, sizeof(int));
+  if (count != 0 && ebl->cached_regs_mapping == NULL)
+    return false;
   ebl->cached_n_regs_mapping = count;
 
   /* Locations of perf_regs in the regs[] array, according to
-     perf_regs_mask:  */
+     perf_regs_mask.  Initialize the whole array (not just up to the
+     highest set bit): the loop below indexes perf_to_regs[] by
+     dwarf_to_perf[i], which can be larger than the highest set bit in
+     perf_regs_mask.  Leaving the tail uninitialized would read stack
+     garbage and could turn into an out-of-bounds write into the
+     cached_regs_mapping[] heap buffer.  */
   int perf_to_regs[PERF_REG_X86_64_MAX];
   uint64_t expected_mask = is_abi32 ?
     PERF_FRAME_REGISTERS_I386 : PERF_FRAME_REGISTERS_X86_64;
-  for (j = 0, k = 0, bit = 1; k <= kmax; k++, bit <<= 1)
+  for (j = 0, k = 0, bit = 1; k < PERF_REG_X86_64_MAX; k++, bit <<= 1)
     {
       if ((bit & expected_mask) && (bit & perf_regs_mask))
        {
@@ -104,7 +110,7 @@ x86_sample_perf_regs_mapping (Ebl *ebl,
     {
       k = dwarf_to_perf[i];
       j = perf_to_regs[k];
-      if (j < 0) continue;
+      if (j < 0 || j >= (int)ebl->cached_n_regs_mapping) continue;
       ebl->cached_regs_mapping[j] = i;
     }
 
-- 
2.52.0.windows.1

Reply via email to