Merge tag 'signal-for-v5.20' of git://git.kernel.org/pub/scm/linux/kernel/git/ebieder...
authorLinus Torvalds <torvalds@linux-foundation.org>
Sun, 9 Oct 2022 23:14:15 +0000 (16:14 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sun, 9 Oct 2022 23:14:15 +0000 (16:14 -0700)
Pull ptrace update from Eric Biederman:
 "ptrace: Stop supporting SIGKILL for PTRACE_EVENT_EXIT

  Recently I had a conversation where it was pointed out to me that
  SIGKILL sent to a tracee stropped in PTRACE_EVENT_EXIT is quite
  difficult for a tracer to handle.

  Keeping SIGKILL working after the process has been killed is pain from
  an implementation point of view.

  So since the debuggers don't want this behavior let's see if we can
  remove this wart for the userspace API

  If a regression is detected it should only need to be the last change
  that is the reverted. The other two are just general cleanups that
  make the last patch simpler"

* tag 'signal-for-v5.20' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace:
  signal: Drop signals received after a fatal signal has been processed
  signal: Guarantee that SIGNAL_GROUP_EXIT is set on process exit
  signal: Ensure SIGNAL_GROUP_EXIT gets set in do_group_exit

1  2 
fs/coredump.c
kernel/exit.c
kernel/fork.c

diff --combined fs/coredump.c
index 3538f3a63965df169906e744a6af9e43dadd1ae0,b836948c954318e3be304404e27c4937b97b0dd2..7c6bb4e9db20dbd1e9890fc4b842c015d08e40b0
@@@ -354,7 -354,7 +354,7 @@@ static int zap_process(struct task_stru
        struct task_struct *t;
        int nr = 0;
  
-       /* ignore all signals except SIGKILL, see prepare_signal() */
+       /* Allow SIGKILL, see prepare_signal() */
        start->signal->flags = SIGNAL_GROUP_EXIT;
        start->signal->group_exit_code = exit_code;
        start->signal->group_stop_count = 0;
@@@ -816,9 -816,9 +816,9 @@@ static int __dump_skip(struct coredump_
  {
        static char zeroes[PAGE_SIZE];
        struct file *file = cprm->file;
 -      if (file->f_op->llseek && file->f_op->llseek != no_llseek) {
 +      if (file->f_mode & FMODE_LSEEK) {
                if (dump_interrupted() ||
 -                  file->f_op->llseek(file, nr, SEEK_CUR) < 0)
 +                  vfs_llseek(file, nr, SEEK_CUR) < 0)
                        return 0;
                cprm->pos += nr;
                return 1;
        }
  }
  
 +static int dump_emit_page(struct coredump_params *cprm, struct page *page)
 +{
 +      struct bio_vec bvec = {
 +              .bv_page        = page,
 +              .bv_offset      = 0,
 +              .bv_len         = PAGE_SIZE,
 +      };
 +      struct iov_iter iter;
 +      struct file *file = cprm->file;
 +      loff_t pos;
 +      ssize_t n;
 +
 +      if (cprm->to_skip) {
 +              if (!__dump_skip(cprm, cprm->to_skip))
 +                      return 0;
 +              cprm->to_skip = 0;
 +      }
 +      if (cprm->written + PAGE_SIZE > cprm->limit)
 +              return 0;
 +      if (dump_interrupted())
 +              return 0;
 +      pos = file->f_pos;
 +      iov_iter_bvec(&iter, WRITE, &bvec, 1, PAGE_SIZE);
 +      n = __kernel_write_iter(cprm->file, &iter, &pos);
 +      if (n != PAGE_SIZE)
 +              return 0;
 +      file->f_pos = pos;
 +      cprm->written += PAGE_SIZE;
 +      cprm->pos += PAGE_SIZE;
 +
 +      return 1;
 +}
 +
  int dump_emit(struct coredump_params *cprm, const void *addr, int nr)
  {
        if (cprm->to_skip) {
@@@ -896,6 -863,7 +896,6 @@@ int dump_user_range(struct coredump_par
  
        for (addr = start; addr < start + len; addr += PAGE_SIZE) {
                struct page *page;
 -              int stop;
  
                /*
                 * To avoid having to allocate page tables for virtual address
                 */
                page = get_dump_page(addr);
                if (page) {
 -                      void *kaddr = kmap_local_page(page);
 -
 -                      stop = !dump_emit(cprm, kaddr, PAGE_SIZE);
 -                      kunmap_local(kaddr);
 +                      int stop = !dump_emit_page(cprm, page);
                        put_page(page);
                        if (stop)
                                return 0;
diff --combined kernel/exit.c
index 84021b24f79e3d1d2dc11fe70bf69cf620c7fc85,d8ecbaa514f7cee069f89598a44f9af41667eac1..4f7424523bac9ae65745d69350217bfa17d56083
@@@ -733,11 -733,29 +733,29 @@@ static void check_stack_usage(void
  static inline void check_stack_usage(void) {}
  #endif
  
+ static void synchronize_group_exit(struct task_struct *tsk, long code)
+ {
+       struct sighand_struct *sighand = tsk->sighand;
+       struct signal_struct *signal = tsk->signal;
+       spin_lock_irq(&sighand->siglock);
+       signal->quick_threads--;
+       if ((signal->quick_threads == 0) &&
+           !(signal->flags & SIGNAL_GROUP_EXIT)) {
+               signal->flags = SIGNAL_GROUP_EXIT;
+               signal->group_exit_code = code;
+               signal->group_stop_count = 0;
+       }
+       spin_unlock_irq(&sighand->siglock);
+ }
  void __noreturn do_exit(long code)
  {
        struct task_struct *tsk = current;
        int group_dead;
  
+       synchronize_group_exit(tsk, code);
        WARN_ON(tsk->plug);
  
        kcov_task_exit(tsk);
@@@ -905,7 -923,7 +923,7 @@@ do_group_exit(int exit_code
                exit_code = sig->group_exit_code;
        else if (sig->group_exec_task)
                exit_code = 0;
-       else if (!thread_group_empty(current)) {
+       else {
                struct sighand_struct *const sighand = current->sighand;
  
                spin_lock_irq(&sighand->siglock);
@@@ -1051,7 -1069,7 +1069,7 @@@ static int wait_task_zombie(struct wait
                 * p->signal fields because the whole thread group is dead
                 * and nobody can change them.
                 *
 -               * psig->stats_lock also protects us from our sub-theads
 +               * psig->stats_lock also protects us from our sub-threads
                 * which can reap other children at the same time. Until
                 * we change k_getrusage()-like users to rely on this lock
                 * we have to take ->siglock as well.
diff --combined kernel/fork.c
index 2b6bd511c6ed1cdff351f63a6f657e912ffe2ac1,67813b25a56720e105fd45a21a74edba4eeab58d..0c53b7e62d0108fa272ac26336a013655bee7d48
@@@ -1225,7 -1225,6 +1225,7 @@@ void mmput_async(struct mm_struct *mm
                schedule_work(&mm->async_put_work);
        }
  }
 +EXPORT_SYMBOL_GPL(mmput_async);
  #endif
  
  /**
@@@ -1693,6 -1692,7 +1693,7 @@@ static int copy_signal(unsigned long cl
                return -ENOMEM;
  
        sig->nr_threads = 1;
+       sig->quick_threads = 1;
        atomic_set(&sig->live, 1);
        refcount_set(&sig->sigcnt, 1);
  
@@@ -1815,7 -1815,6 +1816,7 @@@ static inline void rcu_copy_process(str
        p->trc_reader_nesting = 0;
        p->trc_reader_special.s = 0;
        INIT_LIST_HEAD(&p->trc_holdout_list);
 +      INIT_LIST_HEAD(&p->trc_blkd_node);
  #endif /* #ifdef CONFIG_TASKS_TRACE_RCU */
  }
  
@@@ -1966,18 -1965,6 +1967,18 @@@ static void copy_oom_score_adj(u64 clon
        mutex_unlock(&oom_adj_mutex);
  }
  
 +#ifdef CONFIG_RV
 +static void rv_task_fork(struct task_struct *p)
 +{
 +      int i;
 +
 +      for (i = 0; i < RV_PER_TASK_MONITORS; i++)
 +              p->rv[i].da_mon.monitoring = false;
 +}
 +#else
 +#define rv_task_fork(p) do {} while (0)
 +#endif
 +
  /*
   * This creates a new process as a copy of the old one,
   * but does not actually start it yet.
@@@ -2413,8 -2400,6 +2414,8 @@@ static __latent_entropy struct task_str
         */
        copy_seccomp(p);
  
 +      rv_task_fork(p);
 +
        rseq_fork(p, clone_flags);
  
        /* Don't start children in a dying pid namespace */
                        __this_cpu_inc(process_counts);
                } else {
                        current->signal->nr_threads++;
+                       current->signal->quick_threads++;
                        atomic_inc(&current->signal->live);
                        refcount_inc(&current->signal->sigcnt);
                        task_join_group_stop(p);