| From 289d07a2dc6c6b6f3e4b8a62669320d99dbe6c3d Mon Sep 17 00:00:00 2001 |
| From: Mark Rutland <mark.rutland@arm.com> |
| Date: Tue, 11 Jul 2017 15:19:22 +0100 |
| Subject: arm64: mm: abort uaccess retries upon fatal signal |
| |
| From: Mark Rutland <mark.rutland@arm.com> |
| |
| commit 289d07a2dc6c6b6f3e4b8a62669320d99dbe6c3d upstream. |
| |
| When there's a fatal signal pending, arm64's do_page_fault() |
| implementation returns 0. The intent is that we'll return to the |
| faulting userspace instruction, delivering the signal on the way. |
| |
| However, if we take a fatal signal during fixing up a uaccess, this |
| results in a return to the faulting kernel instruction, which will be |
| instantly retried, resulting in the same fault being taken forever. As |
| the task never reaches userspace, the signal is not delivered, and the |
| task is left unkillable. While the task is stuck in this state, it can |
| inhibit the forward progress of the system. |
| |
| To avoid this, we must ensure that when a fatal signal is pending, we |
| apply any necessary fixup for a faulting kernel instruction. Thus we |
| will return to an error path, and it is up to that code to make forward |
| progress towards delivering the fatal signal. |
| |
| Cc: Catalin Marinas <catalin.marinas@arm.com> |
| Cc: Laura Abbott <labbott@redhat.com> |
| Reviewed-by: Steve Capper <steve.capper@arm.com> |
| Tested-by: Steve Capper <steve.capper@arm.com> |
| Reviewed-by: James Morse <james.morse@arm.com> |
| Tested-by: James Morse <james.morse@arm.com> |
| Signed-off-by: Mark Rutland <mark.rutland@arm.com> |
| Signed-off-by: Will Deacon <will.deacon@arm.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| arch/arm64/mm/fault.c | 5 ++++- |
| 1 file changed, 4 insertions(+), 1 deletion(-) |
| |
| --- a/arch/arm64/mm/fault.c |
| +++ b/arch/arm64/mm/fault.c |
| @@ -313,8 +313,11 @@ retry: |
| * signal first. We do not need to release the mmap_sem because it |
| * would already be released in __lock_page_or_retry in mm/filemap.c. |
| */ |
| - if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current)) |
| + if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current)) { |
| + if (!user_mode(regs)) |
| + goto no_context; |
| return 0; |
| + } |
| |
| /* |
| * Major/minor page fault accounting is only done on the initial |