x86/mm: Make PV linear pagetables optional

Allowing pagetables to point to other pagetables of the same level
(often called 'linear pagetables') has been included in Xen since its
inception; but recently it has been the source of a number of subtle
reference-counting bugs.

It is not used by Linux or MiniOS; but it is used by NetBSD and Novell
Netware.  There are significant numbers of people who are never going
to use the feature, along with significant numbers who need the
feature.

Add a Kconfig option for the feature (default to 'y').  Also add a
command-line option to control whether PV linear pagetables are
allowed (default to 'true').

NB that we leave linear_pt_count in the page struct.  It's in a union,
so its presence doesn't increase the size of the data struct.
Changing the layout of the other elements based on configuration
options is asking for trouble however; so we'll just leave it there
and ASSERT that it's zero.

Reported-by: Jann Horn <jannh@google.com>
Signed-off-by: George Dunlap <george.dunlap@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
Release-acked-by: Julien Grall <julien.grall@arm.com>
This commit is contained in:
George Dunlap committed 2017-10-27 14:36:45 +01:00
1 parent 5e2bfc23f7
commit 3285e75dea
3 files changed
+76

No files matched your search

+19
View File
@@ -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
> `= <boolean>`
> 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
> `= <integer>`
+20
View File
@@ -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
+37
View File
@@ -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);
}
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.