From f75b1b1bedfb498cc43a992ce4d7ed8df3b1e770 Mon Sep 17 00:00:00 2001 From: Richard Weinberger Date: Sat, 17 Aug 2013 18:46:00 +0200 Subject: um: Implement probe_kernel_read() UML needs it's own probe_kernel_read() to handle kernel mode faults correctly. The implementation uses mincore() on the host side to detect whether a page is owned by the UML kernel process. This fixes also a possible crash when sysrq-t is used. Starting with 3.10 sysrq-t calls probe_kernel_read() to read details from the kernel workers. As kernel worker are completely async pointers may turn NULL while reading them. Cc: Cc: Cc: # 3.10.x Signed-off-by: Richard Weinberger --- arch/um/os-Linux/process.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) (limited to 'arch/um/os-Linux/process.c') diff --git a/arch/um/os-Linux/process.c b/arch/um/os-Linux/process.c index b8f34c9e53ae..67b9c8f5a89e 100644 --- a/arch/um/os-Linux/process.c +++ b/arch/um/os-Linux/process.c @@ -4,6 +4,7 @@ */ #include +#include #include #include #include @@ -232,6 +233,57 @@ out: return ok; } +static int os_page_mincore(void *addr) +{ + char vec[2]; + int ret; + + ret = mincore(addr, UM_KERN_PAGE_SIZE, vec); + if (ret < 0) { + if (errno == ENOMEM || errno == EINVAL) + return 0; + else + return -errno; + } + + return vec[0] & 1; +} + +int os_mincore(void *addr, unsigned long len) +{ + char *vec; + int ret, i; + + if (len <= UM_KERN_PAGE_SIZE) + return os_page_mincore(addr); + + vec = calloc(1, (len + UM_KERN_PAGE_SIZE - 1) / UM_KERN_PAGE_SIZE); + if (!vec) + return -ENOMEM; + + ret = mincore(addr, UM_KERN_PAGE_SIZE, vec); + if (ret < 0) { + if (errno == ENOMEM || errno == EINVAL) + ret = 0; + else + ret = -errno; + + goto out; + } + + for (i = 0; i < ((len + UM_KERN_PAGE_SIZE - 1) / UM_KERN_PAGE_SIZE); i++) { + if (!(vec[i] & 1)) { + ret = 0; + goto out; + } + } + + ret = 1; +out: + free(vec); + return ret; +} + void init_new_thread_signals(void) { set_handler(SIGSEGV); -- cgit v1.2.3-59-g8ed1b