diff options
Diffstat (limited to 'arch/x86/kernel/dumpstack.c')
| -rw-r--r-- | arch/x86/kernel/dumpstack.c | 20 |
1 files changed, 17 insertions, 3 deletions
diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c index 9c8652974f8e..f56895106ccf 100644 --- a/arch/x86/kernel/dumpstack.c +++ b/arch/x86/kernel/dumpstack.c | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | #include <linux/bug.h> | 17 | #include <linux/bug.h> |
| 18 | #include <linux/nmi.h> | 18 | #include <linux/nmi.h> |
| 19 | #include <linux/sysfs.h> | 19 | #include <linux/sysfs.h> |
| 20 | #include <linux/kasan.h> | ||
| 20 | 21 | ||
| 21 | #include <asm/cpu_entry_area.h> | 22 | #include <asm/cpu_entry_area.h> |
| 22 | #include <asm/stacktrace.h> | 23 | #include <asm/stacktrace.h> |
| @@ -89,14 +90,24 @@ static void printk_stack_address(unsigned long address, int reliable, | |||
| 89 | * Thus, the 2/3rds prologue and 64 byte OPCODE_BUFSIZE is just a random | 90 | * Thus, the 2/3rds prologue and 64 byte OPCODE_BUFSIZE is just a random |
| 90 | * guesstimate in attempt to achieve all of the above. | 91 | * guesstimate in attempt to achieve all of the above. |
| 91 | */ | 92 | */ |
| 92 | void show_opcodes(u8 *rip, const char *loglvl) | 93 | void show_opcodes(struct pt_regs *regs, const char *loglvl) |
| 93 | { | 94 | { |
| 94 | #define PROLOGUE_SIZE 42 | 95 | #define PROLOGUE_SIZE 42 |
| 95 | #define EPILOGUE_SIZE 21 | 96 | #define EPILOGUE_SIZE 21 |
| 96 | #define OPCODE_BUFSIZE (PROLOGUE_SIZE + 1 + EPILOGUE_SIZE) | 97 | #define OPCODE_BUFSIZE (PROLOGUE_SIZE + 1 + EPILOGUE_SIZE) |
| 97 | u8 opcodes[OPCODE_BUFSIZE]; | 98 | u8 opcodes[OPCODE_BUFSIZE]; |
| 99 | unsigned long prologue = regs->ip - PROLOGUE_SIZE; | ||
| 100 | bool bad_ip; | ||
| 98 | 101 | ||
| 99 | if (probe_kernel_read(opcodes, rip - PROLOGUE_SIZE, OPCODE_BUFSIZE)) { | 102 | /* |
| 103 | * Make sure userspace isn't trying to trick us into dumping kernel | ||
| 104 | * memory by pointing the userspace instruction pointer at it. | ||
| 105 | */ | ||
| 106 | bad_ip = user_mode(regs) && | ||
| 107 | __chk_range_not_ok(prologue, OPCODE_BUFSIZE, TASK_SIZE_MAX); | ||
| 108 | |||
| 109 | if (bad_ip || probe_kernel_read(opcodes, (u8 *)prologue, | ||
| 110 | OPCODE_BUFSIZE)) { | ||
| 100 | printk("%sCode: Bad RIP value.\n", loglvl); | 111 | printk("%sCode: Bad RIP value.\n", loglvl); |
| 101 | } else { | 112 | } else { |
| 102 | printk("%sCode: %" __stringify(PROLOGUE_SIZE) "ph <%02x> %" | 113 | printk("%sCode: %" __stringify(PROLOGUE_SIZE) "ph <%02x> %" |
| @@ -112,7 +123,7 @@ void show_ip(struct pt_regs *regs, const char *loglvl) | |||
| 112 | #else | 123 | #else |
| 113 | printk("%sRIP: %04x:%pS\n", loglvl, (int)regs->cs, (void *)regs->ip); | 124 | printk("%sRIP: %04x:%pS\n", loglvl, (int)regs->cs, (void *)regs->ip); |
| 114 | #endif | 125 | #endif |
| 115 | show_opcodes((u8 *)regs->ip, loglvl); | 126 | show_opcodes(regs, loglvl); |
| 116 | } | 127 | } |
| 117 | 128 | ||
| 118 | void show_iret_regs(struct pt_regs *regs) | 129 | void show_iret_regs(struct pt_regs *regs) |
| @@ -346,7 +357,10 @@ void oops_end(unsigned long flags, struct pt_regs *regs, int signr) | |||
| 346 | * We're not going to return, but we might be on an IST stack or | 357 | * We're not going to return, but we might be on an IST stack or |
| 347 | * have very little stack space left. Rewind the stack and kill | 358 | * have very little stack space left. Rewind the stack and kill |
| 348 | * the task. | 359 | * the task. |
| 360 | * Before we rewind the stack, we have to tell KASAN that we're going to | ||
| 361 | * reuse the task stack and that existing poisons are invalid. | ||
| 349 | */ | 362 | */ |
| 363 | kasan_unpoison_task_stack(current); | ||
| 350 | rewind_stack_do_exit(signr); | 364 | rewind_stack_do_exit(signr); |
| 351 | } | 365 | } |
| 352 | NOKPROBE_SYMBOL(oops_end); | 366 | NOKPROBE_SYMBOL(oops_end); |
