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