linux/arch/tile/kernel/compat_signal.c
<<
>>
Prefs
   1/*
   2 * Copyright 2010 Tilera Corporation. All Rights Reserved.
   3 *
   4 *   This program is free software; you can redistribute it and/or
   5 *   modify it under the terms of the GNU General Public License
   6 *   as published by the Free Software Foundation, version 2.
   7 *
   8 *   This program is distributed in the hope that it will be useful, but
   9 *   WITHOUT ANY WARRANTY; without even the implied warranty of
  10 *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
  11 *   NON INFRINGEMENT.  See the GNU General Public License for
  12 *   more details.
  13 */
  14
  15#include <linux/sched.h>
  16#include <linux/mm.h>
  17#include <linux/smp.h>
  18#include <linux/kernel.h>
  19#include <linux/signal.h>
  20#include <linux/errno.h>
  21#include <linux/wait.h>
  22#include <linux/unistd.h>
  23#include <linux/stddef.h>
  24#include <linux/personality.h>
  25#include <linux/suspend.h>
  26#include <linux/ptrace.h>
  27#include <linux/elf.h>
  28#include <linux/compat.h>
  29#include <linux/syscalls.h>
  30#include <linux/uaccess.h>
  31#include <asm/processor.h>
  32#include <asm/ucontext.h>
  33#include <asm/sigframe.h>
  34#include <asm/syscalls.h>
  35#include <arch/interrupts.h>
  36
  37struct compat_ucontext {
  38        compat_ulong_t    uc_flags;
  39        compat_uptr_t     uc_link;
  40        struct compat_sigaltstack         uc_stack;
  41        struct sigcontext uc_mcontext;
  42        sigset_t          uc_sigmask;   /* mask last for extensibility */
  43};
  44
  45struct compat_rt_sigframe {
  46        unsigned char save_area[C_ABI_SAVE_AREA_SIZE]; /* caller save area */
  47        struct compat_siginfo info;
  48        struct compat_ucontext uc;
  49};
  50
  51int copy_siginfo_to_user32(struct compat_siginfo __user *to, siginfo_t *from)
  52{
  53        int err;
  54
  55        if (!access_ok(VERIFY_WRITE, to, sizeof(struct compat_siginfo)))
  56                return -EFAULT;
  57
  58        /* If you change siginfo_t structure, please make sure that
  59           this code is fixed accordingly.
  60           It should never copy any pad contained in the structure
  61           to avoid security leaks, but must copy the generic
  62           3 ints plus the relevant union member.  */
  63        err = __put_user(from->si_signo, &to->si_signo);
  64        err |= __put_user(from->si_errno, &to->si_errno);
  65        err |= __put_user((short)from->si_code, &to->si_code);
  66
  67        if (from->si_code < 0) {
  68                err |= __put_user(from->si_pid, &to->si_pid);
  69                err |= __put_user(from->si_uid, &to->si_uid);
  70                err |= __put_user(ptr_to_compat(from->si_ptr), &to->si_ptr);
  71        } else {
  72                /*
  73                 * First 32bits of unions are always present:
  74                 * si_pid === si_band === si_tid === si_addr(LS half)
  75                 */
  76                err |= __put_user(from->_sifields._pad[0],
  77                                  &to->_sifields._pad[0]);
  78                switch (from->si_code >> 16) {
  79                case __SI_FAULT >> 16:
  80                        break;
  81                case __SI_CHLD >> 16:
  82                        err |= __put_user(from->si_utime, &to->si_utime);
  83                        err |= __put_user(from->si_stime, &to->si_stime);
  84                        err |= __put_user(from->si_status, &to->si_status);
  85                        /* FALL THROUGH */
  86                default:
  87                case __SI_KILL >> 16:
  88                        err |= __put_user(from->si_uid, &to->si_uid);
  89                        break;
  90                case __SI_POLL >> 16:
  91                        err |= __put_user(from->si_fd, &to->si_fd);
  92                        break;
  93                case __SI_TIMER >> 16:
  94                        err |= __put_user(from->si_overrun, &to->si_overrun);
  95                        err |= __put_user(ptr_to_compat(from->si_ptr),
  96                                          &to->si_ptr);
  97                        break;
  98                         /* This is not generated by the kernel as of now.  */
  99                case __SI_RT >> 16:
 100                case __SI_MESGQ >> 16:
 101                        err |= __put_user(from->si_uid, &to->si_uid);
 102                        err |= __put_user(from->si_int, &to->si_int);
 103                        break;
 104                }
 105        }
 106        return err;
 107}
 108
 109int copy_siginfo_from_user32(siginfo_t *to, struct compat_siginfo __user *from)
 110{
 111        int err;
 112        u32 ptr32;
 113
 114        if (!access_ok(VERIFY_READ, from, sizeof(struct compat_siginfo)))
 115                return -EFAULT;
 116
 117        err = __get_user(to->si_signo, &from->si_signo);
 118        err |= __get_user(to->si_errno, &from->si_errno);
 119        err |= __get_user(to->si_code, &from->si_code);
 120
 121        err |= __get_user(to->si_pid, &from->si_pid);
 122        err |= __get_user(to->si_uid, &from->si_uid);
 123        err |= __get_user(ptr32, &from->si_ptr);
 124        to->si_ptr = compat_ptr(ptr32);
 125
 126        return err;
 127}
 128
 129/* The assembly shim for this function arranges to ignore the return value. */
 130long compat_sys_rt_sigreturn(void)
 131{
 132        struct pt_regs *regs = current_pt_regs();
 133        struct compat_rt_sigframe __user *frame =
 134                (struct compat_rt_sigframe __user *) compat_ptr(regs->sp);
 135        sigset_t set;
 136
 137        if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
 138                goto badframe;
 139        if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
 140                goto badframe;
 141
 142        set_current_blocked(&set);
 143
 144        if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
 145                goto badframe;
 146
 147        if (compat_restore_altstack(&frame->uc.uc_stack))
 148                goto badframe;
 149
 150        return 0;
 151
 152badframe:
 153        signal_fault("bad sigreturn frame", regs, frame, 0);
 154        return 0;
 155}
 156
 157/*
 158 * Determine which stack to use..
 159 */
 160static inline void __user *compat_get_sigframe(struct k_sigaction *ka,
 161                                               struct pt_regs *regs,
 162                                               size_t frame_size)
 163{
 164        unsigned long sp;
 165
 166        /* Default to using normal stack */
 167        sp = (unsigned long)compat_ptr(regs->sp);
 168
 169        /*
 170         * If we are on the alternate signal stack and would overflow
 171         * it, don't.  Return an always-bogus address instead so we
 172         * will die with SIGSEGV.
 173         */
 174        if (on_sig_stack(sp) && !likely(on_sig_stack(sp - frame_size)))
 175                return (void __user __force *)-1UL;
 176
 177        /* This is the X/Open sanctioned signal stack switching.  */
 178        if (ka->sa.sa_flags & SA_ONSTACK) {
 179                if (sas_ss_flags(sp) == 0)
 180                        sp = current->sas_ss_sp + current->sas_ss_size;
 181        }
 182
 183        sp -= frame_size;
 184        /*
 185         * Align the stack pointer according to the TILE ABI,
 186         * i.e. so that on function entry (sp & 15) == 0.
 187         */
 188        sp &= -16UL;
 189        return (void __user *) sp;
 190}
 191
 192int compat_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
 193                          sigset_t *set, struct pt_regs *regs)
 194{
 195        unsigned long restorer;
 196        struct compat_rt_sigframe __user *frame;
 197        int err = 0;
 198        int usig;
 199
 200        frame = compat_get_sigframe(ka, regs, sizeof(*frame));
 201
 202        if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
 203                goto give_sigsegv;
 204
 205        usig = current_thread_info()->exec_domain
 206                && current_thread_info()->exec_domain->signal_invmap
 207                && sig < 32
 208                ? current_thread_info()->exec_domain->signal_invmap[sig]
 209                : sig;
 210
 211        /* Always write at least the signal number for the stack backtracer. */
 212        if (ka->sa.sa_flags & SA_SIGINFO) {
 213                /* At sigreturn time, restore the callee-save registers too. */
 214                err |= copy_siginfo_to_user32(&frame->info, info);
 215                regs->flags |= PT_FLAGS_RESTORE_REGS;
 216        } else {
 217                err |= __put_user(info->si_signo, &frame->info.si_signo);
 218        }
 219
 220        /* Create the ucontext.  */
 221        err |= __clear_user(&frame->save_area, sizeof(frame->save_area));
 222        err |= __put_user(0, &frame->uc.uc_flags);
 223        err |= __put_user(0, &frame->uc.uc_link);
 224        err |= __compat_save_altstack(&frame->uc.uc_stack, regs->sp);
 225        err |= setup_sigcontext(&frame->uc.uc_mcontext, regs);
 226        err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
 227        if (err)
 228                goto give_sigsegv;
 229
 230        restorer = VDSO_BASE;
 231        if (ka->sa.sa_flags & SA_RESTORER)
 232                restorer = ptr_to_compat_reg(ka->sa.sa_restorer);
 233
 234        /*
 235         * Set up registers for signal handler.
 236         * Registers that we don't modify keep the value they had from
 237         * user-space at the time we took the signal.
 238         * We always pass siginfo and mcontext, regardless of SA_SIGINFO,
 239         * since some things rely on this (e.g. glibc's debug/segfault.c).
 240         */
 241        regs->pc = ptr_to_compat_reg(ka->sa.sa_handler);
 242        regs->ex1 = PL_ICS_EX1(USER_PL, 1); /* set crit sec in handler */
 243        regs->sp = ptr_to_compat_reg(frame);
 244        regs->lr = restorer;
 245        regs->regs[0] = (unsigned long) usig;
 246        regs->regs[1] = ptr_to_compat_reg(&frame->info);
 247        regs->regs[2] = ptr_to_compat_reg(&frame->uc);
 248        regs->flags |= PT_FLAGS_CALLER_SAVES;
 249        return 0;
 250
 251give_sigsegv:
 252        signal_fault("bad setup frame", regs, frame, sig);
 253        return -EFAULT;
 254}
 255