Re: [Xen-devel] [PATCH V2] xen: support enabling SMEP/SMAP for HVM only
>>> On 12.08.16 at 12:03,wrote: > On Thu, Aug 11, 2016 at 07:14:06AM -0600, Jan Beulich wrote: >> >>> On 11.08.16 at 11:17, wrote: >> > @@ -1404,12 +1438,20 @@ void __init noreturn __start_xen(unsigned long > mbi_p) >> > if ( !opt_smep ) >> > setup_clear_cpu_cap(X86_FEATURE_SMEP); >> > if ( cpu_has_smep ) >> > +{ >> > set_in_cr4(X86_CR4_SMEP); >> > +if ( smep_hvm_only ) >> > +write_cr4(read_cr4() & ~X86_CR4_SMEP); >> > +} >> >> So that'll clear CR4.SMEP right here, but won't help with CR4 loads >> from mmu_cr4_features (as e.g. happens indirectly during VM exits, >> since the HOST_CR4 field gets set from this variable). >> >> Did you in fact test your change, including validation of the features >> correctly remaining off over the lifetime of the system? >> >> Further, considering that you don't clear the two flags from Xen's >> internal feature bitmap, and taken together with the internal feature >> bitmap driving alternative instruction patching, I'd assume pointless >> (and performance wise perhaps harmful) patching to now take place. >> > Let me see whether I understand this correctly... > > Regarding alternative instruction patching, if enabling SMAP for HVM but > disabling it for Xen, SMAP bit must be set in x86_capability feature > bitmap and cleared in mmu_cr4_features, which means instruction patching > would take place and a #UD may occur (since SMAP is disable in Xen, but > STAC/CLAC are patched and called). No #UD would occur (hence I only said "performance wise perhaps harmful"), as per the SDM. > A little dirty solution I can think of now is to temperarily clear SMAP > bit in x86_capability before patching instruction and then set it back > when instruction patching finish, like: > > ``` > if ( opt_smap == SMAP_HVM_ONLY ) > setup_clear_cpu_cap(X86_FEATURE_SMAP); > > alternative_instructions(); > > if ( opt_smap == SMAP_HVM_ONLY ) > __set_bit(X86_FEATURE_SMAP, boot_cpu_data.x86_capability); > ``` Except that this would need further adjustment (e.g. using just __clear_bit() instead of setup_clear_cpu_cap(), or else you'd break CPU hotplug). I'm not against "a little dirty" solutions, as long as it doesn't end in plain hackery, and as long as the end result indeed meets all requirements. > Appreciate it if you have a better solution. Well, if I had a reasonably good solution, I could have gone and simply implemented it. It is the need to consider all resulting cases properly which makes this involved, and hence we've turned to you (Intel) for assistance. Jan ___ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel
Re: [Xen-devel] [PATCH V2] xen: support enabling SMEP/SMAP for HVM only
On Thu, Aug 11, 2016 at 07:14:06AM -0600, Jan Beulich wrote: > >>> On 11.08.16 at 11:17,wrote: > > @@ -1404,12 +1438,20 @@ void __init noreturn __start_xen(unsigned long > > mbi_p) > > if ( !opt_smep ) > > setup_clear_cpu_cap(X86_FEATURE_SMEP); > > if ( cpu_has_smep ) > > +{ > > set_in_cr4(X86_CR4_SMEP); > > +if ( smep_hvm_only ) > > +write_cr4(read_cr4() & ~X86_CR4_SMEP); > > +} > > So that'll clear CR4.SMEP right here, but won't help with CR4 loads > from mmu_cr4_features (as e.g. happens indirectly during VM exits, > since the HOST_CR4 field gets set from this variable). > > Did you in fact test your change, including validation of the features > correctly remaining off over the lifetime of the system? > > Further, considering that you don't clear the two flags from Xen's > internal feature bitmap, and taken together with the internal feature > bitmap driving alternative instruction patching, I'd assume pointless > (and performance wise perhaps harmful) patching to now take place. > Let me see whether I understand this correctly... Regarding alternative instruction patching, if enabling SMAP for HVM but disabling it for Xen, SMAP bit must be set in x86_capability feature bitmap and cleared in mmu_cr4_features, which means instruction patching would take place and a #UD may occur (since SMAP is disable in Xen, but STAC/CLAC are patched and called). A little dirty solution I can think of now is to temperarily clear SMAP bit in x86_capability before patching instruction and then set it back when instruction patching finish, like: ``` if ( opt_smap == SMAP_HVM_ONLY ) setup_clear_cpu_cap(X86_FEATURE_SMAP); alternative_instructions(); if ( opt_smap == SMAP_HVM_ONLY ) __set_bit(X86_FEATURE_SMAP, boot_cpu_data.x86_capability); ``` Appreciate it if you have a better solution. ___ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel
Re: [Xen-devel] [PATCH V2] xen: support enabling SMEP/SMAP for HVM only
>>> On 11.08.16 at 11:17,wrote: > Enhance "skaj...@intel.com>mep" and "smap" command line options to support I guess that was meant to be "smep". > enabling SMEP > or SMAP for HVM only with allowing "hvm" as a value. A primary complaint of mine on v1 was not addressed: The description continues to not explain why what is being done is sufficient. > --- a/docs/misc/xen-command-line.markdown > +++ b/docs/misc/xen-command-line.markdown > @@ -1427,19 +1427,21 @@ enabling more sockets and cores to go into deeper > sleep states. > > Set the serial transmit buffer size. > > -### smep > -> `= ` > +### smap > +> `= | hvm` > > > Default: `true` > > -Flag to enable Supervisor Mode Execution Protection > +Flag to enable Supervisor Mode Access Prevention > +Using `smap=hvm` to enable SMAP for HVM guests only. Use ... > --- a/xen/arch/x86/cpuid.c > +++ b/xen/arch/x86/cpuid.c > @@ -4,6 +4,7 @@ > #include > #include > #include > +#include > > const uint32_t known_features[] = INIT_KNOWN_FEATURES; > const uint32_t special_features[] = INIT_SPECIAL_FEATURES; > @@ -118,6 +119,10 @@ static void __init calculate_pv_featureset(void) > __set_bit(X86_FEATURE_HTT, pv_featureset); > __set_bit(X86_FEATURE_X2APIC, pv_featureset); > __set_bit(X86_FEATURE_CMP_LEGACY, pv_featureset); > +if ( smep_hvm_only ) > +__clear_bit(X86_FEATURE_SMEP, pv_featureset); > +if ( smap_hvm_only ) > +__clear_bit(X86_FEATURE_SMAP, pv_featureset); These flags already can't be set in pv_featureset, so the change is pointless. > --- a/xen/arch/x86/setup.c > +++ b/xen/arch/x86/setup.c > @@ -61,13 +61,19 @@ boolean_param("nosmp", opt_nosmp); > static unsigned int __initdata max_cpus; > integer_param("maxcpus", max_cpus); > > -/* smep: Enable/disable Supervisor Mode Execution Protection (default on). */ > -static bool_t __initdata opt_smep = 1; > -boolean_param("smep", opt_smep); > - > -/* smap: Enable/disable Supervisor Mode Access Prevention (default on). */ > -static bool_t __initdata opt_smap = 1; > -boolean_param("smap", opt_smap); > +/* Supervisor Mode Execution Protection (default on). */ > +/* "smep=on": Enable SMEP for Xen and guests. */ > +/* "smep=hvm": Enable SMEP for HVM only. */ > +/* "smep=off": Disable SMEP for Xen and guests. */ > +static void parse_smep_param(char *s); > +custom_param("smep", parse_smep_param); > + > +/* Supervisor Mode Access Prevention (default on). */ > +/* "smep=on": Enable SMAP for Xen and guests. */ > +/* "smep=hvm": Enable SMAP for HVM only. */ > +/* "smep=off": Disable SMAP for Xen and guests.*/ > +static void parse_smap_param(char *s); > +custom_param("smap", parse_smap_param); The commentary goes too far imo; what's wrong with retaining the earlier comments? Also please avoid forward declarations of static functions when you easily can. > @@ -111,6 +117,34 @@ struct cpuinfo_x86 __read_mostly boot_cpu_data = { 0, 0, > 0, 0, -1 }; > > unsigned long __read_mostly mmu_cr4_features = XEN_MINIMAL_CR4; > > +static bool_t __initdata opt_smep = 1; > +bool_t __initdata smep_hvm_only = 0; Why two variables when one (of non-boolean type) will do? > +static void __init parse_smep_param(char *s) > +{ > +if ( !parse_bool(s) ) > +{ > +opt_smep = 0; > +} > +else if ( !strcmp(s, "hvm") ) > +{ > +smep_hvm_only = 1; > +} > +} A command line like "smep=hvm smep=on" would no longer work afaict. Also - stray braces. > @@ -1404,12 +1438,20 @@ void __init noreturn __start_xen(unsigned long mbi_p) > if ( !opt_smep ) > setup_clear_cpu_cap(X86_FEATURE_SMEP); > if ( cpu_has_smep ) > +{ > set_in_cr4(X86_CR4_SMEP); > +if ( smep_hvm_only ) > +write_cr4(read_cr4() & ~X86_CR4_SMEP); > +} So that'll clear CR4.SMEP right here, but won't help with CR4 loads from mmu_cr4_features (as e.g. happens indirectly during VM exits, since the HOST_CR4 field gets set from this variable). Did you in fact test your change, including validation of the features correctly remaining off over the lifetime of the system? Further, considering that you don't clear the two flags from Xen's internal feature bitmap, and taken together with the internal feature bitmap driving alternative instruction patching, I'd assume pointless (and performance wise perhaps harmful) patching to now take place. Speaking of performance: The extremely bad performance with the 32-bit PV fix patches in was pretty unexpected. I'd now like to be double certain that nothing similarly unexpected happens due to the back on forth between SMEP/SMAP enabled and disabled during VM entry and exit. One would think there should be no such effect, but I'd prefer this to be confirmed. Jan ___ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel
[Xen-devel] [PATCH V2] xen: support enabling SMEP/SMAP for HVM only
Enhance "skaj...@intel.com>mep" and "smap" command line options to support enabling SMEP or SMAP for HVM only with allowing "hvm" as a value. Signed-off-by: He Chen--- Changes in V2: * Allow "hvm" as a value to "smep" and "smap" command line options. * Clear SMEP/SMAP CPUID bits for pv guests if they are set to hvm only. * Refine docs. * Rewrite commit message. --- docs/misc/xen-command-line.markdown | 14 + xen/arch/x86/cpuid.c| 5 xen/arch/x86/setup.c| 58 - xen/include/asm-x86/setup.h | 3 ++ 4 files changed, 66 insertions(+), 14 deletions(-) diff --git a/docs/misc/xen-command-line.markdown b/docs/misc/xen-command-line.markdown index 3a250cb..0e49358 100644 --- a/docs/misc/xen-command-line.markdown +++ b/docs/misc/xen-command-line.markdown @@ -1427,19 +1427,21 @@ enabling more sockets and cores to go into deeper sleep states. Set the serial transmit buffer size. -### smep -> `= ` +### smap +> `= | hvm` > Default: `true` -Flag to enable Supervisor Mode Execution Protection +Flag to enable Supervisor Mode Access Prevention +Using `smap=hvm` to enable SMAP for HVM guests only. -### smap -> `= ` +### smep +> `= | hvm` > Default: `true` -Flag to enable Supervisor Mode Access Prevention +Flag to enable Supervisor Mode Execution Protection +Using `smep=hvm` to enable SMEP for HVM guests only. ### snb\_igd\_quirk > `= | cap | ` diff --git a/xen/arch/x86/cpuid.c b/xen/arch/x86/cpuid.c index 38e34bd..afa16b8 100644 --- a/xen/arch/x86/cpuid.c +++ b/xen/arch/x86/cpuid.c @@ -4,6 +4,7 @@ #include #include #include +#include const uint32_t known_features[] = INIT_KNOWN_FEATURES; const uint32_t special_features[] = INIT_SPECIAL_FEATURES; @@ -118,6 +119,10 @@ static void __init calculate_pv_featureset(void) __set_bit(X86_FEATURE_HTT, pv_featureset); __set_bit(X86_FEATURE_X2APIC, pv_featureset); __set_bit(X86_FEATURE_CMP_LEGACY, pv_featureset); +if ( smep_hvm_only ) +__clear_bit(X86_FEATURE_SMEP, pv_featureset); +if ( smap_hvm_only ) +__clear_bit(X86_FEATURE_SMAP, pv_featureset); sanitise_featureset(pv_featureset); } diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index 217c775..625b9b4 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -61,13 +61,19 @@ boolean_param("nosmp", opt_nosmp); static unsigned int __initdata max_cpus; integer_param("maxcpus", max_cpus); -/* smep: Enable/disable Supervisor Mode Execution Protection (default on). */ -static bool_t __initdata opt_smep = 1; -boolean_param("smep", opt_smep); - -/* smap: Enable/disable Supervisor Mode Access Prevention (default on). */ -static bool_t __initdata opt_smap = 1; -boolean_param("smap", opt_smap); +/* Supervisor Mode Execution Protection (default on). */ +/* "smep=on": Enable SMEP for Xen and guests. */ +/* "smep=hvm": Enable SMEP for HVM only. */ +/* "smep=off": Disable SMEP for Xen and guests. */ +static void parse_smep_param(char *s); +custom_param("smep", parse_smep_param); + +/* Supervisor Mode Access Prevention (default on). */ +/* "smep=on": Enable SMAP for Xen and guests. */ +/* "smep=hvm": Enable SMAP for HVM only. */ +/* "smep=off": Disable SMAP for Xen and guests.*/ +static void parse_smap_param(char *s); +custom_param("smap", parse_smap_param); unsigned long __read_mostly cr4_pv32_mask; @@ -111,6 +117,34 @@ struct cpuinfo_x86 __read_mostly boot_cpu_data = { 0, 0, 0, 0, -1 }; unsigned long __read_mostly mmu_cr4_features = XEN_MINIMAL_CR4; +static bool_t __initdata opt_smep = 1; +bool_t __initdata smep_hvm_only = 0; +static void __init parse_smep_param(char *s) +{ +if ( !parse_bool(s) ) +{ +opt_smep = 0; +} +else if ( !strcmp(s, "hvm") ) +{ +smep_hvm_only = 1; +} +} + +static bool_t __initdata opt_smap = 1; +bool_t __initdata smap_hvm_only = 0; +static void __init parse_smap_param(char *s) +{ +if ( !parse_bool(s) ) +{ +opt_smap = 0; +} +else if ( !strcmp(s, "hvm") ) +{ +smap_hvm_only = 1; +} +} + bool_t __read_mostly acpi_disabled; bool_t __initdata acpi_force; static char __initdata acpi_param[10] = ""; @@ -1404,12 +1438,20 @@ void __init noreturn __start_xen(unsigned long mbi_p) if ( !opt_smep ) setup_clear_cpu_cap(X86_FEATURE_SMEP); if ( cpu_has_smep ) +{ set_in_cr4(X86_CR4_SMEP); +if ( smep_hvm_only ) +write_cr4(read_cr4() & ~X86_CR4_SMEP); +} if ( !opt_smap ) setup_clear_cpu_cap(X86_FEATURE_SMAP); if ( cpu_has_smap ) +{ set_in_cr4(X86_CR4_SMAP); +if ( smap_hvm_only ) +write_cr4(read_cr4() & ~X86_CR4_SMAP); +} cr4_pv32_mask = mmu_cr4_features & XEN_CR4_PV32_BITS; @@ -1570,7 +1612,7 @@ void __init noreturn __start_xen(unsigned long mbi_p)
[Xen-devel] [PATCH V2] xen: support enabling SMEP/SMAP for HVM only
Enhance "smep" and "smap" command line options to support enabling SMEP or SMAP for HVM only with allowing "hvm" as a value. Signed-off-by: He Chen--- Changes in V2: * Allow "hvm" as a value to "smep" and "smap" command line options. * Clear SMEP/SMAP CPUID bits for pv guests if they are set to hvm only. * Refine docs. * Rewrite commit message. --- docs/misc/xen-command-line.markdown | 14 + xen/arch/x86/cpuid.c| 5 xen/arch/x86/setup.c| 58 - xen/include/asm-x86/setup.h | 3 ++ 4 files changed, 66 insertions(+), 14 deletions(-) diff --git a/docs/misc/xen-command-line.markdown b/docs/misc/xen-command-line.markdown index 3a250cb..0e49358 100644 --- a/docs/misc/xen-command-line.markdown +++ b/docs/misc/xen-command-line.markdown @@ -1427,19 +1427,21 @@ enabling more sockets and cores to go into deeper sleep states. Set the serial transmit buffer size. -### smep -> `= ` +### smap +> `= | hvm` > Default: `true` -Flag to enable Supervisor Mode Execution Protection +Flag to enable Supervisor Mode Access Prevention +Using `smap=hvm` to enable SMAP for HVM guests only. -### smap -> `= ` +### smep +> `= | hvm` > Default: `true` -Flag to enable Supervisor Mode Access Prevention +Flag to enable Supervisor Mode Execution Protection +Using `smep=hvm` to enable SMEP for HVM guests only. ### snb\_igd\_quirk > `= | cap | ` diff --git a/xen/arch/x86/cpuid.c b/xen/arch/x86/cpuid.c index 38e34bd..afa16b8 100644 --- a/xen/arch/x86/cpuid.c +++ b/xen/arch/x86/cpuid.c @@ -4,6 +4,7 @@ #include #include #include +#include const uint32_t known_features[] = INIT_KNOWN_FEATURES; const uint32_t special_features[] = INIT_SPECIAL_FEATURES; @@ -118,6 +119,10 @@ static void __init calculate_pv_featureset(void) __set_bit(X86_FEATURE_HTT, pv_featureset); __set_bit(X86_FEATURE_X2APIC, pv_featureset); __set_bit(X86_FEATURE_CMP_LEGACY, pv_featureset); +if ( smep_hvm_only ) +__clear_bit(X86_FEATURE_SMEP, pv_featureset); +if ( smap_hvm_only ) +__clear_bit(X86_FEATURE_SMAP, pv_featureset); sanitise_featureset(pv_featureset); } diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index 217c775..625b9b4 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -61,13 +61,19 @@ boolean_param("nosmp", opt_nosmp); static unsigned int __initdata max_cpus; integer_param("maxcpus", max_cpus); -/* smep: Enable/disable Supervisor Mode Execution Protection (default on). */ -static bool_t __initdata opt_smep = 1; -boolean_param("smep", opt_smep); - -/* smap: Enable/disable Supervisor Mode Access Prevention (default on). */ -static bool_t __initdata opt_smap = 1; -boolean_param("smap", opt_smap); +/* Supervisor Mode Execution Protection (default on). */ +/* "smep=on": Enable SMEP for Xen and guests. */ +/* "smep=hvm": Enable SMEP for HVM only. */ +/* "smep=off": Disable SMEP for Xen and guests. */ +static void parse_smep_param(char *s); +custom_param("smep", parse_smep_param); + +/* Supervisor Mode Access Prevention (default on). */ +/* "smep=on": Enable SMAP for Xen and guests. */ +/* "smep=hvm": Enable SMAP for HVM only. */ +/* "smep=off": Disable SMAP for Xen and guests.*/ +static void parse_smap_param(char *s); +custom_param("smap", parse_smap_param); unsigned long __read_mostly cr4_pv32_mask; @@ -111,6 +117,34 @@ struct cpuinfo_x86 __read_mostly boot_cpu_data = { 0, 0, 0, 0, -1 }; unsigned long __read_mostly mmu_cr4_features = XEN_MINIMAL_CR4; +static bool_t __initdata opt_smep = 1; +bool_t __initdata smep_hvm_only = 0; +static void __init parse_smep_param(char *s) +{ +if ( !parse_bool(s) ) +{ +opt_smep = 0; +} +else if ( !strcmp(s, "hvm") ) +{ +smep_hvm_only = 1; +} +} + +static bool_t __initdata opt_smap = 1; +bool_t __initdata smap_hvm_only = 0; +static void __init parse_smap_param(char *s) +{ +if ( !parse_bool(s) ) +{ +opt_smap = 0; +} +else if ( !strcmp(s, "hvm") ) +{ +smap_hvm_only = 1; +} +} + bool_t __read_mostly acpi_disabled; bool_t __initdata acpi_force; static char __initdata acpi_param[10] = ""; @@ -1404,12 +1438,20 @@ void __init noreturn __start_xen(unsigned long mbi_p) if ( !opt_smep ) setup_clear_cpu_cap(X86_FEATURE_SMEP); if ( cpu_has_smep ) +{ set_in_cr4(X86_CR4_SMEP); +if ( smep_hvm_only ) +write_cr4(read_cr4() & ~X86_CR4_SMEP); +} if ( !opt_smap ) setup_clear_cpu_cap(X86_FEATURE_SMAP); if ( cpu_has_smap ) +{ set_in_cr4(X86_CR4_SMAP); +if ( smap_hvm_only ) +write_cr4(read_cr4() & ~X86_CR4_SMAP); +} cr4_pv32_mask = mmu_cr4_features & XEN_CR4_PV32_BITS; @@ -1570,7 +1612,7 @@ void __init noreturn __start_xen(unsigned long mbi_p)