Print this page
    
OS-3822 OS-3780 creates a life of fd crime in libproc
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/lib/libproc/common/Pidle.c
          +++ new/usr/src/lib/libproc/common/Pidle.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.
  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 2009 Sun Microsystems, Inc.  All rights reserved.
  23   23   * Use is subject to license terms.
  24   24   */
  25   25  /*
  26   26   * Copyright (c) 2013 by Delphix. All rights reserved.
  27   27   */
  28   28  
  29   29  #include <stdlib.h>
  30   30  #include <libelf.h>
  31   31  #include <libgen.h>
  32   32  #include <string.h>
  33   33  #include <strings.h>
  34   34  #include <errno.h>
  35   35  #include <sys/sysmacros.h>
  36   36  
  37   37  #include "libproc.h"
  38   38  #include "Pcontrol.h"
  39   39  
  40   40  /*ARGSUSED*/
  41   41  static ssize_t
  42   42  Pread_idle(struct ps_prochandle *P, void *buf, size_t n, uintptr_t addr,
  43   43      void *data)
  44   44  {
  45   45          size_t resid = n;
  46   46  
  47   47          while (resid > 0) {
  48   48                  map_info_t *mp;
  49   49                  uintptr_t mapoff;
  50   50                  ssize_t len;
  51   51                  off64_t off;
  52   52  
  53   53                  if ((mp = Paddr2mptr(P, addr)) == NULL)
  54   54                          break;
  55   55  
  56   56                  mapoff = addr - mp->map_pmap.pr_vaddr;
  57   57                  len = MIN(resid, mp->map_pmap.pr_size - mapoff);
  58   58                  off = mp->map_offset + mapoff;
  59   59  
  60   60                  if ((len = pread64(P->asfd, buf, len, off)) <= 0)
  61   61                          break;
  62   62  
  63   63                  resid -= len;
  64   64                  addr += len;
  65   65                  buf = (char *)buf + len;
  66   66          }
  67   67  
  68   68          return (n - resid);
  69   69  }
  70   70  
  71   71  /*ARGSUSED*/
  72   72  static ssize_t
  73   73  Pwrite_idle(struct ps_prochandle *P, const void *buf, size_t n, uintptr_t addr,
  74   74      void *data)
  75   75  {
  76   76          errno = EIO;
  77   77          return (-1);
  78   78  }
  79   79  
  80   80  /*ARGSUSED*/
  81   81  static int
  82   82  Ppriv_idle(struct ps_prochandle *P, prpriv_t **pprv, void *data)
  83   83  {
  84   84          prpriv_t *pp;
  85   85  
  86   86          pp = proc_get_priv(P->pid);
  87   87          if (pp == NULL) {
  88   88                  return (-1);
  89   89          }
  90   90  
  91   91          *pprv = pp;
  92   92          return (0);
  93   93  }
  94   94  
  95   95  /* Default operations for the idl ops vector. */
  96   96  static void *
  97   97  Pidle_voidp()
  98   98  {
  99   99          errno = ENODATA;
 100  100          return (NULL);
 101  101  }
 102  102  
 103  103  static int
 104  104  Pidle_int()
 105  105  {
 106  106          errno = ENODATA;
 107  107          return (-1);
 108  108  }
 109  109  
 110  110  static const ps_ops_t P_idle_ops = {
 111  111          .pop_pread      = Pread_idle,
 112  112          .pop_pwrite     = Pwrite_idle,
 113  113          .pop_cred       = (pop_cred_t)Pidle_int,
 114  114          .pop_priv       = Ppriv_idle,
 115  115          .pop_psinfo     = (pop_psinfo_t)Pidle_voidp,
 116  116          .pop_platform   = (pop_platform_t)Pidle_voidp,
 117  117          .pop_uname      = (pop_uname_t)Pidle_int,
 118  118          .pop_zonename   = (pop_zonename_t)Pidle_voidp,
 119  119  #if defined(__i386) || defined(__amd64)
 120  120          .pop_ldt        = (pop_ldt_t)Pidle_int
 121  121  #endif
 122  122  };
 123  123  
 124  124  static int
 125  125  idle_add_mapping(struct ps_prochandle *P, GElf_Phdr *php, file_info_t *fp)
 126  126  {
 127  127          prmap_t pmap;
 128  128  
 129  129          dprintf("mapping base %llx filesz %llu memsz %llu offset %llu\n",
 130  130              (u_longlong_t)php->p_vaddr, (u_longlong_t)php->p_filesz,
 131  131              (u_longlong_t)php->p_memsz, (u_longlong_t)php->p_offset);
 132  132  
 133  133          pmap.pr_vaddr = (uintptr_t)php->p_vaddr;
 134  134          pmap.pr_size = php->p_filesz;
 135  135          (void) strncpy(pmap.pr_mapname, fp->file_pname,
 136  136              sizeof (pmap.pr_mapname));
 137  137          pmap.pr_offset = php->p_offset;
 138  138  
 139  139          pmap.pr_mflags = 0;
 140  140          if (php->p_flags & PF_R)
 141  141                  pmap.pr_mflags |= MA_READ;
 142  142          if (php->p_flags & PF_W)
 143  143                  pmap.pr_mflags |= MA_WRITE;
 144  144          if (php->p_flags & PF_X)
 145  145                  pmap.pr_mflags |= MA_EXEC;
 146  146  
 147  147          pmap.pr_pagesize = 0;
 148  148          pmap.pr_shmid = -1;
 149  149  
 150  150          return (Padd_mapping(P, php->p_offset, fp, &pmap));
 151  151  }
 152  152  
 153  153  struct ps_prochandle *
 154  154  Pgrab_file(const char *fname, int *perr)
 155  155  {
 156  156          struct ps_prochandle *P = NULL;
 157  157          char buf[PATH_MAX];
 158  158          GElf_Ehdr ehdr;
 159  159          Elf *elf = NULL;
 160  160          size_t phnum;
 161  161          file_info_t *fp = NULL;
 162  162          int fd;
 163  163          int i;
 164  164  
 165  165          if ((fd = open64(fname, O_RDONLY)) < 0) {
 166  166                  dprintf("couldn't open file");
 167  167                  *perr = (errno == ENOENT) ? G_NOEXEC : G_STRANGE;
 168  168                  return (NULL);
 169  169          }
 170  170  
 171  171          if (elf_version(EV_CURRENT) == EV_NONE) {
 172  172                  dprintf("libproc ELF version is more recent than libelf");
 173  173                  *perr = G_ELF;
 174  174                  goto err;
 175  175          }
 176  176  
 177  177          if ((P = calloc(1, sizeof (struct ps_prochandle))) == NULL) {
 178  178                  *perr = G_STRANGE;
 179  179                  goto err;
 180  180          }
 181  181  
 182  182          (void) mutex_init(&P->proc_lock, USYNC_THREAD, NULL);
 183  183          P->state = PS_IDLE;
 184  184          P->pid = (pid_t)-1;
 185  185          P->asfd = fd;
 186  186          P->ctlfd = -1;
 187  187          P->statfd = -1;
 188  188          P->agentctlfd = -1;
 189  189          P->agentstatfd = -1;
 190  190          P->info_valid = -1;
 191  191          Pinit_ops(&P->ops, &P_idle_ops);
 192  192          Pinitsym(P);
 193  193  
 194  194          if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
 195  195                  *perr = G_ELF;
 196  196                  return (NULL);
 197  197          }
 198  198  
 199  199          /*
 200  200           * Construct a file_info_t that corresponds to this file.
 201  201           */
 202  202          if ((fp = calloc(1, sizeof (file_info_t))) == NULL) {
 203  203                  *perr = G_STRANGE;
 204  204                  goto err;
 205  205          }
 206  206  
 207  207          if ((fp->file_lo = calloc(1, sizeof (rd_loadobj_t))) == NULL) {
 208  208                  *perr = G_STRANGE;
 209  209                  goto err;
 210  210          }
 211  211  
 212  212          if (*fname == '/') {
 213  213                  (void) strncpy(fp->file_pname, fname, sizeof (fp->file_pname));
 214  214          } else {
 215  215                  size_t sz;
 216  216  
 217  217                  if (getcwd(fp->file_pname, sizeof (fp->file_pname) - 1) ==
 218  218                      NULL) {
  
    | 
      ↓ open down ↓ | 
    218 lines elided | 
    
      ↑ open up ↑ | 
  
 219  219                          *perr = G_STRANGE;
 220  220                          goto err;
 221  221                  }
 222  222  
 223  223                  sz = strlen(fp->file_pname);
 224  224                  (void) snprintf(&fp->file_pname[sz],
 225  225                      sizeof (fp->file_pname) - sz, "/%s", fname);
 226  226          }
 227  227  
 228  228          fp->file_fd = fd;
      229 +        fp->file_dbgfile = -1;
 229  230          fp->file_lo->rl_lmident = LM_ID_BASE;
 230  231          if ((fp->file_lname = strdup(fp->file_pname)) == NULL) {
 231  232                  *perr = G_STRANGE;
 232  233                  goto err;
 233  234          }
 234  235          fp->file_lbase = basename(fp->file_lname);
 235  236  
 236  237          if ((P->execname = strdup(fp->file_pname)) == NULL) {
 237  238                  *perr = G_STRANGE;
 238  239                  goto err;
 239  240          }
 240  241  
 241  242          P->num_files++;
 242  243          list_link(fp, &P->file_head);
 243  244  
 244  245          if (gelf_getehdr(elf, &ehdr) == NULL) {
 245  246                  *perr = G_STRANGE;
 246  247                  goto err;
 247  248          }
 248  249  
 249  250          if (elf_getphdrnum(elf, &phnum) == -1) {
 250  251                  *perr = G_STRANGE;
 251  252                  goto err;
 252  253          }
 253  254  
 254  255          dprintf("Pgrab_file: program header count = %lu\n", (ulong_t)phnum);
 255  256  
 256  257          /*
 257  258           * Sift through the program headers making the relevant maps.
 258  259           */
 259  260          for (i = 0; i < phnum; i++) {
 260  261                  GElf_Phdr phdr, *php;
 261  262  
 262  263                  if ((php = gelf_getphdr(elf, i, &phdr)) == NULL) {
 263  264                          *perr = G_STRANGE;
 264  265                          goto err;
 265  266                  }
 266  267  
 267  268                  if (php->p_type != PT_LOAD)
 268  269                          continue;
 269  270  
 270  271                  if (idle_add_mapping(P, php, fp) != 0) {
 271  272                          *perr = G_STRANGE;
 272  273                          goto err;
 273  274                  }
 274  275          }
 275  276          Psort_mappings(P);
 276  277  
 277  278          (void) elf_end(elf);
 278  279  
 279  280          P->map_exec = fp->file_map;
 280  281  
 281  282          P->status.pr_flags = PR_STOPPED;
 282  283          P->status.pr_nlwp = 0;
 283  284          P->status.pr_pid = (pid_t)-1;
 284  285          P->status.pr_ppid = (pid_t)-1;
 285  286          P->status.pr_pgid = (pid_t)-1;
 286  287          P->status.pr_sid = (pid_t)-1;
 287  288          P->status.pr_taskid = (taskid_t)-1;
 288  289          P->status.pr_projid = (projid_t)-1;
 289  290          P->status.pr_zoneid = (zoneid_t)-1;
 290  291          switch (ehdr.e_ident[EI_CLASS]) {
 291  292          case ELFCLASS32:
 292  293                  P->status.pr_dmodel = PR_MODEL_ILP32;
 293  294                  break;
 294  295          case ELFCLASS64:
 295  296                  P->status.pr_dmodel = PR_MODEL_LP64;
 296  297                  break;
 297  298          default:
 298  299                  *perr = G_FORMAT;
 299  300                  goto err;
 300  301          }
 301  302  
 302  303          /*
 303  304           * Pfindobj() checks what zone a process is associated with, so
 304  305           * we call it after initializing pr_zoneid to -1.  This ensures
 305  306           * we don't get associated with any zone on the system.
 306  307           */
 307  308          if (Pfindobj(P, fp->file_lname, buf, sizeof (buf)) != NULL) {
 308  309                  free(P->execname);
 309  310                  P->execname = strdup(buf);
 310  311                  if ((fp->file_rname = strdup(buf)) != NULL)
 311  312                          fp->file_rbase = basename(fp->file_rname);
 312  313          }
 313  314  
 314  315          /*
 315  316           * The file and map lists are complete, and will never need to be
 316  317           * adjusted.
 317  318           */
 318  319          P->info_valid = 1;
 319  320  
 320  321          return (P);
 321  322  err:
 322  323          (void) close(fd);
 323  324          if (P != NULL)
 324  325                  Pfree(P);
 325  326          if (elf != NULL)
 326  327                  (void) elf_end(elf);
 327  328          return (NULL);
 328  329  }
  
    | 
      ↓ open down ↓ | 
    90 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX