diff mbox series

x86/altcall: silence undue warning

Message ID 0e3594ff-c637-46f2-bc95-7a26b5471b86@suse.com (mailing list archive)
State New, archived
Headers show
Series x86/altcall: silence undue warning | expand

Commit Message

Jan Beulich March 1, 2022, 11:36 a.m. UTC
Suitable compiler options are passed only when the actual feature
(XEN_IBT) is enabled, not when merely the compiler capability was found
to be available.

Fixes: 12e3410e071e ("x86/altcall: Check and optimise altcall targets")
Signed-off-by: Jan Beulich <jbeulich@suse.com>
---
Furthermore, is "Optimised away ..." really appropriate in what
37ed5da851b8 ("x86/altcall: Optimise away endbr64 instruction where
possible") added? If this really was an optimization (rather than
hardening), shouldn't we purge ENDBR also when !cpu_has_xen_ibt, and
then ideally all of them? Whereas if this is mainly about hardening,
wouldn't the message better say "Purged" or "Clobbered"?

Comments

Andrew Cooper March 1, 2022, 12:48 p.m. UTC | #1
On 01/03/2022 11:36, Jan Beulich wrote:
> Suitable compiler options are passed only when the actual feature
> (XEN_IBT) is enabled, not when merely the compiler capability was found
> to be available.
>
> Fixes: 12e3410e071e ("x86/altcall: Check and optimise altcall targets")
> Signed-off-by: Jan Beulich <jbeulich@suse.com>

Hmm yes.  This is fallout from separating CONFIG_HAS_CC_CET_IBT and
CONFIG_XEN_IBT.

Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>

> ---
> Furthermore, is "Optimised away ..." really appropriate in what
> 37ed5da851b8 ("x86/altcall: Optimise away endbr64 instruction where
> possible") added? If this really was an optimization (rather than
> hardening), shouldn't we purge ENDBR also when !cpu_has_xen_ibt, and
> then ideally all of them? Whereas if this is mainly about hardening,
> wouldn't the message better say "Purged" or "Clobbered"?

I did have an RFC about this.  Turning ENDBR into NOP4 matters, on a
CET-IBT-active system, to restrict the available options an attacker has
when they have already managed to hijack a function pointer (i.e.
already got a partial write gadget).

From that point of view, it is hardening.

The first version of this logic was trying to use UD1 in the same way as
Linux does, to harden non-CET builds too, but that does depend on having
objtool so all direct branches can have their targets updated to miss
the UD1 instruction.

~Andrew

P.S. I'd still like to have "away %u of %u endbr64's".  It occurs to me
that now we have check-endbr64.sh, we could `wc -l` the $VALID file and
re-link this back in, but then we couldn't check the final objects.
Jan Beulich March 1, 2022, 1:34 p.m. UTC | #2
On 01.03.2022 13:48, Andrew Cooper wrote:
> On 01/03/2022 11:36, Jan Beulich wrote:
>> Suitable compiler options are passed only when the actual feature
>> (XEN_IBT) is enabled, not when merely the compiler capability was found
>> to be available.
>>
>> Fixes: 12e3410e071e ("x86/altcall: Check and optimise altcall targets")
>> Signed-off-by: Jan Beulich <jbeulich@suse.com>
> 
> Hmm yes.  This is fallout from separating CONFIG_HAS_CC_CET_IBT and
> CONFIG_XEN_IBT.
> 
> Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>

Thanks.

>> ---
>> Furthermore, is "Optimised away ..." really appropriate in what
>> 37ed5da851b8 ("x86/altcall: Optimise away endbr64 instruction where
>> possible") added? If this really was an optimization (rather than
>> hardening), shouldn't we purge ENDBR also when !cpu_has_xen_ibt, and
>> then ideally all of them? Whereas if this is mainly about hardening,
>> wouldn't the message better say "Purged" or "Clobbered"?
> 
> I did have an RFC about this.  Turning ENDBR into NOP4 matters, on a
> CET-IBT-active system, to restrict the available options an attacker has
> when they have already managed to hijack a function pointer (i.e.
> already got a partial write gadget).
> 
> From that point of view, it is hardening.

But then you don't say whether there's any optimization aspect here.
My question was really about the wording of that log message.

> The first version of this logic was trying to use UD1 in the same way as
> Linux does, to harden non-CET builds too, but that does depend on having
> objtool so all direct branches can have their targets updated to miss
> the UD1 instruction.

I think it would be possible (but likely cumbersome) to arrange for
this also without objtool.

> P.S. I'd still like to have "away %u of %u endbr64's".  It occurs to me
> that now we have check-endbr64.sh, we could `wc -l` the $VALID file and
> re-link this back in, but then we couldn't check the final objects.

I was thinking about this wish of yours as well; I simply didn't know how
important you view it to have this information. Not being able to check
the final objects is not an issue: If the data is available after the 2nd
linking pass, contents of .text isn't going to change anymore. All
addresses are the same for the 2nd and 3rd linking passes. Hence if the
checking was inserted between these two passes, the value of interest
could be propagated suitably.

Jan
Andrew Cooper March 1, 2022, 2:23 p.m. UTC | #3
On 01/03/2022 13:34, Jan Beulich wrote:
> On 01.03.2022 13:48, Andrew Cooper wrote:
>> On 01/03/2022 11:36, Jan Beulich wrote:
>>> Suitable compiler options are passed only when the actual feature
>>> (XEN_IBT) is enabled, not when merely the compiler capability was found
>>> to be available.
>>>
>>> Fixes: 12e3410e071e ("x86/altcall: Check and optimise altcall targets")
>>> Signed-off-by: Jan Beulich <jbeulich@suse.com>
>> Hmm yes.  This is fallout from separating CONFIG_HAS_CC_CET_IBT and
>> CONFIG_XEN_IBT.
>>
>> Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
> Thanks.
>
>>> ---
>>> Furthermore, is "Optimised away ..." really appropriate in what
>>> 37ed5da851b8 ("x86/altcall: Optimise away endbr64 instruction where
>>> possible") added? If this really was an optimization (rather than
>>> hardening), shouldn't we purge ENDBR also when !cpu_has_xen_ibt, and
>>> then ideally all of them? Whereas if this is mainly about hardening,
>>> wouldn't the message better say "Purged" or "Clobbered"?
>> I did have an RFC about this.  Turning ENDBR into NOP4 matters, on a
>> CET-IBT-active system, to restrict the available options an attacker has
>> when they have already managed to hijack a function pointer (i.e.
>> already got a partial write gadget).
>>
>> From that point of view, it is hardening.
> But then you don't say whether there's any optimization aspect here.
> My question was really about the wording of that log message.

The optimisation aspect is direct branch target +4, because that is what
saves on decode bandwidth.

>
>> The first version of this logic was trying to use UD1 in the same way as
>> Linux does, to harden non-CET builds too, but that does depend on having
>> objtool so all direct branches can have their targets updated to miss
>> the UD1 instruction.
> I think it would be possible (but likely cumbersome) to arrange for
> this also without objtool.

It's only useful non-CET hardware to cross-check that things won't
explode when CET is enabled, due to mispositioned branches/etc.

An actual attacker on non-CET hardware would just adjust the function
pointer +4 to skip the UD1.

>> P.S. I'd still like to have "away %u of %u endbr64's".  It occurs to me
>> that now we have check-endbr64.sh, we could `wc -l` the $VALID file and
>> re-link this back in, but then we couldn't check the final objects.
> I was thinking about this wish of yours as well; I simply didn't know how
> important you view it to have this information.

The most useful piece of information is how many ENDBR64's remain,
because those denote the extent of the attackers ability to hijack
function pointers without suffering #CP.  Ideally, the number produced
at boot wants cross-checking with script which can take xen-syms,
calculate $VALID - $CF_CLOBBER and identify all the expected
runtime-active targets.

At the moment, I can guestimate based on knowing how many where disabled
at boot time, and how many were in the original build, but I don't
expect anyone else to know that an all-enabled build of Xen is ~1600
ENDBR64's.

~Andrew
Jan Beulich March 1, 2022, 2:54 p.m. UTC | #4
On 01.03.2022 15:23, Andrew Cooper wrote:
> On 01/03/2022 13:34, Jan Beulich wrote:
>> On 01.03.2022 13:48, Andrew Cooper wrote:
>>> On 01/03/2022 11:36, Jan Beulich wrote:
>>>> Suitable compiler options are passed only when the actual feature
>>>> (XEN_IBT) is enabled, not when merely the compiler capability was found
>>>> to be available.
>>>>
>>>> Fixes: 12e3410e071e ("x86/altcall: Check and optimise altcall targets")
>>>> Signed-off-by: Jan Beulich <jbeulich@suse.com>
>>> Hmm yes.  This is fallout from separating CONFIG_HAS_CC_CET_IBT and
>>> CONFIG_XEN_IBT.
>>>
>>> Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
>> Thanks.
>>
>>>> ---
>>>> Furthermore, is "Optimised away ..." really appropriate in what
>>>> 37ed5da851b8 ("x86/altcall: Optimise away endbr64 instruction where
>>>> possible") added? If this really was an optimization (rather than
>>>> hardening), shouldn't we purge ENDBR also when !cpu_has_xen_ibt, and
>>>> then ideally all of them? Whereas if this is mainly about hardening,
>>>> wouldn't the message better say "Purged" or "Clobbered"?
>>> I did have an RFC about this.  Turning ENDBR into NOP4 matters, on a
>>> CET-IBT-active system, to restrict the available options an attacker has
>>> when they have already managed to hijack a function pointer (i.e.
>>> already got a partial write gadget).
>>>
>>> From that point of view, it is hardening.
>> But then you don't say whether there's any optimization aspect here.
>> My question was really about the wording of that log message.
> 
> The optimisation aspect is direct branch target +4, because that is what
> saves on decode bandwidth.

But that's the other, entirely independent ENDBR-related piece of code in
the function. All we do in the loop ahead of emitting the message here is
"add_nops(ptr, ENDBR64_LEN)". There's no counting at all of how many
times we advance a call target by 4.

Jan
diff mbox series

Patch

--- a/xen/arch/x86/alternative.c
+++ b/xen/arch/x86/alternative.c
@@ -295,7 +295,7 @@  static void init_or_livepatch _apply_alt
                      * marginal perf improvement which saves on instruction
                      * decode bandwidth.
                      */
-                    if ( IS_ENABLED(CONFIG_HAS_CC_CET_IBT) )
+                    if ( IS_ENABLED(CONFIG_XEN_IBT) )
                     {
                         if ( is_endbr64(dest) )
                             dest += ENDBR64_LEN;