diff options
author | Jan Beulich <jbeulich@novell.com> | 2007-05-02 13:27:10 -0400 |
---|---|---|
committer | Andi Kleen <andi@basil.nowhere.org> | 2007-05-02 13:27:10 -0400 |
commit | d01ad8dd56527be72947b4b9997bb2c05783c3ed (patch) | |
tree | 4bb9ad792fae974101d0baec755202eebc8181aa | |
parent | 90a0a06aa81692028864c21f981905fda46b1208 (diff) |
[PATCH] x86: Improve handling of kernel mappings in change_page_attr
Fix various broken corner cases in i386 and x86-64 change_page_attr.
AK: split off from tighten kernel image access rights
Signed-off-by: Jan Beulich <jbeulich@novell.com>
Signed-off-by: Andi Kleen <ak@suse.de>
-rw-r--r-- | arch/i386/mm/pageattr.c | 4 | ||||
-rw-r--r-- | arch/x86_64/mm/pageattr.c | 16 | ||||
-rw-r--r-- | include/asm-i386/pgtable.h | 2 |
3 files changed, 16 insertions, 6 deletions
diff --git a/arch/i386/mm/pageattr.c b/arch/i386/mm/pageattr.c index 412ebbd8adb0..ea6b6d4a0a2a 100644 --- a/arch/i386/mm/pageattr.c +++ b/arch/i386/mm/pageattr.c | |||
@@ -142,7 +142,7 @@ __change_page_attr(struct page *page, pgprot_t prot) | |||
142 | return -EINVAL; | 142 | return -EINVAL; |
143 | kpte_page = virt_to_page(kpte); | 143 | kpte_page = virt_to_page(kpte); |
144 | if (pgprot_val(prot) != pgprot_val(PAGE_KERNEL)) { | 144 | if (pgprot_val(prot) != pgprot_val(PAGE_KERNEL)) { |
145 | if ((pte_val(*kpte) & _PAGE_PSE) == 0) { | 145 | if (!pte_huge(*kpte)) { |
146 | set_pte_atomic(kpte, mk_pte(page, prot)); | 146 | set_pte_atomic(kpte, mk_pte(page, prot)); |
147 | } else { | 147 | } else { |
148 | pgprot_t ref_prot; | 148 | pgprot_t ref_prot; |
@@ -158,7 +158,7 @@ __change_page_attr(struct page *page, pgprot_t prot) | |||
158 | kpte_page = split; | 158 | kpte_page = split; |
159 | } | 159 | } |
160 | page_private(kpte_page)++; | 160 | page_private(kpte_page)++; |
161 | } else if ((pte_val(*kpte) & _PAGE_PSE) == 0) { | 161 | } else if (!pte_huge(*kpte)) { |
162 | set_pte_atomic(kpte, mk_pte(page, PAGE_KERNEL)); | 162 | set_pte_atomic(kpte, mk_pte(page, PAGE_KERNEL)); |
163 | BUG_ON(page_private(kpte_page) == 0); | 163 | BUG_ON(page_private(kpte_page) == 0); |
164 | page_private(kpte_page)--; | 164 | page_private(kpte_page)--; |
diff --git a/arch/x86_64/mm/pageattr.c b/arch/x86_64/mm/pageattr.c index 76ee90a5abe0..bf4aa8dd4254 100644 --- a/arch/x86_64/mm/pageattr.c +++ b/arch/x86_64/mm/pageattr.c | |||
@@ -179,16 +179,24 @@ __change_page_attr(unsigned long address, unsigned long pfn, pgprot_t prot, | |||
179 | int change_page_attr_addr(unsigned long address, int numpages, pgprot_t prot) | 179 | int change_page_attr_addr(unsigned long address, int numpages, pgprot_t prot) |
180 | { | 180 | { |
181 | unsigned long phys_base_pfn = __pa_symbol(__START_KERNEL_map) >> PAGE_SHIFT; | 181 | unsigned long phys_base_pfn = __pa_symbol(__START_KERNEL_map) >> PAGE_SHIFT; |
182 | int err = 0; | 182 | int err = 0, kernel_map = 0; |
183 | int i; | 183 | int i; |
184 | 184 | ||
185 | if (address >= __START_KERNEL_map | ||
186 | && address < __START_KERNEL_map + KERNEL_TEXT_SIZE) { | ||
187 | address = (unsigned long)__va(__pa(address)); | ||
188 | kernel_map = 1; | ||
189 | } | ||
190 | |||
185 | down_write(&init_mm.mmap_sem); | 191 | down_write(&init_mm.mmap_sem); |
186 | for (i = 0; i < numpages; i++, address += PAGE_SIZE) { | 192 | for (i = 0; i < numpages; i++, address += PAGE_SIZE) { |
187 | unsigned long pfn = __pa(address) >> PAGE_SHIFT; | 193 | unsigned long pfn = __pa(address) >> PAGE_SHIFT; |
188 | 194 | ||
189 | err = __change_page_attr(address, pfn, prot, PAGE_KERNEL); | 195 | if (!kernel_map || pte_present(pfn_pte(0, prot))) { |
190 | if (err) | 196 | err = __change_page_attr(address, pfn, prot, PAGE_KERNEL); |
191 | break; | 197 | if (err) |
198 | break; | ||
199 | } | ||
192 | /* Handle kernel mapping too which aliases part of the | 200 | /* Handle kernel mapping too which aliases part of the |
193 | * lowmem */ | 201 | * lowmem */ |
194 | if ((pfn >= phys_base_pfn) && | 202 | if ((pfn >= phys_base_pfn) && |
diff --git a/include/asm-i386/pgtable.h b/include/asm-i386/pgtable.h index c3b58d473a55..143ddc42b86f 100644 --- a/include/asm-i386/pgtable.h +++ b/include/asm-i386/pgtable.h | |||
@@ -159,6 +159,7 @@ void paging_init(void); | |||
159 | 159 | ||
160 | extern unsigned long long __PAGE_KERNEL, __PAGE_KERNEL_EXEC; | 160 | extern unsigned long long __PAGE_KERNEL, __PAGE_KERNEL_EXEC; |
161 | #define __PAGE_KERNEL_RO (__PAGE_KERNEL & ~_PAGE_RW) | 161 | #define __PAGE_KERNEL_RO (__PAGE_KERNEL & ~_PAGE_RW) |
162 | #define __PAGE_KERNEL_RX (__PAGE_KERNEL_EXEC & ~_PAGE_RW) | ||
162 | #define __PAGE_KERNEL_NOCACHE (__PAGE_KERNEL | _PAGE_PCD) | 163 | #define __PAGE_KERNEL_NOCACHE (__PAGE_KERNEL | _PAGE_PCD) |
163 | #define __PAGE_KERNEL_LARGE (__PAGE_KERNEL | _PAGE_PSE) | 164 | #define __PAGE_KERNEL_LARGE (__PAGE_KERNEL | _PAGE_PSE) |
164 | #define __PAGE_KERNEL_LARGE_EXEC (__PAGE_KERNEL_EXEC | _PAGE_PSE) | 165 | #define __PAGE_KERNEL_LARGE_EXEC (__PAGE_KERNEL_EXEC | _PAGE_PSE) |
@@ -166,6 +167,7 @@ extern unsigned long long __PAGE_KERNEL, __PAGE_KERNEL_EXEC; | |||
166 | #define PAGE_KERNEL __pgprot(__PAGE_KERNEL) | 167 | #define PAGE_KERNEL __pgprot(__PAGE_KERNEL) |
167 | #define PAGE_KERNEL_RO __pgprot(__PAGE_KERNEL_RO) | 168 | #define PAGE_KERNEL_RO __pgprot(__PAGE_KERNEL_RO) |
168 | #define PAGE_KERNEL_EXEC __pgprot(__PAGE_KERNEL_EXEC) | 169 | #define PAGE_KERNEL_EXEC __pgprot(__PAGE_KERNEL_EXEC) |
170 | #define PAGE_KERNEL_RX __pgprot(__PAGE_KERNEL_RX) | ||
169 | #define PAGE_KERNEL_NOCACHE __pgprot(__PAGE_KERNEL_NOCACHE) | 171 | #define PAGE_KERNEL_NOCACHE __pgprot(__PAGE_KERNEL_NOCACHE) |
170 | #define PAGE_KERNEL_LARGE __pgprot(__PAGE_KERNEL_LARGE) | 172 | #define PAGE_KERNEL_LARGE __pgprot(__PAGE_KERNEL_LARGE) |
171 | #define PAGE_KERNEL_LARGE_EXEC __pgprot(__PAGE_KERNEL_LARGE_EXEC) | 173 | #define PAGE_KERNEL_LARGE_EXEC __pgprot(__PAGE_KERNEL_LARGE_EXEC) |