lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:	Sat, 2 Sep 2006 13:04:45 +0200
From:	Frank v Waveren <fvw@....cx>
To:	Andrew Morton <akpm@...l.org>
Cc:	tglx@...utronix.de, Ingo Molnar <mingo@...e.hu>,
	LKML <linux-kernel@...r.kernel.org>
Subject: Re: [PATCH] prevent timespec/timeval to ktime_t overflow

Here's a different patch, which should actually sleep for the
specified amount of time up to 2^64 seconds with a loop around the
sleeps and a tally of how long is left to sleep. It does mean we wake
up once every 300 years on long sleeps, but that shouldn't cause any
huge performance problems.

It's not particularly pretty, the restart handler means there's a
little code duplication and the limit of 4 args in the restart block
is heaps of fun, but on the bright side this may avoid the hangs
Andrew was complaining of. As it's a patch to nanosleep instead of
timespec_to_ktime, it won't catch it if there are any other buggy
users. It should be compatible with Thomas' patch though, so once the
hangs on FC3 are resolved both could be used.

Thomas: This doesn't exactly preserve the pre-ktime behaviour, but I
assume that's ok if instead it does what it says on the tin?

Syscall restarts and such are new territory to me, so if people could
cast a critical eye over this for bugs I'd be most grateful.

Signed-off-by: Frank v Waveren <fvw@....cx>

diff -urpN linux-2.6.17.11/include/linux/ktime.h linux-2.6.17.11-fvw/include/linux/ktime.h
--- linux-2.6.17.11/include/linux/ktime.h	2006-08-23 23:16:33.000000000 +0200
+++ linux-2.6.17.11-fvw/include/linux/ktime.h	2006-09-02 10:48:43.000000000 +0200
@@ -57,6 +57,7 @@ typedef union {
 } ktime_t;
 
 #define KTIME_MAX			(~((u64)1 << 63))
+#define KTIME_SEC_MAX                   (KTIME_MAX / NSEC_PER_SEC)
 
 /*
  * ktime_t definitions when using the 64-bit scalar representation:
diff -urpN linux-2.6.17.11/kernel/hrtimer.c linux-2.6.17.11-fvw/kernel/hrtimer.c
--- linux-2.6.17.11/kernel/hrtimer.c	2006-08-23 23:16:33.000000000 +0200
+++ linux-2.6.17.11-fvw/kernel/hrtimer.c	2006-09-02 12:07:02.000000000 +0200
@@ -706,31 +706,46 @@ static long __sched nanosleep_restart(st
 {
 	struct hrtimer_sleeper t;
 	struct timespec __user *rmtp;
-	struct timespec tu;
+	struct timespec tu, touter, tinner;
 	ktime_t time;
 
 	restart->fn = do_no_restart_syscall;
 
-	hrtimer_init(&t.timer, restart->arg3, HRTIMER_ABS);
-	t.timer.expires.tv64 = ((u64)restart->arg1 << 32) | (u64) restart->arg0;
-
-	if (do_nanosleep(&t, HRTIMER_ABS))
-		return 0;
-
-	rmtp = (struct timespec __user *) restart->arg2;
-	if (rmtp) {
-		time = ktime_sub(t.timer.expires, t.timer.base->get_time());
-		if (time.tv64 <= 0)
-			return 0;
-		tu = ktime_to_timespec(time);
-		if (copy_to_user(rmtp, &tu, sizeof(tu)))
-			return -EFAULT;
-	}
-
-	restart->fn = nanosleep_restart;
-
-	/* The other values in restart are already filled in */
-	return -ERESTART_RESTARTBLOCK;
+	time.tv64=(((u64)restart->arg1 & 0xFFFFFF) << 32) | (u64) restart->arg0;
+	touter=ktime_to_timespec(time);
+        touter.tv_sec += (u64)restart->arg1 >> 32;
+   
+        while (unlikely(touter.tv_sec > 0 || touter.tv_nsec > 0))
+   	{
+	        tinner.tv_sec = touter.tv_sec % KTIME_SEC_MAX;
+                touter.tv_sec -= tinner.tv_sec;
+                tinner.tv_nsec = touter.tv_nsec;
+                touter.tv_nsec = 0;
+
+
+	        hrtimer_init(&t.timer, restart->arg3, HRTIMER_ABS);
+		t.timer.expires = timespec_to_ktime(tinner);
+
+		if (do_nanosleep(&t, HRTIMER_ABS))
+			continue;
+
+		rmtp = (struct timespec __user *) restart->arg2;
+		if (rmtp) {
+			time = ktime_sub(t.timer.expires, t.timer.base->get_time());
+			if (time.tv64 <= 0)
+				continue;
+			tu = ktime_to_timespec(time);
+			if (copy_to_user(rmtp, &tu, sizeof(tu)))
+				return -EFAULT;
+		}
+
+		restart->fn = nanosleep_restart;
+
+		/* The other values in restart are already filled in */
+		return -ERESTART_RESTARTBLOCK;
+        }
+   	
+   return 0;
 }
 
 long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp,
@@ -738,35 +753,55 @@ long hrtimer_nanosleep(struct timespec *
 {
 	struct restart_block *restart;
 	struct hrtimer_sleeper t;
-	struct timespec tu;
+	struct timespec tu, touter, tinner;
 	ktime_t rem;
 
-	hrtimer_init(&t.timer, clockid, mode);
-	t.timer.expires = timespec_to_ktime(*rqtp);
-	if (do_nanosleep(&t, mode))
-		return 0;
-
-	/* Absolute timers do not update the rmtp value and restart: */
-	if (mode == HRTIMER_ABS)
-		return -ERESTARTNOHAND;
-
-	if (rmtp) {
-		rem = ktime_sub(t.timer.expires, t.timer.base->get_time());
-		if (rem.tv64 <= 0)
-			return 0;
-		tu = ktime_to_timespec(rem);
-		if (copy_to_user(rmtp, &tu, sizeof(tu)))
-			return -EFAULT;
-	}
+        touter=*rqtp;
+        
+        while (touter.tv_sec > 0 || touter.tv_nsec > 0)
+        {
+	        tinner.tv_sec = touter.tv_sec % KTIME_SEC_MAX;
+                touter.tv_sec -= tinner.tv_sec;
+                tinner.tv_nsec = touter.tv_nsec;
+                touter.tv_nsec = 0;
+           
+        	hrtimer_init(&t.timer, clockid, mode);
+		t.timer.expires = timespec_to_ktime(tinner);
+		if (do_nanosleep(&t, mode))
+		       	continue;
+
+		/* Absolute timers do not update the rmtp value and restart: */
+		if (mode == HRTIMER_ABS)
+			return -ERESTARTNOHAND;
+
+		if (rmtp) {
+			rem = ktime_sub(t.timer.expires, t.timer.base->get_time());
+			if (rem.tv64 <= 0)
+				continue;
+			tu = ktime_to_timespec(rem);
+                        tu.tv_sec+=touter.tv_sec; /* No need to add tv_nsec, it always
+                                                   * gets fully handled on the first 
+                                                   * iteration */
+			if (copy_to_user(rmtp, &tu, sizeof(tu)))
+				return -EFAULT;
+		}
+
+		restart = &current_thread_info()->restart_block;
+		restart->fn = nanosleep_restart;
+		restart->arg0 = t.timer.expires.tv64 & 0xFFFFFFFF;
+                /* Iff longs are 64 bits, we may have a non-zero touter.tv_sec.
+                 * As long is 64 bits, the restart args are also 64 bits so
+                 * we can store the touter.tv_sec in the high 32 bits of 
+                 * arg2 */
+		restart->arg1 = (t.timer.expires.tv64 >> 32) + ((u64)touter.tv_sec << 32);
+		restart->arg2 = (unsigned long) rmtp;
+		restart->arg3 = (unsigned long) t.timer.base->index;
 
-	restart = &current_thread_info()->restart_block;
-	restart->fn = nanosleep_restart;
-	restart->arg0 = t.timer.expires.tv64 & 0xFFFFFFFF;
-	restart->arg1 = t.timer.expires.tv64 >> 32;
-	restart->arg2 = (unsigned long) rmtp;
-	restart->arg3 = (unsigned long) t.timer.base->index;
+		return -ERESTART_RESTARTBLOCK;
+        }
 
-	return -ERESTART_RESTARTBLOCK;
+   return 0;
+	
 }
 
 asmlinkage long


-- 
Frank v Waveren                                  Key fingerprint: BDD7 D61E
fvw@....cx                                              5D39 CF05 4BFC F57A
Public key: hkp://wwwkeys.pgp.net/468D62C8              FA00 7D51 468D 62C8

Download attachment "signature.asc" of type "application/pgp-signature" (190 bytes)

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ