Spectre V1 defense in GCC
Spectre V1 defense in GCC
Posted Jul 10, 2018 23:50 UTC (Tue) by lambda (subscriber, #40735)In reply to: Spectre V1 defense in GCC by Sesse
Parent article: Spectre V1 defense in GCC
The docs part of the patches provide a better description of the actual behavior. It always returns the given value when executing non-speculatively. When executing speculatively, it either blocks until all speculation is resolved, or if the architecture supports it, returns the fallback value if there is outstanding speculation that could turn out to be incorrect. This basically means that in the speculative scenarios that could cause issues, you will just work with the dummy value, and the speculation will be useless but safe.
+(speculation_safe_value, +"This target hook can be used to generate a target-specific code\n\ + sequence that implements the @code{__builtin_speculation_safe_value}\n\ + built-in function. The function must always return @var{val} in\n\ + @var{result} in mode @var{mode} when the cpu is not executing\n\ + speculatively, but must never return that when speculating until it\n\ + is known that the speculation will not be unwound. The hook supports\n\ + two primary mechanisms for implementing the requirements. The first\n\ + is to emit a speculation barrier which forces the processor to wait\n\ + until all prior speculative operations have been resolved; the second\n\ + is to use a target-specific mechanism that can track the speculation\n\ + state and to return @var{failval} if it can determine that\n\ + speculation must be unwound at a later time.\n\ + \n\ + The default implementation simply copies @var{val} to @var{result} and\n\ + emits a @code{speculation_barrier} instruction if that is defined. If\n\ + @code{speculation_barrier} is not defined for the target a warning will\n\ + be generated.",
There are some examples later in the thread that shows how this can be used, such as the following. This is written with the assumption that mem[0] is a safe, if potentially incorrect, value to return:
void *mem; void* f(unsigned untrusted) { if (untrusted < 100) return mem[__builtin_speculation_safe_value (untrusted)]; return NULL; }
Posted Jul 11, 2018 0:21 UTC (Wed)
by roc (subscriber, #30627)
[Link] (6 responses)
Posted Jul 11, 2018 0:41 UTC (Wed)
by lambda (subscriber, #40735)
[Link] (2 responses)
There is another example which uses
Point taken that the first example isn't necessarily good if you, say, have a zero-length slice that you're bounds checking against, or something of the sort.
Luckily, this intrinsic should only need to be used in relatively few places, which can be intensively code reviewed; anything which allows code to execute within a process but shouldn't have access to all of the data in the process, such as a JavaScript or wasm engine. I feel like it shouldn't be too hard to encapsulate most such bounds checks into a relatively small number of functions, which could be thoroughly checked.
Posted Jul 11, 2018 13:13 UTC (Wed)
by matthias (subscriber, #94967)
[Link] (1 responses)
I am less optimistic. Actually this affects all parts of code that deal with user input, not only scripting languages. A JPEG image needs to be interpreted to be printed on screen. If I tamper with the image, I might trigger speculative execution in the JPEG library. Certainly harder to exploit than using JavaScript, but is it impossible?
Posted Jul 11, 2018 14:16 UTC (Wed)
by epa (subscriber, #39769)
[Link]
Posted Jul 12, 2018 10:06 UTC (Thu)
by edeloget (subscriber, #88392)
[Link] (2 responses)
It's more or less required by the C standard unless I'm mistaken (for element[n] to be a valid expression, element shall be a valid pointer). gcc developers are not that interested in non-standard code :)
Posted Jul 12, 2018 11:17 UTC (Thu)
by excors (subscriber, #95769)
[Link]
(As a more realistic example, you could have some kind of dynamic array which stores a size and a pointer to the storage, but that pointer is an uninitialised value if size is 0. Speculatively reading from the 'safe' index 0 could be bad, and the CPU might do that even if the C code always checks size before accessing the storage.)
Posted Jul 14, 2018 4:50 UTC (Sat)
by roc (subscriber, #30627)
[Link]
It's completely plausible that element[0] is uninitialized and the program never touches it during non-speculative execution, therefore is completely OK w.r.t. the C standard, but the CPU reads element[0] speculatively, leaking information about the uninitialized data.
Spectre V1 defense in GCC
Spectre V1 defense in GCC
return *__builtin_speculation_safe_value (mem + untrusted);
so that it will speculate a NULL pointer dereference instead, if you can't afford to leak mem[0]
, or are in code where you can't tell if leaking mem[0]
is safe.
Spectre V1 defense in GCC
Spectre V1 defense in GCC
Spectre V1 defense in GCC
Spectre V1 defense in GCC
Spectre V1 defense in GCC