mirror of
https://github.com/tobast/libunwind-eh_elf.git
synced 2025-04-02 12:12:18 +02:00
Bad pointer validation for 32 bit x86.
This corresponds to commit 649f1fb344
.
Signed-off-by: Paul Pluzhnikov <ppluzhnikov@google.com>
This commit is contained in:
parent
5822fca27a
commit
ff0ae70cc3
6 changed files with 80 additions and 10 deletions
|
@ -65,8 +65,17 @@ struct cursor
|
||||||
}
|
}
|
||||||
sigcontext_format;
|
sigcontext_format;
|
||||||
unw_word_t sigcontext_addr;
|
unw_word_t sigcontext_addr;
|
||||||
|
int validate;
|
||||||
|
ucontext_t *uc;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static inline ucontext_t *
|
||||||
|
dwarf_get_uc(const struct dwarf_cursor *cursor)
|
||||||
|
{
|
||||||
|
const struct cursor *c = (struct cursor *) cursor->as_arg;
|
||||||
|
return c->uc;
|
||||||
|
}
|
||||||
|
|
||||||
#define DWARF_GET_LOC(l) ((l).val)
|
#define DWARF_GET_LOC(l) ((l).val)
|
||||||
|
|
||||||
#ifdef UNW_LOCAL_ONLY
|
#ifdef UNW_LOCAL_ONLY
|
||||||
|
@ -75,10 +84,10 @@ struct cursor
|
||||||
# define DWARF_LOC(r, t) ((dwarf_loc_t) { .val = (r) })
|
# define DWARF_LOC(r, t) ((dwarf_loc_t) { .val = (r) })
|
||||||
# define DWARF_IS_REG_LOC(l) 0
|
# define DWARF_IS_REG_LOC(l) 0
|
||||||
# define DWARF_REG_LOC(c,r) (DWARF_LOC((unw_word_t) \
|
# define DWARF_REG_LOC(c,r) (DWARF_LOC((unw_word_t) \
|
||||||
tdep_uc_addr((c)->as_arg, (r)), 0))
|
tdep_uc_addr(dwarf_get_uc(c), (r)), 0))
|
||||||
# define DWARF_MEM_LOC(c,m) DWARF_LOC ((m), 0)
|
# define DWARF_MEM_LOC(c,m) DWARF_LOC ((m), 0)
|
||||||
# define DWARF_FPREG_LOC(c,r) (DWARF_LOC((unw_word_t) \
|
# define DWARF_FPREG_LOC(c,r) (DWARF_LOC((unw_word_t) \
|
||||||
tdep_uc_addr((c)->as_arg, (r)), 0))
|
tdep_uc_addr(dwarf_get_uc(c), (r)), 0))
|
||||||
|
|
||||||
static inline int
|
static inline int
|
||||||
dwarf_getfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t *val)
|
dwarf_getfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t *val)
|
||||||
|
@ -103,8 +112,8 @@ dwarf_get (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t *val)
|
||||||
{
|
{
|
||||||
if (!DWARF_GET_LOC (loc))
|
if (!DWARF_GET_LOC (loc))
|
||||||
return -1;
|
return -1;
|
||||||
*val = *(unw_word_t *) DWARF_GET_LOC (loc);
|
return (*c->as->acc.access_mem) (c->as, DWARF_GET_LOC (loc), val,
|
||||||
return 0;
|
0, c->as_arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int
|
static inline int
|
||||||
|
@ -112,8 +121,8 @@ dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val)
|
||||||
{
|
{
|
||||||
if (!DWARF_GET_LOC (loc))
|
if (!DWARF_GET_LOC (loc))
|
||||||
return -1;
|
return -1;
|
||||||
*(unw_word_t *) DWARF_GET_LOC (loc) = val;
|
return (*c->as->acc.access_mem) (c->as, DWARF_GET_LOC (loc), &val,
|
||||||
return 0;
|
1, c->as_arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
#else /* !UNW_LOCAL_ONLY */
|
#else /* !UNW_LOCAL_ONLY */
|
||||||
|
|
|
@ -102,6 +102,47 @@ get_dyn_info_list_addr (unw_addr_space_t as, unw_word_t *dyn_info_list_addr,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define PAGE_SIZE 4096
|
||||||
|
#define PAGE_START(a) ((a) & ~(PAGE_SIZE-1))
|
||||||
|
|
||||||
|
/* Cache of already validated addresses */
|
||||||
|
#define NLGA 4
|
||||||
|
static unw_word_t last_good_addr[NLGA];
|
||||||
|
static int lga_victim;
|
||||||
|
|
||||||
|
static int
|
||||||
|
validate_mem (unw_word_t addr)
|
||||||
|
{
|
||||||
|
int i, victim;
|
||||||
|
|
||||||
|
addr = PAGE_START(addr);
|
||||||
|
|
||||||
|
for (i = 0; i < NLGA; i++)
|
||||||
|
{
|
||||||
|
if (last_good_addr[i] && (addr == last_good_addr[i]))
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msync ((void *) addr, 1, MS_SYNC) == -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
victim = lga_victim;
|
||||||
|
for (i = 0; i < NLGA; i++) {
|
||||||
|
if (!last_good_addr[victim]) {
|
||||||
|
last_good_addr[victim++] = addr;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
victim = (victim + 1) % NLGA;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* All slots full. Evict the victim. */
|
||||||
|
last_good_addr[victim] = addr;
|
||||||
|
victim = (victim + 1) % NLGA;
|
||||||
|
lga_victim = victim;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
access_mem (unw_addr_space_t as, unw_word_t addr, unw_word_t *val, int write,
|
access_mem (unw_addr_space_t as, unw_word_t addr, unw_word_t *val, int write,
|
||||||
void *arg)
|
void *arg)
|
||||||
|
@ -113,6 +154,10 @@ access_mem (unw_addr_space_t as, unw_word_t addr, unw_word_t *val, int write,
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
/* validate address */
|
||||||
|
const struct cursor *c = (const struct cursor *)arg;
|
||||||
|
if (c && c->validate && validate_mem(addr))
|
||||||
|
return -1;
|
||||||
*val = *(unw_word_t *) addr;
|
*val = *(unw_word_t *) addr;
|
||||||
Debug (16, "mem[%x] -> %x\n", addr, *val);
|
Debug (16, "mem[%x] -> %x\n", addr, *val);
|
||||||
}
|
}
|
||||||
|
@ -124,7 +169,7 @@ access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val, int write,
|
||||||
void *arg)
|
void *arg)
|
||||||
{
|
{
|
||||||
unw_word_t *addr;
|
unw_word_t *addr;
|
||||||
ucontext_t *uc = arg;
|
ucontext_t *uc = ((struct cursor *)arg)->uc;
|
||||||
|
|
||||||
if (unw_is_fpreg (reg))
|
if (unw_is_fpreg (reg))
|
||||||
goto badreg;
|
goto badreg;
|
||||||
|
@ -153,7 +198,7 @@ static int
|
||||||
access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val,
|
access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val,
|
||||||
int write, void *arg)
|
int write, void *arg)
|
||||||
{
|
{
|
||||||
ucontext_t *uc = arg;
|
ucontext_t *uc = ((struct cursor *)arg)->uc;
|
||||||
unw_fpreg_t *addr;
|
unw_fpreg_t *addr;
|
||||||
|
|
||||||
if (!unw_is_fpreg (reg))
|
if (!unw_is_fpreg (reg))
|
||||||
|
|
|
@ -47,7 +47,9 @@ unw_init_local (unw_cursor_t *cursor, ucontext_t *uc)
|
||||||
Debug (1, "(cursor=%p)\n", c);
|
Debug (1, "(cursor=%p)\n", c);
|
||||||
|
|
||||||
c->dwarf.as = unw_local_addr_space;
|
c->dwarf.as = unw_local_addr_space;
|
||||||
c->dwarf.as_arg = uc;
|
c->dwarf.as_arg = c;
|
||||||
|
c->uc = uc;
|
||||||
|
c->validate = 0;
|
||||||
return common_init (c);
|
return common_init (c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,16 @@ unw_init_remote (unw_cursor_t *cursor, unw_addr_space_t as, void *as_arg)
|
||||||
|
|
||||||
c->dwarf.as = as;
|
c->dwarf.as = as;
|
||||||
c->dwarf.as_arg = as_arg;
|
c->dwarf.as_arg = as_arg;
|
||||||
|
if (as == unw_local_addr_space)
|
||||||
|
{
|
||||||
|
c->dwarf.as_arg = c;
|
||||||
|
c->uc = as_arg;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
c->dwarf.as_arg = as_arg;
|
||||||
|
c->uc = 0;
|
||||||
|
}
|
||||||
return common_init (c);
|
return common_init (c);
|
||||||
#endif /* !UNW_LOCAL_ONLY */
|
#endif /* !UNW_LOCAL_ONLY */
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ x86_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, void *arg)
|
||||||
{
|
{
|
||||||
#if defined(__linux)
|
#if defined(__linux)
|
||||||
struct cursor *c = (struct cursor *) cursor;
|
struct cursor *c = (struct cursor *) cursor;
|
||||||
ucontext_t *uc = c->dwarf.as_arg;
|
ucontext_t *uc = c->uc;
|
||||||
|
|
||||||
/* Ensure c->pi is up-to-date. On x86, it's relatively common to be
|
/* Ensure c->pi is up-to-date. On x86, it's relatively common to be
|
||||||
missing DWARF unwind info. We don't want to fail in that case,
|
missing DWARF unwind info. We don't want to fail in that case,
|
||||||
|
|
|
@ -49,6 +49,10 @@ unw_step (unw_cursor_t *cursor)
|
||||||
or skip over the signal trampoline. */
|
or skip over the signal trampoline. */
|
||||||
struct dwarf_loc ebp_loc, eip_loc;
|
struct dwarf_loc ebp_loc, eip_loc;
|
||||||
|
|
||||||
|
/* We could get here because of missing/bad unwind information.
|
||||||
|
Validate all addresses before dereferencing. */
|
||||||
|
c->validate = 1;
|
||||||
|
|
||||||
Debug (13, "dwarf_step() failed (ret=%d), trying frame-chain\n", ret);
|
Debug (13, "dwarf_step() failed (ret=%d), trying frame-chain\n", ret);
|
||||||
|
|
||||||
if (unw_is_signal_frame (cursor))
|
if (unw_is_signal_frame (cursor))
|
||||||
|
|
Loading…
Add table
Reference in a new issue