summaryrefslogtreecommitdiff
path: root/0001-S390-Do-not-clobber-r7-in-clone-BZ-31402.patch
diff options
context:
space:
mode:
Diffstat (limited to '0001-S390-Do-not-clobber-r7-in-clone-BZ-31402.patch')
-rw-r--r--0001-S390-Do-not-clobber-r7-in-clone-BZ-31402.patch157
1 files changed, 157 insertions, 0 deletions
diff --git a/0001-S390-Do-not-clobber-r7-in-clone-BZ-31402.patch b/0001-S390-Do-not-clobber-r7-in-clone-BZ-31402.patch
new file mode 100644
index 0000000..02bfee3
--- /dev/null
+++ b/0001-S390-Do-not-clobber-r7-in-clone-BZ-31402.patch
@@ -0,0 +1,157 @@
+From ee4806e978467d705b26ccb7dfddb9e0a710f8e4 Mon Sep 17 00:00:00 2001
+From: Stefan Liebler <stli@linux.ibm.com>
+Date: Thu, 22 Feb 2024 15:03:27 +0100
+Subject: [PATCH 01/26] S390: Do not clobber r7 in clone [BZ #31402]
+
+Starting with commit e57d8fc97b90127de4ed3e3a9cdf663667580935
+"S390: Always use svc 0"
+clone clobbers the call-saved register r7 in error case:
+function or stack is NULL.
+
+This patch restores the saved registers also in the error case.
+Furthermore the existing test misc/tst-clone is extended to check
+all error cases and that clone does not clobber registers in this
+error case.
+
+(cherry picked from commit 02782fd12849b6673cb5c2728cb750e8ec295aa3)
+Note: Added ia64 __clone2 call to tst-clone.c.
+---
+ sysdeps/unix/sysv/linux/s390/s390-32/clone.S | 1 +
+ sysdeps/unix/sysv/linux/s390/s390-64/clone.S | 1 +
+ sysdeps/unix/sysv/linux/tst-clone.c | 76 ++++++++++++++++----
+ 3 files changed, 65 insertions(+), 13 deletions(-)
+
+diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/clone.S b/sysdeps/unix/sysv/linux/s390/s390-32/clone.S
+index 5d8d873383..fd1e509cf4 100644
+--- a/sysdeps/unix/sysv/linux/s390/s390-32/clone.S
++++ b/sysdeps/unix/sysv/linux/s390/s390-32/clone.S
+@@ -53,6 +53,7 @@ ENTRY(__clone)
+ br %r14
+ error:
+ lhi %r2,-EINVAL
++ lm %r6,%r7,24(%r15) /* Load registers. */
+ j SYSCALL_ERROR_LABEL
+ PSEUDO_END (__clone)
+
+diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/clone.S b/sysdeps/unix/sysv/linux/s390/s390-64/clone.S
+index f1c4288a3d..7b37b18010 100644
+--- a/sysdeps/unix/sysv/linux/s390/s390-64/clone.S
++++ b/sysdeps/unix/sysv/linux/s390/s390-64/clone.S
+@@ -54,6 +54,7 @@ ENTRY(__clone)
+ br %r14
+ error:
+ lghi %r2,-EINVAL
++ lmg %r6,%r7,48(%r15) /* Restore registers. */
+ jg SYSCALL_ERROR_LABEL
+ PSEUDO_END (__clone)
+
+diff --git a/sysdeps/unix/sysv/linux/tst-clone.c b/sysdeps/unix/sysv/linux/tst-clone.c
+index 56348707d4..95bd0f6ccb 100644
+--- a/sysdeps/unix/sysv/linux/tst-clone.c
++++ b/sysdeps/unix/sysv/linux/tst-clone.c
+@@ -16,12 +16,16 @@
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+-/* BZ #2386 */
++/* BZ #2386, BZ #31402 */
+ #include <errno.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <unistd.h>
+ #include <sched.h>
++#include <stackinfo.h> /* For _STACK_GROWS_{UP,DOWN}. */
++#include <support/check.h>
++
++volatile unsigned v = 0xdeadbeef;
+
+ #ifdef __ia64__
+ extern int __clone2 (int (*__fn) (void *__arg), void *__child_stack_base,
+@@ -35,26 +39,72 @@ int child_fn(void *arg)
+ }
+
+ static int
+-do_test (void)
++__attribute__((noinline))
++do_clone (int (*fn)(void *), void *stack)
+ {
+ int result;
++ unsigned int a = v;
++ unsigned int b = v;
++ unsigned int c = v;
++ unsigned int d = v;
++ unsigned int e = v;
++ unsigned int f = v;
++ unsigned int g = v;
++ unsigned int h = v;
++ unsigned int i = v;
++ unsigned int j = v;
++ unsigned int k = v;
++ unsigned int l = v;
++ unsigned int m = v;
++ unsigned int n = v;
++ unsigned int o = v;
+
+ #ifdef __ia64__
+- result = __clone2 (child_fn, NULL, 0, 0, NULL, NULL, NULL);
++ result = __clone2 (fn, stack, stack != NULL ? 128 * 1024 : 0, 0, NULL, NULL,
++ NULL);
++#else
++ result = clone (fn, stack, 0, NULL);
++#endif
++
++ /* Check that clone does not clobber call-saved registers. */
++ TEST_VERIFY (a == v && b == v && c == v && d == v && e == v && f == v
++ && g == v && h == v && i == v && j == v && k == v && l == v
++ && m == v && n == v && o == v);
++
++ return result;
++}
++
++static void
++__attribute__((noinline))
++do_test_single (int (*fn)(void *), void *stack)
++{
++ printf ("%s (fn=%p, stack=%p)\n", __FUNCTION__, fn, stack);
++ errno = 0;
++
++ int result = do_clone (fn, stack);
++
++ TEST_COMPARE (errno, EINVAL);
++ TEST_COMPARE (result, -1);
++}
++
++static int
++do_test (void)
++{
++ char st[128 * 1024] __attribute__ ((aligned));
++ void *stack = NULL;
++#if defined __ia64__ || _STACK_GROWS_UP
++ stack = st;
++#elif _STACK_GROWS_DOWN
++ stack = st + sizeof (st);
+ #else
+- result = clone (child_fn, NULL, 0, NULL);
++# error "Define either _STACK_GROWS_DOWN or _STACK_GROWS_UP"
+ #endif
+
+- if (errno != EINVAL || result != -1)
+- {
+- printf ("FAIL: clone()=%d (wanted -1) errno=%d (wanted %d)\n",
+- result, errno, EINVAL);
+- return 1;
+- }
++ do_test_single (child_fn, NULL);
++ do_test_single (NULL, stack);
++ do_test_single (NULL, NULL);
+
+- puts ("All OK");
+ return 0;
+ }
+
+-#define TEST_FUNCTION do_test ()
+-#include "../test-skeleton.c"
++#include <support/test-driver.c>
+--
+2.33.0
+