diff options
-rw-r--r-- | arch/x86/include/asm/set_memory.h | 1 | ||||
-rw-r--r-- | arch/x86/mm/init.c | 26 | ||||
-rw-r--r-- | arch/x86/mm/pageattr.c | 13 |
3 files changed, 38 insertions, 2 deletions
diff --git a/arch/x86/include/asm/set_memory.h b/arch/x86/include/asm/set_memory.h index bd090367236c..34cffcef7375 100644 --- a/arch/x86/include/asm/set_memory.h +++ b/arch/x86/include/asm/set_memory.h | |||
@@ -46,6 +46,7 @@ int set_memory_np(unsigned long addr, int numpages); | |||
46 | int set_memory_4k(unsigned long addr, int numpages); | 46 | int set_memory_4k(unsigned long addr, int numpages); |
47 | int set_memory_encrypted(unsigned long addr, int numpages); | 47 | int set_memory_encrypted(unsigned long addr, int numpages); |
48 | int set_memory_decrypted(unsigned long addr, int numpages); | 48 | int set_memory_decrypted(unsigned long addr, int numpages); |
49 | int set_memory_np_noalias(unsigned long addr, int numpages); | ||
49 | 50 | ||
50 | int set_memory_array_uc(unsigned long *addr, int addrinarray); | 51 | int set_memory_array_uc(unsigned long *addr, int addrinarray); |
51 | int set_memory_array_wc(unsigned long *addr, int addrinarray); | 52 | int set_memory_array_wc(unsigned long *addr, int addrinarray); |
diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c index bc11dedffc45..74b157ac078d 100644 --- a/arch/x86/mm/init.c +++ b/arch/x86/mm/init.c | |||
@@ -780,8 +780,30 @@ void free_init_pages(char *what, unsigned long begin, unsigned long end) | |||
780 | */ | 780 | */ |
781 | void free_kernel_image_pages(void *begin, void *end) | 781 | void free_kernel_image_pages(void *begin, void *end) |
782 | { | 782 | { |
783 | free_init_pages("unused kernel image", | 783 | unsigned long begin_ul = (unsigned long)begin; |
784 | (unsigned long)begin, (unsigned long)end); | 784 | unsigned long end_ul = (unsigned long)end; |
785 | unsigned long len_pages = (end_ul - begin_ul) >> PAGE_SHIFT; | ||
786 | |||
787 | |||
788 | free_init_pages("unused kernel image", begin_ul, end_ul); | ||
789 | |||
790 | /* | ||
791 | * PTI maps some of the kernel into userspace. For performance, | ||
792 | * this includes some kernel areas that do not contain secrets. | ||
793 | * Those areas might be adjacent to the parts of the kernel image | ||
794 | * being freed, which may contain secrets. Remove the "high kernel | ||
795 | * image mapping" for these freed areas, ensuring they are not even | ||
796 | * potentially vulnerable to Meltdown regardless of the specific | ||
797 | * optimizations PTI is currently using. | ||
798 | * | ||
799 | * The "noalias" prevents unmapping the direct map alias which is | ||
800 | * needed to access the freed pages. | ||
801 | * | ||
802 | * This is only valid for 64bit kernels. 32bit has only one mapping | ||
803 | * which can't be treated in this way for obvious reasons. | ||
804 | */ | ||
805 | if (IS_ENABLED(CONFIG_X86_64) && cpu_feature_enabled(X86_FEATURE_PTI)) | ||
806 | set_memory_np_noalias(begin_ul, len_pages); | ||
785 | } | 807 | } |
786 | 808 | ||
787 | void __ref free_initmem(void) | 809 | void __ref free_initmem(void) |
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c index c04153796f61..0a74996a1149 100644 --- a/arch/x86/mm/pageattr.c +++ b/arch/x86/mm/pageattr.c | |||
@@ -53,6 +53,7 @@ static DEFINE_SPINLOCK(cpa_lock); | |||
53 | #define CPA_FLUSHTLB 1 | 53 | #define CPA_FLUSHTLB 1 |
54 | #define CPA_ARRAY 2 | 54 | #define CPA_ARRAY 2 |
55 | #define CPA_PAGES_ARRAY 4 | 55 | #define CPA_PAGES_ARRAY 4 |
56 | #define CPA_NO_CHECK_ALIAS 8 /* Do not search for aliases */ | ||
56 | 57 | ||
57 | #ifdef CONFIG_PROC_FS | 58 | #ifdef CONFIG_PROC_FS |
58 | static unsigned long direct_pages_count[PG_LEVEL_NUM]; | 59 | static unsigned long direct_pages_count[PG_LEVEL_NUM]; |
@@ -1486,6 +1487,9 @@ static int change_page_attr_set_clr(unsigned long *addr, int numpages, | |||
1486 | 1487 | ||
1487 | /* No alias checking for _NX bit modifications */ | 1488 | /* No alias checking for _NX bit modifications */ |
1488 | checkalias = (pgprot_val(mask_set) | pgprot_val(mask_clr)) != _PAGE_NX; | 1489 | checkalias = (pgprot_val(mask_set) | pgprot_val(mask_clr)) != _PAGE_NX; |
1490 | /* Has caller explicitly disabled alias checking? */ | ||
1491 | if (in_flag & CPA_NO_CHECK_ALIAS) | ||
1492 | checkalias = 0; | ||
1489 | 1493 | ||
1490 | ret = __change_page_attr_set_clr(&cpa, checkalias); | 1494 | ret = __change_page_attr_set_clr(&cpa, checkalias); |
1491 | 1495 | ||
@@ -1772,6 +1776,15 @@ int set_memory_np(unsigned long addr, int numpages) | |||
1772 | return change_page_attr_clear(&addr, numpages, __pgprot(_PAGE_PRESENT), 0); | 1776 | return change_page_attr_clear(&addr, numpages, __pgprot(_PAGE_PRESENT), 0); |
1773 | } | 1777 | } |
1774 | 1778 | ||
1779 | int set_memory_np_noalias(unsigned long addr, int numpages) | ||
1780 | { | ||
1781 | int cpa_flags = CPA_NO_CHECK_ALIAS; | ||
1782 | |||
1783 | return change_page_attr_set_clr(&addr, numpages, __pgprot(0), | ||
1784 | __pgprot(_PAGE_PRESENT), 0, | ||
1785 | cpa_flags, NULL); | ||
1786 | } | ||
1787 | |||
1775 | int set_memory_4k(unsigned long addr, int numpages) | 1788 | int set_memory_4k(unsigned long addr, int numpages) |
1776 | { | 1789 | { |
1777 | return change_page_attr_set_clr(&addr, numpages, __pgprot(0), | 1790 | return change_page_attr_set_clr(&addr, numpages, __pgprot(0), |