aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/unwind.c
diff options
context:
space:
mode:
authorJan Beulich <jbeulich@novell.com>2006-12-06 20:14:13 -0500
committerAndi Kleen <andi@basil.nowhere.org>2006-12-06 20:14:13 -0500
commit359ad0d4015a9ab39243f2ebc4eb07915bd618b2 (patch)
tree90f05d8d9ab048029bfe1e451a012b4d5896aafe /kernel/unwind.c
parenteef5e0d185fc049bda11fa14ba286fbd357da896 (diff)
[PATCH] unwinder: more sanity checks in Dwarf2 unwinder
Tighten the requirements on both input to and output from the Dwarf2 unwinder. Signed-off-by: Jan Beulich <jbeulich@novell.com> Signed-off-by: Andi Kleen <ak@suse.de>
Diffstat (limited to 'kernel/unwind.c')
-rw-r--r--kernel/unwind.c16
1 files changed, 15 insertions, 1 deletions
diff --git a/kernel/unwind.c b/kernel/unwind.c
index af48168a3afb..7e721f104105 100644
--- a/kernel/unwind.c
+++ b/kernel/unwind.c
@@ -95,6 +95,7 @@ static const struct {
95 95
96typedef unsigned long uleb128_t; 96typedef unsigned long uleb128_t;
97typedef signed long sleb128_t; 97typedef signed long sleb128_t;
98#define sleb128abs __builtin_labs
98 99
99static struct unwind_table { 100static struct unwind_table {
100 struct { 101 struct {
@@ -787,7 +788,7 @@ int unwind(struct unwind_frame_info *frame)
787#define FRAME_REG(r, t) (((t *)frame)[reg_info[r].offs]) 788#define FRAME_REG(r, t) (((t *)frame)[reg_info[r].offs])
788 const u32 *fde = NULL, *cie = NULL; 789 const u32 *fde = NULL, *cie = NULL;
789 const u8 *ptr = NULL, *end = NULL; 790 const u8 *ptr = NULL, *end = NULL;
790 unsigned long pc = UNW_PC(frame) - frame->call_frame; 791 unsigned long pc = UNW_PC(frame) - frame->call_frame, sp;
791 unsigned long startLoc = 0, endLoc = 0, cfa; 792 unsigned long startLoc = 0, endLoc = 0, cfa;
792 unsigned i; 793 unsigned i;
793 signed ptrType = -1; 794 signed ptrType = -1;
@@ -936,6 +937,9 @@ int unwind(struct unwind_frame_info *frame)
936 state.dataAlign = get_sleb128(&ptr, end); 937 state.dataAlign = get_sleb128(&ptr, end);
937 if (state.codeAlign == 0 || state.dataAlign == 0 || ptr >= end) 938 if (state.codeAlign == 0 || state.dataAlign == 0 || ptr >= end)
938 cie = NULL; 939 cie = NULL;
940 else if (UNW_PC(frame) % state.codeAlign
941 || UNW_SP(frame) % sleb128abs(state.dataAlign))
942 return -EPERM;
939 else { 943 else {
940 retAddrReg = state.version <= 1 ? *ptr++ : get_uleb128(&ptr, end); 944 retAddrReg = state.version <= 1 ? *ptr++ : get_uleb128(&ptr, end);
941 /* skip augmentation */ 945 /* skip augmentation */
@@ -968,6 +972,8 @@ int unwind(struct unwind_frame_info *frame)
968#ifdef CONFIG_FRAME_POINTER 972#ifdef CONFIG_FRAME_POINTER
969 unsigned long top, bottom; 973 unsigned long top, bottom;
970 974
975 if ((UNW_SP(frame) | UNW_FP(frame)) % sizeof(unsigned long))
976 return -EPERM;
971 top = STACK_TOP(frame->task); 977 top = STACK_TOP(frame->task);
972 bottom = STACK_BOTTOM(frame->task); 978 bottom = STACK_BOTTOM(frame->task);
973# if FRAME_RETADDR_OFFSET < 0 979# if FRAME_RETADDR_OFFSET < 0
@@ -1018,6 +1024,7 @@ int unwind(struct unwind_frame_info *frame)
1018 || state.regs[retAddrReg].where == Nowhere 1024 || state.regs[retAddrReg].where == Nowhere
1019 || state.cfa.reg >= ARRAY_SIZE(reg_info) 1025 || state.cfa.reg >= ARRAY_SIZE(reg_info)
1020 || reg_info[state.cfa.reg].width != sizeof(unsigned long) 1026 || reg_info[state.cfa.reg].width != sizeof(unsigned long)
1027 || FRAME_REG(state.cfa.reg, unsigned long) % sizeof(unsigned long)
1021 || state.cfa.offs % sizeof(unsigned long)) 1028 || state.cfa.offs % sizeof(unsigned long))
1022 return -EIO; 1029 return -EIO;
1023 /* update frame */ 1030 /* update frame */
@@ -1038,6 +1045,8 @@ int unwind(struct unwind_frame_info *frame)
1038#else 1045#else
1039# define CASES CASE(8); CASE(16); CASE(32); CASE(64) 1046# define CASES CASE(8); CASE(16); CASE(32); CASE(64)
1040#endif 1047#endif
1048 pc = UNW_PC(frame);
1049 sp = UNW_SP(frame);
1041 for (i = 0; i < ARRAY_SIZE(state.regs); ++i) { 1050 for (i = 0; i < ARRAY_SIZE(state.regs); ++i) {
1042 if (REG_INVALID(i)) { 1051 if (REG_INVALID(i)) {
1043 if (state.regs[i].where == Nowhere) 1052 if (state.regs[i].where == Nowhere)
@@ -1118,6 +1127,11 @@ int unwind(struct unwind_frame_info *frame)
1118 } 1127 }
1119 } 1128 }
1120 1129
1130 if (UNW_PC(frame) % state.codeAlign
1131 || UNW_SP(frame) % sleb128abs(state.dataAlign)
1132 || (pc == UNW_PC(frame) && sp == UNW_SP(frame)))
1133 return -EIO;
1134
1121 return 0; 1135 return 0;
1122#undef CASES 1136#undef CASES
1123#undef FRAME_REG 1137#undef FRAME_REG