root/kernel/signal.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sys_sigprocmask
  2. sys_sgetmask
  3. sys_ssetmask
  4. sys_sigpending
  5. sys_sigsuspend
  6. check_pending
  7. sys_signal
  8. sys_sigaction
  9. sys_sigreturn
  10. setup_frame
  11. do_signal

   1 /*
   2  *  linux/kernel/signal.c
   3  *
   4  *  Copyright (C) 1991, 1992  Linus Torvalds
   5  */
   6 
   7 #include <linux/sched.h>
   8 #include <linux/kernel.h>
   9 #include <linux/signal.h>
  10 #include <linux/errno.h>
  11 #include <linux/wait.h>
  12 #include <linux/ptrace.h>
  13 #include <linux/unistd.h>
  14 
  15 #include <asm/segment.h>
  16 
  17 #define _S(nr) (1<<((nr)-1))
  18 
  19 #define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
  20 
  21 extern int core_dump(long signr,struct pt_regs * regs);
  22 
  23 asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs);
  24 
  25 struct sigcontext_struct {
  26         unsigned short gs, __gsh;
  27         unsigned short fs, __fsh;
  28         unsigned short es, __esh;
  29         unsigned short ds, __dsh;
  30         unsigned long edi;
  31         unsigned long esi;
  32         unsigned long ebp;
  33         unsigned long esp;
  34         unsigned long ebx;
  35         unsigned long edx;
  36         unsigned long ecx;
  37         unsigned long eax;
  38         unsigned long trapno;
  39         unsigned long err;
  40         unsigned long eip;
  41         unsigned short cs, __csh;
  42         unsigned long eflags;
  43         unsigned long esp_at_signal;
  44         unsigned short ss, __ssh;
  45         unsigned long i387;
  46         unsigned long oldmask;
  47         unsigned long cr2;
  48 };
  49 
  50 asmlinkage int sys_sigprocmask(int how, sigset_t *set, sigset_t *oset)
     /* [previous][next][first][last][top][bottom][index][help] */
  51 {
  52         sigset_t new_set, old_set = current->blocked;
  53         int error;
  54 
  55         if (set) {
  56                 error = verify_area(VERIFY_READ, set, sizeof(sigset_t));
  57                 if (error)
  58                         return error;
  59                 new_set = get_fs_long((unsigned long *) set) & _BLOCKABLE;
  60                 switch (how) {
  61                 case SIG_BLOCK:
  62                         current->blocked |= new_set;
  63                         break;
  64                 case SIG_UNBLOCK:
  65                         current->blocked &= ~new_set;
  66                         break;
  67                 case SIG_SETMASK:
  68                         current->blocked = new_set;
  69                         break;
  70                 default:
  71                         return -EINVAL;
  72                 }
  73         }
  74         if (oset) {
  75                 error = verify_area(VERIFY_WRITE, oset, sizeof(sigset_t));
  76                 if (error)
  77                         return error;
  78                 put_fs_long(old_set, (unsigned long *) oset);
  79         }
  80         return 0;
  81 }
  82 
  83 asmlinkage int sys_sgetmask(void)
     /* [previous][next][first][last][top][bottom][index][help] */
  84 {
  85         return current->blocked;
  86 }
  87 
  88 asmlinkage int sys_ssetmask(int newmask)
     /* [previous][next][first][last][top][bottom][index][help] */
  89 {
  90         int old=current->blocked;
  91 
  92         current->blocked = newmask & _BLOCKABLE;
  93         return old;
  94 }
  95 
  96 asmlinkage int sys_sigpending(sigset_t *set)
     /* [previous][next][first][last][top][bottom][index][help] */
  97 {
  98         int error;
  99         /* fill in "set" with signals pending but blocked. */
 100         error = verify_area(VERIFY_WRITE, set, 4);
 101         if (!error)
 102                 put_fs_long(current->blocked & current->signal, (unsigned long *)set);
 103         return error;
 104 }
 105 
 106 /*
 107  * atomically swap in the new signal mask, and wait for a signal.
 108  */
 109 asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, unsigned long set)
     /* [previous][next][first][last][top][bottom][index][help] */
 110 {
 111         unsigned long mask;
 112         struct pt_regs * regs = (struct pt_regs *) &restart;
 113 
 114         mask = current->blocked;
 115         current->blocked = set & _BLOCKABLE;
 116         regs->eax = -EINTR;
 117         while (1) {
 118                 current->state = TASK_INTERRUPTIBLE;
 119                 schedule();
 120                 if (do_signal(mask,regs))
 121                         return -EINTR;
 122         }
 123 }
 124 
 125 /*
 126  * POSIX 3.3.1.3:
 127  *  "Setting a signal action to SIG_IGN for a signal that is pending
 128  *   shall cause the pending signal to be discarded, whether or not
 129  *   it is blocked" (but SIGCHLD is unspecified: linux leaves it alone).
 130  *
 131  *  "Setting a signal action to SIG_DFL for a signal that is pending
 132  *   and whose default action is to ignore the signal (for example,
 133  *   SIGCHLD), shall cause the pending signal to be discarded, whether
 134  *   or not it is blocked"
 135  *
 136  * Note the silly behaviour of SIGCHLD: SIG_IGN means that the signal
 137  * isn't actually ignored, but does automatic child reaping, while
 138  * SIG_DFL is explicitly said by POSIX to force the signal to be ignored..
 139  */
 140 static void check_pending(int signum)
     /* [previous][next][first][last][top][bottom][index][help] */
 141 {
 142         struct sigaction *p;
 143 
 144         p = signum - 1 + current->sigaction;
 145         if (p->sa_handler == SIG_IGN) {
 146                 if (signum == SIGCHLD)
 147                         return;
 148                 current->signal &= ~_S(signum);
 149                 return;
 150         }
 151         if (p->sa_handler == SIG_DFL) {
 152                 if (signum != SIGCONT && signum != SIGCHLD && signum != SIGWINCH)
 153                         return;
 154                 current->signal &= ~_S(signum);
 155                 return;
 156         }       
 157 }
 158 
 159 asmlinkage int sys_signal(int signum, unsigned long handler)
     /* [previous][next][first][last][top][bottom][index][help] */
 160 {
 161         struct sigaction tmp;
 162 
 163         if (signum<1 || signum>32 || signum==SIGKILL || signum==SIGSTOP)
 164                 return -EINVAL;
 165         if (handler >= TASK_SIZE)
 166                 return -EFAULT;
 167         tmp.sa_handler = (void (*)(int)) handler;
 168         tmp.sa_mask = 0;
 169         tmp.sa_flags = SA_ONESHOT | SA_NOMASK;
 170         tmp.sa_restorer = NULL;
 171         handler = (long) current->sigaction[signum-1].sa_handler;
 172         current->sigaction[signum-1] = tmp;
 173         check_pending(signum);
 174         return handler;
 175 }
 176 
 177 asmlinkage int sys_sigaction(int signum, const struct sigaction * action,
     /* [previous][next][first][last][top][bottom][index][help] */
 178         struct sigaction * oldaction)
 179 {
 180         struct sigaction new_sa, *p;
 181 
 182         if (signum<1 || signum>32 || signum==SIGKILL || signum==SIGSTOP)
 183                 return -EINVAL;
 184         p = signum - 1 + current->sigaction;
 185         if (action) {
 186                 int err = verify_area(VERIFY_READ, action, sizeof(*action));
 187                 if (err)
 188                         return err;
 189                 memcpy_fromfs(&new_sa, action, sizeof(struct sigaction));
 190                 if (new_sa.sa_flags & SA_NOMASK)
 191                         new_sa.sa_mask = 0;
 192                 else {
 193                         new_sa.sa_mask |= _S(signum);
 194                         new_sa.sa_mask &= _BLOCKABLE;
 195                 }
 196                 if (TASK_SIZE <= (unsigned long) new_sa.sa_handler)
 197                         return -EFAULT;
 198         }
 199         if (oldaction) {
 200                 int err = verify_area(VERIFY_WRITE, oldaction, sizeof(*oldaction));
 201                 if (err)
 202                         return err;
 203                 memcpy_tofs(oldaction, p, sizeof(struct sigaction));
 204         }
 205         if (action) {
 206                 *p = new_sa;
 207                 check_pending(signum);
 208         }
 209         return 0;
 210 }
 211 
 212 asmlinkage int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options);
 213 
 214 /*
 215  * This sets regs->esp even though we don't actually use sigstacks yet..
 216  */
 217 asmlinkage int sys_sigreturn(unsigned long __unused)
     /* [previous][next][first][last][top][bottom][index][help] */
 218 {
 219 #define COPY(x) regs->x = context.x
 220 #define COPY_SEG(x) \
 221 if ((context.x & 0xfffc) && (context.x & 3) != 3) goto badframe; COPY(x);
 222 #define COPY_SEG_STRICT(x) \
 223 if (!(context.x & 0xfffc) || (context.x & 3) != 3) goto badframe; COPY(x);
 224         struct sigcontext_struct context;
 225         struct pt_regs * regs;
 226 
 227         regs = (struct pt_regs *) &__unused;
 228         if (verify_area(VERIFY_READ, (void *) regs->esp, sizeof(context)))
 229                 goto badframe;
 230         memcpy_fromfs(&context,(void *) regs->esp, sizeof(context));
 231         current->blocked = context.oldmask & _BLOCKABLE;
 232         COPY_SEG(ds);
 233         COPY_SEG(es);
 234         COPY_SEG(fs);
 235         COPY_SEG(gs);
 236         COPY_SEG_STRICT(ss);
 237         COPY_SEG_STRICT(cs);
 238         COPY(eip);
 239         COPY(ecx); COPY(edx);
 240         COPY(ebx);
 241         COPY(esp); COPY(ebp);
 242         COPY(edi); COPY(esi);
 243         regs->eflags &= ~0xCD5;
 244         regs->eflags |= context.eflags & 0xCD5;
 245         regs->orig_eax = -1;            /* disable syscall checks */
 246         return context.eax;
 247 badframe:
 248         do_exit(SIGSEGV);
 249 }
 250 
 251 /*
 252  * Set up a signal frame... Make the stack look the way iBCS2 expects
 253  * it to look.
 254  */
 255 static void setup_frame(struct sigaction * sa, unsigned long ** fp, unsigned long eip,
     /* [previous][next][first][last][top][bottom][index][help] */
 256         struct pt_regs * regs, int signr, unsigned long oldmask)
 257 {
 258         unsigned long * frame;
 259 
 260 #define __CODE ((unsigned long)(frame+24))
 261 #define CODE(x) ((unsigned long *) ((x)+__CODE))
 262         frame = *fp;
 263         if (regs->ss != USER_DS)
 264                 frame = (unsigned long *) sa->sa_restorer;
 265         frame -= 32;
 266         if (verify_area(VERIFY_WRITE,frame,32*4))
 267                 do_exit(SIGSEGV);
 268 /* set up the "normal" stack seen by the signal handler (iBCS2) */
 269         put_fs_long(__CODE,frame);
 270         put_fs_long(signr, frame+1);
 271         put_fs_long(regs->gs, frame+2);
 272         put_fs_long(regs->fs, frame+3);
 273         put_fs_long(regs->es, frame+4);
 274         put_fs_long(regs->ds, frame+5);
 275         put_fs_long(regs->edi, frame+6);
 276         put_fs_long(regs->esi, frame+7);
 277         put_fs_long(regs->ebp, frame+8);
 278         put_fs_long((long)*fp, frame+9);
 279         put_fs_long(regs->ebx, frame+10);
 280         put_fs_long(regs->edx, frame+11);
 281         put_fs_long(regs->ecx, frame+12);
 282         put_fs_long(regs->eax, frame+13);
 283         put_fs_long(current->tss.trap_no, frame+14);
 284         put_fs_long(current->tss.error_code, frame+15);
 285         put_fs_long(eip, frame+16);
 286         put_fs_long(regs->cs, frame+17);
 287         put_fs_long(regs->eflags, frame+18);
 288         put_fs_long(regs->esp, frame+19);
 289         put_fs_long(regs->ss, frame+20);
 290         put_fs_long(0,frame+21);                /* 387 state pointer - not implemented*/
 291 /* non-iBCS2 extensions.. */
 292         put_fs_long(oldmask, frame+22);
 293         put_fs_long(current->tss.cr2, frame+23);
 294 /* set up the return code... */
 295         put_fs_long(0x0000b858, CODE(0));       /* popl %eax ; movl $,%eax */
 296         put_fs_long(0x80cd0000, CODE(4));       /* int $0x80 */
 297         put_fs_long(__NR_sigreturn, CODE(2));
 298         *fp = frame;
 299 #undef __CODE
 300 #undef CODE
 301 }
 302 
 303 /*
 304  * Note that 'init' is a special process: it doesn't get signals it doesn't
 305  * want to handle. Thus you cannot kill init even with a SIGKILL even by
 306  * mistake.
 307  *
 308  * Note that we go through the signals twice: once to check the signals that
 309  * the kernel can handle, and then we build all the user-level signal handling
 310  * stack-frames in one go after that.
 311  */
 312 asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
     /* [previous][next][first][last][top][bottom][index][help] */
 313 {
 314         unsigned long mask = ~current->blocked;
 315         unsigned long handler_signal = 0;
 316         unsigned long *frame = NULL;
 317         unsigned long eip = 0;
 318         unsigned long signr;
 319         struct sigaction * sa;
 320 
 321         while ((signr = current->signal & mask)) {
 322                 __asm__("bsf %2,%1\n\t"
 323                         "btrl %1,%0"
 324                         :"=m" (current->signal),"=r" (signr)
 325                         :"1" (signr));
 326                 sa = current->sigaction + signr;
 327                 signr++;
 328                 if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
 329                         current->exit_code = signr;
 330                         current->state = TASK_STOPPED;
 331                         notify_parent(current);
 332                         schedule();
 333                         if (!(signr = current->exit_code))
 334                                 continue;
 335                         current->exit_code = 0;
 336                         if (signr == SIGSTOP)
 337                                 continue;
 338                         if (_S(signr) & current->blocked) {
 339                                 current->signal |= _S(signr);
 340                                 continue;
 341                         }
 342                         sa = current->sigaction + signr - 1;
 343                 }
 344                 if (sa->sa_handler == SIG_IGN) {
 345                         if (signr != SIGCHLD)
 346                                 continue;
 347                         /* check for SIGCHLD: it's special */
 348                         while (sys_waitpid(-1,NULL,WNOHANG) > 0)
 349                                 /* nothing */;
 350                         continue;
 351                 }
 352                 if (sa->sa_handler == SIG_DFL) {
 353                         if (current->pid == 1)
 354                                 continue;
 355                         switch (signr) {
 356                         case SIGCONT: case SIGCHLD: case SIGWINCH:
 357                                 continue;
 358 
 359                         case SIGSTOP: case SIGTSTP: case SIGTTIN: case SIGTTOU:
 360                                 if (current->flags & PF_PTRACED)
 361                                         continue;
 362                                 current->state = TASK_STOPPED;
 363                                 current->exit_code = signr;
 364                                 if (!(current->p_pptr->sigaction[SIGCHLD-1].sa_flags & 
 365                                                 SA_NOCLDSTOP))
 366                                         notify_parent(current);
 367                                 schedule();
 368                                 continue;
 369 
 370                         case SIGQUIT: case SIGILL: case SIGTRAP:
 371                         case SIGIOT: case SIGFPE: case SIGSEGV:
 372                                 if (core_dump(signr,regs))
 373                                         signr |= 0x80;
 374                                 /* fall through */
 375                         default:
 376                                 current->signal |= _S(signr & 0x7f);
 377                                 do_exit(signr);
 378                         }
 379                 }
 380                 /*
 381                  * OK, we're invoking a handler
 382                  */
 383                 if (regs->orig_eax >= 0) {
 384                         if (regs->eax == -ERESTARTNOHAND ||
 385                            (regs->eax == -ERESTARTSYS && !(sa->sa_flags & SA_RESTART)))
 386                                 regs->eax = -EINTR;
 387                 }
 388                 handler_signal |= 1 << (signr-1);
 389                 mask &= ~sa->sa_mask;
 390         }
 391         if (regs->orig_eax >= 0 &&
 392             (regs->eax == -ERESTARTNOHAND ||
 393              regs->eax == -ERESTARTSYS ||
 394              regs->eax == -ERESTARTNOINTR)) {
 395                 regs->eax = regs->orig_eax;
 396                 regs->eip -= 2;
 397         }
 398         if (!handler_signal)            /* no handler will be called - return 0 */
 399                 return 0;
 400         eip = regs->eip;
 401         frame = (unsigned long *) regs->esp;
 402         signr = 1;
 403         sa = current->sigaction;
 404         for (mask = 1 ; mask ; sa++,signr++,mask += mask) {
 405                 if (mask > handler_signal)
 406                         break;
 407                 if (!(mask & handler_signal))
 408                         continue;
 409                 setup_frame(sa,&frame,eip,regs,signr,oldmask);
 410                 eip = (unsigned long) sa->sa_handler;
 411                 if (sa->sa_flags & SA_ONESHOT)
 412                         sa->sa_handler = NULL;
 413 /* force a supervisor-mode page-in of the signal handler to reduce races */
 414                 __asm__("testb $0,%%fs:%0": :"m" (*(char *) eip));
 415                 regs->cs = USER_CS; regs->ss = USER_DS;
 416                 regs->ds = USER_DS; regs->es = USER_DS;
 417                 regs->gs = USER_DS; regs->fs = USER_DS;
 418                 current->blocked |= sa->sa_mask;
 419                 oldmask |= sa->sa_mask;
 420         }
 421         regs->esp = (unsigned long) frame;
 422         regs->eip = eip;                /* "return" to the first handler */
 423         current->tss.trap_no = current->tss.error_code = 0;
 424         return 1;
 425 }

/* [previous][next][first][last][top][bottom][index][help] */