Skip to content

Commit c5cea06

Browse files
mrutland-armwildea01
authored andcommitted
arm64: fix dump_instr when PAN and UAO are in use
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]> #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]>
1 parent 5edb564 commit c5cea06

File tree

1 file changed

+13
-13
lines changed

1 file changed

+13
-13
lines changed

arch/arm64/kernel/traps.c

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,7 @@ static void dump_mem(const char *lvl, const char *str, unsigned long bottom,
6464

6565
/*
6666
* We need to switch to kernel mode so that we can use __get_user
67-
* to safely read from kernel space. Note that we now dump the
68-
* code first, just in case the backtrace kills us.
67+
* to safely read from kernel space.
6968
*/
7069
fs = get_fs();
7170
set_fs(KERNEL_DS);
@@ -111,21 +110,12 @@ static void dump_backtrace_entry(unsigned long where)
111110
print_ip_sym(where);
112111
}
113112

114-
static void dump_instr(const char *lvl, struct pt_regs *regs)
113+
static void __dump_instr(const char *lvl, struct pt_regs *regs)
115114
{
116115
unsigned long addr = instruction_pointer(regs);
117-
mm_segment_t fs;
118116
char str[sizeof("00000000 ") * 5 + 2 + 1], *p = str;
119117
int i;
120118

121-
/*
122-
* We need to switch to kernel mode so that we can use __get_user
123-
* to safely read from kernel space. Note that we now dump the
124-
* code first, just in case the backtrace kills us.
125-
*/
126-
fs = get_fs();
127-
set_fs(KERNEL_DS);
128-
129119
for (i = -4; i < 1; i++) {
130120
unsigned int val, bad;
131121

@@ -139,8 +129,18 @@ static void dump_instr(const char *lvl, struct pt_regs *regs)
139129
}
140130
}
141131
printk("%sCode: %s\n", lvl, str);
132+
}
142133

143-
set_fs(fs);
134+
static void dump_instr(const char *lvl, struct pt_regs *regs)
135+
{
136+
if (!user_mode(regs)) {
137+
mm_segment_t fs = get_fs();
138+
set_fs(KERNEL_DS);
139+
__dump_instr(lvl, regs);
140+
set_fs(fs);
141+
} else {
142+
__dump_instr(lvl, regs);
143+
}
144144
}
145145

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

0 commit comments

Comments
 (0)