ACK/CMNT: [SRU][Xenial][PATCH 2/3] UBUNTU: SAUCE: x86/speculation: Cleanup IBRS runtime control handling

Juerg Haefliger juerg.haefliger at canonical.com
Wed Dec 5 10:41:28 UTC 2018


On Tue, 4 Dec 2018 13:48:37 -0600
Tyler Hicks <tyhicks at canonical.com> wrote:

> On 2018-12-03 14:17:49, Juerg Haefliger wrote:
> > > > +#define ubuntu_restrict_branch_speculation_start()			\
> > > > +do {									\
> > > > +	u64 val = x86_spec_ctrl_base | SPEC_CTRL_IBRS;			\
> > > > +									\
> > > > +	if (ibrs_enabled)						\
> > > > +		native_wrmsrl(MSR_IA32_SPEC_CTRL, val);			\
> > > > +} while (0)
> > > > +
> > > > +#define ubuntu_restrict_branch_speculation_end()			\
> > > > +do {									\
> > > > +	u64 val = x86_spec_ctrl_base;					\
> > > > +									\
> > > > +	if (ibrs_enabled)						\
> > > > +		native_wrmsrl(MSR_IA32_SPEC_CTRL, val);			\
> > > > + } while (0)  
> > 
> > I just realized that the above is incorrect. If ibrs_enabled == 2 then we set
> > the IBRS bit on every CPU and should not fiddle with them here, no?
> > 
> > So it should be:
> >   if (ibrs_enabled == 1)
> >       native_wrmsrl(MSR_IA32_SPEC_CTRL, val);  
> 
> Yes, I think that's correct.

After running some more tests I take my earlier statement back. Primarily
because it would change the current behaviour. So I leave it as it is until
somebody reports an issue.

 
> > 
> >   
> > > >  	/*
> > > >  	 * Retpoline means the kernel is safe because it has no indirect
> > > >  	 * branches. Enhanced IBRS protects firmware too, so, enable restricted
> > > > @@ -463,9 +446,23 @@ specv2_set_mode:
> > > >  	 * the CPU supports Enhanced IBRS, kernel might un-intentionally not
> > > >  	 * enable IBRS around firmware calls.
> > > >  	 */
> > > > -	if (boot_cpu_has(X86_FEATURE_IBRS) && mode != SPECTRE_V2_IBRS_ENHANCED) {
> > > > -		setup_force_cpu_cap(X86_FEATURE_USE_IBRS_FW);
> > > > -		pr_info("Enabling Restricted Speculation for firmware calls\n");
> > > > +	if (boot_cpu_has(X86_FEATURE_IBRS)) {
> > > > +		if (mode != SPECTRE_V2_IBRS_ENHANCED) {
> > > > +			setup_force_cpu_cap(X86_FEATURE_USE_IBRS_FW);
> > > > +			pr_info("Enabling Restricted Speculation for firmware calls\n");
> > > > +		}
> > > > +		if (noibrs ||
> > > > +		    mode == SPECTRE_V2_RETPOLINE_GENERIC ||
> > > > +		    mode == SPECTRE_V2_RETPOLINE_AMD ||
> > > > +		    mode == SPECTRE_V2_IBRS_ENHANCED) {
> > > > +			/*
> > > > +			 * IBRS disabled via commandline or the kernel is
> > > > +			 * retpoline compiled or the HW supports enhanced IBRS
> > > > +			 */
> > > > +			set_ibrs_enabled(0);    
> > > 
> > > It took me a while to understand that IBRS Enhanced handling here (and
> > > then all the subtle details at runtime...). I now see that the IBRS bit
> > > of the IA32_SPEC_CTRL MSR is set earlier in this function if IBRS
> > > Enhanced is supported. Additionally, the SPEC_CTRL_IBRS bit is set in
> > > the x86_spec_ctrl_base bitmask. The above call to set_ibrs_enabled(0)
> > > ensures that ibrs_enabled is set to 0. That means that the IBRS bit of
> > > the IA32_SPEC_CTRL MSR will not be twiddled in future calls to
> > > ubuntu_restrict_branch_speculation_{start,end}() which is the correct
> > > behavior for IBRS Enhanced but it is a bit confusing since ibrs_enabled
> > > is 0.  
> > 
> > Hmm... The call set_ibrs_enabled(0) will clear the IBRS bit on all CPUs.
> > On hindsight, that seems wrong in the presence of enhanced IBRS. Maybe we
> > should disable the runtime control completely if mode ==
> > SPECTRE_V2_IBRS_ENHANCED?  
> 
> The call set_ibrs_enabled(0) won't clear the IBRS bit because
> x86_spec_ctrl_base has the SPEC_CTRL_IBRS bit set when Enhanced IBRS is
> supported.

Oh, right. Convoluted... :-(


> However, one of the main benefits of Enhanced IBRS is that
> you write to the MSR once and then don't have to toggle it at all so
> set_ibrs_enabled(0) will be inefficient.
> >   
> > > > +int set_ibrs_enabled(unsigned int val)
> > > > +{
> > > > +	int error = 0;
> > > > +	unsigned int cpu;
> > > > +
> > > > +	mutex_lock(&spec_ctrl_mutex);
> > > > +
> > > > +	/* Only enable/disable IBRS if the CPU supports it */
> > > > +	if (boot_cpu_has(X86_FEATURE_IBRS)) {
> > > > +		ibrs_enabled = val;
> > > > +		pr_info("Spectre V2 : Spectre v2 mitigation: %s Indirect "    
> > > 
> > > I think the "Spectre V2 : " portion of this message is redundant and is
> > > also not present in upstream's message which could confuse user or
> > > scripts that are looking at log messages. Can it be removed when
> > > applying the patch?  
> > 
> > Again, this is how upstream reported it until just recently.
> > 
> > 
> >    
> > > > +			"Branch Restricted Speculation%s\n",
> > > > +			ibrs_enabled ? "Enabling" : "Disabling",
> > > > +			ibrs_enabled == 2 ? " (user space)" : "");
> > > > +
> > > > +		if (ibrs_enabled == 0) {
> > > > +			/* Always disable IBRS */
> > > > +			u64 val = x86_spec_ctrl_base;
> > > > +
> > > > +			for_each_online_cpu(cpu) {
> > > > +				wrmsrl_on_cpu(cpu, MSR_IA32_SPEC_CTRL, val);
> > > > +			}
> > > > +		} else if (ibrs_enabled == 2) {
> > > > +			/* Always enable IBRS, even in user space */
> > > > +			u64 val = x86_spec_ctrl_base | SPEC_CTRL_IBRS;
> > > > +
> > > > +			for_each_online_cpu(cpu) {
> > > > +				wrmsrl_on_cpu(cpu, MSR_IA32_SPEC_CTRL, val);
> > > > +			}
> > > > +		}
> > > > +	} else {
> > > > +		ibrs_enabled = 0;
> > > > +		if (val) {
> > > > +			/* IBRS is not supported but we try to turn it on */
> > > > +			error = -EINVAL;
> > > > +		}
> > > > +	}
> > > > +
> > > > +	/* Update the shadow variable */
> > > > +	__ibrs_enabled = ibrs_enabled;
> > > > +
> > > > +	mutex_unlock(&spec_ctrl_mutex);
> > > > +
> > > > +	return error;
> > > > +}
> > > > +
> > > > +static int ibrs_enabled_handler(struct ctl_table *table, int write,
> > > > +                               void __user *buffer, size_t *lenp,
> > > > +                               loff_t *ppos)
> > > > +{
> > > > +	int error;
> > > > +
> > > > +	error = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
> > > > +	if (error)
> > > > +		return error;
> > > > +
> > > > +	return set_ibrs_enabled(__ibrs_enabled);
> > > > +}
> > > >  #endif    
> > > 
> > > IBRS Enhanced cannot be disabled with this sysctl since ibrs_enabled is
> > > already 0 and the corresponding bit is set in x86_spec_ctrl_base. I
> > > personally don't feel like this is a problem but I wanted to mention it.  
> > 
> > As mentioned above, with enhanced IBRS we can still fiddle with the IBRS bit
> > in the MSR via the runtime controls. We probably don't want that.  
>
> Now I'm thinking that it makes sense to be able to disable and enable
> Enhanced IBRS with the sysctl. Why wouldn't we want to support that?

Because it introduces another ubuntu-only-impossible-to-test-hard-to-maintain
feature with questionable benefit. Until there's a user request for it
I'm leaning towards disabling the runtime controls in Enhanced IBRS mode.

...Juerg


 
> Tyler

-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 833 bytes
Desc: OpenPGP digital signature
URL: <https://lists.ubuntu.com/archives/kernel-team/attachments/20181205/00a728b1/attachment.sig>


More information about the kernel-team mailing list