diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-11-10 02:41:39 +0100 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-11-10 02:41:39 +0100 |
commit | e7a7912a91cc1a274fab17f8a66b1e9dcfe00047 (patch) | |
tree | d6a7e32b9af7227e16265f3f280fe97b2b766af4 /arch/arm | |
parent | Merge tag 'pm-final-4.14' of git://git.kernel.org/pub/scm/linux/kernel/git/ra... (diff) | |
parent | ARM: 8720/1: ensure dump_instr() checks addr_limit (diff) | |
download | linux-e7a7912a91cc1a274fab17f8a66b1e9dcfe00047.tar.xz linux-e7a7912a91cc1a274fab17f8a66b1e9dcfe00047.zip |
Merge branch 'fixes' of git://git.armlinux.org.uk/~rmk/linux-arm
Pull ARM fix from Russell King:
"Last ARM fix for 4.14.
This plugs a hole in dump_instr(), which, with certain conditions
satisfied, can dump instructions from kernel space"
* 'fixes' of git://git.armlinux.org.uk/~rmk/linux-arm:
ARM: 8720/1: ensure dump_instr() checks addr_limit
Diffstat (limited to 'arch/arm')
-rw-r--r-- | arch/arm/kernel/traps.c | 28 |
1 files changed, 18 insertions, 10 deletions
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index 948c648fea00..0fcd82f01388 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -154,30 +154,26 @@ static void dump_mem(const char *lvl, const char *str, unsigned long bottom, 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); const int thumb = thumb_mode(regs); const int width = thumb ? 4 : 8; - mm_segment_t fs; char str[sizeof("00000000 ") * 5 + 2 + 1], *p = str; int i; /* - * We need to switch to kernel mode so that we can use __get_user - * to safely read from kernel space. Note that we now dump the - * code first, just in case the backtrace kills us. + * Note that we now dump the code first, just in case the backtrace + * kills us. */ - fs = get_fs(); - set_fs(KERNEL_DS); for (i = -4; i < 1 + !!thumb; i++) { unsigned int val, bad; if (thumb) - bad = __get_user(val, &((u16 *)addr)[i]); + bad = get_user(val, &((u16 *)addr)[i]); else - bad = __get_user(val, &((u32 *)addr)[i]); + bad = get_user(val, &((u32 *)addr)[i]); if (!bad) p += sprintf(p, i == 0 ? "(%0*x) " : "%0*x ", @@ -188,8 +184,20 @@ static void dump_instr(const char *lvl, struct pt_regs *regs) } } printk("%sCode: %s\n", lvl, str); +} - set_fs(fs); +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); + } else { + __dump_instr(lvl, regs); + } } #ifdef CONFIG_ARM_UNWIND |