public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Chris Wright <chrisw@sous-sol.org>
To: linux-kernel@vger.kernel.org, stable@kernel.org
Cc: Justin Forbes <jmforbes@linuxtx.org>,
	Zwane Mwaikambo <zwane@arm.linux.org.uk>,
	"Theodore Ts'o" <tytso@mit.edu>,
	Randy Dunlap <rdunlap@xenotime.net>,
	Dave Jones <davej@redhat.com>,
	Chuck Wolber <chuckw@quantumlinux.com>,
	Chris Wedgwood <reviews@ml.cw.f00f.org>,
	Michael Krufky <mkrufky@linuxtv.org>,
	torvalds@osdl.org, akpm@osdl.org, alan@lxorguk.ukuu.org.uk,
	Linus Torvalds <torvalds@woody.osdl.org>,
	Doug Chapman <dchapman@redhat.com>,
	Marcel Holtmann <holtmann@redhat.com>,
	Hugh Dickins <hugh@veritas.com>, Oleg Nesterov <oleg@tv-sign.ru>
Subject: [patch 50/50] Fix incorrect user space access locking in mincore() (CVE-2006-4814)
Date: Fri, 05 Jan 2007 18:28:43 -0800	[thread overview]
Message-ID: <20070106023734.211998000@sous-sol.org> (raw)
In-Reply-To: 20070106022753.334962000@sous-sol.org

[-- Attachment #1: fix-incorrect-user-space-access-locking-in-mincore.patch --]
[-- Type: text/plain, Size: 6727 bytes --]

-stable review patch.  If anyone has any objections, please let us know.
------------------

From: Linus Torvalds <torvalds@woody.osdl.org>

Doug Chapman noticed that mincore() will doa "copy_to_user()" of the
result while holding the mmap semaphore for reading, which is a big
no-no.  While a recursive read-lock on a semaphore in the case of a page
fault happens to work, we don't actually allow them due to deadlock
schenarios with writers due to fairness issues.

Doug and Marcel sent in a patch to fix it, but I decided to just rewrite
the mess instead - not just fixing the locking problem, but making the
code smaller and (imho) much easier to understand.

Cc: Doug Chapman <dchapman@redhat.com>
Cc: Marcel Holtmann <holtmann@redhat.com>
Cc: Hugh Dickins <hugh@veritas.com>
Cc: Andrew Morton <akpm@osdl.org>
[chrisw: fold in subsequent fix: 4fb23e439ce0]
Acked-by: Hugh Dickins <hugh@veritas.com>
[chrisw: fold in subsequent fix: 825020c3866e]
Signed-off-by: Oleg Nesterov <oleg@tv-sign.ru>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Chris Wright <chrisw@sous-sol.org>
---
 mm/mincore.c |  181 +++++++++++++++++++++++++----------------------------------
 1 file changed, 77 insertions(+), 104 deletions(-)

--- linux-2.6.19.1.orig/mm/mincore.c
+++ linux-2.6.19.1/mm/mincore.c
@@ -1,7 +1,7 @@
 /*
  *	linux/mm/mincore.c
  *
- * Copyright (C) 1994-1999  Linus Torvalds
+ * Copyright (C) 1994-2006  Linus Torvalds
  */
 
 /*
@@ -38,46 +38,51 @@ static unsigned char mincore_page(struct
 	return present;
 }
 
-static long mincore_vma(struct vm_area_struct * vma,
-	unsigned long start, unsigned long end, unsigned char __user * vec)
+/*
+ * Do a chunk of "sys_mincore()". We've already checked
+ * all the arguments, we hold the mmap semaphore: we should
+ * just return the amount of info we're asked for.
+ */
+static long do_mincore(unsigned long addr, unsigned char *vec, unsigned long pages)
 {
-	long error, i, remaining;
-	unsigned char * tmp;
-
-	error = -ENOMEM;
-	if (!vma->vm_file)
-		return error;
-
-	start = ((start - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff;
-	if (end > vma->vm_end)
-		end = vma->vm_end;
-	end = ((end - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff;
-
-	error = -EAGAIN;
-	tmp = (unsigned char *) __get_free_page(GFP_KERNEL);
-	if (!tmp)
-		return error;
-
-	/* (end - start) is # of pages, and also # of bytes in "vec */
-	remaining = (end - start),
+	unsigned long i, nr, pgoff;
+	struct vm_area_struct *vma = find_vma(current->mm, addr);
 
-	error = 0;
-	for (i = 0; remaining > 0; remaining -= PAGE_SIZE, i++) {
-		int j = 0;
-		long thispiece = (remaining < PAGE_SIZE) ?
-						remaining : PAGE_SIZE;
+	/*
+	 * find_vma() didn't find anything above us, or we're
+	 * in an unmapped hole in the address space: ENOMEM.
+	 */
+	if (!vma || addr < vma->vm_start)
+		return -ENOMEM;
 
-		while (j < thispiece)
-			tmp[j++] = mincore_page(vma, start++);
+	/*
+	 * Ok, got it. But check whether it's a segment we support
+	 * mincore() on. Right now, we don't do any anonymous mappings.
+	 *
+	 * FIXME: This is just stupid. And returning ENOMEM is 
+	 * stupid too. We should just look at the page tables. But
+	 * this is what we've traditionally done, so we'll just
+	 * continue doing it.
+	 */
+	if (!vma->vm_file)
+		return -ENOMEM;
 
-		if (copy_to_user(vec + PAGE_SIZE * i, tmp, thispiece)) {
-			error = -EFAULT;
-			break;
-		}
-	}
+	/*
+	 * Calculate how many pages there are left in the vma, and
+	 * what the pgoff is for our address.
+	 */
+	nr = (vma->vm_end - addr) >> PAGE_SHIFT;
+	if (nr > pages)
+		nr = pages;
+
+	pgoff = (addr - vma->vm_start) >> PAGE_SHIFT;
+	pgoff += vma->vm_pgoff;
+
+	/* And then we just fill the sucker in.. */
+	for (i = 0 ; i < nr; i++, pgoff++)
+		vec[i] = mincore_page(vma, pgoff);
 
-	free_page((unsigned long) tmp);
-	return error;
+	return nr;
 }
 
 /*
@@ -107,82 +112,50 @@ static long mincore_vma(struct vm_area_s
 asmlinkage long sys_mincore(unsigned long start, size_t len,
 	unsigned char __user * vec)
 {
-	int index = 0;
-	unsigned long end, limit;
-	struct vm_area_struct * vma;
-	size_t max;
-	int unmapped_error = 0;
-	long error;
+	long retval;
+	unsigned long pages;
+	unsigned char *tmp;
 
-	/* check the arguments */
+	/* Check the start address: needs to be page-aligned.. */
  	if (start & ~PAGE_CACHE_MASK)
-		goto einval;
-
-	limit = TASK_SIZE;
-	if (start >= limit)
-		goto enomem;
+		return -EINVAL;
 
-	if (!len)
-		return 0;
+	/* ..and we need to be passed a valid user-space range */
+	if (!access_ok(VERIFY_READ, (void __user *) start, len))
+		return -ENOMEM;
 
-	max = limit - start;
-	len = PAGE_CACHE_ALIGN(len);
-	if (len > max || !len)
-		goto enomem;
+	/* This also avoids any overflows on PAGE_CACHE_ALIGN */
+	pages = len >> PAGE_SHIFT;
+	pages += (len & ~PAGE_MASK) != 0;
 
-	end = start + len;
+	if (!access_ok(VERIFY_WRITE, vec, pages))
+		return -EFAULT;
 
-	/* check the output buffer whilst holding the lock */
-	error = -EFAULT;
-	down_read(&current->mm->mmap_sem);
-
-	if (!access_ok(VERIFY_WRITE, vec, len >> PAGE_SHIFT))
-		goto out;
-
-	/*
-	 * If the interval [start,end) covers some unmapped address
-	 * ranges, just ignore them, but return -ENOMEM at the end.
-	 */
-	error = 0;
+	tmp = (void *) __get_free_page(GFP_USER);
+	if (!tmp)
+		return -EAGAIN;
 
-	vma = find_vma(current->mm, start);
-	while (vma) {
-		/* Here start < vma->vm_end. */
-		if (start < vma->vm_start) {
-			unmapped_error = -ENOMEM;
-			start = vma->vm_start;
-		}
+	retval = 0;
+	while (pages) {
+		/*
+		 * Do at most PAGE_SIZE entries per iteration, due to
+		 * the temporary buffer size.
+		 */
+		down_read(&current->mm->mmap_sem);
+		retval = do_mincore(start, tmp, min(pages, PAGE_SIZE));
+		up_read(&current->mm->mmap_sem);
 
-		/* Here vma->vm_start <= start < vma->vm_end. */
-		if (end <= vma->vm_end) {
-			if (start < end) {
-				error = mincore_vma(vma, start, end,
-							&vec[index]);
-				if (error)
-					goto out;
-			}
-			error = unmapped_error;
-			goto out;
+		if (retval <= 0)
+			break;
+		if (copy_to_user(vec, tmp, retval)) {
+			retval = -EFAULT;
+			break;
 		}
-
-		/* Here vma->vm_start <= start < vma->vm_end < end. */
-		error = mincore_vma(vma, start, vma->vm_end, &vec[index]);
-		if (error)
-			goto out;
-		index += (vma->vm_end - start) >> PAGE_CACHE_SHIFT;
-		start = vma->vm_end;
-		vma = vma->vm_next;
+		pages -= retval;
+		vec += retval;
+		start += retval << PAGE_SHIFT;
+		retval = 0;
 	}
-
-	/* we found a hole in the area queried if we arrive here */
-	error = -ENOMEM;
-
-out:
-	up_read(&current->mm->mmap_sem);
-	return error;
-
-einval:
-	return -EINVAL;
-enomem:
-	return -ENOMEM;
+	free_page((unsigned long) tmp);
+	return retval;
 }

--

  parent reply	other threads:[~2007-01-06  2:36 UTC|newest]

Thread overview: 70+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-01-06  2:27 [patch 00/50] -stable review Chris Wright
2007-01-06  2:27 ` [patch 01/50] dm-crypt: Select CRYPTO_CBC Chris Wright
2007-01-06  2:27 ` [patch 02/50] sha512: Fix sha384 block size Chris Wright
2007-01-06  2:27 ` [patch 03/50] read_zero_pagealigned() locking fix Chris Wright
2007-01-06  2:27 ` [patch 04/50] ieee80211softmac: Fix mutex_lock at exit of ieee80211_softmac_get_genie Chris Wright
2007-01-08 15:24   ` John W. Linville
2007-01-06  2:27 ` [patch 05/50] x86-64: Mark rdtsc as sync only for netburst, not for core2 Chris Wright
2007-01-06  2:27 ` [patch 06/50] bonding: incorrect bonding state reported via ioctl Chris Wright
2007-01-06  2:28 ` [patch 07/50] DVB: lgdt330x: fix signal / lock status detection bug Chris Wright
2007-01-06  2:28 ` [patch 08/50] V4L: Fix broken TUNER_LG_NTSC_TAPE radio support Chris Wright
2007-01-06  2:28 ` [patch 09/50] Revert "[PATCH] zd1211rw: Removed unneeded packed attributes" Chris Wright
2007-01-08 15:32   ` John W. Linville
2007-01-06  2:28 ` [patch 10/50] libata: handle 0xff status properly Chris Wright
2007-01-06  2:28 ` [patch 11/50] ieee1394: ohci1394: add PPC_PMAC platform code to driver probe Chris Wright
2007-01-06  2:28 ` [patch 12/50] kbuild: dont put temp files in source Chris Wright
2007-01-06  2:28 ` [patch 13/50] ARM: Add sys_*at syscalls Chris Wright
2007-01-06  2:28 ` [patch 14/50] sched: remove __cpuinitdata anotation to cpu_isolated_map Chris Wright
2007-01-06  2:28 ` [patch 15/50] IB/srp: Fix FMR mapping for 32-bit kernels and addresses above 4G Chris Wright
2007-01-06  2:28 ` [patch 16/50] SCSI: add missing cdb clearing in scsi_execute() Chris Wright
2007-01-06  2:28 ` [patch 17/50] Bluetooth: Add packet size checks for CAPI messages (CVE-2006-6106) Chris Wright
2007-01-06  2:28 ` [patch 18/50] i2c: fix broken ds1337 initialization Chris Wright
2007-01-06  2:28 ` [patch 19/50] sched: fix bad missed wakeups in the i386, x86_64, ia64, ACPI and APM idle code Chris Wright
2007-01-06  2:28 ` [patch 20/50] Fix for shmem_truncate_range() BUG_ON() Chris Wright
2007-01-06  2:28 ` [patch 21/50] smc911x: fix netpoll compilation faliure Chris Wright
2007-01-06  2:28 ` [patch 22/50] fix aoe without scatter-gather [Bug 7662] Chris Wright
2007-01-06  2:28 ` [patch 23/50] UDP: Fix reversed logic in udp_get_port() Chris Wright
2007-01-06  2:28 ` [patch 24/50] cciss: fix XFER_READ/XFER_WRITE in do_cciss_request Chris Wright
2007-01-06  2:28 ` [patch 25/50] [stable] [stable patch] i386: CPU hotplug broken with 2GB VMSPLIT Chris Wright
2007-01-06  2:28 ` [patch 26/50] ramfs breaks without CONFIG_BLOCK Chris Wright
2007-01-06  2:28 ` [patch 27/50] Buglet in vmscan.c Chris Wright
2007-01-06  2:28 ` [patch 28/50] softmac: Fixed handling of deassociation from AP Chris Wright
2007-01-08 15:14   ` John W. Linville
2007-01-06  2:28 ` [patch 29/50] zd1211rw: Call ieee80211_rx in tasklet Chris Wright
2007-01-08 15:20   ` John W. Linville
2007-01-06  2:28 ` [patch 30/50] handle ext3 directory corruption better (CVE-2006-6053) Chris Wright
2007-01-06  2:28 ` [patch 31/50] corrupted cramfs filesystems cause kernel oops (CVE-2006-5823) Chris Wright
2007-01-06  2:28 ` [patch 32/50] ext2: skip pages past number of blocks in ext2_find_entry (CVE-2006-6054) Chris Wright
2007-01-06  2:28 ` [patch 33/50] PKTGEN: Fix module load/unload races Chris Wright
2007-01-06  2:28 ` [patch 34/50] SPARC64: Fix "mem=xxx" handling Chris Wright
2007-01-06  2:28 ` [patch 35/50] SPARC64: Handle ISA devices with no regs property Chris Wright
2007-01-06  2:28 ` [patch 36/50] NET: Dont export linux/random.h outside __KERNEL__ Chris Wright
2007-01-06  2:28 ` [patch 37/50] sparc32: add offset in pci_map_sg() Chris Wright
2007-01-06  2:28 ` [patch 38/50] VM: Fix nasty and subtle race in shared mmaped page writeback Chris Wright
2007-01-06  2:28 ` [patch 39/50] V4L: cx2341x: audio_properties is an u16, not u8 Chris Wright
2007-01-06  2:28 ` [patch 40/50] dvb-core: fix bug in CRC-32 checking on 64-bit systems Chris Wright
2007-01-06  2:28 ` [patch 41/50] V4L: cx88: Fix leadtek_eeprom tagging Chris Wright
2007-01-06  2:28 ` [patch 42/50] ebtables: dont compute gap before checking struct type Chris Wright
2007-01-06  2:28 ` [patch 43/50] SOUND: Sparc CS4231: Fix IRQ return value and initialization Chris Wright
2007-01-06  2:28 ` [patch 44/50] SOUND: Sparc CS4231: Use 64 for period_bytes_min Chris Wright
2007-01-06 14:20   ` [patch 43/50] SOUND: Sparc CS4231: Fix IRQ return value and initialization Jan Engelhardt
2007-01-06  2:28 ` [patch 45/50] IPV4/IPV6: Fix inet{,6} device initialization order Chris Wright
2007-01-06  2:28 ` [patch 46/50] asix: Fix typo for AX88772 PHY Selection Chris Wright
2007-01-06  2:28 ` [patch 47/50] NetLabel: correctly fill in unused CIPSOv4 level and category mappings Chris Wright
2007-01-06  2:28 ` [patch 48/50] connector: some fixes for ia64 unaligned access errors Chris Wright
2007-01-06  2:28 ` [patch 49/50] fix OOM killing of swapoff Chris Wright
2007-01-06  2:28 ` Chris Wright [this message]
2007-01-06  2:37 ` [patch 00/50] -stable review Chris Wright
2007-02-04 18:24 ` Michael Krufky
2007-02-05 21:43   ` [stable] " Greg KH
2007-02-05 22:12     ` Chris Wright
2007-02-05 22:18       ` Greg KH
2007-02-05 22:16     ` Michael Krufky
2007-02-05 22:33       ` Greg KH
2007-02-07 21:08         ` Michael Krufky
2007-02-09 19:41           ` Michael Krufky
2007-02-09 19:51             ` Greg KH
2007-02-20 23:12               ` Greg KH
2007-02-21  2:29                 ` Michael Krufky
2007-02-21 21:01                   ` [v4l-dvb-maintainer] " Michael Krufky
2007-02-26 14:35                     ` Adrian Bunk

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=20070106023734.211998000@sous-sol.org \
    --to=chrisw@sous-sol.org \
    --cc=akpm@osdl.org \
    --cc=alan@lxorguk.ukuu.org.uk \
    --cc=chuckw@quantumlinux.com \
    --cc=davej@redhat.com \
    --cc=dchapman@redhat.com \
    --cc=holtmann@redhat.com \
    --cc=hugh@veritas.com \
    --cc=jmforbes@linuxtx.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mkrufky@linuxtv.org \
    --cc=oleg@tv-sign.ru \
    --cc=rdunlap@xenotime.net \
    --cc=reviews@ml.cw.f00f.org \
    --cc=stable@kernel.org \
    --cc=torvalds@osdl.org \
    --cc=torvalds@woody.osdl.org \
    --cc=tytso@mit.edu \
    --cc=zwane@arm.linux.org.uk \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox