diff --git a/docs/misc/xen-command-line.markdown b/docs/misc/xen-command-line.markdown index eb4995e68b..781110d4b2 100644 --- a/docs/misc/xen-command-line.markdown +++ b/docs/misc/xen-command-line.markdown @@ -1422,6 +1422,25 @@ The following resources are available: CDP, one COS will corespond two CBMs other than one with CAT, due to the sum of CBMs is fixed, that means actual `cos_max` in use will automatically reduce to half when CDP is enabled. + +### pv-linear-pt +> `= ` + +> Default: `true` + +Only available if Xen is compiled with CONFIG\_PV\_LINEAR\_PT support +enabled. + +Allow PV guests to have pagetable entries pointing to other pagetables +of the same level (i.e., allowing L2 PTEs to point to other L2 pages). +This technique is often called "linear pagetables", and is sometimes +used to allow operating systems a simple way to consistently map the +current process's pagetables into its own virtual address space. + +Linux and MiniOS don't use this technique. NetBSD and Novell Netware +do; there may be other custom operating systems which do. If you're +certain you don't plan on having PV guests which use this feature, +turning it off can reduce the attack surface. ### rcu-idle-timer-period-ms > `= ` diff --git a/xen/arch/x86/Kconfig b/xen/arch/x86/Kconfig index 64955dc017..7c4582922f 100644 --- a/xen/arch/x86/Kconfig +++ b/xen/arch/x86/Kconfig @@ -37,6 +37,26 @@ source "arch/Kconfig" config PV def_bool y +config PV_LINEAR_PT + bool "Support for PV linear pagetables" + depends on PV + default y + ---help--- + Linear pagetables (also called "recursive pagetables") refers + to the practice of a guest operating system having pagetable + entries pointing to other pagetables of the same level (i.e., + allowing L2 PTEs to point to other L2 pages). Some operating + systems use it as a simple way to consistently map the current + process's pagetables into its own virtual address space. + + Linux and MiniOS don't use this technique. NetBSD and Novell + Netware do; there may be other custom operating systems which + do. If you're certain you don't plan on having PV guests + which use this feature, turning it off can reduce the attack + surface. + + If unsure, say Y. + config HVM def_bool y diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c index 1ff4a9d629..a20fdcaea4 100644 --- a/xen/arch/x86/mm.c +++ b/xen/arch/x86/mm.c @@ -626,6 +626,8 @@ static void put_data_page( put_page(page); } +#ifdef CONFIG_PV_LINEAR_PT + static bool inc_linear_entries(struct page_info *pg) { typeof(pg->linear_pt_count) nc = read_atomic(&pg->linear_pt_count), oc; @@ -693,6 +695,9 @@ static void dec_linear_uses(struct page_info *pg) * frame if it is mapped by a different root table. This is sufficient and * also necessary to allow validation of a root table mapping itself. */ +static bool __read_mostly opt_pv_linear_pt = true; +boolean_param("pv-linear-pt", opt_pv_linear_pt); + #define define_get_linear_pagetable(level) \ static int \ get_##level##_linear_pagetable( \ @@ -702,6 +707,13 @@ get_##level##_linear_pagetable( \ struct page_info *page; \ unsigned long pfn; \ \ + if ( !opt_pv_linear_pt ) \ + { \ + gdprintk(XENLOG_WARNING, \ + "Attempt to create linear p.t. (feature disabled)\n"); \ + return 0; \ + } \ + \ if ( (level##e_get_flags(pde) & _PAGE_RW) ) \ { \ gdprintk(XENLOG_WARNING, \ @@ -759,6 +771,27 @@ get_##level##_linear_pagetable( \ return 1; \ } +#else /* CONFIG_PV_LINEAR_PT */ + +#define define_get_linear_pagetable(level) \ +static int \ +get_##level##_linear_pagetable( \ + level##_pgentry_t pde, unsigned long pde_pfn, struct domain *d) \ +{ \ + return 0; \ +} + +static void dec_linear_uses(struct page_info *pg) +{ + ASSERT(pg->linear_pt_count == 0); +} + +static void dec_linear_entries(struct page_info *pg) +{ + ASSERT(pg->linear_pt_count == 0); +} + +#endif /* CONFIG_PV_LINEAR_PT */ bool is_iomem_page(mfn_t mfn) { @@ -2444,6 +2477,7 @@ static int _put_page_type(struct page_info *page, bool preemptible, break; } +#ifdef CONFIG_PV_LINEAR_PT if ( ptpg && PGT_type_equal(x, ptpg->u.inuse.type_info) ) { /* @@ -2458,6 +2492,9 @@ static int _put_page_type(struct page_info *page, bool preemptible, ASSERT(ptpg->linear_pt_count > 0); ptpg = NULL; } +#else /* CONFIG_PV_LINEAR_PT */ + BUG_ON(ptpg && PGT_type_equal(x, ptpg->u.inuse.type_info)); +#endif set_tlbflush_timestamp(page); }