Browse Source

[PATCH] Fix pte_exec/mkexec and use it in change_page_attr()

Fix the pte_exec/mkexec page table accessor functions to really
use the NX bit. Previously they only checked the USER bit, but
weren't actually used for anything.

Then use them in change_page_attr() to manipulate the NX bit
properly.

Signed-off-by: Andi Kleen <ak@suse.de>
Andi Kleen 18 năm trước cách đây
mục cha
commit
df992848f5
2 tập tin đã thay đổi với 7 bổ sung5 xóa
  1. 5 3
      arch/x86_64/mm/pageattr.c
  2. 2 2
      include/asm-x86_64/pgtable.h

+ 5 - 3
arch/x86_64/mm/pageattr.c

@@ -190,10 +190,12 @@ int change_page_attr_addr(unsigned long address, int numpages, pgprot_t prot)
 		 * lowmem */
 		if (__pa(address) < KERNEL_TEXT_SIZE) {
 			unsigned long addr2;
-			pgprot_t prot2 = prot;
+			pgprot_t prot2;
 			addr2 = __START_KERNEL_map + __pa(address);
- 			pgprot_val(prot2) &= ~_PAGE_NX;
-			err = __change_page_attr(addr2, pfn, prot2, PAGE_KERNEL_EXEC);
+			/* Make sure the kernel mappings stay executable */
+			prot2 = pte_pgprot(pte_mkexec(pfn_pte(0, prot)));
+			err = __change_page_attr(addr2, pfn, prot2,
+						 PAGE_KERNEL_EXEC);
 		} 
 	} 	
 	up_write(&init_mm.mmap_sem); 

+ 2 - 2
include/asm-x86_64/pgtable.h

@@ -265,7 +265,7 @@ static inline pte_t pfn_pte(unsigned long page_nr, pgprot_t pgprot)
 #define __LARGE_PTE (_PAGE_PSE|_PAGE_PRESENT)
 static inline int pte_user(pte_t pte)		{ return pte_val(pte) & _PAGE_USER; }
 static inline int pte_read(pte_t pte)		{ return pte_val(pte) & _PAGE_USER; }
-static inline int pte_exec(pte_t pte)		{ return pte_val(pte) & _PAGE_USER; }
+static inline int pte_exec(pte_t pte)		{ return !(pte_val(pte) & _PAGE_NX); }
 static inline int pte_dirty(pte_t pte)		{ return pte_val(pte) & _PAGE_DIRTY; }
 static inline int pte_young(pte_t pte)		{ return pte_val(pte) & _PAGE_ACCESSED; }
 static inline int pte_write(pte_t pte)		{ return pte_val(pte) & _PAGE_RW; }
@@ -278,7 +278,7 @@ static inline pte_t pte_mkclean(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) &
 static inline pte_t pte_mkold(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_ACCESSED)); return pte; }
 static inline pte_t pte_wrprotect(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_RW)); return pte; }
 static inline pte_t pte_mkread(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) | _PAGE_USER)); return pte; }
-static inline pte_t pte_mkexec(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) | _PAGE_USER)); return pte; }
+static inline pte_t pte_mkexec(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_NX)); return pte; }
 static inline pte_t pte_mkdirty(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) | _PAGE_DIRTY)); return pte; }
 static inline pte_t pte_mkyoung(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) | _PAGE_ACCESSED)); return pte; }
 static inline pte_t pte_mkwrite(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) | _PAGE_RW)); return pte; }