From 477c9f2ba26ccd77016f2c97941fc8b35e332e35 Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Wed, 26 Jul 2023 09:54:03 +0930 Subject: PR30657, gprof heap buffer overflow PR 30657 * cg_arcs.c (cg_assemble): Sanity check find_call addresses. * i386.c (i386_find_call): Don't access past end of core_text_space. * aarch64.c (aarch64_find_call): Round up lowpc, round down highpc. * alpha.c (alpha_find_call): Likewise. * mips.c (mips_find_call): Likewise. * sparc.c (sparc_find_call): Likewise. * vax.c (vax_find_call): Sanity check core_text_space accesses. --- gprof/aarch64.c | 3 ++- gprof/alpha.c | 4 +++- gprof/cg_arcs.c | 7 ++++++- gprof/i386.c | 3 +++ gprof/mips.c | 2 ++ gprof/sparc.c | 4 +++- gprof/vax.c | 24 ++++++++++++++++++------ 7 files changed, 37 insertions(+), 10 deletions(-) (limited to 'gprof') diff --git a/gprof/aarch64.c b/gprof/aarch64.c index 68febf9..3ab6067 100644 --- a/gprof/aarch64.c +++ b/gprof/aarch64.c @@ -54,7 +54,8 @@ aarch64_find_call (Sym *parent, bfd_vma p_lowpc, bfd_vma p_highpc) DBG (CALLDEBUG, printf ("[find_call] %s: 0x%lx to 0x%lx\n", parent->name, (unsigned long) p_lowpc, (unsigned long) p_highpc)); - + p_lowpc = (p_lowpc + 3) & ~3; + p_highpc &= ~3; for (pc = p_lowpc; pc < p_highpc; pc += 4) { diff --git a/gprof/alpha.c b/gprof/alpha.c index d84cdf0..df714be 100644 --- a/gprof/alpha.c +++ b/gprof/alpha.c @@ -107,7 +107,9 @@ alpha_find_call (Sym *parent, bfd_vma p_lowpc, bfd_vma p_highpc) DBG (CALLDEBUG, printf (_("[find_call] %s: 0x%lx to 0x%lx\n"), parent->name, (unsigned long) p_lowpc, (unsigned long) p_highpc)); - for (pc = (p_lowpc + 3) & ~(bfd_vma) 3; pc < p_highpc; pc += 4) + p_lowpc = (p_lowpc + 3) & ~3; + p_highpc &= ~3; + for (pc = p_lowpc; pc < p_highpc; pc += 4) { insn = bfd_get_32 (core_bfd, ((unsigned char *) core_text_space + pc - core_text_sect->vma)); diff --git a/gprof/cg_arcs.c b/gprof/cg_arcs.c index e76c2cb..cfffb09 100644 --- a/gprof/cg_arcs.c +++ b/gprof/cg_arcs.c @@ -37,6 +37,7 @@ #include "cg_print.h" #include "utils.h" #include "sym_ids.h" +#include "corefile.h" static int cmp_topo (const void *, const void *); static void propagate_time (Sym *); @@ -622,7 +623,11 @@ cg_assemble (void) parent->cg.cyc.num = 0; parent->cg.cyc.head = parent; parent->cg.cyc.next = 0; - if (ignore_direct_calls) + if (ignore_direct_calls + && parent->addr >= core_text_sect->vma + && parent->addr < core_text_sect->vma + core_text_sect->size + && (parent + 1)->addr >= core_text_sect->vma + && (parent + 1)->addr <= core_text_sect->vma + core_text_sect->size) find_call (parent, parent->addr, (parent + 1)->addr); } diff --git a/gprof/i386.c b/gprof/i386.c index bdf8bd1..62f6f96 100644 --- a/gprof/i386.c +++ b/gprof/i386.c @@ -57,6 +57,9 @@ i386_find_call (Sym *parent, bfd_vma p_lowpc, bfd_vma p_highpc) parent->name, (unsigned long) p_lowpc, (unsigned long) p_highpc)); + if (p_highpc < 5) + return; + p_highpc -= 5; for (pc = p_lowpc; pc < p_highpc; ++pc) { instructp = (unsigned char *) core_text_space + pc - core_text_sect->vma; diff --git a/gprof/mips.c b/gprof/mips.c index e198a6f..0ccd17d 100644 --- a/gprof/mips.c +++ b/gprof/mips.c @@ -59,6 +59,8 @@ mips_find_call (Sym *parent, bfd_vma p_lowpc, bfd_vma p_highpc) DBG (CALLDEBUG, printf (_("[find_call] %s: 0x%lx to 0x%lx\n"), parent->name, (unsigned long) p_lowpc, (unsigned long) p_highpc)); + p_lowpc = (p_lowpc + 3) & ~3; + p_highpc &= ~3; for (pc = p_lowpc; pc < p_highpc; pc += 4) { op = bfd_get_32 (core_bfd, ((unsigned char *)core_text_space diff --git a/gprof/sparc.c b/gprof/sparc.c index 44724c4..019e58b 100644 --- a/gprof/sparc.c +++ b/gprof/sparc.c @@ -51,7 +51,9 @@ sparc_find_call (Sym *parent, bfd_vma p_lowpc, bfd_vma p_highpc) DBG (CALLDEBUG, printf ("[find_call] %s: 0x%lx to 0x%lx\n", parent->name, (unsigned long) p_lowpc, (unsigned long) p_highpc)); - for (pc = (p_lowpc + 3) & ~(bfd_vma) 3; pc < p_highpc; pc += 4) + p_lowpc = (p_lowpc + 3) & ~3; + p_highpc &= ~3; + for (pc = p_lowpc; pc < p_highpc; pc += 4) { insn = bfd_get_32 (core_bfd, ((unsigned char *) core_text_space + pc - core_text_sect->vma)); diff --git a/gprof/vax.c b/gprof/vax.c index 9294235..fafe2b1 100644 --- a/gprof/vax.c +++ b/gprof/vax.c @@ -252,6 +252,8 @@ vax_find_call (Sym *parent, bfd_vma p_lowpc, bfd_vma p_highpc) (unsigned long) p_highpc)); for (pc = p_lowpc; pc < p_highpc; pc += length) { + unsigned char *operand; + length = 1; instructp = ((unsigned char *) core_text_space + pc - core_text_sect->vma); @@ -263,7 +265,10 @@ vax_find_call (Sym *parent, bfd_vma p_lowpc, bfd_vma p_highpc) */ DBG (CALLDEBUG, printf ("[findcall]\t0x%lx:calls", (unsigned long) pc)); - firstmode = vax_operandmode (instructp + length); + if (pc - core_text_sect->vma + length >= core_text_sect->size) + goto botched; + operand = instructp + length; + firstmode = vax_operandmode (operand); switch (firstmode) { case literal: @@ -272,8 +277,11 @@ vax_find_call (Sym *parent, bfd_vma p_lowpc, bfd_vma p_highpc) default: goto botched; } - length += vax_operandlength (instructp + length); - mode = vax_operandmode (instructp + length); + length += vax_operandlength (operand); + if (pc - core_text_sect->vma + length >= core_text_sect->size) + goto botched; + operand = instructp + length; + mode = vax_operandmode (operand); DBG (CALLDEBUG, printf ("\tfirst operand is %s", vax_operandname (firstmode)); printf ("\tsecond operand is %s\n", vax_operandname (mode))); @@ -294,8 +302,10 @@ vax_find_call (Sym *parent, bfd_vma p_lowpc, bfd_vma p_highpc) * [are there others that we miss?, * e.g. arrays of pointers to functions???] */ + length += vax_operandlength (operand); + if (pc - core_text_sect->vma + length > core_text_sect->size) + goto botched; arc_add (parent, &indirectchild, (unsigned long) 0); - length += vax_operandlength (instructp + length); continue; case byterel: case wordrel: @@ -305,7 +315,10 @@ vax_find_call (Sym *parent, bfd_vma p_lowpc, bfd_vma p_highpc) * check that this is the address of * a function. */ - destpc = pc + vax_offset (instructp + length); + length += vax_operandlength (operand); + if (pc - core_text_sect->vma + length > core_text_sect->size) + goto botched; + destpc = pc + vax_offset (operand); if (hist_check_address (destpc)) { child = sym_lookup (&symtab, destpc); @@ -324,7 +337,6 @@ vax_find_call (Sym *parent, bfd_vma p_lowpc, bfd_vma p_highpc) * a hit */ arc_add (parent, child, (unsigned long) 0); - length += vax_operandlength (instructp + length); continue; } } -- cgit v1.1