All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jiri Slaby <jslaby@suse.cz>
To: stable@vger.kernel.org
Cc: Kees Cook <keescook@chromium.org>,
	Brad Spengler <spender@grsecurity.net>,
	Jiri Slaby <jslaby@suse.cz>
Subject: [patch added to 3.12-stable] mm: Tighten x86 /dev/mem with zeroing reads
Date: Wed,  3 May 2017 14:22:40 +0200	[thread overview]
Message-ID: <20170503122327.12095-2-jslaby@suse.cz> (raw)
In-Reply-To: <20170503122327.12095-1-jslaby@suse.cz>

From: Kees Cook <keescook@chromium.org>

This patch has been added to the 3.12 stable tree. If you have any
objections, please let us know.

===============

commit a4866aa812518ed1a37d8ea0c881dc946409de94 upstream.

Under CONFIG_STRICT_DEVMEM, reading System RAM through /dev/mem is
disallowed. However, on x86, the first 1MB was always allowed for BIOS
and similar things, regardless of it actually being System RAM. It was
possible for heap to end up getting allocated in low 1MB RAM, and then
read by things like x86info or dd, which would trip hardened usercopy:

usercopy: kernel memory exposure attempt detected from ffff880000090000 (dma-kmalloc-256) (4096 bytes)

This changes the x86 exception for the low 1MB by reading back zeros for
System RAM areas instead of blindly allowing them. More work is needed to
extend this to mmap, but currently mmap doesn't go through usercopy, so
hardened usercopy won't Oops the kernel.

Reported-by: Tommi Rantala <tommi.t.rantala@nokia.com>
Tested-by: Tommi Rantala <tommi.t.rantala@nokia.com>
Signed-off-by: Kees Cook <keescook@chromium.org>
Cc: Brad Spengler <spender@grsecurity.net>
Signed-off-by: Jiri Slaby <jslaby@suse.cz>
---
 arch/x86/mm/init.c | 41 +++++++++++++++++++--------
 drivers/char/mem.c | 82 ++++++++++++++++++++++++++++++++++--------------------
 2 files changed, 82 insertions(+), 41 deletions(-)

diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c
index 04664cdb7fda..bee0b8b77beb 100644
--- a/arch/x86/mm/init.c
+++ b/arch/x86/mm/init.c
@@ -475,21 +475,40 @@ void __init init_mem_mapping(void)
  * devmem_is_allowed() checks to see if /dev/mem access to a certain address
  * is valid. The argument is a physical page number.
  *
- *
- * On x86, access has to be given to the first megabyte of ram because that area
- * contains bios code and data regions used by X and dosemu and similar apps.
- * Access has to be given to non-kernel-ram areas as well, these contain the PCI
- * mmio resources as well as potential bios/acpi data regions.
+ * On x86, access has to be given to the first megabyte of RAM because that
+ * area traditionally contains BIOS code and data regions used by X, dosemu,
+ * and similar apps. Since they map the entire memory range, the whole range
+ * must be allowed (for mapping), but any areas that would otherwise be
+ * disallowed are flagged as being "zero filled" instead of rejected.
+ * Access has to be given to non-kernel-ram areas as well, these contain the
+ * PCI mmio resources as well as potential bios/acpi data regions.
  */
 int devmem_is_allowed(unsigned long pagenr)
 {
-	if (pagenr < 256)
-		return 1;
-	if (iomem_is_exclusive(pagenr << PAGE_SHIFT))
+	if (page_is_ram(pagenr)) {
+		/*
+		 * For disallowed memory regions in the low 1MB range,
+		 * request that the page be shown as all zeros.
+		 */
+		if (pagenr < 256)
+			return 2;
+
+		return 0;
+	}
+
+	/*
+	 * This must follow RAM test, since System RAM is considered a
+	 * restricted resource under CONFIG_STRICT_IOMEM.
+	 */
+	if (iomem_is_exclusive(pagenr << PAGE_SHIFT)) {
+		/* Low 1MB bypasses iomem restrictions. */
+		if (pagenr < 256)
+			return 1;
+
 		return 0;
-	if (!page_is_ram(pagenr))
-		return 1;
-	return 0;
+	}
+
+	return 1;
 }
 
 void free_init_pages(char *what, unsigned long begin, unsigned long end)
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index ea424a261fff..f8f4dd84f8eb 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -60,6 +60,10 @@ static inline int valid_mmap_phys_addr_range(unsigned long pfn, size_t size)
 #endif
 
 #ifdef CONFIG_STRICT_DEVMEM
+static inline int page_is_allowed(unsigned long pfn)
+{
+	return devmem_is_allowed(pfn);
+}
 static inline int range_is_allowed(unsigned long pfn, unsigned long size)
 {
 	u64 from = ((u64)pfn) << PAGE_SHIFT;
@@ -75,6 +79,10 @@ static inline int range_is_allowed(unsigned long pfn, unsigned long size)
 	return 1;
 }
 #else
+static inline int page_is_allowed(unsigned long pfn)
+{
+	return 1;
+}
 static inline int range_is_allowed(unsigned long pfn, unsigned long size)
 {
 	return 1;
@@ -119,23 +127,31 @@ static ssize_t read_mem(struct file *file, char __user *buf,
 
 	while (count > 0) {
 		unsigned long remaining;
+		int allowed;
 
 		sz = size_inside_page(p, count);
 
-		if (!range_is_allowed(p >> PAGE_SHIFT, count))
+		allowed = page_is_allowed(p >> PAGE_SHIFT);
+		if (!allowed)
 			return -EPERM;
+		if (allowed == 2) {
+			/* Show zeros for restricted memory. */
+			remaining = clear_user(buf, sz);
+		} else {
+			/*
+			 * On ia64 if a page has been mapped somewhere as
+			 * uncached, then it must also be accessed uncached
+			 * by the kernel or data corruption may occur.
+			 */
+			ptr = xlate_dev_mem_ptr(p);
+			if (!ptr)
+				return -EFAULT;
 
-		/*
-		 * On ia64 if a page has been mapped somewhere as uncached, then
-		 * it must also be accessed uncached by the kernel or data
-		 * corruption may occur.
-		 */
-		ptr = xlate_dev_mem_ptr(p);
-		if (!ptr)
-			return -EFAULT;
+			remaining = copy_to_user(buf, ptr, sz);
+
+			unxlate_dev_mem_ptr(p, ptr);
+		}
 
-		remaining = copy_to_user(buf, ptr, sz);
-		unxlate_dev_mem_ptr(p, ptr);
 		if (remaining)
 			return -EFAULT;
 
@@ -178,30 +194,36 @@ static ssize_t write_mem(struct file *file, const char __user *buf,
 #endif
 
 	while (count > 0) {
+		int allowed;
+
 		sz = size_inside_page(p, count);
 
-		if (!range_is_allowed(p >> PAGE_SHIFT, sz))
+		allowed = page_is_allowed(p >> PAGE_SHIFT);
+		if (!allowed)
 			return -EPERM;
 
-		/*
-		 * On ia64 if a page has been mapped somewhere as uncached, then
-		 * it must also be accessed uncached by the kernel or data
-		 * corruption may occur.
-		 */
-		ptr = xlate_dev_mem_ptr(p);
-		if (!ptr) {
-			if (written)
-				break;
-			return -EFAULT;
-		}
+		/* Skip actual writing when a page is marked as restricted. */
+		if (allowed == 1) {
+			/*
+			 * On ia64 if a page has been mapped somewhere as
+			 * uncached, then it must also be accessed uncached
+			 * by the kernel or data corruption may occur.
+			 */
+			ptr = xlate_dev_mem_ptr(p);
+			if (!ptr) {
+				if (written)
+					break;
+				return -EFAULT;
+			}
 
-		copied = copy_from_user(ptr, buf, sz);
-		unxlate_dev_mem_ptr(p, ptr);
-		if (copied) {
-			written += sz - copied;
-			if (written)
-				break;
-			return -EFAULT;
+			copied = copy_from_user(ptr, buf, sz);
+			unxlate_dev_mem_ptr(p, ptr);
+			if (copied) {
+				written += sz - copied;
+				if (written)
+					break;
+				return -EFAULT;
+			}
 		}
 
 		buf += sz;
-- 
2.12.2

  reply	other threads:[~2017-05-03 12:23 UTC|newest]

Thread overview: 52+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-05-03 12:22 [patch added to 3.12-stable] rtc: tegra: Implement clock handling Jiri Slaby
2017-05-03 12:22 ` Jiri Slaby [this message]
2017-05-03 12:22 ` [patch added to 3.12-stable] virtio-console: avoid DMA from stack Jiri Slaby
2017-05-03 12:22 ` [patch added to 3.12-stable] pegasus: Use heap buffers for all register access Jiri Slaby
2017-05-03 12:22 ` [patch added to 3.12-stable] rtl8150: " Jiri Slaby
2017-05-03 12:22 ` [patch added to 3.12-stable] catc: Combine failure cleanup code in catc_probe() Jiri Slaby
2017-05-03 12:22 ` [patch added to 3.12-stable] catc: Use heap buffer for memory size test Jiri Slaby
2017-05-03 12:22 ` [patch added to 3.12-stable] net: ipv6: check route protocol when deleting routes Jiri Slaby
2017-05-03 12:22 ` [patch added to 3.12-stable] KEYS: Disallow keyrings beginning with '.' to be joined as session keyrings Jiri Slaby
2017-05-03 12:22 ` [patch added to 3.12-stable] KEYS: Change the name of the dead type to ".dead" to prevent user access Jiri Slaby
2017-05-03 12:22 ` [patch added to 3.12-stable] KEYS: fix keyctl_set_reqkey_keyring() to not leak thread keyrings Jiri Slaby
2017-05-03 12:22 ` [patch added to 3.12-stable] tracing: Allocate the snapshot buffer before enabling probe Jiri Slaby
2017-05-03 12:22 ` [patch added to 3.12-stable] ring-buffer: Have ring_buffer_iter_empty() return true when empty Jiri Slaby
2017-05-03 12:22 ` [patch added to 3.12-stable] cifs: Do not send echoes before Negotiate is complete Jiri Slaby
2017-05-03 12:22 ` [patch added to 3.12-stable] CIFS: remove bad_network_name flag Jiri Slaby
2017-05-03 12:22 ` [patch added to 3.12-stable] Drivers: hv: don't leak memory in vmbus_establish_gpadl() Jiri Slaby
2017-05-03 12:22 ` [patch added to 3.12-stable] Drivers: hv: get rid of timeout in vmbus_open() Jiri Slaby
2017-05-03 12:22 ` [patch added to 3.12-stable] Input: elantech - add Fujitsu Lifebook E547 to force crc_enabled Jiri Slaby
2017-05-03 12:22 ` [patch added to 3.12-stable] ACPI / power: Avoid maybe-uninitialized warning Jiri Slaby
2017-05-03 12:22 ` [patch added to 3.12-stable] ubi/upd: Always flush after prepared for an update Jiri Slaby
2017-05-03 12:22 ` [patch added to 3.12-stable] x86/mce/AMD: Give a name to MCA bank 3 when accessed with legacy MSRs Jiri Slaby
2017-05-03 12:23 ` [patch added to 3.12-stable] kvm: arm/arm64: Fix locking for kvm_free_stage2_pgd Jiri Slaby
2017-05-03 12:39   ` Suzuki K Poulose
2017-05-03 13:21     ` Jiri Slaby
2017-05-03 13:31       ` Suzuki K Poulose
2017-05-03 12:23 ` [patch added to 3.12-stable] block: fix del_gendisk() vs blkdev_ioctl crash Jiri Slaby
2017-05-03 12:23 ` [patch added to 3.12-stable] powerpc: Reject binutils 2.24 when building little endian Jiri Slaby
2017-05-03 12:23 ` [patch added to 3.12-stable] ping: implement proper locking Jiri Slaby
2017-05-03 12:23 ` [patch added to 3.12-stable] net/packet: fix overflow in check for tp_frame_nr Jiri Slaby
2017-05-03 12:23 ` [patch added to 3.12-stable] net/packet: fix overflow in check for tp_reserve Jiri Slaby
2017-05-03 12:23 ` [patch added to 3.12-stable] netfilter: arp_tables: fix invoking 32bit "iptable -P INPUT ACCEPT" failed in 64bit kernel Jiri Slaby
2017-05-03 12:23 ` [patch added to 3.12-stable] tty: nozomi: avoid a harmless gcc warning Jiri Slaby
2017-05-03 12:23 ` [patch added to 3.12-stable] hostap: avoid uninitialized variable use in hfa384x_get_rid Jiri Slaby
2017-05-03 12:23 ` [patch added to 3.12-stable] gfs2: avoid uninitialized variable warning Jiri Slaby
2017-05-03 12:23 ` [patch added to 3.12-stable] net: neigh: guard against NULL solicit() method Jiri Slaby
2017-05-03 12:23 ` [patch added to 3.12-stable] net: phy: handle state correctly in phy_stop_machine Jiri Slaby
2017-05-03 12:23 ` [patch added to 3.12-stable] l2tp: take reference on sessions being dumped Jiri Slaby
2017-05-03 12:23 ` [patch added to 3.12-stable] net: ipv4: fix multipath RTM_GETROUTE behavior when iif is given Jiri Slaby
2017-05-03 12:23 ` [patch added to 3.12-stable] sctp: listen on the sock only when it's state is listening or closed Jiri Slaby
2017-05-03 12:23 ` [patch added to 3.12-stable] ip6mr: fix notification device destruction Jiri Slaby
2017-05-03 12:23 ` [patch added to 3.12-stable] ipv6: check raw payload size correctly in ioctl Jiri Slaby
2017-05-03 12:23 ` [patch added to 3.12-stable] ext4: check if in-inode xattr is corrupted in ext4_expand_extra_isize_ea() Jiri Slaby
2017-05-03 12:23 ` [patch added to 3.12-stable] md:raid1: fix a dead loop when read from a WriteMostly disk Jiri Slaby
2017-05-03 12:23 ` [patch added to 3.12-stable] MIPS: Fix crash registers on non-crashing CPUs Jiri Slaby
2017-05-03 12:23 ` [patch added to 3.12-stable] RDS: Fix the atomicity for congestion map update Jiri Slaby
2017-05-03 12:23 ` [patch added to 3.12-stable] xen/x86: don't lose event interrupts Jiri Slaby
2017-05-03 12:23 ` [patch added to 3.12-stable] ALSA: seq: Don't break snd_use_lock_sync() loop by timeout Jiri Slaby
2017-05-03 12:23 ` [patch added to 3.12-stable] MIPS: KGDB: Use kernel context for sleeping threads Jiri Slaby
2017-05-03 12:23 ` [patch added to 3.12-stable] p9_client_readdir() fix Jiri Slaby
2017-05-03 12:23 ` [patch added to 3.12-stable] Input: i8042 - add Clevo P650RS to the i8042 reset list Jiri Slaby
2017-05-03 12:23 ` [patch added to 3.12-stable] nfsd: check for oversized NFSv2/v3 arguments Jiri Slaby
2017-05-03 12:23 ` [patch added to 3.12-stable] ftrace/x86: Fix triple fault with graph tracing and suspend-to-ram Jiri Slaby

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20170503122327.12095-2-jslaby@suse.cz \
    --to=jslaby@suse.cz \
    --cc=keescook@chromium.org \
    --cc=spender@grsecurity.net \
    --cc=stable@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.