Re: 2.5.51 nanosleep fails

Stephen Rothwell
2002-12-13T01:21:54Z

Hi All,

On Thu, 12 Dec 2002 17:27:46 -0500 Jim Houston <jim.houston@attbi.com> wrote:
>
> The problem is that nanosleep didn't check for the NULL pointer
> case and always tries to copy out the remaining time. The attached
> patch will fix this problem.

Equivalent fix for the compatibility layer ...

Not compiled, not tested (I need to get a 64 bit machine ...)

Obviously correct (hopefully) :-)
--
Cheers,
Stephen Rothwell sfr@canb.auug.org.au
http://www.canb.auug.org.au/~sfr/

diff -ruN 2.5.51/kernel/compat.c 2.5.51-ns/kernel/compat.c
--- 2.5.51/kernel/compat.c 2002-12-10 15:10:41.000000000 +1100
+++ 2.5.51-ns/kernel/compat.c 2002-12-13 12:12:00.000000000 +1100
@@ -21,8 +21,7 @@
static long compat_nanosleep_restart(struct restart_block *restart)
{
unsigned long expire = restart->arg0, now = jiffies;
- struct timespec *rmtp = (struct timespec *) restart->arg1;
- long ret;
+ struct compat_timespec *rmtp;

/* Did it expire while we handled signals? */
if (!time_after(expire, now))
@@ -30,22 +29,22 @@

current->state = TASK_INTERRUPTIBLE;
expire = schedule_timeout(expire - now);
+ if (expire == 0)
+ return 0;

- ret = 0;
- if (expire) {
+ rmtp = (struct compat_timespec *)restart->arg1;
+ if (rmtp) {
struct compat_timespec ct;
struct timespec t;

jiffies_to_timespec(expire, &t);
ct.tv_sec = t.tv_sec;
ct.tv_nsec = t.tv_nsec;
-
- ret = -ERESTART_RESTARTBLOCK;
if (copy_to_user(rmtp, &ct, sizeof(ct)))
- ret = -EFAULT;
- /* The 'restart' block is already filled in */
+ return -EFAULT;
}
- return ret;
+ /* The 'restart' block is already filled in */
+ return -ERESTART_RESTARTBLOCK;
}

asmlinkage long compat_sys_nanosleep(struct compat_timespec *rqtp,
@@ -53,8 +52,8 @@
{
struct compat_timespec ct;
struct timespec t;
+ struct restart_block *restart;
unsigned long expire;
- s32 ret;

if (copy_from_user(&ct, rqtp, sizeof(ct)))
return -EFAULT;
@@ -67,25 +66,21 @@
expire = timespec_to_jiffies(&t) + (t.tv_sec || t.tv_nsec);
current->state = TASK_INTERRUPTIBLE;
expire = schedule_timeout(expire);
+ if (expire == 0)
+ return 0;

- ret = 0;
- if (expire) {
- struct restart_block *restart;
-
+ if (rmtp) {
jiffies_to_timespec(expire, &t);
ct.tv_sec = t.tv_sec;
ct.tv_nsec = t.tv_nsec;
-
if (copy_to_user(rmtp, &ct, sizeof(ct)))
return -EFAULT;
-
- restart = &current_thread_info()->restart_block;
- restart->fn = compat_nanosleep_restart;
- restart->arg0 = jiffies + expire;
- restart->arg1 = (unsigned long) rmtp;
- ret = -ERESTART_RESTARTBLOCK;
}
- return ret;
+ restart = &current_thread_info()->restart_block;
+ restart->fn = compat_nanosleep_restart;
+ restart->arg0 = jiffies + expire;
+ restart->arg1 = (unsigned long) rmtp;
+ return -ERESTART_RESTARTBLOCK;
}

/*