diff options
author | Jan Beulich <jbeulich@novell.com> | 2006-12-06 20:14:13 -0500 |
---|---|---|
committer | Andi Kleen <andi@basil.nowhere.org> | 2006-12-06 20:14:13 -0500 |
commit | 359ad0d4015a9ab39243f2ebc4eb07915bd618b2 (patch) | |
tree | 90f05d8d9ab048029bfe1e451a012b4d5896aafe /kernel/unwind.c | |
parent | eef5e0d185fc049bda11fa14ba286fbd357da896 (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.c | 16 |
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 | ||
96 | typedef unsigned long uleb128_t; | 96 | typedef unsigned long uleb128_t; |
97 | typedef signed long sleb128_t; | 97 | typedef signed long sleb128_t; |
98 | #define sleb128abs __builtin_labs | ||
98 | 99 | ||
99 | static struct unwind_table { | 100 | static 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 |