diff mbox series

[uclibc-ng-devel,3/5] nios2: add the missing clone() argument and error checks

Message ID 20260831072837.3529974-4-lordrasmus@gmail.com
State New
Headers show
Series nios2: shared libraries and threads | expand

Commit Message

Ramin Moussavi Aug. 31, 2026, 7:28 a.m. UTC
From: ramin <lordrasmus@gmail.com>

The nios2 __clone() had a "Sanity check arguments" comment and loaded
EINVAL into r2, but never actually tested the arguments and never
checked the syscall result. With a NULL child stack (r5 == 0) the
prologue did "subi r5, r5, 8" and then "stw r4, 4(r5)", writing to
0xfffffffc and taking a SIGSEGV before the trap was ever issued; a
NULL function pointer had the same fate. clone() with a bad stack is
required to fail with EINVAL, not crash -- the uClibc-ng-test "errno"
test does exactly this and segfaulted on nios2.

Add the two argument checks and, after the trap, the error check that
the other ports have. nios2 signals a failed syscall in r7 and returns
the (positive) error number in r2, so the error path negates r2 and
tail-calls __syscall_error, which sets errno and returns -1. This
mirrors glibc's nios2 clone.S.

Verified under qemu-system-nios2: clone(fn, NULL, 0, NULL) now returns
-1/EINVAL and the "errno" test passes instead of crashing.

Signed-off-by: Ramin Moussavi <ramin.moussavi@yacoub.de>
---
 libc/sysdeps/linux/nios2/clone.S | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)
diff mbox series

Patch

diff --git a/libc/sysdeps/linux/nios2/clone.S b/libc/sysdeps/linux/nios2/clone.S
index 04f06348c..512453e76 100644
--- a/libc/sysdeps/linux/nios2/clone.S
+++ b/libc/sysdeps/linux/nios2/clone.S
@@ -33,6 +33,8 @@ 
 ENTRY(__clone)
 	/* Sanity check arguments.  */
 	movi	r2, EINVAL
+	beq	r4, zero, .Lerror	/* No NULL function pointers.  */
+	beq	r5, zero, .Lerror	/* No NULL stack pointers.  */
 
 	subi	r5, r5, 8	/* Reserve argument save space.  */
 	stw	r4, 4(r5)	/* Save function pointer.  */
@@ -49,11 +51,27 @@  ENTRY(__clone)
 
 	trap
 
+	/* Check for error: nios2 flags it in r7 and returns the errno in r2.  */
+	bne	r7, zero, .Lerror
 	/* See if we're on the newly created thread.  */
 	beq	r2, zero, thread_start
 	/* Successful return from the parent */
 	ret
 
+.Lerror:
+	/* __syscall_error expects the negated error number.  */
+	sub	r4, zero, r2
+#ifdef __PIC__
+	nextpc	r22
+1:	movhi	r8, %hiadj(_gp_got - 1b)
+	addi	r8, r8, %lo(_gp_got - 1b)
+	add	r22, r22, r8
+	ldw	r8, %call(__syscall_error)(r22)
+	jmp	r8
+#else
+	jmpi	__syscall_error
+#endif
+
 thread_start:
 	/* We expect the argument registers to be preserved across system
 	   calls and across task cloning, so flags should be in r4 here.  */