[PATCH v14 4/8] signal: deduplicate code dealing with common _sigfault fields

Peter Collingbourne pcc at google.com
Mon Nov 9 21:37:36 EST 2020


On Mon, Nov 9, 2020 at 4:41 PM Eric W. Biederman <ebiederm at xmission.com> wrote:
>
> Peter Collingbourne <pcc at google.com> writes:
>
> > We're about to add more common _sigfault fields, so deduplicate the
> > existing code for initializing _sigfault fields in {send,force}_sig_*,
> > and for copying _sigfault fields in copy_siginfo_to_external32 and
> > post_copy_siginfo_from_user32, to reduce the number of places that
> > will need to be updated by upcoming changes.
>
> Acked-by: "Eric W. Biederman" <ebiederm at xmission.com>

Thanks for the review.

> No real objection but I am wondering if it might be better to
> introduce two small inline functions for setting common fields
> instead of:
>
> > +     if (siginfo_layout_is_fault(layout)) {
> > +             to->si_addr = ptr_to_compat(from->si_addr);
> > +#ifdef __ARCH_SI_TRAPNO
> > +             to->si_trapno = from->si_trapno;
> > +#endif
> > +     }
>
> and
>
> > +     if (siginfo_layout_is_fault(layout)) {
> > +             to->si_addr = compat_ptr(from->si_addr);
> > +#ifdef __ARCH_SI_TRAPNO
> > +             to->si_trapno = from->si_trapno;
> > +#endif
> > +     }
>
> perhaps called:
> copy_sigfault_common_to_external32
> post_copy_sigfault_common_from_user32
>
> I have not benchmarked or anything but my gut says one less conditional
> branch to worry about makes dealing with spectre easier and probably
> produces faster code as well.  Possibly even smaller code.

Dave made the same proposal on an earlier version of the patch which I
responded to in [1]. The main reason for keeping things as I
implemented them was because of the ptrace handling but if we do end
up dropping that as you proposed on the other patch then I think I'd
be happy to move the code into helper functions.

Peter

[1] https://lore.kernel.org/linux-parisc/CAMn1gO42arQKGBj1Nnbs86TGYyogpRR_t73H=GbTmQrbAbV30A@mail.gmail.com/

>
> Eric
>
> > Signed-off-by: Peter Collingbourne <pcc at google.com>
> > Link: https://linux-review.googlesource.com/id/I4f56174e1b7b2bf4a3c8139e6879cbfd52750a24
> > ---
> >  include/linux/signal.h |  13 ++++++
> >  kernel/signal.c        | 101 ++++++++++++++++-------------------------
> >  2 files changed, 53 insertions(+), 61 deletions(-)
> >
> > diff --git a/include/linux/signal.h b/include/linux/signal.h
> > index b256f9c65661..e9fb05041e7a 100644
> > --- a/include/linux/signal.h
> > +++ b/include/linux/signal.h
> > @@ -50,6 +50,19 @@ enum siginfo_layout {
> >
> >  enum siginfo_layout siginfo_layout(unsigned sig, int si_code);
> >
> > +static inline bool siginfo_layout_is_fault(enum siginfo_layout layout)
> > +{
> > +     switch (layout) {
> > +     case SIL_FAULT:
> > +     case SIL_FAULT_MCEERR:
> > +     case SIL_FAULT_BNDERR:
> > +     case SIL_FAULT_PKUERR:
> > +             return true;
> > +     default:
> > +             return false;
> > +     }
> > +}
> > +
> >  /*
> >   * Define some primitives to manipulate sigset_t.
> >   */
> > diff --git a/kernel/signal.c b/kernel/signal.c
> > index ef8f2a28d37c..74e7315c24db 100644
> > --- a/kernel/signal.c
> > +++ b/kernel/signal.c
> > @@ -1650,6 +1650,15 @@ void force_sigsegv(int sig)
> >       force_sig(SIGSEGV);
> >  }
> >
> > +static void set_sigfault_common_fields(struct kernel_siginfo *info, int sig,
> > +                                    int code, void __user *addr)
> > +{
> > +     info->si_signo = sig;
> > +     info->si_errno = 0;
> > +     info->si_code = code;
> > +     info->si_addr = addr;
> > +}
> > +
> >  int force_sig_fault_to_task(int sig, int code, void __user *addr
> >       ___ARCH_SI_TRAPNO(int trapno)
> >       ___ARCH_SI_IA64(int imm, unsigned int flags, unsigned long isr)
> > @@ -1658,10 +1667,7 @@ int force_sig_fault_to_task(int sig, int code, void __user *addr
> >       struct kernel_siginfo info;
> >
> >       clear_siginfo(&info);
> > -     info.si_signo = sig;
> > -     info.si_errno = 0;
> > -     info.si_code  = code;
> > -     info.si_addr  = addr;
> > +     set_sigfault_common_fields(&info, sig, code, addr);
> >  #ifdef __ARCH_SI_TRAPNO
> >       info.si_trapno = trapno;
> >  #endif
> > @@ -1690,10 +1696,7 @@ int send_sig_fault(int sig, int code, void __user *addr
> >       struct kernel_siginfo info;
> >
> >       clear_siginfo(&info);
> > -     info.si_signo = sig;
> > -     info.si_errno = 0;
> > -     info.si_code  = code;
> > -     info.si_addr  = addr;
> > +     set_sigfault_common_fields(&info, sig, code, addr);
> >  #ifdef __ARCH_SI_TRAPNO
> >       info.si_trapno = trapno;
> >  #endif
> > @@ -1711,10 +1714,7 @@ int force_sig_mceerr(int code, void __user *addr, short lsb)
> >
> >       WARN_ON((code != BUS_MCEERR_AO) && (code != BUS_MCEERR_AR));
> >       clear_siginfo(&info);
> > -     info.si_signo = SIGBUS;
> > -     info.si_errno = 0;
> > -     info.si_code = code;
> > -     info.si_addr = addr;
> > +     set_sigfault_common_fields(&info, SIGBUS, code, addr);
> >       info.si_addr_lsb = lsb;
> >       return force_sig_info(&info);
> >  }
> > @@ -1725,10 +1725,7 @@ int send_sig_mceerr(int code, void __user *addr, short lsb, struct task_struct *
> >
> >       WARN_ON((code != BUS_MCEERR_AO) && (code != BUS_MCEERR_AR));
> >       clear_siginfo(&info);
> > -     info.si_signo = SIGBUS;
> > -     info.si_errno = 0;
> > -     info.si_code = code;
> > -     info.si_addr = addr;
> > +     set_sigfault_common_fields(&info, SIGBUS, code, addr);
> >       info.si_addr_lsb = lsb;
> >       return send_sig_info(info.si_signo, &info, t);
> >  }
> > @@ -1739,10 +1736,7 @@ int force_sig_bnderr(void __user *addr, void __user *lower, void __user *upper)
> >       struct kernel_siginfo info;
> >
> >       clear_siginfo(&info);
> > -     info.si_signo = SIGSEGV;
> > -     info.si_errno = 0;
> > -     info.si_code  = SEGV_BNDERR;
> > -     info.si_addr  = addr;
> > +     set_sigfault_common_fields(&info, SIGSEGV, SEGV_BNDERR, addr);
> >       info.si_lower = lower;
> >       info.si_upper = upper;
> >       return force_sig_info(&info);
> > @@ -1754,10 +1748,7 @@ int force_sig_pkuerr(void __user *addr, u32 pkey)
> >       struct kernel_siginfo info;
> >
> >       clear_siginfo(&info);
> > -     info.si_signo = SIGSEGV;
> > -     info.si_errno = 0;
> > -     info.si_code  = SEGV_PKUERR;
> > -     info.si_addr  = addr;
> > +     set_sigfault_common_fields(&info, SIGSEGV, SEGV_PKUERR, addr);
> >       info.si_pkey  = pkey;
> >       return force_sig_info(&info);
> >  }
> > @@ -1771,10 +1762,8 @@ int force_sig_ptrace_errno_trap(int errno, void __user *addr)
> >       struct kernel_siginfo info;
> >
> >       clear_siginfo(&info);
> > -     info.si_signo = SIGTRAP;
> > +     set_sigfault_common_fields(&info, SIGTRAP, TRAP_HWBKPT, addr);
> >       info.si_errno = errno;
> > -     info.si_code  = TRAP_HWBKPT;
> > -     info.si_addr  = addr;
> >       return force_sig_info(&info);
> >  }
> >
> > @@ -3267,12 +3256,23 @@ int copy_siginfo_from_user(kernel_siginfo_t *to, const siginfo_t __user *from)
> >  void copy_siginfo_to_external32(struct compat_siginfo *to,
> >               const struct kernel_siginfo *from)
> >  {
> > +     enum siginfo_layout layout =
> > +             siginfo_layout(from->si_signo, from->si_code);
> > +
> >       memset(to, 0, sizeof(*to));
> >
> >       to->si_signo = from->si_signo;
> >       to->si_errno = from->si_errno;
> >       to->si_code  = from->si_code;
> > -     switch(siginfo_layout(from->si_signo, from->si_code)) {
> > +
> > +     if (siginfo_layout_is_fault(layout)) {
> > +             to->si_addr = ptr_to_compat(from->si_addr);
> > +#ifdef __ARCH_SI_TRAPNO
> > +             to->si_trapno = from->si_trapno;
> > +#endif
> > +     }
> > +
> > +     switch (layout) {
> >       case SIL_KILL:
> >               to->si_pid = from->si_pid;
> >               to->si_uid = from->si_uid;
> > @@ -3287,31 +3287,15 @@ void copy_siginfo_to_external32(struct compat_siginfo *to,
> >               to->si_fd   = from->si_fd;
> >               break;
> >       case SIL_FAULT:
> > -             to->si_addr = ptr_to_compat(from->si_addr);
> > -#ifdef __ARCH_SI_TRAPNO
> > -             to->si_trapno = from->si_trapno;
> > -#endif
> >               break;
> >       case SIL_FAULT_MCEERR:
> > -             to->si_addr = ptr_to_compat(from->si_addr);
> > -#ifdef __ARCH_SI_TRAPNO
> > -             to->si_trapno = from->si_trapno;
> > -#endif
> >               to->si_addr_lsb = from->si_addr_lsb;
> >               break;
> >       case SIL_FAULT_BNDERR:
> > -             to->si_addr = ptr_to_compat(from->si_addr);
> > -#ifdef __ARCH_SI_TRAPNO
> > -             to->si_trapno = from->si_trapno;
> > -#endif
> >               to->si_lower = ptr_to_compat(from->si_lower);
> >               to->si_upper = ptr_to_compat(from->si_upper);
> >               break;
> >       case SIL_FAULT_PKUERR:
> > -             to->si_addr = ptr_to_compat(from->si_addr);
> > -#ifdef __ARCH_SI_TRAPNO
> > -             to->si_trapno = from->si_trapno;
> > -#endif
> >               to->si_pkey = from->si_pkey;
> >               break;
> >       case SIL_CHLD:
> > @@ -3348,11 +3332,22 @@ int __copy_siginfo_to_user32(struct compat_siginfo __user *to,
> >  static int post_copy_siginfo_from_user32(kernel_siginfo_t *to,
> >                                        const struct compat_siginfo *from)
> >  {
> > +     enum siginfo_layout layout =
> > +             siginfo_layout(from->si_signo, from->si_code);
> > +
> >       clear_siginfo(to);
> >       to->si_signo = from->si_signo;
> >       to->si_errno = from->si_errno;
> >       to->si_code  = from->si_code;
> > -     switch(siginfo_layout(from->si_signo, from->si_code)) {
> > +
> > +     if (siginfo_layout_is_fault(layout)) {
> > +             to->si_addr = compat_ptr(from->si_addr);
> > +#ifdef __ARCH_SI_TRAPNO
> > +             to->si_trapno = from->si_trapno;
> > +#endif
> > +     }
> > +
> > +     switch (layout) {
> >       case SIL_KILL:
> >               to->si_pid = from->si_pid;
> >               to->si_uid = from->si_uid;
> > @@ -3367,31 +3362,15 @@ static int post_copy_siginfo_from_user32(kernel_siginfo_t *to,
> >               to->si_fd   = from->si_fd;
> >               break;
> >       case SIL_FAULT:
> > -             to->si_addr = compat_ptr(from->si_addr);
> > -#ifdef __ARCH_SI_TRAPNO
> > -             to->si_trapno = from->si_trapno;
> > -#endif
> >               break;
> >       case SIL_FAULT_MCEERR:
> > -             to->si_addr = compat_ptr(from->si_addr);
> > -#ifdef __ARCH_SI_TRAPNO
> > -             to->si_trapno = from->si_trapno;
> > -#endif
> >               to->si_addr_lsb = from->si_addr_lsb;
> >               break;
> >       case SIL_FAULT_BNDERR:
> > -             to->si_addr = compat_ptr(from->si_addr);
> > -#ifdef __ARCH_SI_TRAPNO
> > -             to->si_trapno = from->si_trapno;
> > -#endif
> >               to->si_lower = compat_ptr(from->si_lower);
> >               to->si_upper = compat_ptr(from->si_upper);
> >               break;
> >       case SIL_FAULT_PKUERR:
> > -             to->si_addr = compat_ptr(from->si_addr);
> > -#ifdef __ARCH_SI_TRAPNO
> > -             to->si_trapno = from->si_trapno;
> > -#endif
> >               to->si_pkey = from->si_pkey;
> >               break;
> >       case SIL_CHLD:



More information about the linux-arm-kernel mailing list