public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Dave Jones <davej@redhat.com>
To: linux-kernel@vger.kernel.org
Cc: arjan@infradead.org, akpm@osdl.org, Stuart_Hayes@Dell.com
Subject: change page attr fix.
Date: Mon, 28 Nov 2005 01:52:33 -0500	[thread overview]
Message-ID: <20051128065233.GA23531@redhat.com> (raw)

The 'make rodata read-only' patch in -mm exposes a latent bug
in the 32-bit change_page_attr() function, which causes
certain CPUs (Those with NX basically) to reboot instantly
after pages are marked read-only.

The same bug got fixed a while back on x86-64, but never got
propagated to i386.

Stuart Hayes from Dell also picked up on this last June,
but it never got fixed, as the only thing affected by it
aparently was the nvidia driver.

Blatantly stealing description from his post..

"It doesn't appear to be fixed (in the i386 arch).  The
 change_page_attr()/split_large_page() code will still still set all the
 4K PTEs to PAGE_KERNEL (setting the _PAGE_NX bit) when a large page
 needs to be split.

 This wouldn't be a problem for the bulk of the kernel memory, but there
 are pages in the lower 4MB of memory that's free, and are part of large
 executable pages that also contain kernel code.  If change_page_attr()
 is called on these, it will set the _PAGE_NX bit on the whole 2MB region
 that was covered by the large page, causing a large chunk of kernel code
 to be non-executable."

Signed-off-by: Arjan van de Ven <arjan@infradead.org>
Signed-off-by: Dave Jones <davej@redhat.com>

--- linux-2.6/arch/i386/mm/pageattr.c.nopatch	2005-10-04 10:33:12.000000000 -0500
+++ linux-2.6/arch/i386/mm/pageattr.c	2005-10-04 10:33:33.000000000 -0500
@@ -31,7 +31,8 @@ pte_t *lookup_address(unsigned long addr
         return pte_offset_kernel(pmd, address);
 } 
 
-static struct page *split_large_page(unsigned long address, pgprot_t prot)
+static struct page *split_large_page(unsigned long address, pgprot_t prot,
+					pgprot_t ref_prot)
 { 
 	int i; 
 	unsigned long addr;
@@ -54,7 +54,7 @@ static struct page *split_large_page(uns
 	pbase = (pte_t *)page_address(base);
 	for (i = 0; i < PTRS_PER_PTE; i++, addr += PAGE_SIZE) {
                set_pte(&pbase[i], pfn_pte(addr >> PAGE_SHIFT,
-                                          addr == address ? prot : PAGE_KERNEL));
+                                          addr == address ? prot : ref_prot));
 	}
 	return base;
 } 
@@ -98,11 +98,17 @@ static void set_pmd_pte(pte_t *kpte, uns
  */
 static inline void revert_page(struct page *kpte_page, unsigned long address)
 {
+	pgprot_t ref_prot;
+
+	ref_prot =
+	((address & LARGE_PAGE_MASK) < (unsigned long)&_etext)
+		? PAGE_KERNEL_LARGE_EXEC : PAGE_KERNEL_LARGE;
+
 	pte_t *linear = (pte_t *) 
 		pmd_offset(pud_offset(pgd_offset_k(address), address), address);
 	set_pmd_pte(linear,  address,
 		    pfn_pte((__pa(address) & LARGE_PAGE_MASK) >> PAGE_SHIFT,
-			    PAGE_KERNEL_LARGE));
+			    ref_prot));
 }
 
 static int
@@ -121,10 +128,16 @@ __change_page_attr(struct page *page, pg
 		if ((pte_val(*kpte) & _PAGE_PSE) == 0) { 
 			set_pte_atomic(kpte, mk_pte(page, prot)); 
 		} else {
-			struct page *split = split_large_page(address, prot); 
+			pgprot_t ref_prot;
+			struct page *split;
+	
+			ref_prot =
+			((address & LARGE_PAGE_MASK) < (unsigned long)&_etext)
+				? PAGE_KERNEL_EXEC : PAGE_KERNEL;
+			split = split_large_page(address, prot, ref_prot); 
 			if (!split)
 				return -ENOMEM;
-			set_pmd_pte(kpte,address,mk_pte(split, PAGE_KERNEL));
+			set_pmd_pte(kpte,address,mk_pte(split, ref_prot));
 			kpte_page = split;
 		}	
 		get_page(kpte_page);


                 reply	other threads:[~2005-11-28  6:52 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

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=20051128065233.GA23531@redhat.com \
    --to=davej@redhat.com \
    --cc=Stuart_Hayes@Dell.com \
    --cc=akpm@osdl.org \
    --cc=arjan@infradead.org \
    --cc=linux-kernel@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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox