PING [Patch][Middle-end]Add -fzero-call-used-regs=[skip|used-gpr|all-gpr|used|all]
Wed Aug 19 23:27:45 GMT 2020
> On Aug 19, 2020, at 5:57 PM, Segher Boessenkool <firstname.lastname@example.org> wrote:
> On Wed, Aug 19, 2020 at 03:05:36PM -0500, Qing Zhao wrote:
>> So, cleaning the scratch registers that are used to pass parameters at return instructions should
>> effectively mitigate ROP attack.
> But that is *very* expensive, in general. Instead of doing just a
> return instruction (which effectively costs 0 cycles, and is just one
> insn), you now have to zero all call-clobbered register at every return
> (typically many returns per function, and you are talking 10+ registers
> even if only considering the simple integer registers).
Yes, the run-time overhead and also the code-size overhead are major concerns. We should minimize the overhead
as much as we can during implementation. However, such overhead cannot be completely avoided for the security purpose.
In order to reduce the overhead for the ROP mitigation, I added 3 new values for -fzero-call-used-regs=used-arg-grp|used-arg|arg
For “used-arg-grp”, we only zero the integer registers that are used in the routine and can pass parameters; this should provide ROP mitigation
with the minimum overhead.
For “used-arg”, in addition to “used-arg-grp”, the other registers (for example, FP registers) that can pass parameters will be zeroed. But I am not
very sure whether this option is really needed in practical.
For “arg”, in addition to “used-arg”, all registers that pass parameters will be zeroed. Same as “used-arg”, I am not very sure whether we need this option
> Numbers on how expensive this is (for what arch, in code size and in
> execution time) would be useful. If it is so expensive that no one will
> use it, it helps security at most none at all :-(
CLEAR Linux project has been using a similar patch since GCC 8, the option it used is an equivalent to -fzero-call-used-regs=used-gpr.
-fzero-call-used-regs=used-arg-gpr in this new proposal will have smaller overhead than the one currently being used in CLEAR Linux.
Victor, do you have any data on the overhead of the option that currently is used by CLEAR project?
>> Q1. Which registers should be set to zeros at the return of the function?
>> A. the caller-saved, i.e, call-used, or call-clobbered registers.
>> For ROP mitigation purpose, only the call-used registers that pass
>> parameters need to be zeroed.
>> For register erasure purpose, all the call-used registers might need to
>> be zeroed. we can provide multiple levels to user for controling the runtime
> The call-clobbered regs are the only ones you *can* touch. That does
> not mean you should clear them all (it doesn't help much at all in some
> cases). Only the backend knows.
I think that for ROP mitigation purpose, we only need to clear the call-used (i.e, call-clobbered) registers that are used in the current routine and
can pass parameters.
But for preventing information leak from callee registers, we might need to clear all the call-used registers at return.
>> So, from both run-time performance and code-size aspects, setting the
>> registers to zero is a better approach.
> From a security perspective, this isn't clear though. But that is a lot
> of extra research ;-)
There has been quite some discussion on this topic at
From those old discussion, we can see that zero value should be good enough for the security purpose (though it’s not perfect).
More information about the Gcc-patches