Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

uaccess: reimplement probe_kernel_address() using probe_kernel_read()

probe_kernel_address() is basically the same as the (later added)
probe_kernel_read().

The return value on EFAULT is a bit different: probe_kernel_address()
returns number-of-bytes-not-copied whereas probe_kernel_read() returns
-EFAULT. All callers have been checked, none cared.

probe_kernel_read() can be overridden by the architecture whereas
probe_kernel_address() cannot. parisc, blackfin and um do this, to insert
additional checking. Hence this patch possibly fixes obscure bugs,
although there are only two probe_kernel_address() callsites outside
arch/.

My first attempt involved removing probe_kernel_address() entirely and
converting all callsites to use probe_kernel_read() directly, but that got
tiresome.

This patch shrinks mm/slab_common.o by 218 bytes. For a single
probe_kernel_address() callsite.

Cc: Steven Miao <realmz6@gmail.com>
Cc: Jeff Dike <jdike@addtoit.com>
Cc: Richard Weinberger <richard@nod.at>
Cc: "James E.J. Bottomley" <jejb@parisc-linux.org>
Cc: Helge Deller <deller@gmx.de>
Cc: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Andrew Morton and committed by
Linus Torvalds
0ab32b6f 86d2adcc

+17 -32
+1 -1
arch/arm/mm/alignment.c
··· 803 803 } 804 804 } 805 805 } else { 806 - fault = probe_kernel_address(instrptr, instr); 806 + fault = probe_kernel_address((void *)instrptr, instr); 807 807 instr = __mem_to_opcode_arm(instr); 808 808 } 809 809
+1 -1
arch/powerpc/sysdev/fsl_pci.c
··· 999 999 ret = get_user(regs->nip, &inst); 1000 1000 pagefault_enable(); 1001 1001 } else { 1002 - ret = probe_kernel_address(regs->nip, inst); 1002 + ret = probe_kernel_address((void *)regs->nip, inst); 1003 1003 } 1004 1004 1005 1005 if (mcheck_handle_load(regs, inst)) {
+10 -30
include/linux/uaccess.h
··· 75 75 76 76 #endif /* ARCH_HAS_NOCACHE_UACCESS */ 77 77 78 - /** 79 - * probe_kernel_address(): safely attempt to read from a location 80 - * @addr: address to read from - its type is type typeof(retval)* 81 - * @retval: read into this variable 82 - * 83 - * Safely read from address @addr into variable @revtal. If a kernel fault 84 - * happens, handle that and return -EFAULT. 85 - * We ensure that the __get_user() is executed in atomic context so that 86 - * do_page_fault() doesn't attempt to take mmap_sem. This makes 87 - * probe_kernel_address() suitable for use within regions where the caller 88 - * already holds mmap_sem, or other locks which nest inside mmap_sem. 89 - * This must be a macro because __get_user() needs to know the types of the 90 - * args. 91 - * 92 - * We don't include enough header files to be able to do the set_fs(). We 93 - * require that the probe_kernel_address() caller will do that. 94 - */ 95 - #define probe_kernel_address(addr, retval) \ 96 - ({ \ 97 - long ret; \ 98 - mm_segment_t old_fs = get_fs(); \ 99 - \ 100 - set_fs(KERNEL_DS); \ 101 - pagefault_disable(); \ 102 - ret = __copy_from_user_inatomic(&(retval), (__force typeof(retval) __user *)(addr), sizeof(retval)); \ 103 - pagefault_enable(); \ 104 - set_fs(old_fs); \ 105 - ret; \ 106 - }) 107 - 108 78 /* 109 79 * probe_kernel_read(): safely attempt to read from a location 110 80 * @dst: pointer to the buffer that shall take the data ··· 100 130 extern long notrace __probe_kernel_write(void *dst, const void *src, size_t size); 101 131 102 132 extern long strncpy_from_unsafe(char *dst, const void *unsafe_addr, long count); 133 + 134 + /** 135 + * probe_kernel_address(): safely attempt to read from a location 136 + * @addr: address to read from 137 + * @retval: read into this variable 138 + * 139 + * Returns 0 on success, or -EFAULT. 140 + */ 141 + #define probe_kernel_address(addr, retval) \ 142 + probe_kernel_read(&retval, addr, sizeof(retval)) 103 143 104 144 #endif /* __LINUX_UACCESS_H__ */
+5
mm/maccess.c
··· 13 13 * 14 14 * Safely read from address @src to the buffer at @dst. If a kernel fault 15 15 * happens, handle that and return -EFAULT. 16 + * 17 + * We ensure that the copy_from_user is executed in atomic context so that 18 + * do_page_fault() doesn't attempt to take mmap_sem. This makes 19 + * probe_kernel_read() suitable for use within regions where the caller 20 + * already holds mmap_sem, or other locks which nest inside mmap_sem. 16 21 */ 17 22 18 23 long __weak probe_kernel_read(void *dst, const void *src, size_t size)