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

/dev/mem: Add bounce buffer for copy-out

As done for /proc/kcore in

commit df04abfd181a ("fs/proc/kcore.c: Add bounce buffer for ktext data")

this adds a bounce buffer when reading memory via /dev/mem. This
is needed to allow kernel text memory to be read out when built with
CONFIG_HARDENED_USERCOPY (which refuses to read out kernel text) and
without CONFIG_STRICT_DEVMEM (which would have refused to read any RAM
contents at all).

Since this build configuration isn't common (most systems with
CONFIG_HARDENED_USERCOPY also have CONFIG_STRICT_DEVMEM), this also tries
to inform Kconfig about the recommended settings.

This patch is modified from Brad Spengler/PaX Team's changes to /dev/mem
code in the last public patch of grsecurity/PaX based on my understanding
of the code. Changes or omissions from the original code are mine and
don't reflect the original grsecurity/PaX code.

Reported-by: Michael Holzheu <holzheu@linux.vnet.ibm.com>
Fixes: f5509cc18daa ("mm: Hardened usercopy")
Signed-off-by: Kees Cook <keescook@chromium.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Kees Cook and committed by
Greg Kroah-Hartman
22ec1a2a d9cc5a0e

+23 -5
+22 -5
drivers/char/mem.c
··· 107 107 phys_addr_t p = *ppos; 108 108 ssize_t read, sz; 109 109 void *ptr; 110 + char *bounce; 111 + int err; 110 112 111 113 if (p != *ppos) 112 114 return 0; ··· 131 129 } 132 130 #endif 133 131 132 + bounce = kmalloc(PAGE_SIZE, GFP_KERNEL); 133 + if (!bounce) 134 + return -ENOMEM; 135 + 134 136 while (count > 0) { 135 137 unsigned long remaining; 136 138 int allowed; 137 139 138 140 sz = size_inside_page(p, count); 139 141 142 + err = -EPERM; 140 143 allowed = page_is_allowed(p >> PAGE_SHIFT); 141 144 if (!allowed) 142 - return -EPERM; 145 + goto failed; 146 + 147 + err = -EFAULT; 143 148 if (allowed == 2) { 144 149 /* Show zeros for restricted memory. */ 145 150 remaining = clear_user(buf, sz); ··· 158 149 */ 159 150 ptr = xlate_dev_mem_ptr(p); 160 151 if (!ptr) 161 - return -EFAULT; 152 + goto failed; 162 153 163 - remaining = copy_to_user(buf, ptr, sz); 164 - 154 + err = probe_kernel_read(bounce, ptr, sz); 165 155 unxlate_dev_mem_ptr(p, ptr); 156 + if (err) 157 + goto failed; 158 + 159 + remaining = copy_to_user(buf, bounce, sz); 166 160 } 167 161 168 162 if (remaining) 169 - return -EFAULT; 163 + goto failed; 170 164 171 165 buf += sz; 172 166 p += sz; 173 167 count -= sz; 174 168 read += sz; 175 169 } 170 + kfree(bounce); 176 171 177 172 *ppos += read; 178 173 return read; 174 + 175 + failed: 176 + kfree(bounce); 177 + return err; 179 178 } 180 179 181 180 static ssize_t write_mem(struct file *file, const char __user *buf,
+1
security/Kconfig
··· 143 143 bool "Harden memory copies between kernel and userspace" 144 144 depends on HAVE_HARDENED_USERCOPY_ALLOCATOR 145 145 select BUG 146 + imply STRICT_DEVMEM 146 147 help 147 148 This option checks for obviously wrong memory regions when 148 149 copying memory to/from the kernel (via copy_to_user() and