git: 77935ceb59fe - stable/13 - linux(4): Fix timeout parameter of rt_sigtimedwait syscall, which is timespec not a timeval.

From: Dmitry Chagin <dchagin_at_FreeBSD.org>
Date: Fri, 17 Jun 2022 19:29:04 UTC
The branch stable/13 has been updated by dchagin:

URL: https://cgit.FreeBSD.org/src/commit/?id=77935ceb59fea7756ca1a66066f99c5e14bef114

commit 77935ceb59fea7756ca1a66066f99c5e14bef114
Author:     Dmitry Chagin <dchagin@FreeBSD.org>
AuthorDate: 2021-06-07 02:35:35 +0000
Commit:     Dmitry Chagin <dchagin@FreeBSD.org>
CommitDate: 2022-06-17 19:27:59 +0000

    linux(4): Fix timeout parameter of rt_sigtimedwait syscall, which is
    timespec not a timeval.
    
    MFC after:      2 weeks
    
    (cherry picked from commit 0f8dab45404f347752470579feccc6d2739b9570)
---
 sys/amd64/linux/syscalls.master   |  2 +-
 sys/amd64/linux32/syscalls.master |  2 +-
 sys/arm/linux/syscalls.master     |  2 +-
 sys/arm64/linux/syscalls.master   |  2 +-
 sys/compat/linux/linux_signal.c   | 30 +++++++++---------------------
 sys/i386/linux/syscalls.master    |  2 +-
 6 files changed, 14 insertions(+), 26 deletions(-)

diff --git a/sys/amd64/linux/syscalls.master b/sys/amd64/linux/syscalls.master
index d99aaa019111..51f9fe00eb7d 100644
--- a/sys/amd64/linux/syscalls.master
+++ b/sys/amd64/linux/syscalls.master
@@ -839,7 +839,7 @@
 		int linux_rt_sigtimedwait(
 		    l_sigset_t *mask,
 		    l_siginfo_t *ptr,
-		    struct l_timeval *timeout,
+		    struct l_timespec *timeout,
 		    l_size_t sigsetsize
 		);
 	}
diff --git a/sys/amd64/linux32/syscalls.master b/sys/amd64/linux32/syscalls.master
index d3a124c6e8c2..79ee1f30a00d 100644
--- a/sys/amd64/linux32/syscalls.master
+++ b/sys/amd64/linux32/syscalls.master
@@ -949,7 +949,7 @@
 		int linux_rt_sigtimedwait(
 		    l_sigset_t *mask,
 		    l_siginfo_t *ptr,
-		    struct l_timeval *timeout,
+		    struct l_timespec *timeout,
 		    l_size_t sigsetsize
 		);
 	}
diff --git a/sys/arm/linux/syscalls.master b/sys/arm/linux/syscalls.master
index 02a504459760..d67f9c3b2069 100644
--- a/sys/arm/linux/syscalls.master
+++ b/sys/arm/linux/syscalls.master
@@ -804,7 +804,7 @@
 		int linux_rt_sigtimedwait(
 		    l_sigset_t *mask,
 		    l_siginfo_t *ptr,
-		    struct l_timeval *timeout,
+		    struct l_timespec *timeout,
 		    l_size_t sigsetsize
 		);
 	}
diff --git a/sys/arm64/linux/syscalls.master b/sys/arm64/linux/syscalls.master
index 9342a0913d6e..3d27ed496278 100644
--- a/sys/arm64/linux/syscalls.master
+++ b/sys/arm64/linux/syscalls.master
@@ -829,7 +829,7 @@
 		int linux_rt_sigtimedwait(
 		    l_sigset_t *mask,
 		    l_siginfo_t *ptr,
-		    struct l_timeval *timeout,
+		    struct l_timespec *timeout,
 		    l_size_t sigsetsize
 		);
 	}
diff --git a/sys/compat/linux/linux_signal.c b/sys/compat/linux/linux_signal.c
index f2c458a1c42c..50dae4d90d43 100644
--- a/sys/compat/linux/linux_signal.c
+++ b/sys/compat/linux/linux_signal.c
@@ -51,6 +51,7 @@ __FBSDID("$FreeBSD$");
 #include <machine/../linux/linux_proto.h>
 #endif
 #include <compat/linux/linux_signal.h>
+#include <compat/linux/linux_timer.h>
 #include <compat/linux/linux_util.h>
 #include <compat/linux/linux_emul.h>
 #include <compat/linux/linux_misc.h>
@@ -397,9 +398,8 @@ linux_rt_sigtimedwait(struct thread *td,
 	struct linux_rt_sigtimedwait_args *args)
 {
 	int error, sig;
-	l_timeval ltv;
-	struct timeval tv;
 	struct timespec ts, *tsa;
+	struct l_timespec lts;
 	l_sigset_t lset;
 	sigset_t bset;
 	l_siginfo_t linfo;
@@ -414,27 +414,15 @@ linux_rt_sigtimedwait(struct thread *td,
 
 	tsa = NULL;
 	if (args->timeout) {
-		if ((error = copyin(args->timeout, &ltv, sizeof(ltv))))
+		if ((error = copyin(args->timeout, &lts, sizeof(lts))))
+			return (error);
+		error = linux_to_native_timespec(&ts, &lts);
+		if (error != 0)
 			return (error);
-		tv.tv_sec = (long)ltv.tv_sec;
-		tv.tv_usec = (suseconds_t)ltv.tv_usec;
-		if (itimerfix(&tv)) {
-			/*
-			 * The timeout was invalid. Convert it to something
-			 * valid that will act as it does under Linux.
-			 */
-			tv.tv_sec += tv.tv_usec / 1000000;
-			tv.tv_usec %= 1000000;
-			if (tv.tv_usec < 0) {
-				tv.tv_sec -= 1;
-				tv.tv_usec += 1000000;
-			}
-			if (tv.tv_sec < 0)
-				timevalclear(&tv);
-		}
-		TIMEVAL_TO_TIMESPEC(&tv, &ts);
 		tsa = &ts;
-	}
+	} else
+		tsa = NULL;
+
 	error = kern_sigtimedwait(td, bset, &info, tsa);
 	if (error)
 		return (error);
diff --git a/sys/i386/linux/syscalls.master b/sys/i386/linux/syscalls.master
index 7e1ab24e9f75..aa6eb7c1c46f 100644
--- a/sys/i386/linux/syscalls.master
+++ b/sys/i386/linux/syscalls.master
@@ -974,7 +974,7 @@
 		int linux_rt_sigtimedwait(
 		    l_sigset_t *mask,
 		    l_siginfo_t *ptr,
-		    struct l_timeval *timeout,
+		    struct l_timespec *timeout,
 		    l_size_t sigsetsize
 		);
 	}