Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932346Ab3IYAYt (ORCPT ); Tue, 24 Sep 2013 20:24:49 -0400 Received: from mail.linuxfoundation.org ([140.211.169.12]:39830 "EHLO mail.linuxfoundation.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932374Ab3IYAVH (ORCPT ); Tue, 24 Sep 2013 20:21:07 -0400 From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Richard Weinberger , stian@nixia.no, tj@kernel.org Subject: [ 105/117] um: Implement probe_kernel_read() Date: Tue, 24 Sep 2013 17:19:31 -0700 Message-Id: <20130925001752.389676652@linuxfoundation.org> X-Mailer: git-send-email 1.8.4.3.gca3854a In-Reply-To: <20130925001740.833541979@linuxfoundation.org> References: <20130925001740.833541979@linuxfoundation.org> User-Agent: quilt/0.60-5.1.1 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 3974 Lines: 153 3.11-stable review patch. If anyone has any objections, please let me know. ------------------ From: Richard Weinberger commit f75b1b1bedfb498cc43a992ce4d7ed8df3b1e770 upstream. 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. Signed-off-by: Richard Weinberger Cc: Cc: Signed-off-by: Greg Kroah-Hartman --- arch/um/include/shared/os.h | 1 arch/um/kernel/Makefile | 2 - arch/um/kernel/maccess.c | 24 ++++++++++++++++++++ arch/um/os-Linux/process.c | 52 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 78 insertions(+), 1 deletion(-) --- a/arch/um/include/shared/os.h +++ b/arch/um/include/shared/os.h @@ -200,6 +200,7 @@ extern int os_unmap_memory(void *addr, i extern int os_drop_memory(void *addr, int length); extern int can_drop_memory(void); extern void os_flush_stdout(void); +extern int os_mincore(void *addr, unsigned long len); /* execvp.c */ extern int execvp_noalloc(char *buf, const char *file, char *const argv[]); --- a/arch/um/kernel/Makefile +++ b/arch/um/kernel/Makefile @@ -13,7 +13,7 @@ clean-files := obj-y = config.o exec.o exitcode.o irq.o ksyms.o mem.o \ physmem.o process.o ptrace.o reboot.o sigio.o \ signal.o smp.o syscall.o sysrq.o time.o tlb.o trap.o \ - um_arch.o umid.o skas/ + um_arch.o umid.o maccess.o skas/ obj-$(CONFIG_BLK_DEV_INITRD) += initrd.o obj-$(CONFIG_GPROF) += gprof_syms.o --- /dev/null +++ b/arch/um/kernel/maccess.c @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2013 Richard Weinberger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include + +long probe_kernel_read(void *dst, const void *src, size_t size) +{ + void *psrc = (void *)rounddown((unsigned long)src, PAGE_SIZE); + + if ((unsigned long)src < PAGE_SIZE || size <= 0) + return -EFAULT; + + if (os_mincore(psrc, size + src - psrc) <= 0) + return -EFAULT; + + return __probe_kernel_read(dst, src, size); +} --- 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); -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/