Skip to content

Commit

Permalink
UPSTREAM: arm64: fix dump_instr when PAN and UAO are in use
Browse files Browse the repository at this point in the history
If the kernel is set to show unhandled signals, and a user task does not
handle a SIGILL as a result of an instruction abort, we will attempt to
log the offending instruction with dump_instr before killing the task.

We use dump_instr to log the encoding of the offending userspace
instruction. However, dump_instr is also used to dump instructions from
kernel space, and internally always switches to KERNEL_DS before dumping
the instruction with get_user. When both PAN and UAO are in use, reading
a user instruction via get_user while in KERNEL_DS will result in a
permission fault, which leads to an Oops.

As we have regs corresponding to the context of the original instruction
abort, we can inspect this and only flip to KERNEL_DS if the original
abort was taken from the kernel, avoiding this issue. At the same time,
remove the redundant (and incorrect) comments regarding the order
dump_mem and dump_instr are called in.

Cc: Catalin Marinas <[email protected]>
Cc: James Morse <[email protected]>
Cc: Robin Murphy <[email protected]>
Cc: <[email protected]> OnePlusOSS#4.6+
Signed-off-by: Mark Rutland <[email protected]>
Reported-by: Vladimir Murzin <[email protected]>
Tested-by: Vladimir Murzin <[email protected]>
Fixes: 57f4959 ("arm64: kernel: Add support for User Access Override")
Signed-off-by: Will Deacon <[email protected]>

Change-Id: I54c00f3598d227a7e2767b357cb453075dcce7bd
(cherry picked from commit c5cea06)
Signed-off-by: Sami Tolvanen <[email protected]>
  • Loading branch information
Mark Rutland authored and nikhil18 committed Sep 26, 2017
1 parent 114df5d commit e0160a0
Showing 1 changed file with 13 additions and 13 deletions.
26 changes: 13 additions & 13 deletions arch/arm64/kernel/traps.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,7 @@ static void dump_mem(const char *lvl, const char *str, unsigned long bottom,

/*
* 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.
* to safely read from kernel space.
*/
fs = get_fs();
set_fs(KERNEL_DS);
Expand Down Expand Up @@ -116,21 +115,12 @@ static void dump_backtrace_entry(unsigned long where)
print_ip_sym(where);
}

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);
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.
*/
fs = get_fs();
set_fs(KERNEL_DS);

for (i = -4; i < 1; i++) {
unsigned int val, bad;

Expand All @@ -144,8 +134,18 @@ 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)
{
if (!user_mode(regs)) {
mm_segment_t fs = get_fs();
set_fs(KERNEL_DS);
__dump_instr(lvl, regs);
set_fs(fs);
} else {
__dump_instr(lvl, regs);
}
}

static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk)
Expand Down

0 comments on commit e0160a0

Please sign in to comment.