Re: GCC 15 -fzero-init-padding-bits= option and redzone clobber
Peter Zijlstra <[email protected]>
| Newsgroups | org.kernel.vger.linux-toolchains |
|---|---|
| Message-ID | <[email protected]> |
On Thu, Nov 28, 2024 at 12:19:10PM +0100, Jakub Jelinek wrote:
> Hi!
>
> This is just a FYI, since today GCC 15 no longer zero initializes padding
> bits in unions where the standard doesn't require it.
> So e.g.
> void foo (void)
> {
> union U { int a; long b[64]; };
> /* This clears everything including padding bits,
> required by at least C23 (note, GCC 15 defaults to -std=gnu23) */
> union U u = {};
> /* This used to clear everything, but only clears
> v.a in GCC 15 by default. */
> union U v = {0};
> }
> If you want to keep the old behavior e.g. for security purposes (the whole
> union can be copied to user etc.), one can use
> -fzero-init-padding-bits=unions to restore the GCC 14 and older behavior.
> And, -fzero-init-padding-bits=all can be used to clear padding bits even
> in cases where the standard doesn't require them even in structures, e.g.
> void bar (void)
> {
> struct S { char a; int b; };
> /* C23 requires padding bits to be cleared here. */
> struct S s = {};
> /* But not here. -fzero-init-padding-bits=all does that anyway. */
> struct S t = { 1, 2 };
> }
> Note, there is also __builtin_clear_padding builtin to clear padding bits
> already since GCC 11, though it doesn't clear bits in unions unless they
> are padding bits for all possible members, as it doesn't know which union
> member is current.
*groan* I suppose we should enable that flag when present :/
> Another new feature since today that might be relevant to kernel is
> the "redzone" inline asm clobber.
> It can/should be used on inline asm which does or could clobber memory
> below the stack pointer and so its presence must disable use of redzone
> (currently on x86_64 and powerpc*),
At least on x86_64 we don't currently have a redzone. I'm assuming the
"memory" clobber still very much includes everything?
And why was it deemed okay to change behaviour that might break existing
code?
> whether because say pushf/pop pair
> or because the inline asm performs calls without taking into account
> the red zone (e.g. on x86_64 that would be something like subtracting
> 128 from %rsp at the start and restoring at the end).
> In the past I think kernel used some hacks like clobbering rsp, that is
> something that really shouldn't be used even if it happened to work,
> inline asm is of course allowed to change the stack pointer temporarily,
> but before returning (if it returns at all) it needs to restore it back,
> and clobbers are not about temporary changes during the execution of inline
> asm, but about changes from the start to the end of inline asm.
Mostly we call a full C function on another stack, I don't think we ever
swizzle the stack while inside a C function.
> So
> asm ("call something" : ... : ... : "redzone");
> (of course it likely needs tons of other clobbers for call clobbered
> registers unless it saves them and restores them in the inline asm or
> in whatever it calls).
We have this thing:
/*
* This output constraint should be used for any inline asm which has a "call"
* instruction. Otherwise the asm may be inserted before the frame pointer
* gets set up by the containing function. If you forget to do this, objtool
* may print a "call without frame pointer save/setup" warning.
*/
register unsigned long current_stack_pointer asm(_ASM_SP);
#define ASM_CALL_CONSTRAINT "+r" (current_stack_pointer)
which we use a *LOT*.