Print this page
    
OS-1804 agent lwp clobbers amd64 abi stack redzone
Reviewed by: Robert Mustacchi <rm@joyent.com>
    
      
        | Split | Close | 
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/lib/libproc/common/Psyscall.c
          +++ new/usr/src/lib/libproc/common/Psyscall.c
   1    1  /*
   2    2   * CDDL HEADER START
   3    3   *
   4    4   * The contents of this file are subject to the terms of the
   5    5   * Common Development and Distribution License (the "License").
   6    6   * You may not use this file except in compliance with the License.
   7    7   *
   8    8   * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9    9   * or http://www.opensolaris.org/os/licensing.
  10   10   * See the License for the specific language governing permissions
  11   11   * and limitations under the License.
  12   12   *
  13   13   * When distributing Covered Code, include this CDDL HEADER in each
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  
    | ↓ open down ↓ | 14 lines elided | ↑ open up ↑ | 
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  /*
  22   22   * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  23   23   * Use is subject to license terms.
  24   24   */
  25      -
  26      -#pragma ident   "%Z%%M% %I%     %E% SMI"
       25 +/*
       26 + * Copyright (c) 2013, Joyent Inc. All rights reserved.
       27 + */
  27   28  
  28   29  #include <stdio.h>
  29   30  #include <stdlib.h>
  30   31  #include <unistd.h>
  31   32  #include <ctype.h>
  32   33  #include <fcntl.h>
  33   34  #include <string.h>
  34   35  #include <memory.h>
  35   36  #include <errno.h>
  36   37  #include <dirent.h>
  37   38  #include <limits.h>
  38   39  #include <signal.h>
  39   40  #include <sys/types.h>
  40   41  #include <sys/uio.h>
  41   42  #include <sys/stat.h>
  42   43  #include <sys/resource.h>
  43   44  #include <sys/param.h>
  44   45  #include <sys/stack.h>
  45   46  #include <sys/fault.h>
  46   47  #include <sys/syscall.h>
  47   48  #include <sys/sysmacros.h>
  48   49  
  49   50  #include "libproc.h"
  50   51  #include "Pcontrol.h"
  51   52  #include "Putil.h"
  52   53  #include "P32ton.h"
  53   54  #include "Pisadep.h"
  54   55  
  55   56  extern sigset_t blockable_sigs;
  56   57  
  57   58  static void
  58   59  Pabort_agent(struct ps_prochandle *P)
  59   60  {
  60   61          int sysnum = P->status.pr_lwp.pr_syscall;
  61   62          int stop;
  62   63  
  63   64          dprintf("agent LWP is asleep in syscall %d\n", sysnum);
  64   65          (void) Pstop(P, 0);
  65   66          stop = Psysexit(P, sysnum, TRUE);
  66   67  
  67   68          if (Psetrun(P, 0, PRSABORT) == 0) {
  68   69                  while (Pwait(P, 0) == -1 && errno == EINTR)
  69   70                          continue;
  70   71                  (void) Psysexit(P, sysnum, stop);
  71   72                  dprintf("agent LWP system call aborted\n");
  72   73          }
  73   74  }
  74   75  
  75   76  /*
  76   77   * Create the /proc agent LWP for further operations.
  77   78   */
  78   79  int
  79   80  Pcreate_agent(struct ps_prochandle *P)
  80   81  {
  81   82          int fd;
  82   83          char pathname[PATH_MAX];
  83   84          char *fname;
  84   85          struct {
  85   86                  long    cmd;
  86   87                  prgregset_t regs;
  87   88          } cmd;
  88   89  
  89   90          /*
  90   91           * If not first reference, we already have the /proc agent LWP active.
  91   92           */
  92   93          if (P->agentcnt > 0) {
  93   94                  P->agentcnt++;
  94   95                  return (0);
  95   96          }
  96   97  
  97   98          /*
  98   99           * The agent is not available for use as a mortician or as an
  99  100           * obstetrician.
 100  101           */
 101  102          if (P->state == PS_DEAD || P->state == PS_UNDEAD ||
 102  103              P->state == PS_IDLE) {
 103  104                  errno = ENOENT;
 104  105                  return (-1);
 105  106          }
 106  107  
 107  108          /*
 108  109           * Create the special /proc agent LWP if it doesn't already exist.
 109  110           * Give it the registers of the representative LWP.
 110  111           */
 111  112          (void) Pstop(P, 0);
 112  113          Psync(P);
 113  114          if (!(P->status.pr_lwp.pr_flags & PR_AGENT)) {
 114  115                  cmd.cmd = PCAGENT;
 115  116                  (void) memcpy(&cmd.regs, &P->status.pr_lwp.pr_reg[0],
 116  117                      sizeof (P->status.pr_lwp.pr_reg));
 117  118                  if (write(P->ctlfd, &cmd, sizeof (cmd)) != sizeof (cmd))
 118  119                          goto bad;
 119  120          }
 120  121  
 121  122          /* refresh the process status */
 122  123          (void) Pstopstatus(P, PCNULL, 0);
 123  124  
 124  125          /* open the agent LWP files */
 125  126          (void) snprintf(pathname, sizeof (pathname), "%s/%d/lwp/agent/",
 126  127              procfs_path, (int)P->pid);
 127  128          fname = pathname + strlen(pathname);
 128  129          (void) set_minfd();
 129  130  
 130  131          /*
 131  132           * It is difficult to know how to recover from the two errors
 132  133           * that follow.  The agent LWP exists and we need to kill it,
 133  134           * but we can't because we need it active in order to kill it.
 134  135           * We just hope that these failures never occur.
 135  136           */
 136  137          (void) strcpy(fname, "lwpstatus");
 137  138          if ((fd = open(pathname, O_RDONLY)) < 0 ||
 138  139              (fd = dupfd(fd, 0)) < 0)
 139  140                  goto bad;
 140  141          P->agentstatfd = fd;
 141  142  
 142  143          (void) strcpy(fname, "lwpctl");
 143  144          if ((fd = open(pathname, O_WRONLY)) < 0 ||
 144  145              (fd = dupfd(fd, 0)) < 0)
 145  146                  goto bad;
 146  147          P->agentctlfd = fd;
 147  148  
 148  149          /*
 149  150           * If the agent is currently asleep in a system call, attempt
 150  151           * to abort the system call so it's ready to serve.
 151  152           */
 152  153          if (P->status.pr_lwp.pr_flags & PR_ASLEEP) {
 153  154                  dprintf("Pcreate_agent: aborting agent syscall\n");
 154  155                  Pabort_agent(P);
 155  156          }
 156  157  
 157  158          /* get the agent LWP status */
 158  159          P->agentcnt++;
 159  160          if (Pstopstatus(P, PCNULL, 0) != 0) {
 160  161                  Pdestroy_agent(P);
 161  162                  return (-1);
 162  163          }
 163  164  
 164  165          return (0);
 165  166  
 166  167  bad:
 167  168          if (P->agentstatfd >= 0)
 168  169                  (void) close(P->agentstatfd);
 169  170          if (P->agentctlfd >= 0)
 170  171                  (void) close(P->agentctlfd);
 171  172          P->agentstatfd = -1;
 172  173          P->agentctlfd = -1;
 173  174          /* refresh the process status */
 174  175          (void) Pstopstatus(P, PCNULL, 0);
 175  176          return (-1);
 176  177  }
 177  178  
 178  179  /*
 179  180   * Decrement the /proc agent agent reference count.
 180  181   * On last reference, destroy the agent.
 181  182   */
 182  183  void
 183  184  Pdestroy_agent(struct ps_prochandle *P)
 184  185  {
 185  186          if (P->agentcnt > 1)
 186  187                  P->agentcnt--;
 187  188          else {
 188  189                  int flags;
 189  190  
 190  191                  Psync(P); /* Flush out any pending changes */
 191  192  
 192  193                  (void) Pstopstatus(P, PCNULL, 0);
 193  194                  flags = P->status.pr_lwp.pr_flags;
 194  195  
 195  196                  /*
 196  197                   * If the agent is currently asleep in a system call, attempt
 197  198                   * to abort the system call so we can terminate the agent.
 198  199                   */
 199  200                  if ((flags & (PR_AGENT|PR_ASLEEP)) == (PR_AGENT|PR_ASLEEP)) {
 200  201                          dprintf("Pdestroy_agent: aborting agent syscall\n");
 201  202                          Pabort_agent(P);
 202  203                  }
 203  204  
 204  205                  /*
 205  206                   * The agent itself is destroyed by forcing it to execute
 206  207                   * the _lwp_exit(2) system call.  Close our agent descriptors
 207  208                   * regardless of whether this is successful.
 208  209                   */
 209  210                  (void) pr_lwp_exit(P);
 210  211                  (void) close(P->agentctlfd);
 211  212                  (void) close(P->agentstatfd);
 212  213                  P->agentctlfd = -1;
 213  214                  P->agentstatfd = -1;
 214  215                  P->agentcnt = 0;
 215  216  
 216  217                  /*
 217  218                   * Now that (hopefully) the agent has exited, refresh the
 218  219                   * status: the representative LWP is no longer the agent.
 219  220                   */
 220  221                  (void) Pstopstatus(P, PCNULL, 0);
 221  222          }
 222  223  }
 223  224  
 224  225  /*
 225  226   * Execute the syscall instruction.
 226  227   */
 227  228  static int
 228  229  execute(struct ps_prochandle *P, int sysindex)
 229  230  {
 230  231          int ctlfd = (P->agentctlfd >= 0)? P->agentctlfd : P->ctlfd;
 231  232          int washeld = FALSE;
 232  233          sigset_t hold;          /* mask of held signals */
 233  234          int cursig;
 234  235          struct {
 235  236                  long cmd;
 236  237                  siginfo_t siginfo;
 237  238          } ctl;
 238  239          int sentry;             /* old value of stop-on-syscall-entry */
 239  240  
 240  241          sentry = Psysentry(P, sysindex, TRUE);  /* set stop-on-syscall-entry */
 241  242  
 242  243          /*
 243  244           * If not already blocked, block all signals now.
 244  245           */
 245  246          if (memcmp(&P->status.pr_lwp.pr_lwphold, &blockable_sigs,
 246  247              sizeof (sigset_t)) != 0) {
 247  248                  hold = P->status.pr_lwp.pr_lwphold;
 248  249                  P->status.pr_lwp.pr_lwphold = blockable_sigs;
 249  250                  P->flags |= SETHOLD;
 250  251                  washeld = TRUE;
 251  252          }
 252  253  
 253  254          /*
 254  255           * If there is a current signal, remember it and cancel it.
 255  256           */
 256  257          if ((cursig = P->status.pr_lwp.pr_cursig) != 0) {
 257  258                  ctl.cmd = PCSSIG;
 258  259                  ctl.siginfo = P->status.pr_lwp.pr_info;
 259  260          }
 260  261  
 261  262          if (Psetrun(P, 0, PRCSIG | PRCFAULT) == -1)
 262  263                  goto bad;
 263  264  
 264  265          while (P->state == PS_RUN) {
 265  266                  (void) Pwait(P, 0);
 266  267          }
 267  268          if (P->state != PS_STOP)
 268  269                  goto bad;
 269  270  
 270  271          if (cursig)                             /* restore cursig */
 271  272                  (void) write(ctlfd, &ctl, sizeof (ctl));
 272  273          if (washeld) {          /* restore the signal mask if we set it */
 273  274                  P->status.pr_lwp.pr_lwphold = hold;
 274  275                  P->flags |= SETHOLD;
 275  276          }
 276  277  
 277  278          (void) Psysentry(P, sysindex, sentry);  /* restore sysentry stop */
 278  279  
 279  280          if (P->status.pr_lwp.pr_why  == PR_SYSENTRY &&
 280  281              P->status.pr_lwp.pr_what == sysindex)
 281  282                  return (0);
 282  283  bad:
 283  284          return (-1);
 284  285  }
 285  286  
 286  287  
 287  288  /*
 288  289   * Perform system call in controlled process.
 289  290   */
 290  291  int
 291  292  Psyscall(struct ps_prochandle *P,
 292  293          sysret_t *rval,         /* syscall return values */
 293  294          int sysindex,           /* system call index */
 294  295          uint_t nargs,           /* number of arguments to system call */
 295  296          argdes_t *argp)         /* argument descriptor array */
 296  297  {
 297  298          int agent_created = FALSE;
 298  299          pstatus_t save_pstatus;
 299  300          argdes_t *adp;                  /* pointer to argument descriptor */
 300  301          int i;                          /* general index value */
 301  302          int model;                      /* data model */
 302  303          int error = 0;                  /* syscall errno */
 303  304          int Perr = 0;                   /* local error number */
 304  305          int sexit;                      /* old value of stop-on-syscall-exit */
 305  306          prgreg_t sp;                    /* adjusted stack pointer */
 306  307          prgreg_t ap;                    /* adjusted argument pointer */
 307  308          sigset_t unblock;
 308  309  
 309  310          (void) sigprocmask(SIG_BLOCK, &blockable_sigs, &unblock);
 310  311  
 311  312          rval->sys_rval1 = 0;            /* initialize return values */
 312  313          rval->sys_rval2 = 0;
 313  314  
 314  315          if (sysindex <= 0 || sysindex > PRMAXSYS || nargs > MAXARGS)
 315  316                  goto bad1;      /* programming error */
 316  317  
 317  318          if (P->state == PS_DEAD || P->state == PS_UNDEAD || P->state == PS_IDLE)
 318  319                  goto bad1;      /* dead processes can't perform system calls */
 319  320  
 320  321          model = P->status.pr_dmodel;
 321  322  #ifndef _LP64
 322  323          /* We must be a 64-bit process to deal with a 64-bit process */
 323  324          if (model == PR_MODEL_LP64)
 324  325                  goto bad9;
 325  326  #endif
 326  327  
 327  328          /*
 328  329           * Create the /proc agent LWP in the process to do all the work.
 329  330           * (It may already exist; nested create/destroy is permitted
 330  331           * by virtue of the reference count.)
 331  332           */
 332  333          if (Pcreate_agent(P) != 0)
 333  334                  goto bad8;
 334  335  
 335  336          /*
 336  337           * Save agent's status to restore on exit.
 337  338           */
 338  339          agent_created = TRUE;
 339  340          save_pstatus = P->status;
 340  341  
 341  342          if (P->state != PS_STOP ||              /* check state of LWP */
 342  343              (P->status.pr_flags & PR_ASLEEP))
 343  344                  goto bad2;
 344  345  
  
    | ↓ open down ↓ | 308 lines elided | ↑ open up ↑ | 
 345  346          if (Pscantext(P))                       /* bad text ? */
 346  347                  goto bad3;
 347  348  
 348  349          /*
 349  350           * Validate arguments and compute the stack frame parameters.
 350  351           * Begin with the current stack pointer.
 351  352           */
 352  353  #ifdef _LP64
 353  354          if (model == PR_MODEL_LP64) {
 354  355                  sp = P->status.pr_lwp.pr_reg[R_SP] + STACK_BIAS;
      356 +#if defined(__amd64)
      357 +                /*
      358 +                 * To offset the expense of computerised subtraction, the AMD64
      359 +                 * ABI allows a process the use of a 128-byte area beyond the
      360 +                 * location pointed to by %rsp.  We must advance the agent's
      361 +                 * stack pointer by at least the size of this region or else it
      362 +                 * may corrupt this temporary storage.
      363 +                 */
      364 +                sp -= STACK_RESERVE64;
      365 +#endif
 355  366                  sp = PSTACK_ALIGN64(sp);
 356  367          } else {
 357  368  #endif
 358  369                  sp = (uint32_t)P->status.pr_lwp.pr_reg[R_SP];
 359  370                  sp = PSTACK_ALIGN32(sp);
 360  371  #ifdef _LP64
 361  372          }
 362  373  #endif
 363  374  
 364  375          /*
 365  376           * For each AT_BYREF argument, compute the necessary
 366  377           * stack space and the object's stack address.
 367  378           */
 368  379          for (i = 0, adp = argp; i < nargs; i++, adp++) {
 369  380                  rval->sys_rval1 = i;            /* in case of error */
 370  381                  switch (adp->arg_type) {
 371  382                  default:                        /* programming error */
 372  383                          goto bad4;
 373  384                  case AT_BYVAL:                  /* simple argument */
 374  385                          break;
 375  386                  case AT_BYREF:                  /* must allocate space */
 376  387                          switch (adp->arg_inout) {
 377  388                          case AI_INPUT:
 378  389                          case AI_OUTPUT:
 379  390                          case AI_INOUT:
 380  391                                  if (adp->arg_object == NULL)
 381  392                                          goto bad5;      /* programming error */
 382  393                                  break;
 383  394                          default:                /* programming error */
 384  395                                  goto bad6;
 385  396                          }
 386  397                          /* allocate stack space for BYREF argument */
 387  398                          if (adp->arg_size == 0 || adp->arg_size > MAXARGL)
 388  399                                  goto bad7;      /* programming error */
 389  400  #ifdef _LP64
 390  401                          if (model == PR_MODEL_LP64)
 391  402                                  sp = PSTACK_ALIGN64(sp - adp->arg_size);
 392  403                          else
 393  404  #endif
 394  405                                  sp = PSTACK_ALIGN32(sp - adp->arg_size);
 395  406                          adp->arg_value = sp;    /* stack address for object */
 396  407                          break;
 397  408                  }
 398  409          }
 399  410          rval->sys_rval1 = 0;                    /* in case of error */
 400  411          /*
 401  412           * Point of no return.
 402  413           * Perform the system call entry, adjusting %sp.
 403  414           * This moves the LWP to the stopped-on-syscall-entry state
 404  415           * just before the arguments to the system call are fetched.
 405  416           */
 406  417          ap = Psyscall_setup(P, nargs, sysindex, sp);
 407  418          P->flags |= SETREGS;    /* set registers before continuing */
 408  419          dprintf("Psyscall(): execute(sysindex = %d)\n", sysindex);
 409  420  
 410  421          /*
 411  422           * Execute the syscall instruction and stop on syscall entry.
 412  423           */
 413  424          if (execute(P, sysindex) != 0 ||
 414  425              (!Pissyscall(P, P->status.pr_lwp.pr_reg[R_PC]) &&
 415  426              !Pissyscall_prev(P, P->status.pr_lwp.pr_reg[R_PC], NULL)))
 416  427                  goto bad10;
 417  428  
 418  429          dprintf("Psyscall(): copying arguments\n");
 419  430  
 420  431          /*
 421  432           * The LWP is stopped at syscall entry.
 422  433           * Copy objects to stack frame for each argument.
 423  434           */
 424  435          for (i = 0, adp = argp; i < nargs; i++, adp++) {
 425  436                  rval->sys_rval1 = i;            /* in case of error */
 426  437                  if (adp->arg_type != AT_BYVAL &&
 427  438                      adp->arg_inout != AI_OUTPUT) {
 428  439                          /* copy input byref parameter to process */
 429  440                          if (Pwrite(P, adp->arg_object, adp->arg_size,
 430  441                              (uintptr_t)adp->arg_value) != adp->arg_size)
 431  442                                  goto bad17;
 432  443                  }
 433  444          }
 434  445          rval->sys_rval1 = 0;                    /* in case of error */
 435  446          if (Psyscall_copyinargs(P, nargs, argp, ap) != 0)
 436  447                  goto bad18;
 437  448  
 438  449          /*
 439  450           * Complete the system call.
 440  451           * This moves the LWP to the stopped-on-syscall-exit state.
 441  452           */
 442  453          dprintf("Psyscall(): set running at sysentry\n");
 443  454  
 444  455          sexit = Psysexit(P, sysindex, TRUE);    /* catch this syscall exit */
 445  456          do {
 446  457                  if (Psetrun(P, 0, 0) == -1)
 447  458                          goto bad21;
 448  459                  while (P->state == PS_RUN)
 449  460                          (void) Pwait(P, 0);
 450  461          } while (P->state == PS_STOP && P->status.pr_lwp.pr_why != PR_SYSEXIT);
 451  462          (void) Psysexit(P, sysindex, sexit);    /* restore original setting */
 452  463  
 453  464          /*
 454  465           * If the system call was _lwp_exit(), we expect that our last call
 455  466           * to Pwait() will yield ENOENT because the LWP no longer exists.
 456  467           */
 457  468          if (sysindex == SYS_lwp_exit && errno == ENOENT) {
 458  469                  dprintf("Psyscall(): _lwp_exit successful\n");
 459  470                  rval->sys_rval1 = rval->sys_rval2 = 0;
 460  471                  goto out;
 461  472          }
 462  473  
 463  474          if (P->state != PS_STOP || P->status.pr_lwp.pr_why != PR_SYSEXIT)
 464  475                  goto bad22;
 465  476  
 466  477          if (P->status.pr_lwp.pr_what != sysindex)
 467  478                  goto bad23;
 468  479  
 469  480          if (!Pissyscall_prev(P, P->status.pr_lwp.pr_reg[R_PC], NULL)) {
 470  481                  dprintf("Pissyscall_prev() failed\n");
 471  482                  goto bad24;
 472  483          }
 473  484  
 474  485          dprintf("Psyscall(): caught at sysexit\n");
 475  486  
 476  487          /*
 477  488           * For each argument.
 478  489           */
 479  490          for (i = 0, adp = argp; i < nargs; i++, adp++) {
 480  491                  rval->sys_rval1 = i;            /* in case of error */
 481  492                  if (adp->arg_type != AT_BYVAL &&
 482  493                      adp->arg_inout != AI_INPUT) {
 483  494                          /* copy output byref parameter from process */
 484  495                          if (Pread(P, adp->arg_object, adp->arg_size,
 485  496                              (uintptr_t)adp->arg_value) != adp->arg_size)
 486  497                                  goto bad25;
 487  498                  }
 488  499          }
 489  500  
 490  501          if (Psyscall_copyoutargs(P, nargs, argp, ap) != 0)
 491  502                  goto bad26;
 492  503  
 493  504          /*
 494  505           * Get the return values from the syscall.
 495  506           */
 496  507          if (P->status.pr_lwp.pr_errno) {        /* error return */
 497  508                  error = P->status.pr_lwp.pr_errno;
 498  509                  rval->sys_rval1 = -1L;
 499  510                  rval->sys_rval2 = -1L;
 500  511                  dprintf("Psyscall(%d) fails with errno %d\n",
 501  512                      sysindex, error);
 502  513          } else {                                /* normal return */
 503  514                  rval->sys_rval1 = P->status.pr_lwp.pr_rval1;
 504  515                  rval->sys_rval2 = P->status.pr_lwp.pr_rval2;
 505  516                  dprintf("Psyscall(%d) returns 0x%lx 0x%lx\n", sysindex,
 506  517                      P->status.pr_lwp.pr_rval1, P->status.pr_lwp.pr_rval2);
 507  518          }
 508  519  
 509  520          goto out;
 510  521  
 511  522  bad26:  Perr++;
 512  523  bad25:  Perr++;
 513  524  bad24:  Perr++;
 514  525  bad23:  Perr++;
 515  526  bad22:  Perr++;
 516  527  bad21:  Perr++;
 517  528          Perr++;
 518  529          Perr++;
 519  530  bad18:  Perr++;
 520  531  bad17:  Perr++;
 521  532          Perr++;
 522  533          Perr++;
 523  534          Perr++;
 524  535          Perr++;
 525  536          Perr++;
 526  537          Perr++;
 527  538  bad10:  Perr++;
 528  539  bad9:   Perr++;
 529  540  bad8:   Perr++;
 530  541  bad7:   Perr++;
 531  542  bad6:   Perr++;
 532  543  bad5:   Perr++;
 533  544  bad4:   Perr++;
 534  545  bad3:   Perr++;
 535  546  bad2:   Perr++;
 536  547  bad1:   Perr++;
 537  548          error = -1;
 538  549          dprintf("Psyscall(%d) fails with local error %d\n", sysindex, Perr);
 539  550  
 540  551  out:
 541  552          /*
 542  553           * Destroy the /proc agent LWP now (or just bump down the ref count).
 543  554           */
 544  555          if (agent_created) {
 545  556                  if (P->state != PS_UNDEAD) {
 546  557                          P->status = save_pstatus;
 547  558                          P->flags |= SETREGS;
 548  559                          Psync(P);
 549  560                  }
 550  561                  Pdestroy_agent(P);
 551  562          }
 552  563  
 553  564          (void) sigprocmask(SIG_SETMASK, &unblock, NULL);
 554  565          return (error);
 555  566  }
  
    | ↓ open down ↓ | 191 lines elided | ↑ open up ↑ | 
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX