Commit 18404c3c authored by Mark Rutland's avatar Mark Rutland Committed by Thadeu Lima de Souza Cascardo

ARM: 8720/1: ensure dump_instr() checks addr_limit

BugLink: http://bugs.launchpad.net/bugs/1732698

commit b9dd05c7 upstream.

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: default avatarMark Rutland <mark.rutland@arm.com>
Signed-off-by: default avatarRussell King <rmk+kernel@armlinux.org.uk>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: default avatarStefan Bader <stefan.bader@canonical.com>
Signed-off-by: default avatarThadeu Lima de Souza Cascardo <cascardo@canonical.com>
parent 9ab4a74a
...@@ -132,30 +132,26 @@ static void dump_mem(const char *lvl, const char *str, unsigned long bottom, ...@@ -132,30 +132,26 @@ static void dump_mem(const char *lvl, const char *str, unsigned long bottom,
set_fs(fs); set_fs(fs);
} }
static void dump_instr(const char *lvl, struct pt_regs *regs) static void __dump_instr(const char *lvl, struct pt_regs *regs)
{ {
unsigned long addr = instruction_pointer(regs); unsigned long addr = instruction_pointer(regs);
const int thumb = thumb_mode(regs); const int thumb = thumb_mode(regs);
const int width = thumb ? 4 : 8; const int width = thumb ? 4 : 8;
mm_segment_t fs;
char str[sizeof("00000000 ") * 5 + 2 + 1], *p = str; char str[sizeof("00000000 ") * 5 + 2 + 1], *p = str;
int i; int i;
/* /*
* We need to switch to kernel mode so that we can use __get_user * Note that we now dump the code first, just in case the backtrace
* to safely read from kernel space. Note that we now dump the * kills us.
* code first, just in case the backtrace kills us.
*/ */
fs = get_fs();
set_fs(KERNEL_DS);
for (i = -4; i < 1 + !!thumb; i++) { for (i = -4; i < 1 + !!thumb; i++) {
unsigned int val, bad; unsigned int val, bad;
if (thumb) if (thumb)
bad = __get_user(val, &((u16 *)addr)[i]); bad = get_user(val, &((u16 *)addr)[i]);
else else
bad = __get_user(val, &((u32 *)addr)[i]); bad = get_user(val, &((u32 *)addr)[i]);
if (!bad) if (!bad)
p += sprintf(p, i == 0 ? "(%0*x) " : "%0*x ", p += sprintf(p, i == 0 ? "(%0*x) " : "%0*x ",
...@@ -166,8 +162,20 @@ static void dump_instr(const char *lvl, struct pt_regs *regs) ...@@ -166,8 +162,20 @@ static void dump_instr(const char *lvl, struct pt_regs *regs)
} }
} }
printk("%sCode: %s\n", lvl, str); printk("%sCode: %s\n", lvl, str);
}
static void dump_instr(const char *lvl, struct pt_regs *regs)
{
mm_segment_t fs;
if (!user_mode(regs)) {
fs = get_fs();
set_fs(KERNEL_DS);
__dump_instr(lvl, regs);
set_fs(fs); set_fs(fs);
} else {
__dump_instr(lvl, regs);
}
} }
#ifdef CONFIG_ARM_UNWIND #ifdef CONFIG_ARM_UNWIND
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment