From: Greg KH <gregkh@suse.de>
To: linux-kernel@vger.kernel.org, stable@kernel.org,
git-commits-head@vger.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>,
torvalds@osdl.org, akpm@osdl.org, alan@lxorguk.ukuu.org.uk,
Zachary Amsden <zach@vmware.com>,
Greg Kroah-Hartman <gregkh@suse.de>
Subject: [patch 19/24] x86/PAE: Fix pte_clear for the >4GB RAM case
Date: Thu, 27 Apr 2006 17:22:09 -0700 [thread overview]
Message-ID: <20060428002209.GT18750@kroah.com> (raw)
In-Reply-To: <20060428001557.GA18750@kroah.com>
[-- Attachment #1: x86-pae-fix-pte_clear-for-the-4gb-ram-case.patch --]
[-- Type: text/plain, Size: 5572 bytes --]
-stable review patch. If anyone has any objections, please let us know.
------------------
From: Zachary Amsden <zach@vmware.com>
[PATCH] x86/PAE: Fix pte_clear for the >4GB RAM case
Proposed fix for ptep_get_and_clear_full PAE bug. Pte_clear had the same bug,
so use the same fix for both. Turns out pmd_clear had it as well, but pgds
are not affected.
The problem is rather intricate. Page table entries in PAE mode are 64-bits
wide, but the only atomic 8-byte write operation available in 32-bit mode is
cmpxchg8b, which is expensive (at least on P4), and thus avoided. But it can
happen that the processor may prefetch entries into the TLB in the middle of an
operation which clears a page table entry. So one must always clear the P-bit
in the low word of the page table entry first when clearing it.
Since the sequence *ptep = __pte(0) leaves the order of the write dependent on
the compiler, it must be coded explicitly as a clear of the low word followed
by a clear of the high word. Further, there must be a write memory barrier
here to enforce proper ordering by the compiler (and, in the future, by the
processor as well).
On > 4GB memory machines, the implementation of pte_clear for PAE was clearly
deficient, as it could leave virtual mappings of physical memory above 4GB
aliased to memory below 4GB in the TLB. The implementation of
ptep_get_and_clear_full has a similar bug, although not nearly as likely to
occur, since the mappings being cleared are in the process of being destroyed,
and should never be dereferenced again.
But, as luck would have it, it is possible to trigger bugs even without ever
dereferencing these bogus TLB mappings, even if the clear is followed fairly
soon after with a TLB flush or invalidation. The problem is that memory above
4GB may now be aliased into the first 4GB of memory, and in fact, may hit a
region of memory with non-memory semantics. These regions include AGP and PCI
space. As such, these memory regions are not cached by the processor. This
introduces the bug.
The processor can speculate memory operations, including memory writes, as long
as they are committed with the proper ordering. Speculating a memory write to
a linear address that has a bogus TLB mapping is possible. Normally, the
speculation is harmless. But for cached memory, it does leave the falsely
speculated cacheline unmodified, but in a dirty state. This cache line will be
eventually written back. If this cacheline happens to intersect a region of
memory that is not protected by the cache coherency protocol, it can corrupt
data in I/O memory, which is generally a very bad thing to do, and can cause
total system failure or just plain undefined behavior.
These bugs are extremely unlikely, but the severity is of such magnitude, and
the fix so simple that I think fixing them immediately is justified. Also,
they are nearly impossible to debug.
Signed-off-by: Zachary Amsden <zach@vmware.com>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
include/asm-i386/pgtable-2level.h | 3 +++
include/asm-i386/pgtable-3level.h | 20 ++++++++++++++++++++
include/asm-i386/pgtable.h | 4 +---
3 files changed, 24 insertions(+), 3 deletions(-)
--- linux-2.6.16.11.orig/include/asm-i386/pgtable-2level.h
+++ linux-2.6.16.11/include/asm-i386/pgtable-2level.h
@@ -18,6 +18,9 @@
#define set_pte_atomic(pteptr, pteval) set_pte(pteptr,pteval)
#define set_pmd(pmdptr, pmdval) (*(pmdptr) = (pmdval))
+#define pte_clear(mm,addr,xp) do { set_pte_at(mm, addr, xp, __pte(0)); } while (0)
+#define pmd_clear(xp) do { set_pmd(xp, __pmd(0)); } while (0)
+
#define ptep_get_and_clear(mm,addr,xp) __pte(xchg(&(xp)->pte_low, 0))
#define pte_same(a, b) ((a).pte_low == (b).pte_low)
#define pte_page(x) pfn_to_page(pte_pfn(x))
--- linux-2.6.16.11.orig/include/asm-i386/pgtable-3level.h
+++ linux-2.6.16.11/include/asm-i386/pgtable-3level.h
@@ -85,6 +85,26 @@ static inline void pud_clear (pud_t * pu
#define pmd_offset(pud, address) ((pmd_t *) pud_page(*(pud)) + \
pmd_index(address))
+/*
+ * For PTEs and PDEs, we must clear the P-bit first when clearing a page table
+ * entry, so clear the bottom half first and enforce ordering with a compiler
+ * barrier.
+ */
+static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
+{
+ ptep->pte_low = 0;
+ smp_wmb();
+ ptep->pte_high = 0;
+}
+
+static inline void pmd_clear(pmd_t *pmd)
+{
+ u32 *tmp = (u32 *)pmd;
+ *tmp = 0;
+ smp_wmb();
+ *(tmp + 1) = 0;
+}
+
static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
{
pte_t res;
--- linux-2.6.16.11.orig/include/asm-i386/pgtable.h
+++ linux-2.6.16.11/include/asm-i386/pgtable.h
@@ -204,12 +204,10 @@ extern unsigned long long __PAGE_KERNEL,
extern unsigned long pg0[];
#define pte_present(x) ((x).pte_low & (_PAGE_PRESENT | _PAGE_PROTNONE))
-#define pte_clear(mm,addr,xp) do { set_pte_at(mm, addr, xp, __pte(0)); } while (0)
/* To avoid harmful races, pmd_none(x) should check only the lower when PAE */
#define pmd_none(x) (!(unsigned long)pmd_val(x))
#define pmd_present(x) (pmd_val(x) & _PAGE_PRESENT)
-#define pmd_clear(xp) do { set_pmd(xp, __pmd(0)); } while (0)
#define pmd_bad(x) ((pmd_val(x) & (~PAGE_MASK & ~_PAGE_USER)) != _KERNPG_TABLE)
@@ -269,7 +267,7 @@ static inline pte_t ptep_get_and_clear_f
pte_t pte;
if (full) {
pte = *ptep;
- *ptep = __pte(0);
+ pte_clear(mm, addr, ptep);
} else {
pte = ptep_get_and_clear(mm, addr, ptep);
}
--
next prev parent reply other threads:[~2006-04-28 0:24 UTC|newest]
Thread overview: 27+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <20060428001226.204293000@quad.kroah.org>
2006-04-28 0:15 ` [patch 00/24] -stable review Greg KH
2006-04-28 0:16 ` [patch 01/24] sonypi: correct detection of new ICH7-based laptops Greg KH
2006-04-28 0:16 ` [patch 02/24] cs5535_gpio.c: call cdev_del() during module_exit to unmap kobject references and other cleanups Greg KH
2006-04-28 0:16 ` [patch 03/24] make vm86 call audit_syscall_exit Greg KH
2006-04-29 16:34 ` Sergey Vlasov
2006-05-01 17:54 ` Jason Baron
2006-04-28 0:17 ` [patch 04/24] x86_64: Pass -32 to the assembler when compiling the 32bit vsyscall pages Greg KH
2006-04-28 0:17 ` [patch 05/24] x86_64: Fix a race in the free_iommu path Greg KH
2006-04-28 0:18 ` [patch 06/24] USB: fix array overrun in drivers/usb/serial/option.c Greg KH
2006-04-28 0:18 ` [patch 07/24] tipar oops fix Greg KH
2006-04-28 0:18 ` [patch 08/24] get_dvb_firmware: download nxt2002 firmware from new driver location Greg KH
2006-04-28 0:18 ` [patch 09/24] for_each_possible_cpu Greg KH
2006-04-28 0:18 ` [patch 10/24] fix saa7129 support in saa7127 module for pvr350 tv out Greg KH
2006-04-28 0:19 ` [patch 11/24] cxusb-bluebird: bug-fix: power down corrupts frontend Greg KH
2006-04-28 0:19 ` [patch 12/24] dm snapshot: fix kcopyd destructor Greg KH
2006-04-28 0:19 ` [patch 13/24] dm flush queue EINTR Greg KH
2006-04-28 0:20 ` [patch 14/24] Simplify proc/devices and fix early termination regression Greg KH
2006-04-28 0:20 ` [patch 15/24] Fix reiserfs deadlock Greg KH
2006-04-28 0:21 ` [patch 16/24] Altix snsc: duplicate kobject fix Greg KH
2006-04-28 0:21 ` [patch 17/24] Alpha: strncpy() fix Greg KH
2006-04-28 0:21 ` [patch 18/24] LSM: add missing hook to do_compat_readv_writev() Greg KH
2006-04-28 0:22 ` Greg KH [this message]
2006-04-28 0:22 ` [patch 20/24] NET: e1000: Update truesize with the length of the packet for packet split Greg KH
2006-04-28 0:22 ` [patch 21/24] MIPS: Use "R" constraint for cache_op Greg KH
2006-04-28 0:23 ` [patch 22/24] MIPS: R2 build fixes for gcc < 3.4 Greg KH
2006-04-28 0:23 ` [patch 23/24] MIPS: Fix tx49_blast_icache32_page_indexed Greg KH
2006-04-28 0:24 ` [patch 24/24] MIPS: Fix branch emulation for floating-point exceptions Greg KH
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=20060428002209.GT18750@kroah.com \
--to=gregkh@suse.de \
--cc=akpm@osdl.org \
--cc=alan@lxorguk.ukuu.org.uk \
--cc=chuckw@quantumlinux.com \
--cc=davej@redhat.com \
--cc=git-commits-head@vger.kernel.org \
--cc=jmforbes@linuxtx.org \
--cc=linux-kernel@vger.kernel.org \
--cc=rdunlap@xenotime.net \
--cc=stable@kernel.org \
--cc=torvalds@osdl.org \
--cc=tytso@mit.edu \
--cc=zach@vmware.com \
--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