linux-old/arch/x86_64/ia32/ia32_signal.c
<<
>>
Prefs
   1/*
   2 *  linux/arch/x86_64/ia32/ia32_signal.c
   3 *
   4 *  Copyright (C) 1991, 1992  Linus Torvalds
   5 *
   6 *  1997-11-28  Modified for POSIX.1b signals by Richard Henderson
   7 *  2000-06-20  Pentium III FXSR, SSE support by Gareth Hughes
   8 *  2000-12-*   x86-64 compatibility mode signal handling by Andi Kleen
   9 * 
  10 *  $Id: ia32_signal.c,v 1.32 2003/09/06 18:10:44 ak Exp $
  11 */
  12
  13#include <linux/sched.h>
  14#include <linux/mm.h>
  15#include <linux/smp.h>
  16#include <linux/smp_lock.h>
  17#include <linux/kernel.h>
  18#include <linux/signal.h>
  19#include <linux/errno.h>
  20#include <linux/wait.h>
  21#include <linux/ptrace.h>
  22#include <linux/unistd.h>
  23#include <linux/stddef.h>
  24#include <linux/personality.h>
  25#include <asm/ucontext.h>
  26#include <asm/uaccess.h>
  27#include <asm/i387.h>
  28#include <asm/ia32.h>
  29#include <asm/ptrace.h>
  30#include <asm/ia32_unistd.h>
  31#include <asm/user32.h>
  32#include <asm/sigcontext32.h>
  33#include <asm/fpu32.h>
  34
  35#define ptr_to_u32(x) ((u32)(u64)(x))   /* avoid gcc warning */ 
  36#define u32_to_ptr(x) ((void *)(u64)(x))
  37
  38#define DEBUG_SIG 0
  39
  40#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
  41
  42asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset);
  43void signal_fault(struct pt_regs *regs, void *frame, char *where);
  44
  45static int ia32_copy_siginfo_to_user(siginfo_t32 *to, siginfo_t *from)
  46{
  47        if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t)))
  48                return -EFAULT;
  49        if (from->si_code < 0) { 
  50                /* the only field that's different is the alignment
  51                   of the pointer in sigval_t. Move that 4 bytes down including
  52                   padding. */
  53                memmove(&((siginfo_t32 *)&from)->si_int,
  54                        &from->si_int, 
  55                        sizeof(siginfo_t) - offsetof(siginfo_t, si_int));
  56                /* last 4 bytes stay the same */
  57                return __copy_to_user(to, from, sizeof(siginfo_t32));
  58        } else {
  59                int err;
  60
  61                /* If you change siginfo_t structure, please be sure
  62                   this code is fixed accordingly.
  63                   It should never copy any pad contained in the structure
  64                   to avoid security leaks, but must copy the generic
  65                   3 ints plus the relevant union member.  */
  66                err = __put_user(from->si_signo, &to->si_signo);
  67                err |= __put_user(from->si_errno, &to->si_errno);
  68                err |= __put_user(from->si_code, &to->si_code);
  69                /* First 32bits of unions are always present.  */
  70                err |= __put_user(from->si_pid, &to->si_pid);
  71                switch (from->si_code >> 16) {
  72                case __SI_FAULT >> 16:
  73                        break;
  74                case __SI_CHLD >> 16:
  75                        err |= __put_user(from->si_utime, &to->si_utime);
  76                        err |= __put_user(from->si_stime, &to->si_stime);
  77                        err |= __put_user(from->si_status, &to->si_status);
  78                default:
  79                        err |= __put_user(from->si_uid, &to->si_uid);
  80                        break;
  81                case __SI_POLL >> 16:
  82                        err |= __put_user(from->si_band, &to->si_band); 
  83                        err |= __put_user(from->si_fd, &to->si_fd); 
  84                        break;
  85                /* case __SI_RT: This is not generated by the kernel as of now.  */
  86                }
  87                return err;
  88        }
  89}
  90
  91asmlinkage long
  92sys32_sigsuspend(int history0, int history1, old_sigset_t mask, struct pt_regs regs)
  93{
  94        sigset_t saveset;
  95
  96        mask &= _BLOCKABLE;
  97        spin_lock_irq(&current->sigmask_lock);
  98        saveset = current->blocked;
  99        siginitset(&current->blocked, mask);
 100        recalc_sigpending(current);
 101        spin_unlock_irq(&current->sigmask_lock);
 102
 103        regs.rax = -EINTR;
 104        while (1) {
 105                current->state = TASK_INTERRUPTIBLE;
 106                schedule();
 107                if (do_signal(&regs, &saveset))
 108                        return -EINTR;
 109        }
 110}
 111
 112asmlinkage long
 113sys32_sigaltstack(const stack_ia32_t *uss_ptr, stack_ia32_t *uoss_ptr, 
 114                                  struct pt_regs regs)
 115{
 116        stack_t uss,uoss; 
 117        int ret;
 118        mm_segment_t seg; 
 119        if (uss_ptr) {
 120                u32 val32;
 121                memset(&uss, 0, sizeof(stack_t));
 122        if (!access_ok(VERIFY_READ,uss_ptr,sizeof(stack_ia32_t)) ||
 123                    __get_user(val32, &uss_ptr->ss_sp) ||
 124                    __get_user(uss.ss_flags, &uss_ptr->ss_flags) ||
 125                    __get_user(uss.ss_size, &uss_ptr->ss_size))
 126                return -EFAULT;
 127                uss.ss_sp = u32_to_ptr(val32);  
 128        }
 129        seg = get_fs(); 
 130        set_fs(KERNEL_DS); 
 131        ret = do_sigaltstack(uss_ptr ? &uss : NULL, &uoss, regs.rsp);
 132        set_fs(seg); 
 133        if (ret >= 0 && uoss_ptr)  {
 134                if (!access_ok(VERIFY_WRITE,uoss_ptr,sizeof(stack_ia32_t)) ||
 135                    __put_user(ptr_to_u32(uoss.ss_sp), &uoss_ptr->ss_sp) ||
 136                    __put_user((u32)uoss.ss_flags, &uoss_ptr->ss_flags) ||
 137                    __put_user((u32)uoss.ss_size, &uoss_ptr->ss_size))
 138                        ret = -EFAULT;
 139        }       
 140        return ret;     
 141}
 142
 143/*
 144 * Do a signal return; undo the signal stack.
 145 */
 146
 147struct sigframe
 148{
 149        u32 pretcode;
 150        int sig;
 151        struct sigcontext_ia32 sc;
 152        struct _fpstate_ia32 fpstate;
 153        unsigned int extramask[_IA32_NSIG_WORDS-1];
 154        char retcode[8];
 155};
 156
 157struct rt_sigframe
 158{
 159        u32 pretcode;
 160        int sig;
 161        u32 pinfo;
 162        u32 puc;
 163        struct siginfo32 info;
 164        struct ucontext_ia32 uc;
 165        struct _fpstate_ia32 fpstate;
 166        char retcode[8];
 167};
 168
 169static int
 170ia32_restore_sigcontext(struct pt_regs *regs, struct sigcontext_ia32 *sc, unsigned int *peax)
 171{
 172        unsigned int err = 0;
 173        
 174#if DEBUG_SIG
 175        printk("SIG restore_sigcontext: sc=%p err(%x) eip(%x) cs(%x) flg(%x)\n",
 176                sc, sc->err, sc->eip, sc->cs, sc->eflags);
 177#endif
 178#define COPY(x)         { \
 179        unsigned int reg;       \
 180        err |= __get_user(reg, &sc->e ##x);     \
 181        regs->r ## x = reg;                     \
 182}
 183
 184#define RELOAD_SEG(seg,mask)                                            \
 185        { unsigned int cur;                             \
 186          unsigned short pre;                           \
 187          err |= __get_user(pre, &sc->seg);                             \
 188          asm volatile("movl %%" #seg ",%0" : "=r" (cur));              \
 189          pre |= mask;                                                  \
 190          if (pre != cur) loadsegment(seg,pre); }
 191
 192        /* Reload fs and gs if they have changed in the signal handler.
 193           This does not handle long gs base changes in the handler, but 
 194           does not clobber it at least in the normal case. */ 
 195        
 196        {
 197                unsigned short gs; 
 198                unsigned int curgs;
 199                err |= __get_user(gs, &sc->gs);
 200                asm volatile("movl %%gs,%0" : "=r" (curgs));            
 201                if (gs != curgs) 
 202                        load_gs_index(gs | 3); 
 203        } 
 204        RELOAD_SEG(fs,3);
 205        RELOAD_SEG(ds,3);
 206        RELOAD_SEG(es,3);
 207
 208        COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx);
 209        COPY(dx); COPY(cx); COPY(ip);
 210        /* Don't touch extended registers */ 
 211
 212        err |= __get_user(regs->cs, &sc->cs); 
 213        regs->cs |= 3;  
 214        err |= __get_user(regs->ss, &sc->ss); 
 215        regs->ss |= 3; 
 216        
 217        {
 218                unsigned int tmpflags;
 219                err |= __get_user(tmpflags, &sc->eflags);
 220                regs->eflags = (regs->eflags & ~0x40DD5) | (tmpflags & 0x40DD5);
 221                regs->orig_rax = -1;            /* disable syscall checks */
 222        }
 223
 224        {
 225                u32 tmp;
 226                struct _fpstate_ia32 * buf;
 227                err |= __get_user(tmp, &sc->fpstate);
 228                buf = (struct _fpstate_ia32 *) (u64)tmp;
 229                if (buf) {
 230                        if (verify_area(VERIFY_READ, buf, sizeof(*buf)))
 231                                return 1;
 232                        err |= restore_i387_ia32(current, buf, 0);
 233                }
 234        }
 235
 236        { 
 237                u32 tmp;
 238                err |= __get_user(tmp, &sc->eax);
 239                *peax = tmp;
 240        }
 241        return err;
 242}
 243
 244asmlinkage long sys32_sigreturn(struct pt_regs regs)
 245{
 246        struct sigframe *frame = (struct sigframe *)(regs.rsp - 8);
 247        sigset_t set;
 248        unsigned int eax;
 249
 250        if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
 251                goto badframe;
 252        if (__get_user(set.sig[0], &frame->sc.oldmask)
 253            || (_IA32_NSIG_WORDS > 1
 254                && __copy_from_user((((char *) &set.sig) + 4), &frame->extramask,
 255                                    sizeof(frame->extramask))))
 256                goto badframe;
 257
 258        sigdelsetmask(&set, ~_BLOCKABLE);
 259        spin_lock_irq(&current->sigmask_lock);
 260        current->blocked = set;
 261        recalc_sigpending(current);
 262        spin_unlock_irq(&current->sigmask_lock);
 263        
 264        if (ia32_restore_sigcontext(&regs, &frame->sc, &eax))
 265                goto badframe;
 266        return eax;
 267
 268badframe:
 269        signal_fault(&regs,frame,"32bit sigreturn");
 270        return 0;
 271}       
 272
 273asmlinkage long sys32_rt_sigreturn(struct pt_regs regs)
 274{
 275        struct rt_sigframe *frame = (struct rt_sigframe *)(regs.rsp - 4);
 276        sigset_t set;
 277        stack_t st;
 278        unsigned int eax;
 279
 280        if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
 281                goto badframe;
 282        if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
 283                goto badframe;
 284
 285        sigdelsetmask(&set, ~_BLOCKABLE);
 286        spin_lock_irq(&current->sigmask_lock);
 287        current->blocked = set;
 288        recalc_sigpending(current);
 289        spin_unlock_irq(&current->sigmask_lock);
 290        
 291        if (ia32_restore_sigcontext(&regs, &frame->uc.uc_mcontext, &eax))
 292                goto badframe;
 293
 294        if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st)))
 295                goto badframe;
 296        /* It is more difficult to avoid calling this function than to
 297           call it and ignore errors.  */
 298        {
 299                mm_segment_t oldds = get_fs(); 
 300                set_fs(KERNEL_DS); 
 301                do_sigaltstack(&st, NULL, regs.rsp);
 302                set_fs(oldds);  
 303        }
 304
 305        return eax;
 306
 307badframe:
 308        signal_fault(&regs,frame,"32bit rt sigreturn");
 309        return 0;
 310}       
 311
 312/*
 313 * Set up a signal frame.
 314 */
 315
 316static int
 317ia32_setup_sigcontext(struct sigcontext_ia32 *sc, struct _fpstate_ia32 *fpstate,
 318                 struct pt_regs *regs, unsigned int mask)
 319{
 320        int tmp, err = 0;
 321
 322        tmp = 0;
 323        __asm__("movl %%gs,%0" : "=r"(tmp): "0"(tmp));
 324        err |= __put_user(tmp, (unsigned int *)&sc->gs);
 325        __asm__("movl %%fs,%0" : "=r"(tmp): "0"(tmp));
 326        err |= __put_user(tmp, (unsigned int *)&sc->fs);
 327        __asm__("movl %%ds,%0" : "=r"(tmp): "0"(tmp));
 328        err |= __put_user(tmp, (unsigned int *)&sc->ds);
 329        __asm__("movl %%es,%0" : "=r"(tmp): "0"(tmp));
 330        err |= __put_user(tmp, (unsigned int *)&sc->es);
 331
 332        err |= __put_user((u32)regs->rdi, &sc->edi);
 333        err |= __put_user((u32)regs->rsi, &sc->esi);
 334        err |= __put_user((u32)regs->rbp, &sc->ebp);
 335        err |= __put_user((u32)regs->rsp, &sc->esp);
 336        err |= __put_user((u32)regs->rbx, &sc->ebx);
 337        err |= __put_user((u32)regs->rdx, &sc->edx);
 338        err |= __put_user((u32)regs->rcx, &sc->ecx);
 339        err |= __put_user((u32)regs->rax, &sc->eax);
 340        err |= __put_user((u32)regs->cs, &sc->cs); 
 341        err |= __put_user((u32)regs->ss, &sc->ss); 
 342        err |= __put_user(current->thread.trap_no, &sc->trapno);
 343        err |= __put_user(current->thread.error_code, &sc->err);
 344        err |= __put_user((u32)regs->rip, &sc->eip);
 345        err |= __put_user((u32)regs->eflags, &sc->eflags);
 346        err |= __put_user((u32)regs->rsp, &sc->esp_at_signal);
 347
 348        tmp = save_i387_ia32(current, fpstate, regs, 0);
 349        if (tmp < 0)
 350          err = -EFAULT;
 351        else { 
 352                /* trigger finit in signal handler */
 353                current->used_math = 0;
 354                stts();
 355          err |= __put_user((u32)(u64)(tmp ? fpstate : NULL), &sc->fpstate);
 356        } 
 357
 358        /* non-iBCS2 extensions.. */
 359        err |= __put_user(mask, &sc->oldmask);
 360        err |= __put_user(current->thread.cr2, &sc->cr2);
 361
 362        return err;
 363}
 364
 365/*
 366 * Determine which stack to use..
 367 */
 368static inline void *
 369get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size)
 370{
 371        unsigned long rsp;
 372
 373        /* Default to using normal stack */
 374        rsp = regs->rsp;
 375
 376        /* This is the X/Open sanctioned signal stack switching.  */
 377        if (ka->sa.sa_flags & SA_ONSTACK) {
 378                if (! on_sig_stack(rsp))
 379                        rsp = current->sas_ss_sp + current->sas_ss_size;
 380        }
 381
 382        /* This is the legacy signal stack switching. */
 383        else if ((regs->ss & 0xffff) != __USER_DS &&
 384                !(ka->sa.sa_flags & SA_RESTORER) &&
 385                 ka->sa.sa_restorer) {
 386                rsp = (unsigned long) ka->sa.sa_restorer;
 387        }
 388
 389        return (void *)((rsp - frame_size) & -8UL);
 390}
 391
 392void ia32_setup_frame(int sig, struct k_sigaction *ka,
 393                        sigset32_t *set, struct pt_regs * regs)
 394{
 395        struct sigframe *frame;
 396        int err = 0;
 397
 398        frame = get_sigframe(ka, regs, sizeof(*frame));
 399
 400        if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
 401                goto give_sigsegv;
 402
 403        err |= __put_user((current->exec_domain
 404                           && current->exec_domain->signal_invmap
 405                           && sig < 32
 406                           ? current->exec_domain->signal_invmap[sig]
 407                           : sig),
 408                          &frame->sig);
 409        if (err)
 410                goto give_sigsegv;
 411
 412        err |= ia32_setup_sigcontext(&frame->sc, &frame->fpstate, regs, set->sig[0]);
 413        if (err)
 414                goto give_sigsegv;
 415
 416        if (_IA32_NSIG_WORDS > 1) {
 417                err |= __copy_to_user(frame->extramask, &set->sig[1],
 418                                      sizeof(frame->extramask));
 419        }
 420        if (err)
 421                goto give_sigsegv;
 422
 423        /* Set up to return from userspace.  If provided, use a stub
 424           already in userspace.  */
 425        if (ka->sa.sa_flags & SA_RESTORER) {
 426                err |= __put_user((u32)(u64)ka->sa.sa_restorer, &frame->pretcode);
 427        } else {
 428                err |= __put_user((u32)(u64)frame->retcode, &frame->pretcode);
 429                /* This is popl %eax ; movl $,%eax ; int $0x80 */
 430                err |= __put_user((u16)0xb858, (short *)(frame->retcode+0));
 431                err |= __put_user((u32)__NR_ia32_sigreturn, (int *)(frame->retcode+2));
 432                err |= __put_user((u16)0x80cd, (short *)(frame->retcode+6));
 433        }
 434
 435        if (err)
 436                goto give_sigsegv;
 437
 438        /* Set up registers for signal handler */
 439        regs->rsp = (unsigned long) frame;
 440        regs->rip = (unsigned long) ka->sa.sa_handler;
 441
 442        asm volatile("movl %0,%%ds" :: "r" (__USER32_DS)); 
 443        asm volatile("movl %0,%%es" :: "r" (__USER32_DS)); 
 444
 445        regs->cs = __USER32_CS; 
 446        regs->ss = __USER32_DS; 
 447
 448        set_fs(USER_DS);
 449        regs->eflags &= ~TF_MASK;
 450
 451#if DEBUG_SIG
 452        printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n",
 453                current->comm, current->pid, frame, regs->rip, frame->pretcode);
 454#endif
 455
 456        return;
 457
 458give_sigsegv:
 459        if (sig == SIGSEGV)
 460                ka->sa.sa_handler = SIG_DFL;
 461        signal_fault(regs,frame,"32bit signal deliver");
 462}
 463
 464void ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
 465                           sigset32_t *set, struct pt_regs * regs)
 466{
 467        struct rt_sigframe *frame;
 468        int err = 0;
 469
 470        frame = get_sigframe(ka, regs, sizeof(*frame));
 471
 472        if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
 473                goto give_sigsegv;
 474
 475        err |= __put_user((current->exec_domain
 476                           && current->exec_domain->signal_invmap
 477                           && sig < 32
 478                           ? current->exec_domain->signal_invmap[sig]
 479                           : sig),
 480                          &frame->sig);
 481        err |= __put_user((u32)(u64)&frame->info, &frame->pinfo);
 482        err |= __put_user((u32)(u64)&frame->uc, &frame->puc);
 483        err |= ia32_copy_siginfo_to_user(&frame->info, info);
 484        if (err)
 485                goto give_sigsegv;
 486
 487        /* Create the ucontext.  */
 488        err |= __put_user(0, &frame->uc.uc_flags);
 489        err |= __put_user(0, &frame->uc.uc_link);
 490        err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
 491        err |= __put_user(sas_ss_flags(regs->rsp),
 492                          &frame->uc.uc_stack.ss_flags);
 493        err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
 494        err |= ia32_setup_sigcontext(&frame->uc.uc_mcontext, &frame->fpstate,
 495                                regs, set->sig[0]);
 496        err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
 497        if (err)
 498                goto give_sigsegv;
 499
 500        /* Set up to return from userspace.  If provided, use a stub
 501           already in userspace.  */
 502        if (ka->sa.sa_flags & SA_RESTORER) {
 503                err |= __put_user((u32)(u64)ka->sa.sa_restorer, &frame->pretcode);
 504        } else {
 505                err |= __put_user(ptr_to_u32(frame->retcode), &frame->pretcode);
 506                /* This is movl $,%eax ; int $0x80 */
 507                err |= __put_user(0xb8, (char *)(frame->retcode+0));
 508                err |= __put_user((u32)__NR_ia32_rt_sigreturn, (int *)(frame->retcode+1));
 509                err |= __put_user(0x80cd, (short *)(frame->retcode+5));
 510        }
 511
 512        if (err)
 513                goto give_sigsegv;
 514
 515        /* Set up registers for signal handler */
 516        regs->rsp = (unsigned long) frame;
 517        regs->rip = (unsigned long) ka->sa.sa_handler;
 518
 519        asm volatile("movl %0,%%ds" :: "r" (__USER32_DS)); 
 520        asm volatile("movl %0,%%es" :: "r" (__USER32_DS)); 
 521
 522        regs->cs = __USER32_CS; 
 523        regs->ss = __USER32_DS; 
 524
 525        set_fs(USER_DS);
 526        regs->eflags &= ~TF_MASK;
 527
 528#if DEBUG_SIG
 529        printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n",
 530                current->comm, current->pid, frame, regs->rip, frame->pretcode);
 531#endif
 532
 533        return;
 534
 535give_sigsegv:
 536        if (sig == SIGSEGV)
 537                ka->sa.sa_handler = SIG_DFL;
 538        signal_fault(regs,frame,"32bit rt signal deliver");
 539}
 540
 541
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.