]> git.hungrycats.org Git - linux/commitdiff
[PATCH] Make copy_siginfo_to_user mode explicit
authorStephen Rothwell <sfr@canb.auug.org.au>
Tue, 18 Jun 2002 03:59:18 +0000 (20:59 -0700)
committerLinus Torvalds <torvalds@home.transmeta.com>
Tue, 18 Jun 2002 03:59:18 +0000 (20:59 -0700)
This patch makes copy_siginfo_to_user excplicitly copy the correct
union member.  Previously we were getting the correct result but
really by accident.

kernel/signal.c

index b61c19be49297be0ba08ed2f47b4e658524c09c7..7fccdfbc965f6759a29da83f98d634862c4c80a3 100644 (file)
@@ -1043,37 +1043,58 @@ sys_rt_sigpending(sigset_t *set, size_t sigsetsize)
 
 int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from)
 {
+       int err;
+
        if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t)))
                return -EFAULT;
        if (from->si_code < 0)
-               return __copy_to_user(to, from, sizeof(siginfo_t));
-       else {
-               int err;
-
-               /* If you change siginfo_t structure, please be sure
-                  this code is fixed accordingly.
-                  It should never copy any pad contained in the structure
-                  to avoid security leaks, but must copy the generic
-                  3 ints plus the relevant union member.  */
-               err = __put_user(from->si_signo, &to->si_signo);
-               err |= __put_user(from->si_errno, &to->si_errno);
-               err |= __put_user((short)from->si_code, &to->si_code);
-               /* First 32bits of unions are always present.  */
+               return __copy_to_user(to, from, sizeof(siginfo_t))
+                       ? -EFAULT : 0;
+       /*
+        * If you change siginfo_t structure, please be sure
+        * this code is fixed accordingly.
+        * It should never copy any pad contained in the structure
+        * to avoid security leaks, but must copy the generic
+        * 3 ints plus the relevant union member.
+        */
+       err = __put_user(from->si_signo, &to->si_signo);
+       err |= __put_user(from->si_errno, &to->si_errno);
+       err |= __put_user((short)from->si_code, &to->si_code);
+       switch (from->si_code & __SI_MASK) {
+       case __SI_KILL:
                err |= __put_user(from->si_pid, &to->si_pid);
-               switch (from->si_code >> 16) {
-               case __SI_FAULT >> 16:
-                       break;
-               case __SI_CHLD >> 16:
-                       err |= __put_user(from->si_utime, &to->si_utime);
-                       err |= __put_user(from->si_stime, &to->si_stime);
-                       err |= __put_user(from->si_status, &to->si_status);
-               default:
-                       err |= __put_user(from->si_uid, &to->si_uid);
-                       break;
-               /* case __SI_RT: This is not generated by the kernel as of now.  */
-               }
-               return err;
+               err |= __put_user(from->si_uid, &to->si_uid);
+               break;
+       case __SI_TIMER:
+               err |= __put_user(from->si_timer1, &to->si_timer1);
+               err |= __put_user(from->si_timer2, &to->si_timer2);
+               break;
+       case __SI_POLL:
+               err |= __put_user(from->si_band, &to->si_band);
+               err |= __put_user(from->si_fd, &to->si_fd);
+               break;
+       case __SI_FAULT:
+               err |= __put_user(from->si_addr, &to->si_addr);
+               break;
+       case __SI_CHLD:
+               err |= __put_user(from->si_pid, &to->si_pid);
+               err |= __put_user(from->si_uid, &to->si_uid);
+               err |= __put_user(from->si_status, &to->si_status);
+               err |= __put_user(from->si_utime, &to->si_utime);
+               err |= __put_user(from->si_stime, &to->si_stime);
+               break;
+       case __SI_RT: /* This is not generated by the kernel as of now. */
+               err |= __put_user(from->si_pid, &to->si_pid);
+               err |= __put_user(from->si_uid, &to->si_uid);
+               err |= __put_user(from->si_int, &to->si_int);
+               err |= __put_user(from->si_ptr, &to->si_ptr);
+               break;
+       default: /* this is just in case for now ... */
+               err |= __put_user(from->si_pid, &to->si_pid);
+               err |= __put_user(from->si_uid, &to->si_uid);
+               break;
        }
+       return err;
 }
 
 #endif