about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRich Felker <dalias@aerifal.cx>2020-12-04 17:01:05 -0500
committerRich Felker <dalias@aerifal.cx>2020-12-04 17:01:05 -0500
commit50c7935cd21f33f42013447d57bc19d2e6318aae (patch)
tree77c81294fe005821d1b5e0ccbeced6e401d6b022
parent738c4e945c1218559d36b83cbaba11459fad89c9 (diff)
downloadmusl-50c7935cd21f33f42013447d57bc19d2e6318aae.tar.gz
musl-50c7935cd21f33f42013447d57bc19d2e6318aae.tar.xz
musl-50c7935cd21f33f42013447d57bc19d2e6318aae.zip
fix failure to preserve r6 in s390x asm; per ABI it is call-saved
both __clone and __syscall_cp_asm failed to restore the original value
of r6 after using it as a syscall argument register. the extent of
breakage is not known, and in some cases may be mitigated by the only
callers being internal to libc; if they used r6 but no longer needed
its value after the call, they may not have noticed the problem.
however at least posix_spawn (which uses __clone) was observed
returning to the application with the wrong value in r6, leading to
crash.

since the call frame ABI already provides a place to spill registers,
fixing this is just a matter of using it. in __clone, we also
spuriously restore r6 in the child, since the parent branch directly
returns to the caller. this takes the value from an uninitialized slot
of the child's stack, but is harmless since there is no caller to
return to in the child.
-rw-r--r--src/thread/s390x/clone.s6
-rw-r--r--src/thread/s390x/syscall_cp.s2
2 files changed, 8 insertions, 0 deletions
diff --git a/src/thread/s390x/clone.s b/src/thread/s390x/clone.s
index 577748ea..2125f20b 100644
--- a/src/thread/s390x/clone.s
+++ b/src/thread/s390x/clone.s
@@ -17,6 +17,9 @@ __clone:
 	# if (!tid) syscall(SYS_exit, a(d));
 	# return tid;
 
+	# preserve call-saved register used as syscall arg
+	stg  %r6, 48(%r15)
+
 	# create initial stack frame for new thread
 	nill %r3, 0xfff8
 	aghi %r3, -160
@@ -35,6 +38,9 @@ __clone:
 	lg   %r6, 160(%r15)
 	svc  120
 
+	# restore call-saved register
+	lg   %r6, 48(%r15)
+
 	# if error or if we're the parent, return
 	ltgr %r2, %r2
 	bnzr %r14
diff --git a/src/thread/s390x/syscall_cp.s b/src/thread/s390x/syscall_cp.s
index c1da40de..d094cbf5 100644
--- a/src/thread/s390x/syscall_cp.s
+++ b/src/thread/s390x/syscall_cp.s
@@ -14,6 +14,7 @@ __cp_begin:
 	icm %r2, 15, 0(%r2)
 	jne __cp_cancel
 
+	stg %r6, 48(%r15)
 	stg %r7, 56(%r15)
 	lgr %r1, %r3
 	lgr %r2, %r4
@@ -26,6 +27,7 @@ __cp_begin:
 
 __cp_end:
 	lg  %r7, 56(%r15)
+	lg  %r6, 48(%r15)
 	br  %r14
 
 __cp_cancel: