From c5d69183af17e4fe7080f3e6835d16ca7f35b40f Mon Sep 17 00:00:00 2001
From: "Dmitry V. Levin" <ldv@altlinux.org>
Date: Fri, 15 Jul 2016 17:33:26 +0000
Subject: [PATCH] Fix race condition in decoding rt_sigtimedwait's timeout
 argument

As the value returned by sprint_timespec points to a static area and may
be overwritten by subsequent calls to sprint_timespec, it is not safe to
save this value on entering syscall and use it later on exiting.

* signal.c (SYS_FUNC(rt_sigtimedwait)): On entering syscall, copy the
value returned by sprint_timespec to a dynamically allocated memory,
and save the pointer using set_tcb_priv_data.  On exiting, restore it
using get_tcb_priv_data.
---
 signal.c | 19 +++++++++++--------
 1 file changed, 11 insertions(+), 8 deletions(-)

diff --git a/signal.c b/signal.c
index 8d36675a..cb200bfd 100644
--- a/signal.c
+++ b/signal.c
@@ -662,23 +662,26 @@ SYS_FUNC(rt_sigtimedwait)
 	if (entering(tcp)) {
 		print_sigset_addr_len(tcp, tcp->u_arg[0], tcp->u_arg[3]);
 		tprints(", ");
-		if (!tcp->u_arg[1]) {
+		if (!(tcp->u_arg[1] && verbose(tcp))) {
 			/*
 			 * This is the only "return" parameter,
-			 * if it's NULL, decode all parameters on entry.
+			 * if we are not going to fetch it on exit,
+			 * decode all parameters on entry.
 			 */
-			tprints("NULL, ");
+			printaddr(tcp->u_arg[1]);
+			tprints(", ");
 			print_timespec(tcp, tcp->u_arg[2]);
 			tprintf(", %lu", tcp->u_arg[3]);
-			tcp->auxstr = NULL;
 		} else {
-			tcp->auxstr = sprint_timespec(tcp, tcp->u_arg[2]);
+			char *sts = xstrdup(sprint_timespec(tcp, tcp->u_arg[2]));
+			set_tcb_priv_data(tcp, sts, free);
 		}
 	} else {
-		if (tcp->auxstr) {
+		if (tcp->u_arg[1] && verbose(tcp)) {
 			printsiginfo_at(tcp, tcp->u_arg[1]);
-			tprintf(", %s, %lu", tcp->auxstr, tcp->u_arg[3]);
-			tcp->auxstr = NULL;
+			tprints(", ");
+			tprints(get_tcb_priv_data(tcp));
+			tprintf(", %lu", tcp->u_arg[3]);
 		}
 
 		if (!syserror(tcp) && tcp->u_rval) {
-- 
2.40.0