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*.
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.