Skip to content

Commit 1a8d05a

Browse files
committed
Merge tag 'pull-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull VM_FAULT_RETRY fixes from Al Viro: "Some of the page fault handlers do not deal with the following case correctly: - handle_mm_fault() has returned VM_FAULT_RETRY - there is a pending fatal signal - fault had happened in kernel mode Correct action in such case is not "return unconditionally" - fatal signals are handled only upon return to userland and something like copy_to_user() would end up retrying the faulting instruction and triggering the same fault again and again. What we need to do in such case is to make the caller to treat that as failed uaccess attempt - handle exception if there is an exception handler for faulting instruction or oops if there isn't one. Over the years some architectures had been fixed and now are handling that case properly; some still do not. This series should fix the remaining ones. Status: - m68k, riscv, hexagon, parisc: tested/acked by maintainers. - alpha, sparc32, sparc64: tested locally - bug has been reproduced on the unpatched kernel and verified to be fixed by this series. - ia64, microblaze, nios2, openrisc: build, but otherwise completely untested" * tag 'pull-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: openrisc: fix livelock in uaccess nios2: fix livelock in uaccess microblaze: fix livelock in uaccess ia64: fix livelock in uaccess sparc: fix livelock in uaccess alpha: fix livelock in uaccess parisc: fix livelock in uaccess hexagon: fix livelock in uaccess riscv: fix livelock in uaccess m68k: fix livelock in uaccess
2 parents 95207db + caa82ae commit 1a8d05a

File tree

11 files changed

+48
-11
lines changed

11 files changed

+48
-11
lines changed

arch/alpha/mm/fault.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,8 +152,11 @@ do_page_fault(unsigned long address, unsigned long mmcsr,
152152
the fault. */
153153
fault = handle_mm_fault(vma, address, flags, regs);
154154

155-
if (fault_signal_pending(fault, regs))
155+
if (fault_signal_pending(fault, regs)) {
156+
if (!user_mode(regs))
157+
goto no_context;
156158
return;
159+
}
157160

158161
/* The fault is fully completed (including releasing mmap lock) */
159162
if (fault & VM_FAULT_COMPLETED)

arch/hexagon/mm/vm_fault.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,11 @@ void do_page_fault(unsigned long address, long cause, struct pt_regs *regs)
9393

9494
fault = handle_mm_fault(vma, address, flags, regs);
9595

96-
if (fault_signal_pending(fault, regs))
96+
if (fault_signal_pending(fault, regs)) {
97+
if (!user_mode(regs))
98+
goto no_context;
9799
return;
100+
}
98101

99102
/* The fault is fully completed (including releasing mmap lock) */
100103
if (fault & VM_FAULT_COMPLETED)

arch/ia64/mm/fault.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,11 @@ ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *re
136136
*/
137137
fault = handle_mm_fault(vma, address, flags, regs);
138138

139-
if (fault_signal_pending(fault, regs))
139+
if (fault_signal_pending(fault, regs)) {
140+
if (!user_mode(regs))
141+
goto no_context;
140142
return;
143+
}
141144

142145
/* The fault is fully completed (including releasing mmap lock) */
143146
if (fault & VM_FAULT_COMPLETED)

arch/m68k/mm/fault.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,8 +138,11 @@ int do_page_fault(struct pt_regs *regs, unsigned long address,
138138
fault = handle_mm_fault(vma, address, flags, regs);
139139
pr_debug("handle_mm_fault returns %x\n", fault);
140140

141-
if (fault_signal_pending(fault, regs))
141+
if (fault_signal_pending(fault, regs)) {
142+
if (!user_mode(regs))
143+
goto no_context;
142144
return 0;
145+
}
143146

144147
/* The fault is fully completed (including releasing mmap lock) */
145148
if (fault & VM_FAULT_COMPLETED)

arch/microblaze/mm/fault.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,8 +219,11 @@ void do_page_fault(struct pt_regs *regs, unsigned long address,
219219
*/
220220
fault = handle_mm_fault(vma, address, flags, regs);
221221

222-
if (fault_signal_pending(fault, regs))
222+
if (fault_signal_pending(fault, regs)) {
223+
if (!user_mode(regs))
224+
bad_page_fault(regs, address, SIGBUS);
223225
return;
226+
}
224227

225228
/* The fault is fully completed (including releasing mmap lock) */
226229
if (fault & VM_FAULT_COMPLETED)

arch/nios2/mm/fault.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,11 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long cause,
136136
*/
137137
fault = handle_mm_fault(vma, address, flags, regs);
138138

139-
if (fault_signal_pending(fault, regs))
139+
if (fault_signal_pending(fault, regs)) {
140+
if (!user_mode(regs))
141+
goto no_context;
140142
return;
143+
}
141144

142145
/* The fault is fully completed (including releasing mmap lock) */
143146
if (fault & VM_FAULT_COMPLETED)

arch/openrisc/mm/fault.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,8 +162,11 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long address,
162162

163163
fault = handle_mm_fault(vma, address, flags, regs);
164164

165-
if (fault_signal_pending(fault, regs))
165+
if (fault_signal_pending(fault, regs)) {
166+
if (!user_mode(regs))
167+
goto no_context;
166168
return;
169+
}
167170

168171
/* The fault is fully completed (including releasing mmap lock) */
169172
if (fault & VM_FAULT_COMPLETED)

arch/parisc/mm/fault.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -308,8 +308,13 @@ void do_page_fault(struct pt_regs *regs, unsigned long code,
308308

309309
fault = handle_mm_fault(vma, address, flags, regs);
310310

311-
if (fault_signal_pending(fault, regs))
311+
if (fault_signal_pending(fault, regs)) {
312+
if (!user_mode(regs)) {
313+
msg = "Page fault: fault signal on kernel memory";
314+
goto no_context;
315+
}
312316
return;
317+
}
313318

314319
/* The fault is fully completed (including releasing mmap lock) */
315320
if (fault & VM_FAULT_COMPLETED)

arch/riscv/mm/fault.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -326,8 +326,11 @@ asmlinkage void do_page_fault(struct pt_regs *regs)
326326
* signal first. We do not need to release the mmap_lock because it
327327
* would already be released in __lock_page_or_retry in mm/filemap.c.
328328
*/
329-
if (fault_signal_pending(fault, regs))
329+
if (fault_signal_pending(fault, regs)) {
330+
if (!user_mode(regs))
331+
no_context(regs, addr);
330332
return;
333+
}
331334

332335
/* The fault is fully completed (including releasing mmap lock) */
333336
if (fault & VM_FAULT_COMPLETED)

arch/sparc/mm/fault_32.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,8 +187,11 @@ asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write,
187187
*/
188188
fault = handle_mm_fault(vma, address, flags, regs);
189189

190-
if (fault_signal_pending(fault, regs))
190+
if (fault_signal_pending(fault, regs)) {
191+
if (!from_user)
192+
goto no_context;
191193
return;
194+
}
192195

193196
/* The fault is fully completed (including releasing mmap lock) */
194197
if (fault & VM_FAULT_COMPLETED)

arch/sparc/mm/fault_64.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -424,8 +424,13 @@ asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs)
424424

425425
fault = handle_mm_fault(vma, address, flags, regs);
426426

427-
if (fault_signal_pending(fault, regs))
427+
if (fault_signal_pending(fault, regs)) {
428+
if (regs->tstate & TSTATE_PRIV) {
429+
insn = get_fault_insn(regs, insn);
430+
goto handle_kernel_fault;
431+
}
428432
goto exit_exception;
433+
}
429434

430435
/* The fault is fully completed (including releasing mmap lock) */
431436
if (fault & VM_FAULT_COMPLETED)

0 commit comments

Comments
 (0)