Skip to content

Commit

Permalink
[PATCH] x86/x86_64: mark rodata section read only: generic x86-64 bugfix
Browse files Browse the repository at this point in the history
Bug fix required for the .rodata work on x86-64:

when change_page_attr() and friends need to break up a 2Mb page into 4Kb
pages, it always set the NX bit on the PMD, which causes the cpu to consider
the entire 2Mb region to be NX regardless of the actual PTE perms.  This is
fine in general, with one big exception: the 2Mb page that covers the last
part of the kernel .text!  The fix is to not invent a new permission for the
new PMD entry, but to just inherit the existing one minus the PSE bit.

Signed-off-by: Arjan van de Ven <[email protected]>
Signed-off-by: Ingo Molnar <[email protected]>
Cc: Andi Kleen <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
Arjan van de Ven authored and Linus Torvalds committed Jan 6, 2006
1 parent 63aaf30 commit c728252
Show file tree
Hide file tree
Showing 2 changed files with 9 additions and 2 deletions.
9 changes: 7 additions & 2 deletions arch/x86_64/mm/pageattr.c
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ __change_page_attr(unsigned long address, unsigned long pfn, pgprot_t prot,
pte_t *kpte;
struct page *kpte_page;
unsigned kpte_flags;
pgprot_t ref_prot2;
kpte = lookup_address(address);
if (!kpte) return 0;
kpte_page = virt_to_page(((unsigned long)kpte) & PAGE_MASK);
Expand All @@ -140,10 +141,14 @@ __change_page_attr(unsigned long address, unsigned long pfn, pgprot_t prot,
* split_large_page will take the reference for this change_page_attr
* on the split page.
*/
struct page *split = split_large_page(address, prot, ref_prot);

struct page *split;
ref_prot2 = __pgprot(pgprot_val(pte_pgprot(*lookup_address(address))) & ~(1<<_PAGE_BIT_PSE));

split = split_large_page(address, prot, ref_prot2);
if (!split)
return -ENOMEM;
set_pte(kpte,mk_pte(split, ref_prot));
set_pte(kpte,mk_pte(split, ref_prot2));
kpte_page = split;
}
get_page(kpte_page);
Expand Down
2 changes: 2 additions & 0 deletions include/asm-x86_64/pgtable.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@ static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm, unsigned long

#define pte_same(a, b) ((a).pte == (b).pte)

#define pte_pgprot(a) (__pgprot((a).pte & ~PHYSICAL_PAGE_MASK))

#define PMD_SIZE (1UL << PMD_SHIFT)
#define PMD_MASK (~(PMD_SIZE-1))
#define PUD_SIZE (1UL << PUD_SHIFT)
Expand Down

0 comments on commit c728252

Please sign in to comment.