linux/arch/parisc/kernel
Helge Deller 8b78f26088 parisc: Fix pagefault crash in unaligned __get_user() call
One of the debian buildd servers had this crash in the syslog without
any other information:

 Unaligned handler failed, ret = -2
 clock_adjtime (pid 22578): Unaligned data reference (code 28)
 CPU: 1 PID: 22578 Comm: clock_adjtime Tainted: G  E  4.5.0-2-parisc64-smp #1 Debian 4.5.4-1
 task: 000000007d9960f8 ti: 00000001bde7c000 task.ti: 00000001bde7c000

      YZrvWESTHLNXBCVMcbcbcbcbOGFRQPDI
 PSW: 00001000000001001111100000001111 Tainted: G            E
 r00-03  000000ff0804f80f 00000001bde7c2b0 00000000402d2be8 00000001bde7c2b0
 r04-07  00000000409e1fd0 00000000fa6f7fff 00000001bde7c148 00000000fa6f7fff
 r08-11  0000000000000000 00000000ffffffff 00000000fac9bb7b 000000000002b4d4
 r12-15  000000000015241c 000000000015242c 000000000000002d 00000000fac9bb7b
 r16-19  0000000000028800 0000000000000001 0000000000000070 00000001bde7c218
 r20-23  0000000000000000 00000001bde7c210 0000000000000002 0000000000000000
 r24-27  0000000000000000 0000000000000000 00000001bde7c148 00000000409e1fd0
 r28-31  0000000000000001 00000001bde7c320 00000001bde7c350 00000001bde7c218
 sr00-03  0000000001200000 0000000001200000 0000000000000000 0000000001200000
 sr04-07  0000000000000000 0000000000000000 0000000000000000 0000000000000000

 IASQ: 0000000000000000 0000000000000000 IAOQ: 00000000402d2e84 00000000402d2e88
  IIR: 0ca0d089    ISR: 0000000001200000  IOR: 00000000fa6f7fff
  CPU:        1   CR30: 00000001bde7c000 CR31: ffffffffffffffff
  ORIG_R28: 00000002369fe628
  IAOQ[0]: compat_get_timex+0x2dc/0x3c0
  IAOQ[1]: compat_get_timex+0x2e0/0x3c0
  RP(r2): compat_get_timex+0x40/0x3c0
 Backtrace:
  [<00000000402d4608>] compat_SyS_clock_adjtime+0x40/0xc0
  [<0000000040205024>] syscall_exit+0x0/0x14

This means the userspace program clock_adjtime called the clock_adjtime()
syscall and then crashed inside the compat_get_timex() function.
Syscalls should never crash programs, but instead return EFAULT.

The IIR register contains the executed instruction, which disassebles
into "ldw 0(sr3,r5),r9".
This load-word instruction is part of __get_user() which tried to read the word
at %r5/IOR (0xfa6f7fff). This means the unaligned handler jumped in.  The
unaligned handler is able to emulate all ldw instructions, but it fails if it
fails to read the source e.g. because of page fault.

The following program reproduces the problem:

#define _GNU_SOURCE
#include <unistd.h>
#include <sys/syscall.h>
#include <sys/mman.h>

int main(void) {
        /* allocate 8k */
        char *ptr = mmap(NULL, 2*4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
        /* free second half (upper 4k) and make it invalid. */
        munmap(ptr+4096, 4096);
        /* syscall where first int is unaligned and clobbers into invalid memory region */
        /* syscall should return EFAULT */
        return syscall(__NR_clock_adjtime, 0, ptr+4095);
}

To fix this issue we simply need to check if the faulting instruction address
is in the exception fixup table when the unaligned handler failed. If it
is, call the fixup routine instead of crashing.

While looking at the unaligned handler I found another issue as well: The
target register should not be modified if the handler was unsuccessful.

Signed-off-by: Helge Deller <deller@gmx.de>
Cc: stable@vger.kernel.org
2016-06-05 08:48:24 +02:00
..
.gitignore
asm-offsets.c parisc: Unbreak handling exceptions from kernel modules 2016-04-08 22:14:14 +02:00
audit.c parisc: add kernel audit feature 2013-11-07 22:27:20 +01:00
binfmt_elf32.c parisc: fix redefinition of SET_PERSONALITY 2013-03-02 20:15:28 +01:00
cache.c mm, fs: get rid of PAGE_CACHE_* and page_cache_{get,release} macros 2016-04-04 10:41:08 -07:00
compat_audit.c parisc: add kernel audit feature 2013-11-07 22:27:20 +01:00
drivers.c parisc: convert to dma_map_ops 2016-01-20 17:09:18 -08:00
entry.S parisc: Use long jump to reach ftrace_return_to_handler() 2016-05-23 23:44:44 +02:00
firmware.c parisc: delete __cpuinit usage from all users 2013-07-14 19:36:51 -04:00
ftrace.c parisc: Merge ftrace C-helper and assembler functions into .text.hot section 2016-05-22 21:46:21 +02:00
hardware.c parisc: add serial ports of C8000/1GHz machine to hardware database 2014-07-13 15:51:58 +02:00
head.S parisc: Fix ftrace function tracer 2016-04-14 17:47:19 +02:00
hpmc.S parisc: fix partly 16/64k PAGE_SIZE boot 2013-05-06 23:08:32 +02:00
inventory.c parisc: Fix interrupt routing for C8000 serial ports 2013-07-31 23:42:32 +02:00
irq.c parisc: Filter out spurious interrupts in PA-RISC irq handler 2015-09-08 15:31:16 +02:00
Makefile parisc: Fix ftrace function tracer 2016-04-14 17:47:19 +02:00
module.c parisc: Handle R_PARISC_PCREL32 relocations in kernel modules 2016-04-08 22:10:35 +02:00
pa7300lc.c
pacache.S parisc: Use unshadowed index register for flush instructions in flush_dcache_page_asm and flush_icache_page_asm 2013-06-18 20:29:10 +02:00
parisc_ksyms.c parisc: Avoid function pointers for kernel exception routines 2016-04-08 22:13:45 +02:00
pci-dma.c parisc: convert to dma_map_ops 2016-01-20 17:09:18 -08:00
pci.c parisc: Initialize PCI bridge cache line and default latency 2016-01-12 22:03:21 +01:00
pdc_chassis.c parisc: single_open() leaks 2013-05-05 00:10:41 -04:00
pdc_cons.c parisc: don't use module_init for non-modular core pdc_cons code 2015-06-16 14:12:30 -04:00
perf_asm.S
perf_images.h
perf.c parisc64: don't use module_init for non-modular core perf code 2015-06-16 14:12:30 -04:00
process.c exit_thread: remove empty bodies 2016-05-20 17:58:30 -07:00
processor.c parisc: Fix printk time during boot 2016-06-05 08:45:09 +02:00
ptrace.c parisc: Add ARCH_TRACEHOOK and regset support 2016-05-22 21:39:13 +02:00
real2.S parisc: move pdc_result to real2.S 2008-10-10 16:32:28 +00:00
setup.c parisc: Add Huge Page and HUGETLBFS support 2015-11-22 12:23:10 +01:00
signal32.c parisc: Fix SIGSYS signals in compat case 2016-03-31 12:28:37 +02:00
signal32.h constify copy_siginfo_to_user{,32}() 2013-11-09 00:16:29 -05:00
signal.c parisc: Fix syscall restarts 2015-12-21 10:16:18 +01:00
smp.c arch/hotplug: Call into idle with a proper state 2016-03-01 20:36:57 +01:00
stacktrace.c parisc: add LATENCYTOP_SUPPORT and CONFIG_STACKTRACE_SUPPORT 2009-03-31 02:51:34 +00:00
sys_parisc32.c parisc: drop unused defines and header includes 2014-07-13 15:56:12 +02:00
sys_parisc.c parisc: Drop alloc_hugepages and free_hugepages syscalls 2016-03-23 15:42:18 +01:00
syscall_table.S parisc: Wire up preadv2 and pwritev2 syscalls 2016-03-23 16:22:42 +01:00
syscall.S parisc: Add syscall tracepoint support 2016-05-22 21:38:47 +02:00
time.c parisc: Fix printk time during boot 2016-06-05 08:45:09 +02:00
topology.c parisc: Replace NR_CPUS in parisc code 2009-01-05 19:09:02 +00:00
traps.c parisc: Fix kernel crash with reversed copy_from_user() 2016-04-08 22:14:04 +02:00
unaligned.c parisc: Fix pagefault crash in unaligned __get_user() call 2016-06-05 08:48:24 +02:00
unwind.c parisc: Fix backtrace on PA-RISC 2016-06-04 22:05:07 +02:00
vmlinux.lds.S arch, ftrace: for KASAN put hard/soft IRQ entries into separate sections 2016-03-25 16:37:42 -07:00