Skip to content

Commit 4d5b67a

Browse files
mrutland-armgregkh
authored andcommitted
ARM: 8720/1: ensure dump_instr() checks addr_limit
commit b9dd05c7002ee0ca8b676428b2268c26399b5e31 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: Mark Rutland <mark.rutland@arm.com> Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 3fc61b8 commit 4d5b67a

1 file changed

Lines changed: 18 additions & 10 deletions

File tree

arch/arm/kernel/traps.c

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -132,30 +132,26 @@ static void dump_mem(const char *lvl, const char *str, unsigned long bottom,
132132
set_fs(fs);
133133
}
134134

135-
static void dump_instr(const char *lvl, struct pt_regs *regs)
135+
static void __dump_instr(const char *lvl, struct pt_regs *regs)
136136
{
137137
unsigned long addr = instruction_pointer(regs);
138138
const int thumb = thumb_mode(regs);
139139
const int width = thumb ? 4 : 8;
140-
mm_segment_t fs;
141140
char str[sizeof("00000000 ") * 5 + 2 + 1], *p = str;
142141
int i;
143142

144143
/*
145-
* We need to switch to kernel mode so that we can use __get_user
146-
* to safely read from kernel space. Note that we now dump the
147-
* code first, just in case the backtrace kills us.
144+
* Note that we now dump the code first, just in case the backtrace
145+
* kills us.
148146
*/
149-
fs = get_fs();
150-
set_fs(KERNEL_DS);
151147

152148
for (i = -4; i < 1 + !!thumb; i++) {
153149
unsigned int val, bad;
154150

155151
if (thumb)
156-
bad = __get_user(val, &((u16 *)addr)[i]);
152+
bad = get_user(val, &((u16 *)addr)[i]);
157153
else
158-
bad = __get_user(val, &((u32 *)addr)[i]);
154+
bad = get_user(val, &((u32 *)addr)[i]);
159155

160156
if (!bad)
161157
p += sprintf(p, i == 0 ? "(%0*x) " : "%0*x ",
@@ -166,8 +162,20 @@ static void dump_instr(const char *lvl, struct pt_regs *regs)
166162
}
167163
}
168164
printk("%sCode: %s\n", lvl, str);
165+
}
169166

170-
set_fs(fs);
167+
static void dump_instr(const char *lvl, struct pt_regs *regs)
168+
{
169+
mm_segment_t fs;
170+
171+
if (!user_mode(regs)) {
172+
fs = get_fs();
173+
set_fs(KERNEL_DS);
174+
__dump_instr(lvl, regs);
175+
set_fs(fs);
176+
} else {
177+
__dump_instr(lvl, regs);
178+
}
171179
}
172180

173181
#ifdef CONFIG_ARM_UNWIND

0 commit comments

Comments
 (0)