]> Git Repo - linux.git/commitdiff
Merge branch 'work.sys_wait' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
authorLinus Torvalds <[email protected]>
Wed, 5 Jul 2017 21:10:19 +0000 (14:10 -0700)
committerLinus Torvalds <[email protected]>
Wed, 5 Jul 2017 21:10:19 +0000 (14:10 -0700)
Pull wait syscall updates from Al Viro:
 "Consolidating sys_wait* and compat counterparts.

  Gets rid of set_fs()/double-copy mess, simplifies the whole thing
  (lifting the copyouts to the syscalls means less headache in the part
  that does actual work - fewer failure exits, to start with), gets rid
  of the overhead of field-by-field __put_user()"

* 'work.sys_wait' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
  osf_wait4: switch to kernel_wait4()
  waitid(): switch copyout of siginfo to unsafe_put_user()
  wait_task_zombie: consolidate info logics
  kill wait_noreap_copyout()
  lift getrusage() from wait_noreap_copyout()
  waitid(2): leave copyout of siginfo to syscall itself
  kernel_wait4()/kernel_waitid(): delay copying status to userland
  wait4(2)/waitid(2): separate copying rusage to userland
  move compat wait4 and waitid next to native variants

1  2 
include/linux/sched/task.h
kernel/compat.c
kernel/exit.c

index f0f065c5afcfbf3affb2acb4803f14f10b92bcd6,6b830fd9d809f4745e8b9b7ec3b76d0510f2b0bc..c97e5f09692768d0cf2a3770c45aacf2fdc8baf1
@@@ -9,6 -9,7 +9,7 @@@
  #include <linux/sched.h>
  
  struct task_struct;
+ struct rusage;
  union thread_union;
  
  /*
@@@ -74,6 -75,7 +75,7 @@@ extern long _do_fork(unsigned long, uns
  extern long do_fork(unsigned long, unsigned long, unsigned long, int __user *, int __user *);
  struct task_struct *fork_idle(int);
  extern pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
+ extern long kernel_wait4(pid_t, int *, int, struct rusage *);
  
  extern void free_task(struct task_struct *tsk);
  
@@@ -95,6 -97,8 +97,6 @@@ static inline void put_task_struct(stru
  }
  
  struct task_struct *task_rcu_dereference(struct task_struct **ptask);
 -struct task_struct *try_get_task_struct(struct task_struct **ptask);
 -
  
  #ifdef CONFIG_ARCH_WANTS_DYNAMIC_TASK_STRUCT
  extern int arch_task_struct_size __read_mostly;
diff --combined kernel/compat.c
index ebd8bdc3fd68c70fce5a37588ae22253690410c3,b4cdba6bbd0291cfbdea58b691e80df264af6718..9ce1d4876e60b4738165c430e24db8d1637a14a7
  
  #include <linux/uaccess.h>
  
 -static int compat_get_timex(struct timex *txc, struct compat_timex __user *utp)
 +int compat_get_timex(struct timex *txc, const struct compat_timex __user *utp)
  {
 -      memset(txc, 0, sizeof(struct timex));
 -
 -      if (!access_ok(VERIFY_READ, utp, sizeof(struct compat_timex)) ||
 -                      __get_user(txc->modes, &utp->modes) ||
 -                      __get_user(txc->offset, &utp->offset) ||
 -                      __get_user(txc->freq, &utp->freq) ||
 -                      __get_user(txc->maxerror, &utp->maxerror) ||
 -                      __get_user(txc->esterror, &utp->esterror) ||
 -                      __get_user(txc->status, &utp->status) ||
 -                      __get_user(txc->constant, &utp->constant) ||
 -                      __get_user(txc->precision, &utp->precision) ||
 -                      __get_user(txc->tolerance, &utp->tolerance) ||
 -                      __get_user(txc->time.tv_sec, &utp->time.tv_sec) ||
 -                      __get_user(txc->time.tv_usec, &utp->time.tv_usec) ||
 -                      __get_user(txc->tick, &utp->tick) ||
 -                      __get_user(txc->ppsfreq, &utp->ppsfreq) ||
 -                      __get_user(txc->jitter, &utp->jitter) ||
 -                      __get_user(txc->shift, &utp->shift) ||
 -                      __get_user(txc->stabil, &utp->stabil) ||
 -                      __get_user(txc->jitcnt, &utp->jitcnt) ||
 -                      __get_user(txc->calcnt, &utp->calcnt) ||
 -                      __get_user(txc->errcnt, &utp->errcnt) ||
 -                      __get_user(txc->stbcnt, &utp->stbcnt))
 -              return -EFAULT;
 +      struct compat_timex tx32;
  
 -      return 0;
 -}
 -
 -static int compat_put_timex(struct compat_timex __user *utp, struct timex *txc)
 -{
 -      if (!access_ok(VERIFY_WRITE, utp, sizeof(struct compat_timex)) ||
 -                      __put_user(txc->modes, &utp->modes) ||
 -                      __put_user(txc->offset, &utp->offset) ||
 -                      __put_user(txc->freq, &utp->freq) ||
 -                      __put_user(txc->maxerror, &utp->maxerror) ||
 -                      __put_user(txc->esterror, &utp->esterror) ||
 -                      __put_user(txc->status, &utp->status) ||
 -                      __put_user(txc->constant, &utp->constant) ||
 -                      __put_user(txc->precision, &utp->precision) ||
 -                      __put_user(txc->tolerance, &utp->tolerance) ||
 -                      __put_user(txc->time.tv_sec, &utp->time.tv_sec) ||
 -                      __put_user(txc->time.tv_usec, &utp->time.tv_usec) ||
 -                      __put_user(txc->tick, &utp->tick) ||
 -                      __put_user(txc->ppsfreq, &utp->ppsfreq) ||
 -                      __put_user(txc->jitter, &utp->jitter) ||
 -                      __put_user(txc->shift, &utp->shift) ||
 -                      __put_user(txc->stabil, &utp->stabil) ||
 -                      __put_user(txc->jitcnt, &utp->jitcnt) ||
 -                      __put_user(txc->calcnt, &utp->calcnt) ||
 -                      __put_user(txc->errcnt, &utp->errcnt) ||
 -                      __put_user(txc->stbcnt, &utp->stbcnt) ||
 -                      __put_user(txc->tai, &utp->tai))
 +      if (copy_from_user(&tx32, utp, sizeof(struct compat_timex)))
                return -EFAULT;
 -      return 0;
 -}
  
 -COMPAT_SYSCALL_DEFINE2(gettimeofday, struct compat_timeval __user *, tv,
 -                     struct timezone __user *, tz)
 -{
 -      if (tv) {
 -              struct timeval ktv;
 -              do_gettimeofday(&ktv);
 -              if (compat_put_timeval(&ktv, tv))
 -                      return -EFAULT;
 -      }
 -      if (tz) {
 -              if (copy_to_user(tz, &sys_tz, sizeof(sys_tz)))
 -                      return -EFAULT;
 -      }
 +      txc->modes = tx32.modes;
 +      txc->offset = tx32.offset;
 +      txc->freq = tx32.freq;
 +      txc->maxerror = tx32.maxerror;
 +      txc->esterror = tx32.esterror;
 +      txc->status = tx32.status;
 +      txc->constant = tx32.constant;
 +      txc->precision = tx32.precision;
 +      txc->tolerance = tx32.tolerance;
 +      txc->time.tv_sec = tx32.time.tv_sec;
 +      txc->time.tv_usec = tx32.time.tv_usec;
 +      txc->tick = tx32.tick;
 +      txc->ppsfreq = tx32.ppsfreq;
 +      txc->jitter = tx32.jitter;
 +      txc->shift = tx32.shift;
 +      txc->stabil = tx32.stabil;
 +      txc->jitcnt = tx32.jitcnt;
 +      txc->calcnt = tx32.calcnt;
 +      txc->errcnt = tx32.errcnt;
 +      txc->stbcnt = tx32.stbcnt;
  
        return 0;
  }
  
 -COMPAT_SYSCALL_DEFINE2(settimeofday, struct compat_timeval __user *, tv,
 -                     struct timezone __user *, tz)
 -{
 -      struct timespec64 new_ts;
 -      struct timeval user_tv;
 -      struct timezone new_tz;
 -
 -      if (tv) {
 -              if (compat_get_timeval(&user_tv, tv))
 -                      return -EFAULT;
 -              new_ts.tv_sec = user_tv.tv_sec;
 -              new_ts.tv_nsec = user_tv.tv_usec * NSEC_PER_USEC;
 -      }
 -      if (tz) {
 -              if (copy_from_user(&new_tz, tz, sizeof(*tz)))
 -                      return -EFAULT;
 -      }
 -
 -      return do_sys_settimeofday64(tv ? &new_ts : NULL, tz ? &new_tz : NULL);
 +int compat_put_timex(struct compat_timex __user *utp, const struct timex *txc)
 +{
 +      struct compat_timex tx32;
 +
 +      memset(&tx32, 0, sizeof(struct compat_timex));
 +      tx32.modes = txc->modes;
 +      tx32.offset = txc->offset;
 +      tx32.freq = txc->freq;
 +      tx32.maxerror = txc->maxerror;
 +      tx32.esterror = txc->esterror;
 +      tx32.status = txc->status;
 +      tx32.constant = txc->constant;
 +      tx32.precision = txc->precision;
 +      tx32.tolerance = txc->tolerance;
 +      tx32.time.tv_sec = txc->time.tv_sec;
 +      tx32.time.tv_usec = txc->time.tv_usec;
 +      tx32.tick = txc->tick;
 +      tx32.ppsfreq = txc->ppsfreq;
 +      tx32.jitter = txc->jitter;
 +      tx32.shift = txc->shift;
 +      tx32.stabil = txc->stabil;
 +      tx32.jitcnt = txc->jitcnt;
 +      tx32.calcnt = txc->calcnt;
 +      tx32.errcnt = txc->errcnt;
 +      tx32.stbcnt = txc->stbcnt;
 +      tx32.tai = txc->tai;
 +      if (copy_to_user(utp, &tx32, sizeof(struct compat_timex)))
 +              return -EFAULT;
 +      return 0;
  }
  
  static int __compat_get_timeval(struct timeval *tv, const struct compat_timeval __user *ctv)
@@@ -179,28 -213,141 +179,28 @@@ int compat_convert_timespec(struct time
        return 0;
  }
  
 -static long compat_nanosleep_restart(struct restart_block *restart)
 -{
 -      struct compat_timespec __user *rmtp;
 -      struct timespec rmt;
 -      mm_segment_t oldfs;
 -      long ret;
 -
 -      restart->nanosleep.rmtp = (struct timespec __user *) &rmt;
 -      oldfs = get_fs();
 -      set_fs(KERNEL_DS);
 -      ret = hrtimer_nanosleep_restart(restart);
 -      set_fs(oldfs);
 -
 -      if (ret == -ERESTART_RESTARTBLOCK) {
 -              rmtp = restart->nanosleep.compat_rmtp;
 -
 -              if (rmtp && compat_put_timespec(&rmt, rmtp))
 -                      return -EFAULT;
 -      }
 -
 -      return ret;
 -}
 -
 -COMPAT_SYSCALL_DEFINE2(nanosleep, struct compat_timespec __user *, rqtp,
 -                     struct compat_timespec __user *, rmtp)
 +int get_compat_itimerval(struct itimerval *o, const struct compat_itimerval __user *i)
  {
 -      struct timespec tu, rmt;
 -      struct timespec64 tu64;
 -      mm_segment_t oldfs;
 -      long ret;
 +      struct compat_itimerval v32;
  
 -      if (compat_get_timespec(&tu, rqtp))
 +      if (copy_from_user(&v32, i, sizeof(struct compat_itimerval)))
                return -EFAULT;
 -
 -      tu64 = timespec_to_timespec64(tu);
 -      if (!timespec64_valid(&tu64))
 -              return -EINVAL;
 -
 -      oldfs = get_fs();
 -      set_fs(KERNEL_DS);
 -      ret = hrtimer_nanosleep(&tu64,
 -                              rmtp ? (struct timespec __user *)&rmt : NULL,
 -                              HRTIMER_MODE_REL, CLOCK_MONOTONIC);
 -      set_fs(oldfs);
 -
 -      /*
 -       * hrtimer_nanosleep() can only return 0 or
 -       * -ERESTART_RESTARTBLOCK here because:
 -       *
 -       * - we call it with HRTIMER_MODE_REL and therefor exclude the
 -       *   -ERESTARTNOHAND return path.
 -       *
 -       * - we supply the rmtp argument from the task stack (due to
 -       *   the necessary compat conversion. So the update cannot
 -       *   fail, which excludes the -EFAULT return path as well. If
 -       *   it fails nevertheless we have a bigger problem and wont
 -       *   reach this place anymore.
 -       *
 -       * - if the return value is 0, we do not have to update rmtp
 -       *    because there is no remaining time.
 -       *
 -       * We check for -ERESTART_RESTARTBLOCK nevertheless if the
 -       * core implementation decides to return random nonsense.
 -       */
 -      if (ret == -ERESTART_RESTARTBLOCK) {
 -              struct restart_block *restart = &current->restart_block;
 -
 -              restart->fn = compat_nanosleep_restart;
 -              restart->nanosleep.compat_rmtp = rmtp;
 -
 -              if (rmtp && compat_put_timespec(&rmt, rmtp))
 -                      return -EFAULT;
 -      }
 -      return ret;
 -}
 -
 -static inline long get_compat_itimerval(struct itimerval *o,
 -              struct compat_itimerval __user *i)
 -{
 -      return (!access_ok(VERIFY_READ, i, sizeof(*i)) ||
 -              (__get_user(o->it_interval.tv_sec, &i->it_interval.tv_sec) |
 -               __get_user(o->it_interval.tv_usec, &i->it_interval.tv_usec) |
 -               __get_user(o->it_value.tv_sec, &i->it_value.tv_sec) |
 -               __get_user(o->it_value.tv_usec, &i->it_value.tv_usec)));
 -}
 -
 -static inline long put_compat_itimerval(struct compat_itimerval __user *o,
 -              struct itimerval *i)
 -{
 -      return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) ||
 -              (__put_user(i->it_interval.tv_sec, &o->it_interval.tv_sec) |
 -               __put_user(i->it_interval.tv_usec, &o->it_interval.tv_usec) |
 -               __put_user(i->it_value.tv_sec, &o->it_value.tv_sec) |
 -               __put_user(i->it_value.tv_usec, &o->it_value.tv_usec)));
 -}
 -
 -asmlinkage long sys_ni_posix_timers(void);
 -
 -COMPAT_SYSCALL_DEFINE2(getitimer, int, which,
 -              struct compat_itimerval __user *, it)
 -{
 -      struct itimerval kit;
 -      int error;
 -
 -      if (!IS_ENABLED(CONFIG_POSIX_TIMERS))
 -              return sys_ni_posix_timers();
 -
 -      error = do_getitimer(which, &kit);
 -      if (!error && put_compat_itimerval(it, &kit))
 -              error = -EFAULT;
 -      return error;
 +      o->it_interval.tv_sec = v32.it_interval.tv_sec;
 +      o->it_interval.tv_usec = v32.it_interval.tv_usec;
 +      o->it_value.tv_sec = v32.it_value.tv_sec;
 +      o->it_value.tv_usec = v32.it_value.tv_usec;
 +      return 0;
  }
  
 -COMPAT_SYSCALL_DEFINE3(setitimer, int, which,
 -              struct compat_itimerval __user *, in,
 -              struct compat_itimerval __user *, out)
 +int put_compat_itimerval(struct compat_itimerval __user *o, const struct itimerval *i)
  {
 -      struct itimerval kin, kout;
 -      int error;
 -
 -      if (!IS_ENABLED(CONFIG_POSIX_TIMERS))
 -              return sys_ni_posix_timers();
 +      struct compat_itimerval v32;
  
 -      if (in) {
 -              if (get_compat_itimerval(&kin, in))
 -                      return -EFAULT;
 -      } else
 -              memset(&kin, 0, sizeof(kin));
 -
 -      error = do_setitimer(which, &kin, out ? &kout : NULL);
 -      if (error || !out)
 -              return error;
 -      if (put_compat_itimerval(out, &kout))
 -              return -EFAULT;
 -      return 0;
 +      v32.it_interval.tv_sec = i->it_interval.tv_sec;
 +      v32.it_interval.tv_usec = i->it_interval.tv_usec;
 +      v32.it_value.tv_sec = i->it_value.tv_sec;
 +      v32.it_value.tv_usec = i->it_value.tv_usec;
 +      return copy_to_user(o, &v32, sizeof(struct compat_itimerval)) ? -EFAULT : 0;
  }
  
  static compat_clock_t clock_t_to_compat_clock_t(clock_t x)
@@@ -396,72 -543,6 +396,6 @@@ int put_compat_rusage(const struct rusa
        return 0;
  }
  
- COMPAT_SYSCALL_DEFINE4(wait4,
-       compat_pid_t, pid,
-       compat_uint_t __user *, stat_addr,
-       int, options,
-       struct compat_rusage __user *, ru)
- {
-       if (!ru) {
-               return sys_wait4(pid, stat_addr, options, NULL);
-       } else {
-               struct rusage r;
-               int ret;
-               unsigned int status;
-               mm_segment_t old_fs = get_fs();
-               set_fs (KERNEL_DS);
-               ret = sys_wait4(pid,
-                               (stat_addr ?
-                                (unsigned int __user *) &status : NULL),
-                               options, (struct rusage __user *) &r);
-               set_fs (old_fs);
-               if (ret > 0) {
-                       if (put_compat_rusage(&r, ru))
-                               return -EFAULT;
-                       if (stat_addr && put_user(status, stat_addr))
-                               return -EFAULT;
-               }
-               return ret;
-       }
- }
- COMPAT_SYSCALL_DEFINE5(waitid,
-               int, which, compat_pid_t, pid,
-               struct compat_siginfo __user *, uinfo, int, options,
-               struct compat_rusage __user *, uru)
- {
-       siginfo_t info;
-       struct rusage ru;
-       long ret;
-       mm_segment_t old_fs = get_fs();
-       memset(&info, 0, sizeof(info));
-       set_fs(KERNEL_DS);
-       ret = sys_waitid(which, pid, (siginfo_t __user *)&info, options,
-                        uru ? (struct rusage __user *)&ru : NULL);
-       set_fs(old_fs);
-       if ((ret < 0) || (info.si_signo == 0))
-               return ret;
-       if (uru) {
-               /* sys_waitid() overwrites everything in ru */
-               if (COMPAT_USE_64BIT_TIME)
-                       ret = copy_to_user(uru, &ru, sizeof(ru));
-               else
-                       ret = put_compat_rusage(&ru, uru);
-               if (ret)
-                       return -EFAULT;
-       }
-       BUG_ON(info.si_code & __SI_MASK);
-       info.si_code |= __SI_CHLD;
-       return copy_siginfo_to_user32(uinfo, &info);
- }
  static int compat_get_user_cpu_mask(compat_ulong_t __user *user_mask_ptr,
                                    unsigned len, struct cpumask *new_mask)
  {
@@@ -542,6 -623,193 +476,6 @@@ int put_compat_itimerspec(struct compat
        return 0;
  }
  
 -COMPAT_SYSCALL_DEFINE3(timer_create, clockid_t, which_clock,
 -                     struct compat_sigevent __user *, timer_event_spec,
 -                     timer_t __user *, created_timer_id)
 -{
 -      struct sigevent __user *event = NULL;
 -
 -      if (timer_event_spec) {
 -              struct sigevent kevent;
 -
 -              event = compat_alloc_user_space(sizeof(*event));
 -              if (get_compat_sigevent(&kevent, timer_event_spec) ||
 -                  copy_to_user(event, &kevent, sizeof(*event)))
 -                      return -EFAULT;
 -      }
 -
 -      return sys_timer_create(which_clock, event, created_timer_id);
 -}
 -
 -COMPAT_SYSCALL_DEFINE4(timer_settime, timer_t, timer_id, int, flags,
 -                     struct compat_itimerspec __user *, new,
 -                     struct compat_itimerspec __user *, old)
 -{
 -      long err;
 -      mm_segment_t oldfs;
 -      struct itimerspec newts, oldts;
 -
 -      if (!new)
 -              return -EINVAL;
 -      if (get_compat_itimerspec(&newts, new))
 -              return -EFAULT;
 -      oldfs = get_fs();
 -      set_fs(KERNEL_DS);
 -      err = sys_timer_settime(timer_id, flags,
 -                              (struct itimerspec __user *) &newts,
 -                              (struct itimerspec __user *) &oldts);
 -      set_fs(oldfs);
 -      if (!err && old && put_compat_itimerspec(old, &oldts))
 -              return -EFAULT;
 -      return err;
 -}
 -
 -COMPAT_SYSCALL_DEFINE2(timer_gettime, timer_t, timer_id,
 -                     struct compat_itimerspec __user *, setting)
 -{
 -      long err;
 -      mm_segment_t oldfs;
 -      struct itimerspec ts;
 -
 -      oldfs = get_fs();
 -      set_fs(KERNEL_DS);
 -      err = sys_timer_gettime(timer_id,
 -                              (struct itimerspec __user *) &ts);
 -      set_fs(oldfs);
 -      if (!err && put_compat_itimerspec(setting, &ts))
 -              return -EFAULT;
 -      return err;
 -}
 -
 -COMPAT_SYSCALL_DEFINE2(clock_settime, clockid_t, which_clock,
 -                     struct compat_timespec __user *, tp)
 -{
 -      long err;
 -      mm_segment_t oldfs;
 -      struct timespec ts;
 -
 -      if (compat_get_timespec(&ts, tp))
 -              return -EFAULT;
 -      oldfs = get_fs();
 -      set_fs(KERNEL_DS);
 -      err = sys_clock_settime(which_clock,
 -                              (struct timespec __user *) &ts);
 -      set_fs(oldfs);
 -      return err;
 -}
 -
 -COMPAT_SYSCALL_DEFINE2(clock_gettime, clockid_t, which_clock,
 -                     struct compat_timespec __user *, tp)
 -{
 -      long err;
 -      mm_segment_t oldfs;
 -      struct timespec ts;
 -
 -      oldfs = get_fs();
 -      set_fs(KERNEL_DS);
 -      err = sys_clock_gettime(which_clock,
 -                              (struct timespec __user *) &ts);
 -      set_fs(oldfs);
 -      if (!err && compat_put_timespec(&ts, tp))
 -              return -EFAULT;
 -      return err;
 -}
 -
 -COMPAT_SYSCALL_DEFINE2(clock_adjtime, clockid_t, which_clock,
 -                     struct compat_timex __user *, utp)
 -{
 -      struct timex txc;
 -      mm_segment_t oldfs;
 -      int err, ret;
 -
 -      err = compat_get_timex(&txc, utp);
 -      if (err)
 -              return err;
 -
 -      oldfs = get_fs();
 -      set_fs(KERNEL_DS);
 -      ret = sys_clock_adjtime(which_clock, (struct timex __user *) &txc);
 -      set_fs(oldfs);
 -
 -      err = compat_put_timex(utp, &txc);
 -      if (err)
 -              return err;
 -
 -      return ret;
 -}
 -
 -COMPAT_SYSCALL_DEFINE2(clock_getres, clockid_t, which_clock,
 -                     struct compat_timespec __user *, tp)
 -{
 -      long err;
 -      mm_segment_t oldfs;
 -      struct timespec ts;
 -
 -      oldfs = get_fs();
 -      set_fs(KERNEL_DS);
 -      err = sys_clock_getres(which_clock,
 -                             (struct timespec __user *) &ts);
 -      set_fs(oldfs);
 -      if (!err && tp && compat_put_timespec(&ts, tp))
 -              return -EFAULT;
 -      return err;
 -}
 -
 -static long compat_clock_nanosleep_restart(struct restart_block *restart)
 -{
 -      long err;
 -      mm_segment_t oldfs;
 -      struct timespec tu;
 -      struct compat_timespec __user *rmtp = restart->nanosleep.compat_rmtp;
 -
 -      restart->nanosleep.rmtp = (struct timespec __user *) &tu;
 -      oldfs = get_fs();
 -      set_fs(KERNEL_DS);
 -      err = clock_nanosleep_restart(restart);
 -      set_fs(oldfs);
 -
 -      if ((err == -ERESTART_RESTARTBLOCK) && rmtp &&
 -          compat_put_timespec(&tu, rmtp))
 -              return -EFAULT;
 -
 -      if (err == -ERESTART_RESTARTBLOCK) {
 -              restart->fn = compat_clock_nanosleep_restart;
 -              restart->nanosleep.compat_rmtp = rmtp;
 -      }
 -      return err;
 -}
 -
 -COMPAT_SYSCALL_DEFINE4(clock_nanosleep, clockid_t, which_clock, int, flags,
 -                     struct compat_timespec __user *, rqtp,
 -                     struct compat_timespec __user *, rmtp)
 -{
 -      long err;
 -      mm_segment_t oldfs;
 -      struct timespec in, out;
 -      struct restart_block *restart;
 -
 -      if (compat_get_timespec(&in, rqtp))
 -              return -EFAULT;
 -
 -      oldfs = get_fs();
 -      set_fs(KERNEL_DS);
 -      err = sys_clock_nanosleep(which_clock, flags,
 -                                (struct timespec __user *) &in,
 -                                (struct timespec __user *) &out);
 -      set_fs(oldfs);
 -
 -      if ((err == -ERESTART_RESTARTBLOCK) && rmtp &&
 -          compat_put_timespec(&out, rmtp))
 -              return -EFAULT;
 -
 -      if (err == -ERESTART_RESTARTBLOCK) {
 -              restart = &current->restart_block;
 -              restart->fn = compat_clock_nanosleep_restart;
 -              restart->nanosleep.compat_rmtp = rmtp;
 -      }
 -      return err;
 -}
 -
  /*
   * We currently only need the following fields from the sigevent
   * structure: sigev_value, sigev_signo, sig_notify and (sometimes
@@@ -701,6 -969,64 +635,6 @@@ COMPAT_SYSCALL_DEFINE4(rt_sigtimedwait
        return ret;
  }
  
 -#ifdef __ARCH_WANT_COMPAT_SYS_TIME
 -
 -/* compat_time_t is a 32 bit "long" and needs to get converted. */
 -
 -COMPAT_SYSCALL_DEFINE1(time, compat_time_t __user *, tloc)
 -{
 -      compat_time_t i;
 -      struct timeval tv;
 -
 -      do_gettimeofday(&tv);
 -      i = tv.tv_sec;
 -
 -      if (tloc) {
 -              if (put_user(i,tloc))
 -                      return -EFAULT;
 -      }
 -      force_successful_syscall_return();
 -      return i;
 -}
 -
 -COMPAT_SYSCALL_DEFINE1(stime, compat_time_t __user *, tptr)
 -{
 -      struct timespec tv;
 -      int err;
 -
 -      if (get_user(tv.tv_sec, tptr))
 -              return -EFAULT;
 -
 -      tv.tv_nsec = 0;
 -
 -      err = security_settime(&tv, NULL);
 -      if (err)
 -              return err;
 -
 -      do_settimeofday(&tv);
 -      return 0;
 -}
 -
 -#endif /* __ARCH_WANT_COMPAT_SYS_TIME */
 -
 -COMPAT_SYSCALL_DEFINE1(adjtimex, struct compat_timex __user *, utp)
 -{
 -      struct timex txc;
 -      int err, ret;
 -
 -      err = compat_get_timex(&txc, utp);
 -      if (err)
 -              return err;
 -
 -      ret = do_adjtimex(&txc);
 -
 -      err = compat_put_timex(utp, &txc);
 -      if (err)
 -              return err;
 -
 -      return ret;
 -}
 -
  #ifdef CONFIG_NUMA
  COMPAT_SYSCALL_DEFINE6(move_pages, pid_t, pid, compat_ulong_t, nr_pages,
                       compat_uptr_t __user *, pages32,
diff --combined kernel/exit.c
index c63226283aef8b541c081a6c978e55b355f48ab2,462fc25eec6e7ffe9b4bc33f80134c238b023fdb..b0cc86a2d00babd7d4c97de66b174b983c476bde
@@@ -62,6 -62,7 +62,7 @@@
  #include <linux/kcov.h>
  #include <linux/random.h>
  #include <linux/rcuwait.h>
+ #include <linux/compat.h>
  
  #include <linux/uaccess.h>
  #include <asm/unistd.h>
@@@ -318,6 -319,19 +319,6 @@@ void rcuwait_wake_up(struct rcuwait *w
        rcu_read_unlock();
  }
  
 -struct task_struct *try_get_task_struct(struct task_struct **ptask)
 -{
 -      struct task_struct *task;
 -
 -      rcu_read_lock();
 -      task = task_rcu_dereference(ptask);
 -      if (task)
 -              get_task_struct(task);
 -      rcu_read_unlock();
 -
 -      return task;
 -}
 -
  /*
   * Determine if a process group is "orphaned", according to the POSIX
   * definition in 2.2.2.52.  Orphaned process groups are not to be affected
@@@ -982,16 -996,23 +983,23 @@@ SYSCALL_DEFINE1(exit_group, int, error_
        return 0;
  }
  
+ struct waitid_info {
+       pid_t pid;
+       uid_t uid;
+       int status;
+       int cause;
+ };
  struct wait_opts {
        enum pid_type           wo_type;
        int                     wo_flags;
        struct pid              *wo_pid;
  
-       struct siginfo __user   *wo_info;
-       int __user              *wo_stat;
-       struct rusage __user    *wo_rusage;
+       struct waitid_info      *wo_info;
+       int                     wo_stat;
+       struct rusage           *wo_rusage;
  
 -      wait_queue_t            child_wait;
 +      wait_queue_entry_t              child_wait;
        int                     notask_error;
  };
  
@@@ -1036,34 -1057,6 +1044,6 @@@ eligible_child(struct wait_opts *wo, bo
        return 1;
  }
  
- static int wait_noreap_copyout(struct wait_opts *wo, struct task_struct *p,
-                               pid_t pid, uid_t uid, int why, int status)
- {
-       struct siginfo __user *infop;
-       int retval = wo->wo_rusage
-               ? getrusage(p, RUSAGE_BOTH, wo->wo_rusage) : 0;
-       put_task_struct(p);
-       infop = wo->wo_info;
-       if (infop) {
-               if (!retval)
-                       retval = put_user(SIGCHLD, &infop->si_signo);
-               if (!retval)
-                       retval = put_user(0, &infop->si_errno);
-               if (!retval)
-                       retval = put_user((short)why, &infop->si_code);
-               if (!retval)
-                       retval = put_user(pid, &infop->si_pid);
-               if (!retval)
-                       retval = put_user(uid, &infop->si_uid);
-               if (!retval)
-                       retval = put_user(status, &infop->si_status);
-       }
-       if (!retval)
-               retval = pid;
-       return retval;
- }
  /*
   * Handle sys_wait4 work for one task in state EXIT_ZOMBIE.  We hold
   * read_lock(&tasklist_lock) on entry.  If we return zero, we still hold
   */
  static int wait_task_zombie(struct wait_opts *wo, struct task_struct *p)
  {
-       int state, retval, status;
+       int state, status;
        pid_t pid = task_pid_vnr(p);
        uid_t uid = from_kuid_munged(current_user_ns(), task_uid(p));
-       struct siginfo __user *infop;
+       struct waitid_info *infop;
  
        if (!likely(wo->wo_flags & WEXITED))
                return 0;
  
        if (unlikely(wo->wo_flags & WNOWAIT)) {
-               int exit_code = p->exit_code;
-               int why;
+               status = p->exit_code;
                get_task_struct(p);
                read_unlock(&tasklist_lock);
                sched_annotate_sleep();
-               if ((exit_code & 0x7f) == 0) {
-                       why = CLD_EXITED;
-                       status = exit_code >> 8;
-               } else {
-                       why = (exit_code & 0x80) ? CLD_DUMPED : CLD_KILLED;
-                       status = exit_code & 0x7f;
-               }
-               return wait_noreap_copyout(wo, p, pid, uid, why, status);
+               if (wo->wo_rusage)
+                       getrusage(p, RUSAGE_BOTH, wo->wo_rusage);
+               put_task_struct(p);
+               goto out_info;
        }
        /*
         * Move the task's state to DEAD/TRACE, only one thread can do this.
                spin_unlock_irq(&current->sighand->siglock);
        }
  
-       retval = wo->wo_rusage
-               ? getrusage(p, RUSAGE_BOTH, wo->wo_rusage) : 0;
+       if (wo->wo_rusage)
+               getrusage(p, RUSAGE_BOTH, wo->wo_rusage);
        status = (p->signal->flags & SIGNAL_GROUP_EXIT)
                ? p->signal->group_exit_code : p->exit_code;
-       if (!retval && wo->wo_stat)
-               retval = put_user(status, wo->wo_stat);
-       infop = wo->wo_info;
-       if (!retval && infop)
-               retval = put_user(SIGCHLD, &infop->si_signo);
-       if (!retval && infop)
-               retval = put_user(0, &infop->si_errno);
-       if (!retval && infop) {
-               int why;
-               if ((status & 0x7f) == 0) {
-                       why = CLD_EXITED;
-                       status >>= 8;
-               } else {
-                       why = (status & 0x80) ? CLD_DUMPED : CLD_KILLED;
-                       status &= 0x7f;
-               }
-               retval = put_user((short)why, &infop->si_code);
-               if (!retval)
-                       retval = put_user(status, &infop->si_status);
-       }
-       if (!retval && infop)
-               retval = put_user(pid, &infop->si_pid);
-       if (!retval && infop)
-               retval = put_user(uid, &infop->si_uid);
-       if (!retval)
-               retval = pid;
+       wo->wo_stat = status;
  
        if (state == EXIT_TRACE) {
                write_lock_irq(&tasklist_lock);
        if (state == EXIT_DEAD)
                release_task(p);
  
-       return retval;
+ out_info:
+       infop = wo->wo_info;
+       if (infop) {
+               if ((status & 0x7f) == 0) {
+                       infop->cause = CLD_EXITED;
+                       infop->status = status >> 8;
+               } else {
+                       infop->cause = (status & 0x80) ? CLD_DUMPED : CLD_KILLED;
+                       infop->status = status & 0x7f;
+               }
+               infop->pid = pid;
+               infop->uid = uid;
+       }
+       return pid;
  }
  
  static int *task_stopped_code(struct task_struct *p, bool ptrace)
  static int wait_task_stopped(struct wait_opts *wo,
                                int ptrace, struct task_struct *p)
  {
-       struct siginfo __user *infop;
-       int retval, exit_code, *p_code, why;
+       struct waitid_info *infop;
+       int exit_code, *p_code, why;
        uid_t uid = 0; /* unneeded, required by compiler */
        pid_t pid;
  
@@@ -1298,34 -1271,21 +1258,21 @@@ unlock_sig
        why = ptrace ? CLD_TRAPPED : CLD_STOPPED;
        read_unlock(&tasklist_lock);
        sched_annotate_sleep();
+       if (wo->wo_rusage)
+               getrusage(p, RUSAGE_BOTH, wo->wo_rusage);
+       put_task_struct(p);
  
-       if (unlikely(wo->wo_flags & WNOWAIT))
-               return wait_noreap_copyout(wo, p, pid, uid, why, exit_code);
-       retval = wo->wo_rusage
-               ? getrusage(p, RUSAGE_BOTH, wo->wo_rusage) : 0;
-       if (!retval && wo->wo_stat)
-               retval = put_user((exit_code << 8) | 0x7f, wo->wo_stat);
+       if (likely(!(wo->wo_flags & WNOWAIT)))
+               wo->wo_stat = (exit_code << 8) | 0x7f;
  
        infop = wo->wo_info;
-       if (!retval && infop)
-               retval = put_user(SIGCHLD, &infop->si_signo);
-       if (!retval && infop)
-               retval = put_user(0, &infop->si_errno);
-       if (!retval && infop)
-               retval = put_user((short)why, &infop->si_code);
-       if (!retval && infop)
-               retval = put_user(exit_code, &infop->si_status);
-       if (!retval && infop)
-               retval = put_user(pid, &infop->si_pid);
-       if (!retval && infop)
-               retval = put_user(uid, &infop->si_uid);
-       if (!retval)
-               retval = pid;
-       put_task_struct(p);
-       BUG_ON(!retval);
-       return retval;
+       if (infop) {
+               infop->cause = why;
+               infop->status = exit_code;
+               infop->pid = pid;
+               infop->uid = uid;
+       }
+       return pid;
  }
  
  /*
   */
  static int wait_task_continued(struct wait_opts *wo, struct task_struct *p)
  {
-       int retval;
+       struct waitid_info *infop;
        pid_t pid;
        uid_t uid;
  
        get_task_struct(p);
        read_unlock(&tasklist_lock);
        sched_annotate_sleep();
+       if (wo->wo_rusage)
+               getrusage(p, RUSAGE_BOTH, wo->wo_rusage);
+       put_task_struct(p);
  
-       if (!wo->wo_info) {
-               retval = wo->wo_rusage
-                       ? getrusage(p, RUSAGE_BOTH, wo->wo_rusage) : 0;
-               put_task_struct(p);
-               if (!retval && wo->wo_stat)
-                       retval = put_user(0xffff, wo->wo_stat);
-               if (!retval)
-                       retval = pid;
+       infop = wo->wo_info;
+       if (!infop) {
+               wo->wo_stat = 0xffff;
        } else {
-               retval = wait_noreap_copyout(wo, p, pid, uid,
-                                            CLD_CONTINUED, SIGCONT);
-               BUG_ON(retval == 0);
+               infop->cause = CLD_CONTINUED;
+               infop->pid = pid;
+               infop->uid = uid;
+               infop->status = SIGCONT;
        }
-       return retval;
+       return pid;
  }
  
  /*
@@@ -1528,7 -1486,7 +1473,7 @@@ static int ptrace_do_wait(struct wait_o
        return 0;
  }
  
 -static int child_wait_callback(wait_queue_t *wait, unsigned mode,
 +static int child_wait_callback(wait_queue_entry_t *wait, unsigned mode,
                                int sync, void *key)
  {
        struct wait_opts *wo = container_of(wait, struct wait_opts,
@@@ -1604,8 -1562,8 +1549,8 @@@ end
        return retval;
  }
  
SYSCALL_DEFINE5(waitid, int, which, pid_t, upid, struct siginfo __user *,
-               infop, int, options, struct rusage __user *, ru)
static long kernel_waitid(int which, pid_t upid, struct waitid_info *infop,
+                         int options, struct rusage *ru)
  {
        struct wait_opts wo;
        struct pid *pid = NULL;
        wo.wo_pid       = pid;
        wo.wo_flags     = options;
        wo.wo_info      = infop;
-       wo.wo_stat      = NULL;
        wo.wo_rusage    = ru;
        ret = do_wait(&wo);
  
-       if (ret > 0) {
+       if (ret > 0)
                ret = 0;
-       } else if (infop) {
-               /*
-                * For a WNOHANG return, clear out all the fields
-                * we would set so the user can easily tell the
-                * difference.
-                */
-               if (!ret)
-                       ret = put_user(0, &infop->si_signo);
-               if (!ret)
-                       ret = put_user(0, &infop->si_errno);
-               if (!ret)
-                       ret = put_user(0, &infop->si_code);
-               if (!ret)
-                       ret = put_user(0, &infop->si_pid);
-               if (!ret)
-                       ret = put_user(0, &infop->si_uid);
-               if (!ret)
-                       ret = put_user(0, &infop->si_status);
-       }
  
        put_pid(pid);
        return ret;
  }
  
- SYSCALL_DEFINE4(wait4, pid_t, upid, int __user *, stat_addr,
-               int, options, struct rusage __user *, ru)
+ SYSCALL_DEFINE5(waitid, int, which, pid_t, upid, struct siginfo __user *,
+               infop, int, options, struct rusage __user *, ru)
+ {
+       struct rusage r;
+       struct waitid_info info = {.status = 0};
+       long err = kernel_waitid(which, upid, &info, options, ru ? &r : NULL);
+       if (!err) {
+               if (ru && copy_to_user(ru, &r, sizeof(struct rusage)))
+                       return -EFAULT;
+       }
+       if (!infop)
+               return err;
+       user_access_begin();
+       unsafe_put_user(err ? 0 : SIGCHLD, &infop->si_signo, Efault);
+       unsafe_put_user(0, &infop->si_errno, Efault);
+       unsafe_put_user((short)info.cause, &infop->si_code, Efault);
+       unsafe_put_user(info.pid, &infop->si_pid, Efault);
+       unsafe_put_user(info.uid, &infop->si_uid, Efault);
+       unsafe_put_user(info.status, &infop->si_status, Efault);
+       user_access_end();
+       return err;
+ Efault:
+       user_access_end();
+       return -EFAULT;
+ }
+ long kernel_wait4(pid_t upid, int __user *stat_addr, int options,
+                 struct rusage *ru)
  {
        struct wait_opts wo;
        struct pid *pid = NULL;
        wo.wo_pid       = pid;
        wo.wo_flags     = options | WEXITED;
        wo.wo_info      = NULL;
-       wo.wo_stat      = stat_addr;
+       wo.wo_stat      = 0;
        wo.wo_rusage    = ru;
        ret = do_wait(&wo);
        put_pid(pid);
+       if (ret > 0 && stat_addr && put_user(wo.wo_stat, stat_addr))
+               ret = -EFAULT;
  
        return ret;
  }
  
+ SYSCALL_DEFINE4(wait4, pid_t, upid, int __user *, stat_addr,
+               int, options, struct rusage __user *, ru)
+ {
+       struct rusage r;
+       long err = kernel_wait4(upid, stat_addr, options, ru ? &r : NULL);
+       if (err > 0) {
+               if (ru && copy_to_user(ru, &r, sizeof(struct rusage)))
+                       return -EFAULT;
+       }
+       return err;
+ }
  #ifdef __ARCH_WANT_SYS_WAITPID
  
  /*
@@@ -1722,3 -1703,56 +1690,56 @@@ SYSCALL_DEFINE3(waitpid, pid_t, pid, in
  }
  
  #endif
+ #ifdef CONFIG_COMPAT
+ COMPAT_SYSCALL_DEFINE4(wait4,
+       compat_pid_t, pid,
+       compat_uint_t __user *, stat_addr,
+       int, options,
+       struct compat_rusage __user *, ru)
+ {
+       struct rusage r;
+       long err = kernel_wait4(pid, stat_addr, options, ru ? &r : NULL);
+       if (err > 0) {
+               if (ru && put_compat_rusage(&r, ru))
+                       return -EFAULT;
+       }
+       return err;
+ }
+ COMPAT_SYSCALL_DEFINE5(waitid,
+               int, which, compat_pid_t, pid,
+               struct compat_siginfo __user *, infop, int, options,
+               struct compat_rusage __user *, uru)
+ {
+       struct rusage ru;
+       struct waitid_info info = {.status = 0};
+       long err = kernel_waitid(which, pid, &info, options, uru ? &ru : NULL);
+       if (!err && uru) {
+               /* kernel_waitid() overwrites everything in ru */
+               if (COMPAT_USE_64BIT_TIME)
+                       err = copy_to_user(uru, &ru, sizeof(ru));
+               else
+                       err = put_compat_rusage(&ru, uru);
+               if (err)
+                       return -EFAULT;
+       }
+       if (!infop)
+               return err;
+       user_access_begin();
+       unsafe_put_user(err ? 0 : SIGCHLD, &infop->si_signo, Efault);
+       unsafe_put_user(0, &infop->si_errno, Efault);
+       unsafe_put_user((short)info.cause, &infop->si_code, Efault);
+       unsafe_put_user(info.pid, &infop->si_pid, Efault);
+       unsafe_put_user(info.uid, &infop->si_uid, Efault);
+       unsafe_put_user(info.status, &infop->si_status, Efault);
+       user_access_end();
+       return err;
+ Efault:
+       user_access_end();
+       return -EFAULT;
+ }
+ #endif
This page took 0.103943 seconds and 4 git commands to generate.