Skip to content

Commit b9dd05c

Browse files
mrutland-armRussell King
authored andcommitted
ARM: 8720/1: ensure dump_instr() checks addr_limit
When CONFIG_DEBUG_USER is enabled, it's possible for a user to deliberately trigger dump_instr() with a chosen kernel address. Let's avoid problems resulting from this by using get_user() rather than __get_user(), ensuring that we don't erroneously access kernel memory. So that we can use the same code to dump user instructions and kernel instructions, the common dumping code is factored out to __dump_instr(), with the fs manipulated appropriately in dump_instr() around calls to this. Signed-off-by: Mark Rutland <mark.rutland@arm.com> Cc: stable@vger.kernel.org Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
1 parent dad4675 commit b9dd05c

File tree

1 file changed

+18
-10
lines changed

1 file changed

+18
-10
lines changed

arch/arm/kernel/traps.c

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -154,30 +154,26 @@ static void dump_mem(const char *lvl, const char *str, unsigned long bottom,
154154
set_fs(fs);
155155
}
156156

157-
static void dump_instr(const char *lvl, struct pt_regs *regs)
157+
static void __dump_instr(const char *lvl, struct pt_regs *regs)
158158
{
159159
unsigned long addr = instruction_pointer(regs);
160160
const int thumb = thumb_mode(regs);
161161
const int width = thumb ? 4 : 8;
162-
mm_segment_t fs;
163162
char str[sizeof("00000000 ") * 5 + 2 + 1], *p = str;
164163
int i;
165164

166165
/*
167-
* We need to switch to kernel mode so that we can use __get_user
168-
* to safely read from kernel space. Note that we now dump the
169-
* code first, just in case the backtrace kills us.
166+
* Note that we now dump the code first, just in case the backtrace
167+
* kills us.
170168
*/
171-
fs = get_fs();
172-
set_fs(KERNEL_DS);
173169

174170
for (i = -4; i < 1 + !!thumb; i++) {
175171
unsigned int val, bad;
176172

177173
if (thumb)
178-
bad = __get_user(val, &((u16 *)addr)[i]);
174+
bad = get_user(val, &((u16 *)addr)[i]);
179175
else
180-
bad = __get_user(val, &((u32 *)addr)[i]);
176+
bad = get_user(val, &((u32 *)addr)[i]);
181177

182178
if (!bad)
183179
p += sprintf(p, i == 0 ? "(%0*x) " : "%0*x ",
@@ -188,8 +184,20 @@ static void dump_instr(const char *lvl, struct pt_regs *regs)
188184
}
189185
}
190186
printk("%sCode: %s\n", lvl, str);
187+
}
191188

192-
set_fs(fs);
189+
static void dump_instr(const char *lvl, struct pt_regs *regs)
190+
{
191+
mm_segment_t fs;
192+
193+
if (!user_mode(regs)) {
194+
fs = get_fs();
195+
set_fs(KERNEL_DS);
196+
__dump_instr(lvl, regs);
197+
set_fs(fs);
198+
} else {
199+
__dump_instr(lvl, regs);
200+
}
193201
}
194202

195203
#ifdef CONFIG_ARM_UNWIND

0 commit comments

Comments
 (0)