forked from mirrors/linux
		
	/dev/mem: Add bounce buffer for copy-out
As done for /proc/kcore in commitdf04abfd18("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:f5509cc18d("mm: Hardened usercopy") Signed-off-by: Kees Cook <keescook@chromium.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
		
							parent
							
								
									d9cc5a0edb
								
							
						
					
					
						commit
						22ec1a2aea
					
				
					 2 changed files with 23 additions and 5 deletions
				
			
		|  | @ -107,6 +107,8 @@ static ssize_t read_mem(struct file *file, char __user *buf, | |||
| 	phys_addr_t p = *ppos; | ||||
| 	ssize_t read, sz; | ||||
| 	void *ptr; | ||||
| 	char *bounce; | ||||
| 	int err; | ||||
| 
 | ||||
| 	if (p != *ppos) | ||||
| 		return 0; | ||||
|  | @ -129,15 +131,22 @@ static ssize_t read_mem(struct file *file, char __user *buf, | |||
| 	} | ||||
| #endif | ||||
| 
 | ||||
| 	bounce = kmalloc(PAGE_SIZE, GFP_KERNEL); | ||||
| 	if (!bounce) | ||||
| 		return -ENOMEM; | ||||
| 
 | ||||
| 	while (count > 0) { | ||||
| 		unsigned long remaining; | ||||
| 		int allowed; | ||||
| 
 | ||||
| 		sz = size_inside_page(p, count); | ||||
| 
 | ||||
| 		err = -EPERM; | ||||
| 		allowed = page_is_allowed(p >> PAGE_SHIFT); | ||||
| 		if (!allowed) | ||||
| 			return -EPERM; | ||||
| 			goto failed; | ||||
| 
 | ||||
| 		err = -EFAULT; | ||||
| 		if (allowed == 2) { | ||||
| 			/* Show zeros for restricted memory. */ | ||||
| 			remaining = clear_user(buf, sz); | ||||
|  | @ -149,24 +158,32 @@ static ssize_t read_mem(struct file *file, char __user *buf, | |||
| 			 */ | ||||
| 			ptr = xlate_dev_mem_ptr(p); | ||||
| 			if (!ptr) | ||||
| 				return -EFAULT; | ||||
| 
 | ||||
| 			remaining = copy_to_user(buf, ptr, sz); | ||||
| 				goto failed; | ||||
| 
 | ||||
| 			err = probe_kernel_read(bounce, ptr, sz); | ||||
| 			unxlate_dev_mem_ptr(p, ptr); | ||||
| 			if (err) | ||||
| 				goto failed; | ||||
| 
 | ||||
| 			remaining = copy_to_user(buf, bounce, sz); | ||||
| 		} | ||||
| 
 | ||||
| 		if (remaining) | ||||
| 			return -EFAULT; | ||||
| 			goto failed; | ||||
| 
 | ||||
| 		buf += sz; | ||||
| 		p += sz; | ||||
| 		count -= sz; | ||||
| 		read += sz; | ||||
| 	} | ||||
| 	kfree(bounce); | ||||
| 
 | ||||
| 	*ppos += read; | ||||
| 	return read; | ||||
| 
 | ||||
| failed: | ||||
| 	kfree(bounce); | ||||
| 	return err; | ||||
| } | ||||
| 
 | ||||
| static ssize_t write_mem(struct file *file, const char __user *buf, | ||||
|  |  | |||
|  | @ -143,6 +143,7 @@ config HARDENED_USERCOPY | |||
| 	bool "Harden memory copies between kernel and userspace" | ||||
| 	depends on HAVE_HARDENED_USERCOPY_ALLOCATOR | ||||
| 	select BUG | ||||
| 	imply STRICT_DEVMEM | ||||
| 	help | ||||
| 	  This option checks for obviously wrong memory regions when | ||||
| 	  copying memory to/from the kernel (via copy_to_user() and | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Kees Cook
						Kees Cook