public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: "Richard Earnshaw (lists)" <Richard.Earnshaw@arm.com>
To: Richard Biener <richard.guenther@gmail.com>
Cc: GCC Patches <gcc-patches@gcc.gnu.org>
Subject: Re: [PATCH 0/7] Mitigation against unsafe data speculation (CVE-2017-5753)
Date: Tue, 10 Jul 2018 13:43:00 -0000	[thread overview]
Message-ID: <f3bcd108-a10d-776d-d521-c06594d7155e@arm.com> (raw)
In-Reply-To: <CAFiYyc2YPu_2DsdMpYnKJqBWQFodBGfGUiXcdCEcx+mE9ZUWpw@mail.gmail.com>

On 10/07/18 12:21, Richard Biener wrote:
> On Tue, Jul 10, 2018 at 12:53 PM Richard Earnshaw (lists)
> <Richard.Earnshaw@arm.com> wrote:
>>
>> On 10/07/18 11:10, Richard Biener wrote:
>>> On Tue, Jul 10, 2018 at 10:39 AM Richard Earnshaw (lists)
>>> <Richard.Earnshaw@arm.com> wrote:
>>>>
>>>> On 10/07/18 08:19, Richard Biener wrote:
>>>>> On Mon, Jul 9, 2018 at 6:39 PM Richard Earnshaw
>>>>> <Richard.Earnshaw@arm.com> wrote:
>>>>>>
>>>>>>
>>>>>> The patches I posted earlier this year for mitigating against
>>>>>> CVE-2017-5753 (Spectre variant 1) attracted some useful feedback, from
>>>>>> which it became obvious that a rethink was needed.  This mail, and the
>>>>>> following patches attempt to address that feedback and present a new
>>>>>> approach to mitigating against this form of attack surface.
>>>>>>
>>>>>> There were two major issues with the original approach:
>>>>>>
>>>>>> - The speculation bounds were too tightly constrained - essentially
>>>>>>   they had to represent and upper and lower bound on a pointer, or a
>>>>>>   pointer offset.
>>>>>> - The speculation constraints could only cover the immediately preceding
>>>>>>   branch, which often did not fit well with the structure of the existing
>>>>>>   code.
>>>>>>
>>>>>> An additional criticism was that the shape of the intrinsic did not
>>>>>> fit particularly well with systems that used a single speculation
>>>>>> barrier that essentially had to wait until all preceding speculation
>>>>>> had to be resolved.
>>>>>>
>>>>>> To address all of the above, these patches adopt a new approach, based
>>>>>> in part on a posting by Chandler Carruth to the LLVM developers list
>>>>>> (https://lists.llvm.org/pipermail/llvm-dev/2018-March/122085.html),
>>>>>> but which we have extended to deal with inter-function speculation.
>>>>>> The patches divide the problem into two halves.
>>>>>>
>>>>>> The first half is some target-specific code to track the speculation
>>>>>> condition through the generated code to provide an internal variable
>>>>>> which can tell us whether or not the CPU's control flow speculation
>>>>>> matches the data flow calculations.  The idea is that the internal
>>>>>> variable starts with the value TRUE and if the CPU's control flow
>>>>>> speculation ever causes a jump to the wrong block of code the variable
>>>>>> becomes false until such time as the incorrect control flow
>>>>>> speculation gets unwound.
>>>>>>
>>>>>> The second half is that a new intrinsic function is introduced that is
>>>>>> much simpler than we had before.  The basic version of the intrinsic
>>>>>> is now simply:
>>>>>>
>>>>>>       T var = __builtin_speculation_safe_value (T unsafe_var);
>>>>>>
>>>>>> Full details of the syntax can be found in the documentation patch, in
>>>>>> patch 1.  In summary, when not speculating the intrinsic returns
>>>>>> unsafe_var; when speculating then if it can be shown that the
>>>>>> speculative flow has diverged from the intended control flow then zero
>>>>>> is returned.  An optional second argument can be used to return an
>>>>>> alternative value to zero.  The builtin may cause execution to pause
>>>>>> until the speculation state is resolved.
>>>>>
>>>>> So a trivial target implementation would be to emit a barrier and then
>>>>> it would always return unsafe_var and never zero.  What I don't understand
>>>>> fully is what users should do here, thus what the value of ever returning
>>>>> "unsafe" is.  Also I wonder why the API is forcing you to single-out a
>>>>> special value instead of doing
>>>>>
>>>>>  bool safe = __builtin_speculation_safe_value_p (T unsafe_value);
>>>>>  if (!safe)
>>>>>    /* what now? */
>>>>>
>>>>> I'm only guessing that the correct way to handle "unsafe" is basically
>>>>>
>>>>>  while (__builtin_speculation_safe_value (val) == 0)
>>>>>     ;
>>>>>
>>>>> use val, it's now safe
>>>>
>>>> No, a safe version of val is returned, not a bool telling you it is now
>>>> safe to use the original.
>>>
>>> OK, so making the old value dead is required to preserve the desired
>>> dataflow.
>>>
>>> But how should I use the special value that signaled "failure"?
>>>
>>> Obviously the user isn't supposed to simply replace 'val' with
>>>
>>>  val = __builtin_speculation_safe_value (val);
>>>
>>> to make it speculation-proof.  So - how should the user _use_ this
>>> builtin?  The docs do not say anything about this but says the
>>> very confusing
>>>
>>> +The function may use target-dependent speculation tracking state to cause
>>> +@var{failval} to be returned when it is known that speculative
>>> +execution has incorrectly predicted a conditional branch operation.
>>>
>>> because speculation is about executing instructions as if they were
>>> supposed to be executed.  Once it is known the prediciton was wrong
>>> no more "wrong" instructions will be executed but a previously
>>> speculated instruction cannot know it was "falsely" speculated.
>>>
>>> Does the above try to say that the function may return failval if the
>>> instruction is currently executed speculatively instead?  That would
>>> make sense to me.  And return failval independent of if the speculation
>>> later turns out to be correct or not.
>>>
>>>>  You must use the sanitized version in future,
>>>> not the unprotected version.
>>>>
>>>>
>>>> So the usage is going to be more like:
>>>>
>>>> val = __builtin_speculation_safe_value (val);  // Overwrite val with a
>>>> sanitized version.
>>>>
>>>> You have to use the cleaned up version, the unclean version is still
>>>> vulnerable to incorrect speculation.
>>>
>>> But then where does failval come into play?  The above cannot be correct
>>> if failval matters.
>>
>> failval only comes into play if the CPU is speculating incorrectly.
>> It's just a safe value that some CPUs might use until such time as the
>> speculation gets unwound.  In most cases it can be zero.  Perhaps a more
>> concrete example would be something like.
>>
>>
>> void **mem;
>>
>> void* f(unsigned untrusted)
>> {
>>   if (untrusted < 100)
>>     return mem[untrusted];
>>   return NULL;
>> }
>>
>> This can be rewritten as either:
>>
>> void *mem;
>>
>> void* f(unsigned untrusted)
>> {
>>   if (untrusted < 100)
>>     return mem[__builtin_speculation_safe_value (untrusted)];
>>   return NULL;
>> }
>>
>> if leaking mem[0] is not a problem; or if you're really paranoid:
>>
>> void* f(unsigned untrusted)
>> {
>>   if (untrusted < 100)
>>     return *__builtin_speculation_safe_value (mem + untrusted);
>>   return NULL;
>> }
>>
>> which becomes a NULL pointer dereference if the speculation is
>> incorrect.  The programmer doesn't need to test this code (any test
>> would likely be useless anyway as the CPU would predict the outcome and
>> speculate based on such a prediction).  They do need to think a bit
>> about what might leak if the CPU does miss-speculate, hence the two
>> examples above.
>>
>> A more complex case, where you might want a different failure value can
>> come up if you have a mask operation.  A slightly convoluted example
>> (derived from a real example we found in the Linux kernel) might be
>>
>> if (mode32)
>>   mask_from = 0x100000000;
>> else
>>   mask_from = 0;
>>
>> ... // some code
>>
>> return mem[untrusted_val & (mask_from - 1)];
>>
>> It would probably be better to place the speculation cleanup nearer the
>> initialization of mask_from, especially if mask_from could be used more
>> than once; but in that case 0 is less safe than any other (since 0-1 is
>> all bits 1).  In this case you might write:
>>
>> if (mode32)
>>   mask_from = 0x100000000;
>> else
>>   mask_from = 0;
>>
>> mask_from = __builtin_speculation_safe_value (mask_from, 1);
>>
>> ... // some code
>>
>> return mem[untrusted_val & (mask_from - 1)];
>>
>> And in this case if the speculation is incorrect the (mask_from - 1)
>> expression becomes 0 and the whole range is protected.
>>
>> Note that speculation is fine if it is correct, we don't want to hold
>> things up in that case since it will happen anyway.  It's only a problem
>> if the speculation is incorrect :-)
> 
> Ok, please amend at least the user-level documentation with one or two
> examples like above.
> 
>>
>>>
>>> Does the builtin try to say that iff the current instruction is speculated
>>> then it will return failval, otherwise it will return val and thus following
>>> code needs to handle 'failval' in a way that is safe?
>>
>> No.  From an abstract machine sense the builtin only ever returns its
>> first argument.  The fail value only appears if the CPU guesses the
>> direction of a branch and guesses *incorrectly* (incorrect speculation)
> 
> I understand how it works when the implementation issues a fence.
> How does the actual implementation (assembly) look like that makes
> the CPU know whether it speculated wrongly or not at the time the
> value is needed for further speculation given the *__bsfs (mem + offset)
> instruction _is_ speculated as well.
> 

If you've not already read it, then I suggest you read
https://developer.arm.com/support/arm-security-updates/speculative-processor-vulnerability/download-the-whitepaper
and the link I posted in the original mail to Chandler's posting on this
subject.

In essence, we start with a register (tracker) initialized to ~0.  At
every conditional branch we change

	b.cond tgt
	...
tgt:
	...

into

	b.cond tgt
	// tracker == ~cond ? tracker, 0
	csel	tracker, tracker, 0, ~cond
	...
tgt:
	// tracker == cond ? tracker, 0
	csel	tracker, tracker, 0, cond


Now when we need to inhibit speculation we emit

	and	safe_val, unsafe_val, tracker
	CSDB

Assuming we want the default result of 0 if speculating unsafely.  CSDB
is a light-weight barrier that ensures that all preceding
/data-processing/ instructions are using real results from earlier
instructions: it will resolve any data-flow speculation, but not
necessarily any control-flow speculation.

Obviously the inserted instructions only appear on the edges between the
blocks, but we take care of that during the insertion process.

R.

> Richard.
> 
>>>
>>> Again, the wording "when it is known that speculative execution has
>>> incorrectly predicted a conditional branch operation" is very confusing...
>>>
>>> Richard.
>>>
>>>> R.
>>>>
>>>>>
>>>>> that is, the return value is only interesting in sofar as to whether it is equal
>>>>> to val or the special value?
>>>>>
>>>>> That said, I wonder why we don't hide that details from the user and
>>>>> provide a predicate instead.
>>>>>
>>>>> Richard.
>>>>>
>>>>>> There are seven patches in this set, as follows.
>>>>>>
>>>>>> 1) Introduces the new intrinsic __builtin_sepculation_safe_value.
>>>>>> 2) Adds a basic hard barrier implementation for AArch32 (arm) state.
>>>>>> 3) Adds a basic hard barrier implementation for AArch64 state.
>>>>>> 4) Adds a new command-line option -mtrack-speculation (currently a no-op).
>>>>>> 5) Disables CB[N]Z and TB[N]Z when -mtrack-speculation.
>>>>>> 6) Adds the new speculation tracking pass for AArch64
>>>>>> 7) Uses the new speculation tracking pass to generate CSDB-based barrier
>>>>>>    sequences
>>>>>>
>>>>>> I haven't added a speculation-tracking pass for AArch32 at this time.
>>>>>> It is possible to do this, but would require quite a lot of rework for
>>>>>> the arm backend due to the limited number of registers that are
>>>>>> available.
>>>>>>
>>>>>> Although patch 6 is AArch64 specific, I'd appreciate a review from
>>>>>> someone more familiar with the branch edge code than myself.  There
>>>>>> appear to be a number of tricky issues with more complex edges so I'd
>>>>>> like a second opinion on that code in case I've missed an important
>>>>>> case.
>>>>>>
>>>>>> R.
>>>>>>
>>>>>>
>>>>>>
>>>>>> Richard Earnshaw (7):
>>>>>>   Add __builtin_speculation_safe_value
>>>>>>   Arm - add speculation_barrier pattern
>>>>>>   AArch64 - add speculation barrier
>>>>>>   AArch64 - Add new option -mtrack-speculation
>>>>>>   AArch64 - disable CB[N]Z TB[N]Z when tracking speculation
>>>>>>   AArch64 - new pass to add conditional-branch speculation tracking
>>>>>>   AArch64 - use CSDB based sequences if speculation tracking is enabled
>>>>>>
>>>>>>  gcc/builtin-types.def                     |   6 +
>>>>>>  gcc/builtins.c                            |  57 ++++
>>>>>>  gcc/builtins.def                          |  20 ++
>>>>>>  gcc/c-family/c-common.c                   | 143 +++++++++
>>>>>>  gcc/c-family/c-cppbuiltin.c               |   5 +-
>>>>>>  gcc/config.gcc                            |   2 +-
>>>>>>  gcc/config/aarch64/aarch64-passes.def     |   1 +
>>>>>>  gcc/config/aarch64/aarch64-protos.h       |   3 +-
>>>>>>  gcc/config/aarch64/aarch64-speculation.cc | 494 ++++++++++++++++++++++++++++++
>>>>>>  gcc/config/aarch64/aarch64.c              |  88 +++++-
>>>>>>  gcc/config/aarch64/aarch64.md             | 140 ++++++++-
>>>>>>  gcc/config/aarch64/aarch64.opt            |   4 +
>>>>>>  gcc/config/aarch64/iterators.md           |   3 +
>>>>>>  gcc/config/aarch64/t-aarch64              |  10 +
>>>>>>  gcc/config/arm/arm.md                     |  21 ++
>>>>>>  gcc/config/arm/unspecs.md                 |   1 +
>>>>>>  gcc/doc/cpp.texi                          |   4 +
>>>>>>  gcc/doc/extend.texi                       |  29 ++
>>>>>>  gcc/doc/invoke.texi                       |  10 +-
>>>>>>  gcc/doc/md.texi                           |  15 +
>>>>>>  gcc/doc/tm.texi                           |  20 ++
>>>>>>  gcc/doc/tm.texi.in                        |   2 +
>>>>>>  gcc/target.def                            |  23 ++
>>>>>>  gcc/targhooks.c                           |  27 ++
>>>>>>  gcc/targhooks.h                           |   2 +
>>>>>>  gcc/testsuite/gcc.dg/spec-barrier-1.c     |  40 +++
>>>>>>  gcc/testsuite/gcc.dg/spec-barrier-2.c     |  19 ++
>>>>>>  gcc/testsuite/gcc.dg/spec-barrier-3.c     |  13 +
>>>>>>  28 files changed, 1191 insertions(+), 11 deletions(-)
>>>>>>  create mode 100644 gcc/config/aarch64/aarch64-speculation.cc
>>>>>>  create mode 100644 gcc/testsuite/gcc.dg/spec-barrier-1.c
>>>>>>  create mode 100644 gcc/testsuite/gcc.dg/spec-barrier-2.c
>>>>>>  create mode 100644 gcc/testsuite/gcc.dg/spec-barrier-3.c
>>>>
>>

  reply	other threads:[~2018-07-10 13:43 UTC|newest]

Thread overview: 82+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-07-09 16:39 Richard Earnshaw
2018-07-09 16:39 ` [PATCH 1/7] Add __builtin_speculation_safe_value Richard Earnshaw
2018-07-23 14:28   ` Richard Earnshaw (lists)
2018-07-24 17:26   ` Richard Biener
2018-07-25  9:49     ` Richard Earnshaw (lists)
2018-07-25 10:36       ` Richard Biener
2018-07-25 12:41         ` Richard Earnshaw (lists)
2018-07-25 13:47           ` Richard Biener
2018-07-26 10:03             ` Richard Earnshaw (lists)
2018-07-26 12:41               ` Richard Biener
2018-07-26 13:06                 ` Richard Earnshaw (lists)
2018-07-26 13:13                   ` Richard Biener
2018-07-26 23:34           ` Joseph Myers
2018-07-27  0:46             ` Paul Koning
2018-07-27  8:59               ` Richard Earnshaw (lists)
2018-07-27 10:59                 ` Joseph Myers
2018-07-25 18:03     ` Richard Earnshaw (lists)
2018-07-26  8:42       ` Richard Biener
2018-07-09 16:39 ` [PATCH 6/7] AArch64 - new pass to add conditional-branch speculation tracking Richard Earnshaw
2018-07-11 21:01   ` Jeff Law
2018-07-23 14:33     ` Richard Earnshaw (lists)
2018-07-24 21:31       ` Jeff Law
2018-07-09 16:39 ` [PATCH 4/7] AArch64 - Add new option -mtrack-speculation Richard Earnshaw
2018-07-09 16:39 ` [PATCH 2/7] Arm - add speculation_barrier pattern Richard Earnshaw
2018-07-09 16:39 ` [PATCH 5/7] AArch64 - disable CB[N]Z TB[N]Z when tracking speculation Richard Earnshaw
2018-07-09 16:39 ` [PATCH 7/7] AArch64 - use CSDB based sequences if speculation tracking is enabled Richard Earnshaw
2018-07-09 16:39 ` [PATCH 3/7] AArch64 - add speculation barrier Richard Earnshaw
2018-07-09 23:13 ` [PATCH 0/7] Mitigation against unsafe data speculation (CVE-2017-5753) Jeff Law
2018-07-10  8:49   ` Richard Earnshaw (lists)
2018-07-10 13:48     ` Bill Schmidt
2018-07-10 14:14       ` Richard Earnshaw (lists)
2018-07-10 15:44         ` Jeff Law
2018-07-10 15:42     ` Jeff Law
2018-07-10 16:43       ` Richard Earnshaw (lists)
2018-07-11 20:47         ` Jeff Law
2018-07-11 22:31           ` Richard Earnshaw (lists)
2018-07-10  7:19 ` Richard Biener
2018-07-10  8:39   ` Richard Earnshaw (lists)
2018-07-10 10:10     ` Richard Biener
2018-07-10 10:53       ` Richard Earnshaw (lists)
2018-07-10 11:22         ` Richard Biener
2018-07-10 13:43           ` Richard Earnshaw (lists) [this message]
2018-07-10 15:56         ` Jeff Law
2018-07-27  9:38 ` [PATCH 00/11] (v2) " Richard Earnshaw
2018-07-27  9:38   ` [PATCH 01/11] Add __builtin_speculation_safe_value Richard Earnshaw
2018-07-27 12:11     ` Nathan Sidwell
2018-07-27 12:32       ` Richard Earnshaw (lists)
2018-07-27 12:49         ` Nathan Sidwell
2018-07-27 12:53       ` Richard Earnshaw (lists)
2018-07-30 13:16     ` Richard Biener
2018-07-31 19:25       ` H.J. Lu
2018-07-31 20:51         ` Ian Lance Taylor via gcc-patches
2018-08-01  8:50           ` Richard Earnshaw (lists)
2018-08-01  8:54             ` Jakub Jelinek
2018-08-01  9:25               ` Richard Earnshaw (lists)
2018-07-27  9:38   ` [PATCH 07/11] AArch64 - use CSDB based sequences if speculation tracking is enabled Richard Earnshaw
2018-07-27  9:38   ` [PATCH 10/11] x86 - add speculation_barrier pattern Richard Earnshaw
2018-07-28  8:25     ` Uros Bizjak
2018-07-31 23:15       ` H.J. Lu
2018-07-27  9:38   ` [PATCH 11/11] rs6000 " Richard Earnshaw
2018-07-31 22:01     ` Bill Schmidt
2018-07-31 23:31       ` Segher Boessenkool
2018-07-27  9:38   ` [PATCH 02/11] Arm " Richard Earnshaw
2018-08-06 14:01     ` Christophe Lyon
2018-08-06 15:59       ` Richard Earnshaw (lists)
2018-07-27  9:38   ` [PATCH 03/11] AArch64 - add speculation barrier Richard Earnshaw
2018-07-27  9:38   ` [PATCH 05/11] AArch64 - disable CB[N]Z TB[N]Z when tracking speculation Richard Earnshaw
2018-07-27  9:38   ` [PATCH 04/11] AArch64 - Add new option -mtrack-speculation Richard Earnshaw
2018-07-27  9:38   ` [PATCH 08/11] targhooks - provide an alternative hook for targets that never execute speculatively Richard Earnshaw
2018-07-30 13:17     ` Richard Biener
2018-07-27  9:38   ` [PATCH 09/11] pdp11 - example of a port not needing a speculation barrier Richard Earnshaw
2018-07-27 13:27     ` Paul Koning
2018-07-27 15:19       ` Richard Biener
2018-07-27  9:38   ` [PATCH 06/11] AArch64 - new pass to add conditional-branch speculation tracking Richard Earnshaw
2018-07-27 19:49   ` [PATCH 00/11] (v2) Mitigation against unsafe data speculation (CVE-2017-5753) John David Anglin
2018-08-02 18:40     ` Jeff Law
2018-08-02 20:19       ` John David Anglin
2018-08-03  9:06         ` Richard Earnshaw (lists)
2018-08-06 21:52           ` John David Anglin
2018-08-07 14:05             ` Richard Earnshaw (lists)
2018-08-07 14:56               ` John David Anglin
2018-08-03 17:26         ` Jeff Law

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=f3bcd108-a10d-776d-d521-c06594d7155e@arm.com \
    --to=richard.earnshaw@arm.com \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=richard.guenther@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).