Skip to content

Commit 344179f

Browse files
arndbRussell King (Oracle)
authored andcommitted
ARM: 9106/1: traps: use get_kernel_nofault instead of set_fs()
ARM uses set_fs() and __get_user() to allow the stack dumping code to access possibly invalid pointers carefully. These can be changed to the simpler get_kernel_nofault(), and allow the eventual removal of set_fs(). dump_instr() will print either kernel or user space pointers, depending on how it was called. For dump_mem(), I assume we are only interested in kernel pointers, and the only time that this is called with user_mode(regs)==true is when the regs themselves are unreliable as a result of the condition that caused the trap. Reviewed-by: Christoph Hellwig <[email protected]> Reviewed-by: Linus Walleij <[email protected]> Signed-off-by: Arnd Bergmann <[email protected]> Signed-off-by: Russell King (Oracle) <[email protected]>
1 parent 2423de2 commit 344179f

File tree

1 file changed

+16
-31
lines changed

1 file changed

+16
-31
lines changed

arch/arm/kernel/traps.c

Lines changed: 16 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -122,17 +122,8 @@ static void dump_mem(const char *lvl, const char *str, unsigned long bottom,
122122
unsigned long top)
123123
{
124124
unsigned long first;
125-
mm_segment_t fs;
126125
int i;
127126

128-
/*
129-
* We need to switch to kernel mode so that we can use __get_user
130-
* to safely read from kernel space. Note that we now dump the
131-
* code first, just in case the backtrace kills us.
132-
*/
133-
fs = get_fs();
134-
set_fs(KERNEL_DS);
135-
136127
printk("%s%s(0x%08lx to 0x%08lx)\n", lvl, str, bottom, top);
137128

138129
for (first = bottom & ~31; first < top; first += 32) {
@@ -145,19 +136,17 @@ static void dump_mem(const char *lvl, const char *str, unsigned long bottom,
145136
for (p = first, i = 0; i < 8 && p < top; i++, p += 4) {
146137
if (p >= bottom && p < top) {
147138
unsigned long val;
148-
if (__get_user(val, (unsigned long *)p) == 0)
139+
if (get_kernel_nofault(val, (unsigned long *)p))
149140
sprintf(str + i * 9, " %08lx", val);
150141
else
151142
sprintf(str + i * 9, " ????????");
152143
}
153144
}
154145
printk("%s%04lx:%s\n", lvl, first & 0xffff, str);
155146
}
156-
157-
set_fs(fs);
158147
}
159148

160-
static void __dump_instr(const char *lvl, struct pt_regs *regs)
149+
static void dump_instr(const char *lvl, struct pt_regs *regs)
161150
{
162151
unsigned long addr = instruction_pointer(regs);
163152
const int thumb = thumb_mode(regs);
@@ -173,10 +162,20 @@ static void __dump_instr(const char *lvl, struct pt_regs *regs)
173162
for (i = -4; i < 1 + !!thumb; i++) {
174163
unsigned int val, bad;
175164

176-
if (thumb)
177-
bad = get_user(val, &((u16 *)addr)[i]);
178-
else
179-
bad = get_user(val, &((u32 *)addr)[i]);
165+
if (!user_mode(regs)) {
166+
if (thumb) {
167+
u16 val16;
168+
bad = get_kernel_nofault(val16, &((u16 *)addr)[i]);
169+
val = val16;
170+
} else {
171+
bad = get_kernel_nofault(val, &((u32 *)addr)[i]);
172+
}
173+
} else {
174+
if (thumb)
175+
bad = get_user(val, &((u16 *)addr)[i]);
176+
else
177+
bad = get_user(val, &((u32 *)addr)[i]);
178+
}
180179

181180
if (!bad)
182181
p += sprintf(p, i == 0 ? "(%0*x) " : "%0*x ",
@@ -189,20 +188,6 @@ static void __dump_instr(const char *lvl, struct pt_regs *regs)
189188
printk("%sCode: %s\n", lvl, str);
190189
}
191190

192-
static void dump_instr(const char *lvl, struct pt_regs *regs)
193-
{
194-
mm_segment_t fs;
195-
196-
if (!user_mode(regs)) {
197-
fs = get_fs();
198-
set_fs(KERNEL_DS);
199-
__dump_instr(lvl, regs);
200-
set_fs(fs);
201-
} else {
202-
__dump_instr(lvl, regs);
203-
}
204-
}
205-
206191
#ifdef CONFIG_ARM_UNWIND
207192
static inline void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk,
208193
const char *loglvl)

0 commit comments

Comments
 (0)