2
0
mirror of https://github.com/edk2-porting/linux-next.git synced 2024-12-17 09:43:59 +08:00

[IA64] Correct unwind validation code

Both rp_loc and pfs_loc can be in the register stack area _or_ they can
be in the memory stack area, the latter occurs when a struct pt_regs is
pushed.  Correct the validation check on these fields to check for both
stack areas.  Not allowing for memory stack locations means no
backtrace past ia64_leave_kernel, or any other code that uses
PT_REGS_UNWIND_INFO.

Signed-off-by: Keith Owens <kaos@sgi.com>
Signed-off-by: Tony Luck <tony.luck@intel.com>
This commit is contained in:
Keith Owens 2007-06-26 16:25:22 +10:00 committed by Tony Luck
parent 9be26f4c4b
commit 66fa9b107e

View File

@ -1856,11 +1856,19 @@ find_save_locs (struct unw_frame_info *info)
return 0; return 0;
} }
static int
unw_valid(const struct unw_frame_info *info, unsigned long* p)
{
unsigned long loc = (unsigned long)p;
return (loc >= info->regstk.limit && loc < info->regstk.top) ||
(loc >= info->memstk.top && loc < info->memstk.limit);
}
int int
unw_unwind (struct unw_frame_info *info) unw_unwind (struct unw_frame_info *info)
{ {
unsigned long prev_ip, prev_sp, prev_bsp; unsigned long prev_ip, prev_sp, prev_bsp;
unsigned long ip, pr, num_regs, rp_loc, pfs_loc; unsigned long ip, pr, num_regs;
STAT(unsigned long start, flags;) STAT(unsigned long start, flags;)
int retval; int retval;
@ -1871,8 +1879,7 @@ unw_unwind (struct unw_frame_info *info)
prev_bsp = info->bsp; prev_bsp = info->bsp;
/* validate the return IP pointer */ /* validate the return IP pointer */
rp_loc = (unsigned long) info->rp_loc; if (!unw_valid(info, info->rp_loc)) {
if ((rp_loc < info->regstk.limit) || (rp_loc > info->regstk.top)) {
/* FIXME: should really be level 0 but it occurs too often. KAO */ /* FIXME: should really be level 0 but it occurs too often. KAO */
UNW_DPRINT(1, "unwind.%s: failed to locate return link (ip=0x%lx)!\n", UNW_DPRINT(1, "unwind.%s: failed to locate return link (ip=0x%lx)!\n",
__FUNCTION__, info->ip); __FUNCTION__, info->ip);
@ -1888,8 +1895,7 @@ unw_unwind (struct unw_frame_info *info)
} }
/* validate the previous stack frame pointer */ /* validate the previous stack frame pointer */
pfs_loc = (unsigned long) info->pfs_loc; if (!unw_valid(info, info->pfs_loc)) {
if ((pfs_loc < info->regstk.limit) || (pfs_loc > info->regstk.top)) {
UNW_DPRINT(0, "unwind.%s: failed to locate ar.pfs!\n", __FUNCTION__); UNW_DPRINT(0, "unwind.%s: failed to locate ar.pfs!\n", __FUNCTION__);
STAT(unw.stat.api.unwind_time += ia64_get_itc() - start; local_irq_restore(flags)); STAT(unw.stat.api.unwind_time += ia64_get_itc() - start; local_irq_restore(flags));
return -1; return -1;