diff options
author | Keith Owens <kaos@sgi.com> | 2007-06-26 02:25:22 -0400 |
---|---|---|
committer | Tony Luck <tony.luck@intel.com> | 2007-06-26 16:33:10 -0400 |
commit | 66fa9b107e259d01929fe647796b3021d3a83c4a (patch) | |
tree | 6fe7bde9c86a4d5dffae53ab815b34362eb19571 /arch/ia64/kernel/unwind.c | |
parent | 9be26f4c4b138c425598bd3cc50411bd87fce287 (diff) |
[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>
Diffstat (limited to 'arch/ia64/kernel/unwind.c')
-rw-r--r-- | arch/ia64/kernel/unwind.c | 16 |
1 files changed, 11 insertions, 5 deletions
diff --git a/arch/ia64/kernel/unwind.c b/arch/ia64/kernel/unwind.c index b0b08b5f3eca..c1bdb5131814 100644 --- a/arch/ia64/kernel/unwind.c +++ b/arch/ia64/kernel/unwind.c | |||
@@ -1856,11 +1856,19 @@ find_save_locs (struct unw_frame_info *info) | |||
1856 | return 0; | 1856 | return 0; |
1857 | } | 1857 | } |
1858 | 1858 | ||
1859 | static int | ||
1860 | unw_valid(const struct unw_frame_info *info, unsigned long* p) | ||
1861 | { | ||
1862 | unsigned long loc = (unsigned long)p; | ||
1863 | return (loc >= info->regstk.limit && loc < info->regstk.top) || | ||
1864 | (loc >= info->memstk.top && loc < info->memstk.limit); | ||
1865 | } | ||
1866 | |||
1859 | int | 1867 | int |
1860 | unw_unwind (struct unw_frame_info *info) | 1868 | unw_unwind (struct unw_frame_info *info) |
1861 | { | 1869 | { |
1862 | unsigned long prev_ip, prev_sp, prev_bsp; | 1870 | unsigned long prev_ip, prev_sp, prev_bsp; |
1863 | unsigned long ip, pr, num_regs, rp_loc, pfs_loc; | 1871 | unsigned long ip, pr, num_regs; |
1864 | STAT(unsigned long start, flags;) | 1872 | STAT(unsigned long start, flags;) |
1865 | int retval; | 1873 | int retval; |
1866 | 1874 | ||
@@ -1871,8 +1879,7 @@ unw_unwind (struct unw_frame_info *info) | |||
1871 | prev_bsp = info->bsp; | 1879 | prev_bsp = info->bsp; |
1872 | 1880 | ||
1873 | /* validate the return IP pointer */ | 1881 | /* validate the return IP pointer */ |
1874 | rp_loc = (unsigned long) info->rp_loc; | 1882 | if (!unw_valid(info, info->rp_loc)) { |
1875 | if ((rp_loc < info->regstk.limit) || (rp_loc > info->regstk.top)) { | ||
1876 | /* FIXME: should really be level 0 but it occurs too often. KAO */ | 1883 | /* FIXME: should really be level 0 but it occurs too often. KAO */ |
1877 | UNW_DPRINT(1, "unwind.%s: failed to locate return link (ip=0x%lx)!\n", | 1884 | UNW_DPRINT(1, "unwind.%s: failed to locate return link (ip=0x%lx)!\n", |
1878 | __FUNCTION__, info->ip); | 1885 | __FUNCTION__, info->ip); |
@@ -1888,8 +1895,7 @@ unw_unwind (struct unw_frame_info *info) | |||
1888 | } | 1895 | } |
1889 | 1896 | ||
1890 | /* validate the previous stack frame pointer */ | 1897 | /* validate the previous stack frame pointer */ |
1891 | pfs_loc = (unsigned long) info->pfs_loc; | 1898 | if (!unw_valid(info, info->pfs_loc)) { |
1892 | if ((pfs_loc < info->regstk.limit) || (pfs_loc > info->regstk.top)) { | ||
1893 | UNW_DPRINT(0, "unwind.%s: failed to locate ar.pfs!\n", __FUNCTION__); | 1899 | UNW_DPRINT(0, "unwind.%s: failed to locate ar.pfs!\n", __FUNCTION__); |
1894 | STAT(unw.stat.api.unwind_time += ia64_get_itc() - start; local_irq_restore(flags)); | 1900 | STAT(unw.stat.api.unwind_time += ia64_get_itc() - start; local_irq_restore(flags)); |
1895 | return -1; | 1901 | return -1; |