diff mbox series

Mitigation for "clone on sparc might fail with -EFAULT for no valid reason" (bz 31394)

Message ID 20240728133223.885378-1-dilfridge@gentoo.org
State New
Headers show
Series Mitigation for "clone on sparc might fail with -EFAULT for no valid reason" (bz 31394) | expand

Commit Message

Andreas K. Huettel July 28, 2024, 1:30 p.m. UTC
From: Michael Karcher <sourceware-bugzilla@mkarcher.dialup.fu-berlin.de>

Bug: https://www.mail-archive.com/debian-glibc@lists.debian.org/msg62592.html
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=31394
See-also: https://lore.kernel.org/sparclinux/62f9be9d-a086-4134-9a9f-5df8822708af@mkarcher.dialup.fu-berlin.de/
---
This is not my code, so it technically needs a SOB from Michael. -Andreas (dilfridge)
---
 sysdeps/unix/sysv/linux/sparc/sparc32/clone.S | 3 +++
 sysdeps/unix/sysv/linux/sparc/sparc64/clone.S | 3 +++
 2 files changed, 6 insertions(+)

Comments

Michael.Karcher July 28, 2024, 1:55 p.m. UTC | #1
It seems the kernel can not deal with uncommitted stack space in the area intended
for the register window when executing the clone() system call. So create a nested
frame (proxy for the kernel frame) and flush it from the processor to memory to
force committing pages to the stack before invoking the system call.

Signed-off-by: Michael Karcher<sourceware-bugzilla@mkarcher.dialup.fu-berlin.de>

Bug: https://www.mail-archive.com/debian-glibc@lists.debian.org/msg62592.html
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=31394
See-also: https://lore.kernel.org/sparclinux/62f9be9d-a086-4134-9a9f-5df8822708af@mkarcher.dialup.fu-berlin.de/
---
  sysdeps/unix/sysv/linux/sparc/sparc32/clone.S | 3 +++
  sysdeps/unix/sysv/linux/sparc/sparc64/clone.S | 3 +++
  2 files changed, 6 insertions(+)

diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/clone.S b/sysdeps/unix/sysv/linux/sparc/sparc32/clone.S
index 748d25fcfe..c9cf9bb055 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/clone.S
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/clone.S
@@ -28,6 +28,9 @@
  	.text
  ENTRY (__clone)
  	save	%sp,-96,%sp
+	save	%sp,-96,%sp
+	flushw
+	restore
  	cfi_def_cfa_register(%fp)
  	cfi_window_save
  	cfi_register(%o7, %i7)
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/clone.S b/sysdeps/unix/sysv/linux/sparc/sparc64/clone.S
index e5ff2cf1a0..370d51fda2 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/clone.S
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/clone.S
@@ -32,6 +32,9 @@
  
  ENTRY (__clone)
  	save	%sp, -192, %sp
+	save	%sp, -192, %sp
+	flushw
+	restore
  	cfi_def_cfa_register(%fp)
  	cfi_window_save
  	cfi_register(%o7, %i7)
Florian Weimer Aug. 2, 2024, 12:10 p.m. UTC | #2
* Andreas K. Hüttel:

> From: Michael Karcher <sourceware-bugzilla@mkarcher.dialup.fu-berlin.de>
>
> Bug: https://www.mail-archive.com/debian-glibc@lists.debian.org/msg62592.html
> Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=31394
> See-also: https://lore.kernel.org/sparclinux/62f9be9d-a086-4134-9a9f-5df8822708af@mkarcher.dialup.fu-berlin.de/
> ---
> This is not my code, so it technically needs a SOB from Michael. -Andreas (dilfridge)
> ---
>  sysdeps/unix/sysv/linux/sparc/sparc32/clone.S | 3 +++
>  sysdeps/unix/sysv/linux/sparc/sparc64/clone.S | 3 +++
>  2 files changed, 6 insertions(+)
>
> diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/clone.S b/sysdeps/unix/sysv/linux/sparc/sparc32/clone.S
> index 748d25fcfe..c9cf9bb055 100644
> --- a/sysdeps/unix/sysv/linux/sparc/sparc32/clone.S
> +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/clone.S
> @@ -28,6 +28,9 @@
>  	.text
>  ENTRY (__clone)
>  	save	%sp,-96,%sp
> +	save	%sp,-96,%sp
> +	flushw
> +	restore
>  	cfi_def_cfa_register(%fp)
>  	cfi_window_save
>  	cfi_register(%o7, %i7)

This causes sparcv8-linux-gnu-leon3 fail to build with:

../sysdeps/unix/sysv/linux/sparc/sparc32/clone.S: Assembler messages:
../sysdeps/unix/sysv/linux/sparc/sparc32/clone.S:32: Error: Architecture mismatch on "flushw ".
../sysdeps/unix/sysv/linux/sparc/sparc32/clone.S:32: (Requires v9|v9a|v9b|v9c|v9d|v9e|v9v|v9m|m8; requested architecture is leon.)

What should we do about it?  Add #ifdef __sparcv9 around the workaround?

Thanks,
Florian
Adhemerval Zanella Netto Aug. 2, 2024, 1:16 p.m. UTC | #3
On 02/08/24 09:10, Florian Weimer wrote:
> * Andreas K. Hüttel:
> 
>> From: Michael Karcher <sourceware-bugzilla@mkarcher.dialup.fu-berlin.de>
>>
>> Bug: https://www.mail-archive.com/debian-glibc@lists.debian.org/msg62592.html
>> Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=31394
>> See-also: https://lore.kernel.org/sparclinux/62f9be9d-a086-4134-9a9f-5df8822708af@mkarcher.dialup.fu-berlin.de/
>> ---
>> This is not my code, so it technically needs a SOB from Michael. -Andreas (dilfridge)
>> ---
>>  sysdeps/unix/sysv/linux/sparc/sparc32/clone.S | 3 +++
>>  sysdeps/unix/sysv/linux/sparc/sparc64/clone.S | 3 +++
>>  2 files changed, 6 insertions(+)
>>
>> diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/clone.S b/sysdeps/unix/sysv/linux/sparc/sparc32/clone.S
>> index 748d25fcfe..c9cf9bb055 100644
>> --- a/sysdeps/unix/sysv/linux/sparc/sparc32/clone.S
>> +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/clone.S
>> @@ -28,6 +28,9 @@
>>  	.text
>>  ENTRY (__clone)
>>  	save	%sp,-96,%sp
>> +	save	%sp,-96,%sp
>> +	flushw
>> +	restore
>>  	cfi_def_cfa_register(%fp)
>>  	cfi_window_save
>>  	cfi_register(%o7, %i7)
> 
> This causes sparcv8-linux-gnu-leon3 fail to build with:
> 
> ../sysdeps/unix/sysv/linux/sparc/sparc32/clone.S: Assembler messages:
> ../sysdeps/unix/sysv/linux/sparc/sparc32/clone.S:32: Error: Architecture mismatch on "flushw ".
> ../sysdeps/unix/sysv/linux/sparc/sparc32/clone.S:32: (Requires v9|v9a|v9b|v9c|v9d|v9e|v9v|v9m|m8; requested architecture is leon.)
> 
> What should we do about it?  Add #ifdef __sparcv9 around the workaround?
> 

Maybe use 'ta 3' for pre sparcv9 which seems what gcc uses for flush_register_window?
Michael.Karcher Aug. 3, 2024, 11:14 a.m. UTC | #4
Am 02.08.2024 um 15:16 schrieb Adhemerval Zanella Netto:

> On 02/08/24 09:10, Florian Weimer wrote:
>> * Andreas K. Hüttel:
>>> +	save	%sp,-96,%sp
>>> +	flushw
>>> +	restore
>> This causes sparcv8-linux-gnu-leon3 fail to build with:
>>
>> ../sysdeps/unix/sysv/linux/sparc/sparc32/clone.S: Assembler messages:
>> ../sysdeps/unix/sysv/linux/sparc/sparc32/clone.S:32: Error: Architecture mismatch on "flushw ".
>> ../sysdeps/unix/sysv/linux/sparc/sparc32/clone.S:32: (Requires v9|v9a|v9b|v9c|v9d|v9e|v9v|v9m|m8; requested architecture is leon.)
>>
>> What should we do about it?  Add #ifdef __sparcv9 around the workaround?
> Maybe use 'ta 3' for pre sparcv9 which seems what gcc uses for flush_register_window?

I suggest to try to reproduce the underlying issue on Leon. You can use the
reproducer in tbe bugzilla item as starting point, but you likely have to
remove the SPARC64_STACK_BIAS stuff from it, and furthermore adjust the
wasteamount calculation, as it currently contains the Sparc64 page size minus 1
in the bit mask 0x1FFF, and the size of a void pointer in the constant 8.

Also, the value 1024 that appears in the increment of the for loop and the
printf call later is the page size divided by the size of a void pointer, and
might also need adjustment for "optimal experience" with that reproducer.

If I understand it correctly, you can run Sparc32 programs on Sparc64 systems,
and it already is established that the Sparc64 kernel does need the flushw
before invoking clone(), even on 32-bit userspace. If we expect the leon-compatible
libc to ever be executed on Sparc64 systems, I don't think just diabling the
work-around is a proper solution. If using "ta 3" works with 64-bit kernels
as well (but it is likely slower than flushw), using ta3 if we can't be sure
the binary will run on v9, and flushw if we can seems like the correct strategy
forwards.

John Paul Adrian, would you be able to test whether "ta 3" instead of "flushw" in
sparc32/clone.s works on the Sparc 64 system we discovered the issue on and
report back the result? Maybe you/we can also prepare an official 32-bit version
of the demo tool.

Do we have a physical leon3-based system at hand to test whether the workaround
is required at all for leon, and whether "ta 3" works?

Kind regards,
   Michael Karcher
Michael.Karcher Aug. 3, 2024, 3:04 p.m. UTC | #5
Am 03.08.2024 um 13:14 schrieb Michael.Karcher:

> Am 02.08.2024 um 15:16 schrieb Adhemerval Zanella Netto:
>> On 02/08/24 09:10, Florian Weimer wrote:
>>> * Andreas K. Hüttel:
>>>> +    save    %sp,-96,%sp
>>>> +    flushw
>>>> +    restore
>>> This causes sparcv8-linux-gnu-leon3 fail to build with:
>>>
>>> ../sysdeps/unix/sysv/linux/sparc/sparc32/clone.S: Assembler messages:
>>> ../sysdeps/unix/sysv/linux/sparc/sparc32/clone.S:32: Error: Architecture mismatch on "flushw ".
>>> ../sysdeps/unix/sysv/linux/sparc/sparc32/clone.S:32: (Requires v9|v9a|v9b|v9c|v9d|v9e|v9v|v9m|m8; requested architecture is leon.)
>>>
>>> What should we do about it?  Add #ifdef __sparcv9 around the workaround?
>> Maybe use 'ta 3' for pre sparcv9 which seems what gcc uses for flush_register_window?
> John Paul Adrian, would you be able to test whether "ta 3" instead of "flushw" in
> sparc32/clone.s works on the Sparc 64 system we discovered the issue on and
> report back the result? Maybe you/we can also prepare an official 32-bit version
> of the demo tool.

As commented in bugzilla, we tested the behaviour on a Sparc V9 host, and were able
to reproduce the behaviour reliably for both 32-bit and 64-bit binaries if a libc
without workaround was used. Either flushw or ta 3 will fix the issue (but a nop in
that place instead of the flushw or ta 3 instruction) will not work, proving that
it is indeed the flushw/ta 3 that makes clone work reliably.

As a result, I recommend to use flushw on v9 only, and fall back to ta 3 on v8 or
earlier. Thanks to Adhemerval Zanella Netto for the suggestion to use ta 3.

Kind regards,
   Michael Karcher
Florian Weimer Aug. 3, 2024, 3:18 p.m. UTC | #6
* Michael Karcher:

> As commented in bugzilla, we tested the behaviour on a Sparc V9 host,
> and were able to reproduce the behaviour reliably for both 32-bit and
> 64-bit binaries if a libc without workaround was used. Either flushw
> or ta 3 will fix the issue (but a nop in that place instead of the
> flushw or ta 3 instruction) will not work, proving that it is indeed
> the flushw/ta 3 that makes clone work reliably.
>
> As a result, I recommend to use flushw on v9 only, and fall back to ta
> 3 on v8 or earlier. Thanks to Adhemerval Zanella Netto for the
> suggestion to use ta 3.

What will happen on SPARC v8 LEON CPUs?  Will they be able to execute
the “ta 3” instruction?  Or do we need to add run-time dispatch?

Thanks,
Florian
John Paul Adrian Glaubitz Aug. 3, 2024, 4:27 p.m. UTC | #7
On Sat, 2024-08-03 at 17:18 +0200, Florian Weimer wrote:
> * Michael Karcher:
> 
> > As commented in bugzilla, we tested the behaviour on a Sparc V9 host,
> > and were able to reproduce the behaviour reliably for both 32-bit and
> > 64-bit binaries if a libc without workaround was used. Either flushw
> > or ta 3 will fix the issue (but a nop in that place instead of the
> > flushw or ta 3 instruction) will not work, proving that it is indeed
> > the flushw/ta 3 that makes clone work reliably.
> > 
> > As a result, I recommend to use flushw on v9 only, and fall back to ta
> > 3 on v8 or earlier. Thanks to Adhemerval Zanella Netto for the
> > suggestion to use ta 3.
> 
> What will happen on SPARC v8 LEON CPUs?  Will they be able to execute
> the “ta 3” instruction?  Or do we need to add run-time dispatch?

I think that "ta 3" works already on SPARC v7 meaning it should work on all
SPARC CPUs, including the SPARC Leon v8 unless I am misunderstanding this.

Adrian
Michael.Karcher Aug. 3, 2024, 4:43 p.m. UTC | #8
Am 03.08.2024 um 17:18 schrieb Florian Weimer:

> * Michael Karcher:
>
>> As commented in bugzilla, we tested the behaviour on a Sparc V9 host,
>> and were able to reproduce the behaviour reliably for both 32-bit and
>> 64-bit binaries if a libc without workaround was used. Either flushw
>> or ta 3 will fix the issue (but a nop in that place instead of the
>> flushw or ta 3 instruction) will not work, proving that it is indeed
>> the flushw/ta 3 that makes clone work reliably.
>>
>> As a result, I recommend to use flushw on v9 only, and fall back to ta
>> 3 on v8 or earlier. Thanks to Adhemerval Zanella Netto for the
>> suggestion to use ta 3.
> What will happen on SPARC v8 LEON CPUs?  Will they be able to execute
> the “ta 3” instruction?  Or do we need to add run-time dispatch?
>
> Thanks,
> Florian

"ta 3" invokes the kernel handler for CPU trap number 3. The Sparc
Processor Supplement to the System V ABI defines: "By executing a type 3
trap, a process asks the system to flush all its register windows to the
stack". The "ta" instruction is implemented on all remotely relevant
SPARC CPUs, and there is no reason to believe that Linux on LEON chose
to not implement this aspect of the System V ABI.

With SPARC v9, the new machine instruction FLUSHW causes a "spill trap"
if there are any dirty windows below the current one. A spill trap should
be handled the same way as the user-defined trap type 3 by the kernel.
In the clone issue workaround, the extra save/restore pair causes the window
of the userspace clone function to already be below the current window, and
as that window is also freshly opened, it is surely not yet flushed so
flushw will always raise a spill trap.

Looking at it a second time, it is likely that we don't need the extra
save/restore pair around the "ta 3" instruction, which I just confirmed
by replacing the extra save/restore pair with NOPs. I will leave it to the
SPARC v9 experts to judge whether "save/flushw/restore" or "ta 3" is
the "better" approach on v9. On v8, "ta 3" is the only possible approach.

So these additions to the prologue of clone have been positively tested:
- save/flushw/restore (requires SPARC v9)
- save/ta 3/restore
- ta 3

And these additions have been negatively tested:
- flushw only (requires SPARC v9)
- no addition at all

Kind regards,
   Michael Karcher
diff mbox series

Patch

diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/clone.S b/sysdeps/unix/sysv/linux/sparc/sparc32/clone.S
index 748d25fcfe..c9cf9bb055 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/clone.S
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/clone.S
@@ -28,6 +28,9 @@ 
 	.text
 ENTRY (__clone)
 	save	%sp,-96,%sp
+	save	%sp,-96,%sp
+	flushw
+	restore
 	cfi_def_cfa_register(%fp)
 	cfi_window_save
 	cfi_register(%o7, %i7)
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/clone.S b/sysdeps/unix/sysv/linux/sparc/sparc64/clone.S
index e5ff2cf1a0..370d51fda2 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/clone.S
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/clone.S
@@ -32,6 +32,9 @@ 
 
 ENTRY (__clone)
 	save	%sp, -192, %sp
+	save	%sp, -192, %sp
+	flushw
+	restore
 	cfi_def_cfa_register(%fp)
 	cfi_window_save
 	cfi_register(%o7, %i7)