linux/arch/x86/kernel/signal_compat.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2#include <linux/compat.h>
   3#include <linux/uaccess.h>
   4#include <linux/ptrace.h>
   5
   6/*
   7 * The compat_siginfo_t structure and handing code is very easy
   8 * to break in several ways.  It must always be updated when new
   9 * updates are made to the main siginfo_t, and
  10 * copy_siginfo_to_user32() must be updated when the
  11 * (arch-independent) copy_siginfo_to_user() is updated.
  12 *
  13 * It is also easy to put a new member in the compat_siginfo_t
  14 * which has implicit alignment which can move internal structure
  15 * alignment around breaking the ABI.  This can happen if you,
  16 * for instance, put a plain 64-bit value in there.
  17 */
  18static inline void signal_compat_build_tests(void)
  19{
  20        int _sifields_offset = offsetof(compat_siginfo_t, _sifields);
  21
  22        /*
  23         * If adding a new si_code, there is probably new data in
  24         * the siginfo.  Make sure folks bumping the si_code
  25         * limits also have to look at this code.  Make sure any
  26         * new fields are handled in copy_siginfo_to_user32()!
  27         */
  28        BUILD_BUG_ON(NSIGILL  != 8);
  29        BUILD_BUG_ON(NSIGFPE  != 8);
  30        BUILD_BUG_ON(NSIGSEGV != 4);
  31        BUILD_BUG_ON(NSIGBUS  != 5);
  32        BUILD_BUG_ON(NSIGTRAP != 4);
  33        BUILD_BUG_ON(NSIGCHLD != 6);
  34        BUILD_BUG_ON(NSIGSYS  != 1);
  35
  36        /* This is part of the ABI and can never change in size: */
  37        BUILD_BUG_ON(sizeof(compat_siginfo_t) != 128);
  38        /*
  39         * The offsets of all the (unioned) si_fields are fixed
  40         * in the ABI, of course.  Make sure none of them ever
  41         * move and are always at the beginning:
  42         */
  43        BUILD_BUG_ON(offsetof(compat_siginfo_t, _sifields) != 3 * sizeof(int));
  44#define CHECK_CSI_OFFSET(name)    BUILD_BUG_ON(_sifields_offset != offsetof(compat_siginfo_t, _sifields.name))
  45
  46         /*
  47         * Ensure that the size of each si_field never changes.
  48         * If it does, it is a sign that the
  49         * copy_siginfo_to_user32() code below needs to updated
  50         * along with the size in the CHECK_SI_SIZE().
  51         *
  52         * We repeat this check for both the generic and compat
  53         * siginfos.
  54         *
  55         * Note: it is OK for these to grow as long as the whole
  56         * structure stays within the padding size (checked
  57         * above).
  58         */
  59#define CHECK_CSI_SIZE(name, size) BUILD_BUG_ON(size != sizeof(((compat_siginfo_t *)0)->_sifields.name))
  60#define CHECK_SI_SIZE(name, size) BUILD_BUG_ON(size != sizeof(((siginfo_t *)0)->_sifields.name))
  61
  62        CHECK_CSI_OFFSET(_kill);
  63        CHECK_CSI_SIZE  (_kill, 2*sizeof(int));
  64        CHECK_SI_SIZE   (_kill, 2*sizeof(int));
  65
  66        CHECK_CSI_OFFSET(_timer);
  67        CHECK_CSI_SIZE  (_timer, 5*sizeof(int));
  68        CHECK_SI_SIZE   (_timer, 6*sizeof(int));
  69
  70        CHECK_CSI_OFFSET(_rt);
  71        CHECK_CSI_SIZE  (_rt, 3*sizeof(int));
  72        CHECK_SI_SIZE   (_rt, 4*sizeof(int));
  73
  74        CHECK_CSI_OFFSET(_sigchld);
  75        CHECK_CSI_SIZE  (_sigchld, 5*sizeof(int));
  76        CHECK_SI_SIZE   (_sigchld, 8*sizeof(int));
  77
  78        CHECK_CSI_OFFSET(_sigchld_x32);
  79        CHECK_CSI_SIZE  (_sigchld_x32, 7*sizeof(int));
  80        /* no _sigchld_x32 in the generic siginfo_t */
  81
  82        CHECK_CSI_OFFSET(_sigfault);
  83        CHECK_CSI_SIZE  (_sigfault, 4*sizeof(int));
  84        CHECK_SI_SIZE   (_sigfault, 8*sizeof(int));
  85
  86        CHECK_CSI_OFFSET(_sigpoll);
  87        CHECK_CSI_SIZE  (_sigpoll, 2*sizeof(int));
  88        CHECK_SI_SIZE   (_sigpoll, 4*sizeof(int));
  89
  90        CHECK_CSI_OFFSET(_sigsys);
  91        CHECK_CSI_SIZE  (_sigsys, 3*sizeof(int));
  92        CHECK_SI_SIZE   (_sigsys, 4*sizeof(int));
  93
  94        /* any new si_fields should be added here */
  95}
  96
  97void sigaction_compat_abi(struct k_sigaction *act, struct k_sigaction *oact)
  98{
  99        /* Don't leak in-kernel non-uapi flags to user-space */
 100        if (oact)
 101                oact->sa.sa_flags &= ~(SA_IA32_ABI | SA_X32_ABI);
 102
 103        if (!act)
 104                return;
 105
 106        /* Don't let flags to be set from userspace */
 107        act->sa.sa_flags &= ~(SA_IA32_ABI | SA_X32_ABI);
 108
 109        if (in_ia32_syscall())
 110                act->sa.sa_flags |= SA_IA32_ABI;
 111        if (in_x32_syscall())
 112                act->sa.sa_flags |= SA_X32_ABI;
 113}
 114
 115int __copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from,
 116                bool x32_ABI)
 117{
 118        int err = 0;
 119
 120        signal_compat_build_tests();
 121
 122        if (!access_ok(VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
 123                return -EFAULT;
 124
 125        put_user_try {
 126                /* If you change siginfo_t structure, please make sure that
 127                   this code is fixed accordingly.
 128                   It should never copy any pad contained in the structure
 129                   to avoid security leaks, but must copy the generic
 130                   3 ints plus the relevant union member.  */
 131                put_user_ex(from->si_signo, &to->si_signo);
 132                put_user_ex(from->si_errno, &to->si_errno);
 133                put_user_ex(from->si_code, &to->si_code);
 134
 135                if (from->si_code < 0) {
 136                        put_user_ex(from->si_pid, &to->si_pid);
 137                        put_user_ex(from->si_uid, &to->si_uid);
 138                        put_user_ex(ptr_to_compat(from->si_ptr), &to->si_ptr);
 139                } else {
 140                        /*
 141                         * First 32bits of unions are always present:
 142                         * si_pid === si_band === si_tid === si_addr(LS half)
 143                         */
 144                        put_user_ex(from->_sifields._pad[0],
 145                                          &to->_sifields._pad[0]);
 146                        switch (siginfo_layout(from->si_signo, from->si_code)) {
 147                        case SIL_FAULT:
 148                                if (from->si_signo == SIGBUS &&
 149                                    (from->si_code == BUS_MCEERR_AR ||
 150                                     from->si_code == BUS_MCEERR_AO))
 151                                        put_user_ex(from->si_addr_lsb, &to->si_addr_lsb);
 152
 153                                if (from->si_signo == SIGSEGV) {
 154                                        if (from->si_code == SEGV_BNDERR) {
 155                                                compat_uptr_t lower = (unsigned long)from->si_lower;
 156                                                compat_uptr_t upper = (unsigned long)from->si_upper;
 157                                                put_user_ex(lower, &to->si_lower);
 158                                                put_user_ex(upper, &to->si_upper);
 159                                        }
 160                                        if (from->si_code == SEGV_PKUERR)
 161                                                put_user_ex(from->si_pkey, &to->si_pkey);
 162                                }
 163                                break;
 164                        case SIL_SYS:
 165                                put_user_ex(from->si_syscall, &to->si_syscall);
 166                                put_user_ex(from->si_arch, &to->si_arch);
 167                                break;
 168                        case SIL_CHLD:
 169                                if (!x32_ABI) {
 170                                        put_user_ex(from->si_utime, &to->si_utime);
 171                                        put_user_ex(from->si_stime, &to->si_stime);
 172                                } else {
 173                                        put_user_ex(from->si_utime, &to->_sifields._sigchld_x32._utime);
 174                                        put_user_ex(from->si_stime, &to->_sifields._sigchld_x32._stime);
 175                                }
 176                                put_user_ex(from->si_status, &to->si_status);
 177                                /* FALL THROUGH */
 178                        case SIL_KILL:
 179                                put_user_ex(from->si_uid, &to->si_uid);
 180                                break;
 181                        case SIL_POLL:
 182                                put_user_ex(from->si_fd, &to->si_fd);
 183                                break;
 184                        case SIL_TIMER:
 185                                put_user_ex(from->si_overrun, &to->si_overrun);
 186                                put_user_ex(ptr_to_compat(from->si_ptr),
 187                                            &to->si_ptr);
 188                                break;
 189                        case SIL_RT:
 190                                put_user_ex(from->si_uid, &to->si_uid);
 191                                put_user_ex(from->si_int, &to->si_int);
 192                                break;
 193                        }
 194                }
 195        } put_user_catch(err);
 196
 197        return err;
 198}
 199
 200/* from syscall's path, where we know the ABI */
 201int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
 202{
 203        return __copy_siginfo_to_user32(to, from, in_x32_syscall());
 204}
 205
 206int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
 207{
 208        int err = 0;
 209        u32 ptr32;
 210
 211        if (!access_ok(VERIFY_READ, from, sizeof(compat_siginfo_t)))
 212                return -EFAULT;
 213
 214        get_user_try {
 215                get_user_ex(to->si_signo, &from->si_signo);
 216                get_user_ex(to->si_errno, &from->si_errno);
 217                get_user_ex(to->si_code, &from->si_code);
 218
 219                get_user_ex(to->si_pid, &from->si_pid);
 220                get_user_ex(to->si_uid, &from->si_uid);
 221                get_user_ex(ptr32, &from->si_ptr);
 222                to->si_ptr = compat_ptr(ptr32);
 223        } get_user_catch(err);
 224
 225        return err;
 226}
 227