Print this page
sync further changes from uts/aslr
7029 want per-process exploit mitigation features (secflags)
7030 want basic address space layout randomization (aslr)
7031 noexec_user_stack should be a secflag
7032 want a means to forbid mappings around NULL.

Split Close
Expand all
Collapse all
          --- old/usr/src/uts/common/exec/elf/elf.c
          +++ new/usr/src/uts/common/exec/elf/elf.c
↓ open down ↓ 34 lines elided ↑ open up ↑
  35   35  #include <sys/sysmacros.h>
  36   36  #include <sys/signal.h>
  37   37  #include <sys/cred.h>
  38   38  #include <sys/user.h>
  39   39  #include <sys/errno.h>
  40   40  #include <sys/vnode.h>
  41   41  #include <sys/mman.h>
  42   42  #include <sys/kmem.h>
  43   43  #include <sys/proc.h>
  44   44  #include <sys/pathname.h>
       45 +#include <sys/policy.h>
  45   46  #include <sys/cmn_err.h>
  46   47  #include <sys/systm.h>
  47   48  #include <sys/elf.h>
  48   49  #include <sys/vmsystm.h>
  49   50  #include <sys/debug.h>
  50   51  #include <sys/auxv.h>
  51   52  #include <sys/exec.h>
  52   53  #include <sys/prsystm.h>
  53   54  #include <vm/as.h>
  54   55  #include <vm/rm.h>
↓ open down ↓ 3 lines elided ↑ open up ↑
  58   59  #include <sys/systeminfo.h>
  59   60  #include <sys/vmparam.h>
  60   61  #include <sys/machelf.h>
  61   62  #include <sys/shm_impl.h>
  62   63  #include <sys/archsystm.h>
  63   64  #include <sys/fasttrap.h>
  64   65  #include <sys/brand.h>
  65   66  #include "elf_impl.h"
  66   67  #include <sys/sdt.h>
  67   68  #include <sys/siginfo.h>
       69 +#include <sys/random.h>
  68   70  
  69   71  extern int at_flags;
       72 +extern volatile size_t aslr_max_brk_skew;
  70   73  
  71   74  #define ORIGIN_STR      "ORIGIN"
  72   75  #define ORIGIN_STR_SIZE 6
  73   76  
  74   77  static int getelfhead(vnode_t *, cred_t *, Ehdr *, int *, int *, int *);
  75   78  static int getelfphdr(vnode_t *, cred_t *, const Ehdr *, int, caddr_t *,
  76   79      ssize_t *);
  77   80  static int getelfshdr(vnode_t *, cred_t *, const Ehdr *, int, int, caddr_t *,
  78   81      ssize_t *, caddr_t *, ssize_t *);
  79   82  static size_t elfsize(Ehdr *, int, caddr_t, uintptr_t *);
↓ open down ↓ 75 lines elided ↑ open up ↑
 155  158           */
 156  159          if (phdrp->p_memsz < PT_SUNWDTRACE_SIZE ||
 157  160              (phdrp->p_flags & (PF_R | PF_W | PF_X)) != (PF_R | PF_W | PF_X))
 158  161                  return (-1);
 159  162  
 160  163          args->thrptr = phdrp->p_vaddr + base;
 161  164  
 162  165          return (0);
 163  166  }
 164  167  
      168 +static int
      169 +handle_secflag_dt(proc_t *p, uint_t dt, uint_t val)
      170 +{
      171 +        uint_t flag;
      172 +
      173 +        switch (dt) {
      174 +        case DT_SUNW_ASLR:
      175 +                flag = PROC_SEC_ASLR;
      176 +                break;
      177 +        default:
      178 +                return (EINVAL);
      179 +        }
      180 +
      181 +        if (val == 0) {
      182 +                if (secflag_isset(p->p_secflags.psf_lower, flag))
      183 +                        return (EPERM);
      184 +                if ((secpolicy_psecflags(CRED(), p, p) != 0) &&
      185 +                    secflag_isset(p->p_secflags.psf_inherit, flag))
      186 +                        return (EPERM);
      187 +
      188 +                secflag_clear(&p->p_secflags.psf_effective, flag);
      189 +        } else {
      190 +                if (!secflag_isset(p->p_secflags.psf_upper, flag))
      191 +                        return (EPERM);
      192 +
      193 +                if ((secpolicy_psecflags(CRED(), p, p) != 0) &&
      194 +                    !secflag_isset(p->p_secflags.psf_inherit, flag))
      195 +                        return (EPERM);
      196 +
      197 +                secflag_set(&p->p_secflags.psf_effective, flag);
      198 +        }
      199 +
      200 +        return (0);
      201 +}
      202 +
 165  203  /*
 166  204   * Map in the executable pointed to by vp. Returns 0 on success.
 167  205   */
 168  206  int
 169  207  mapexec_brand(vnode_t *vp, uarg_t *args, Ehdr *ehdr, Addr *uphdr_vaddr,
 170  208      intptr_t *voffset, caddr_t exec_file, int *interp, caddr_t *bssbase,
 171  209      caddr_t *brkbase, size_t *brksize, uintptr_t *lddatap)
 172  210  {
 173  211          size_t          len;
 174  212          struct vattr    vat;
↓ open down ↓ 73 lines elided ↑ open up ↑
 248  286          caddr_t         phdrbase = NULL;
 249  287          caddr_t         bssbase = 0;
 250  288          caddr_t         brkbase = 0;
 251  289          size_t          brksize = 0;
 252  290          ssize_t         dlnsize;
 253  291          aux_entry_t     *aux;
 254  292          int             error;
 255  293          ssize_t         resid;
 256  294          int             fd = -1;
 257  295          intptr_t        voffset;
 258      -        Phdr            *dyphdr = NULL;
      296 +        Phdr            *intphdr = NULL;
      297 +        Phdr            *dynamicphdr = NULL;
 259  298          Phdr            *stphdr = NULL;
 260  299          Phdr            *uphdr = NULL;
 261  300          Phdr            *junk = NULL;
 262  301          size_t          len;
 263  302          ssize_t         phdrsize;
 264  303          int             postfixsize = 0;
 265  304          int             i, hsize;
 266  305          Phdr            *phdrp;
 267  306          Phdr            *dataphdrp = NULL;
 268  307          Phdr            *dtrphdr;
 269  308          Phdr            *capphdr = NULL;
 270  309          Cap             *cap = NULL;
 271  310          ssize_t         capsize;
      311 +        Dyn             *dyn = NULL;
 272  312          int             hasu = 0;
 273  313          int             hasauxv = 0;
 274      -        int             hasdy = 0;
      314 +        int             hasintp = 0;
 275  315          int             branded = 0;
 276  316  
 277  317          struct proc *p = ttoproc(curthread);
 278  318          struct user *up = PTOU(p);
 279  319          struct bigwad {
 280  320                  Ehdr    ehdr;
 281  321                  aux_entry_t     elfargs[__KERN_NAUXV_IMPL];
 282  322                  char            dl_name[MAXPATHLEN];
 283  323                  char            pathbuf[MAXPATHLEN];
 284  324                  struct vattr    vattr;
↓ open down ↓ 78 lines elided ↑ open up ↑
 363  403           * Determine aux size now so that stack can be built
 364  404           * in one shot (except actual copyout of aux image),
 365  405           * determine any non-default stack protections,
 366  406           * and still have this code be machine independent.
 367  407           */
 368  408          hsize = ehdrp->e_phentsize;
 369  409          phdrp = (Phdr *)phdrbase;
 370  410          for (i = nphdrs; i > 0; i--) {
 371  411                  switch (phdrp->p_type) {
 372  412                  case PT_INTERP:
 373      -                        hasauxv = hasdy = 1;
      413 +                        hasauxv = hasintp = 1;
 374  414                          break;
 375  415                  case PT_PHDR:
 376  416                          hasu = 1;
 377  417                          break;
 378  418                  case PT_SUNWSTACK:
 379  419                          args->stk_prot = PROT_USER;
 380  420                          if (phdrp->p_flags & PF_R)
 381  421                                  args->stk_prot |= PROT_READ;
 382  422                          if (phdrp->p_flags & PF_W)
 383  423                                  args->stk_prot |= PROT_WRITE;
 384  424                          if (phdrp->p_flags & PF_X)
 385  425                                  args->stk_prot |= PROT_EXEC;
 386  426                          break;
 387  427                  case PT_LOAD:
 388  428                          dataphdrp = phdrp;
 389  429                          break;
 390  430                  case PT_SUNWCAP:
 391  431                          capphdr = phdrp;
 392  432                          break;
      433 +                case PT_DYNAMIC:
      434 +                        dynamicphdr = phdrp;
      435 +                        break;
 393  436                  }
 394  437                  phdrp = (Phdr *)((caddr_t)phdrp + hsize);
 395  438          }
 396  439  
 397  440          if (ehdrp->e_type != ET_EXEC) {
 398  441                  dataphdrp = NULL;
 399  442                  hasauxv = 1;
 400  443          }
 401  444  
 402  445          /* Copy BSS permissions to args->dat_prot */
↓ open down ↓ 22 lines elided ↑ open up ↑
 425  468                   *      AT_PAGESZ
 426  469                   *      AT_SUN_AUXFLAGS
 427  470                   *      AT_SUN_HWCAP
 428  471                   *      AT_SUN_HWCAP2
 429  472                   *      AT_SUN_PLATFORM (added in stk_copyout)
 430  473                   *      AT_SUN_EXECNAME (added in stk_copyout)
 431  474                   *      AT_NULL
 432  475                   *
 433  476                   * total == 9
 434  477                   */
 435      -                if (hasdy && hasu) {
      478 +                if (hasintp && hasu) {
 436  479                          /*
 437  480                           * Has PT_INTERP & PT_PHDR - the auxvectors that
 438  481                           * will be built are:
 439  482                           *
 440  483                           *      AT_PHDR
 441  484                           *      AT_PHENT
 442  485                           *      AT_PHNUM
 443  486                           *      AT_ENTRY
 444  487                           *      AT_LDDATA
 445  488                           *
 446  489                           * total = 5
 447  490                           */
 448  491                          args->auxsize = (9 + 5) * sizeof (aux_entry_t);
 449      -                } else if (hasdy) {
      492 +                } else if (hasintp) {
 450  493                          /*
 451  494                           * Has PT_INTERP but no PT_PHDR
 452  495                           *
 453  496                           *      AT_EXECFD
 454  497                           *      AT_LDDATA
 455  498                           *
 456  499                           * total = 2
 457  500                           */
 458  501                          args->auxsize = (9 + 2) * sizeof (aux_entry_t);
 459  502                  } else {
↓ open down ↓ 12 lines elided ↑ open up ↑
 472  515  
 473  516          if ((brand_action != EBA_NATIVE) && (PROC_IS_BRANDED(p))) {
 474  517                  branded = 1;
 475  518                  /*
 476  519                   * We will be adding 4 entries to the aux vectors.  One for
 477  520                   * the the brandname and 3 for the brand specific aux vectors.
 478  521                   */
 479  522                  args->auxsize += 4 * sizeof (aux_entry_t);
 480  523          }
 481  524  
      525 +        /* If the binary has an explicit ASLR flag, it must be honoured */
      526 +        if ((dynamicphdr != NULL) &&
      527 +            (dynamicphdr->p_filesz > 0)) {
      528 +                Dyn *dp;
      529 +                off_t i = 0;
      530 +
      531 +#define DYN_STRIDE      100
      532 +                for (i = 0; i < dynamicphdr->p_filesz;
      533 +                    i += sizeof (*dyn) * DYN_STRIDE) {
      534 +                        int ndyns = (dynamicphdr->p_filesz - i) / sizeof (*dyn);
      535 +                        size_t dynsize;
      536 +
      537 +                        ndyns = MIN(DYN_STRIDE, ndyns);
      538 +                        dynsize = ndyns * sizeof (*dyn);
      539 +
      540 +                        dyn = kmem_alloc(dynsize, KM_SLEEP);
      541 +
      542 +                        if ((error = vn_rdwr(UIO_READ, vp, (caddr_t)dyn,
      543 +                            dynsize, (offset_t)(dynamicphdr->p_offset + i),
      544 +                            UIO_SYSSPACE, 0, (rlim64_t)0,
      545 +                            CRED(), &resid)) != 0) {
      546 +                                uprintf("%s: cannot read .dynamic section\n",
      547 +                                    exec_file);
      548 +                                goto out;
      549 +                        }
      550 +
      551 +                        for (dp = dyn; dp < (dyn + ndyns); dp++) {
      552 +                                if (dp->d_tag == DT_SUNW_ASLR) {
      553 +                                        if ((error = handle_secflag_dt(p,
      554 +                                            DT_SUNW_ASLR,
      555 +                                            dp->d_un.d_val)) != 0) {
      556 +                                                uprintf("%s: error setting "
      557 +                                                    "security-flag from "
      558 +                                                    "DT_SUNW_ASLR: %d\n",
      559 +                                                    exec_file, error);
      560 +                                                goto out;
      561 +                                        }
      562 +                                }
      563 +                        }
      564 +
      565 +                        kmem_free(dyn, dynsize);
      566 +                }
      567 +        }
      568 +
 482  569          /* Hardware/Software capabilities */
 483  570          if (capphdr != NULL &&
 484  571              (capsize = capphdr->p_filesz) > 0 &&
 485  572              capsize <= 16 * sizeof (*cap)) {
 486  573                  int ncaps = capsize / sizeof (*cap);
 487  574                  Cap *cp;
 488  575  
 489  576                  cap = kmem_alloc(capsize, KM_SLEEP);
 490  577                  if ((error = vn_rdwr(UIO_READ, vp, (caddr_t)cap,
 491  578                      capsize, (offset_t)capphdr->p_offset,
↓ open down ↓ 30 lines elided ↑ open up ↑
 522  609           * If this is an ET_DYN executable (shared object),
 523  610           * determine its memory size so that mapelfexec() can load it.
 524  611           */
 525  612          if (ehdrp->e_type == ET_DYN)
 526  613                  len = elfsize(ehdrp, nphdrs, phdrbase, NULL);
 527  614          else
 528  615                  len = 0;
 529  616  
 530  617          dtrphdr = NULL;
 531  618  
 532      -        if ((error = mapelfexec(vp, ehdrp, nphdrs, phdrbase, &uphdr, &dyphdr,
      619 +        if ((error = mapelfexec(vp, ehdrp, nphdrs, phdrbase, &uphdr, &intphdr,
 533  620              &stphdr, &dtrphdr, dataphdrp, &bssbase, &brkbase, &voffset, NULL,
 534  621              len, execsz, &brksize)) != 0)
 535  622                  goto bad;
 536  623  
 537      -        if (uphdr != NULL && dyphdr == NULL)
      624 +        if (uphdr != NULL && intphdr == NULL)
 538  625                  goto bad;
 539  626  
 540  627          if (dtrphdr != NULL && dtrace_safe_phdr(dtrphdr, args, voffset) != 0) {
 541  628                  uprintf("%s: Bad DTrace phdr in %s\n", exec_file, exec_file);
 542  629                  goto bad;
 543  630          }
 544  631  
 545      -        if (dyphdr != NULL) {
      632 +        if (intphdr != NULL) {
 546  633                  size_t          len;
 547  634                  uintptr_t       lddata;
 548  635                  char            *p;
 549  636                  struct vnode    *nvp;
 550  637  
 551      -                dlnsize = dyphdr->p_filesz;
      638 +                dlnsize = intphdr->p_filesz;
 552  639  
 553  640                  if (dlnsize > MAXPATHLEN || dlnsize <= 0)
 554  641                          goto bad;
 555  642  
 556  643                  /*
 557  644                   * Read in "interpreter" pathname.
 558  645                   */
 559      -                if ((error = vn_rdwr(UIO_READ, vp, dlnp, dyphdr->p_filesz,
 560      -                    (offset_t)dyphdr->p_offset, UIO_SYSSPACE, 0, (rlim64_t)0,
      646 +                if ((error = vn_rdwr(UIO_READ, vp, dlnp, intphdr->p_filesz,
      647 +                    (offset_t)intphdr->p_offset, UIO_SYSSPACE, 0, (rlim64_t)0,
 561  648                      CRED(), &resid)) != 0) {
 562  649                          uprintf("%s: Cannot obtain interpreter pathname\n",
 563  650                              exec_file);
 564  651                          goto bad;
 565  652                  }
 566  653  
 567  654                  if (resid != 0 || dlnp[dlnsize - 1] != '\0')
 568  655                          goto bad;
 569  656  
 570  657                  /*
↓ open down ↓ 197 lines elided ↑ open up ↑
 768  855  
 769  856                  /*
 770  857                   * Record the user addr of the auxflags aux vector entry
 771  858                   * since brands may optionally want to manipulate this field.
 772  859                   */
 773  860                  args->auxp_auxflags =
 774  861                      (char *)((char *)args->stackend +
 775  862                      ((char *)&aux->a_type -
 776  863                      (char *)bigwad->elfargs));
 777  864                  ADDAUX(aux, AT_SUN_AUXFLAGS, auxf);
      865 +
 778  866                  /*
 779  867                   * Hardware capability flag word (performance hints)
 780  868                   * Used for choosing faster library routines.
 781  869                   * (Potentially different between 32-bit and 64-bit ABIs)
 782  870                   */
 783  871  #if defined(_LP64)
 784  872                  if (args->to_model == DATAMODEL_NATIVE) {
 785  873                          ADDAUX(aux, AT_SUN_HWCAP, auxv_hwcap)
 786  874                          ADDAUX(aux, AT_SUN_HWCAP2, auxv_hwcap_2)
 787  875                  } else {
↓ open down ↓ 389 lines elided ↑ open up ↑
1177 1265          return (0);
1178 1266  }
1179 1267  
1180 1268  static int
1181 1269  mapelfexec(
1182 1270          vnode_t *vp,
1183 1271          Ehdr *ehdr,
1184 1272          int nphdrs,
1185 1273          caddr_t phdrbase,
1186 1274          Phdr **uphdr,
1187      -        Phdr **dyphdr,
     1275 +        Phdr **intphdr,
1188 1276          Phdr **stphdr,
1189 1277          Phdr **dtphdr,
1190 1278          Phdr *dataphdrp,
1191 1279          caddr_t *bssbase,
1192 1280          caddr_t *brkbase,
1193 1281          intptr_t *voffset,
1194 1282          intptr_t *minaddr,
1195 1283          size_t len,
1196 1284          long *execsz,
1197 1285          size_t *brksize)
↓ open down ↓ 3 lines elided ↑ open up ↑
1201 1289          caddr_t addr = NULL;
1202 1290          size_t zfodsz;
1203 1291          int ptload = 0;
1204 1292          int page;
1205 1293          off_t offset;
1206 1294          int hsize = ehdr->e_phentsize;
1207 1295          caddr_t mintmp = (caddr_t)-1;
1208 1296          extern int use_brk_lpg;
1209 1297  
1210 1298          if (ehdr->e_type == ET_DYN) {
     1299 +                secflagset_t flags = 0;
1211 1300                  /*
1212 1301                   * Obtain the virtual address of a hole in the
1213 1302                   * address space to map the "interpreter".
1214 1303                   */
1215      -                map_addr(&addr, len, (offset_t)0, 1, 0);
     1304 +                if (secflag_enabled(curproc, PROC_SEC_ASLR))
     1305 +                        flags |= _MAP_RANDOMIZE;
     1306 +
     1307 +                map_addr(&addr, len, (offset_t)0, 1, flags);
1216 1308                  if (addr == NULL)
1217 1309                          return (ENOMEM);
1218 1310                  *voffset = (intptr_t)addr;
1219 1311  
1220 1312                  /*
1221 1313                   * Calculate the minimum vaddr so it can be subtracted out.
1222 1314                   * According to the ELF specification, since PT_LOAD sections
1223 1315                   * must be sorted by increasing p_vaddr values, this is
1224 1316                   * guaranteed to be the first PT_LOAD section.
1225 1317                   */
↓ open down ↓ 6 lines elided ↑ open up ↑
1232 1324                          phdr = (Phdr *)((caddr_t)phdr + hsize);
1233 1325                  }
1234 1326  
1235 1327          } else {
1236 1328                  *voffset = 0;
1237 1329          }
1238 1330          phdr = (Phdr *)phdrbase;
1239 1331          for (i = nphdrs; i > 0; i--) {
1240 1332                  switch (phdr->p_type) {
1241 1333                  case PT_LOAD:
1242      -                        if ((*dyphdr != NULL) && (*uphdr == NULL))
     1334 +                        if ((*intphdr != NULL) && (*uphdr == NULL))
1243 1335                                  return (0);
1244 1336  
1245 1337                          ptload = 1;
1246 1338                          prot = PROT_USER;
1247 1339                          if (phdr->p_flags & PF_R)
1248 1340                                  prot |= PROT_READ;
1249 1341                          if (phdr->p_flags & PF_W)
1250 1342                                  prot |= PROT_WRITE;
1251 1343                          if (phdr->p_flags & PF_X)
1252 1344                                  prot |= PROT_EXEC;
↓ open down ↓ 34 lines elided ↑ open up ↑
1287 1379                                              curproc, addr + phdr->p_filesz +
1288 1380                                              tlen, zfodsz - tlen, 0));
1289 1381                                  }
1290 1382                          }
1291 1383  
1292 1384                          if (curproc->p_brkpageszc != 0 && phdr == dataphdrp &&
1293 1385                              (prot & PROT_WRITE)) {
1294 1386                                  uint_t  szc = curproc->p_brkpageszc;
1295 1387                                  size_t pgsz = page_get_pagesize(szc);
1296 1388                                  caddr_t ebss = addr + phdr->p_memsz;
     1389 +                                /*
     1390 +                                 * If we need extra space to keep the BSS an
     1391 +                                 * integral number of pages in size, some of
     1392 +                                 * that space may fall beyond p_brkbase, so we
     1393 +                                 * need to set p_brksize to account for it
     1394 +                                 * being (logically) part of the brk.
     1395 +                                 */
1297 1396                                  size_t extra_zfodsz;
1298 1397  
1299 1398                                  ASSERT(pgsz > PAGESIZE);
1300 1399  
1301 1400                                  extra_zfodsz = P2NPHASE((uintptr_t)ebss, pgsz);
1302 1401  
1303 1402                                  if (error = execmap(vp, addr, phdr->p_filesz,
1304 1403                                      zfodsz + extra_zfodsz, phdr->p_offset,
1305 1404                                      prot, page, szc))
1306 1405                                          goto bad;
↓ open down ↓ 12 lines elided ↑ open up ↑
1319 1418                          if (brkbase != NULL && addr >= *brkbase) {
1320 1419                                  *brkbase = addr + phdr->p_memsz;
1321 1420                          }
1322 1421  
1323 1422                          *execsz += btopr(phdr->p_memsz);
1324 1423                          break;
1325 1424  
1326 1425                  case PT_INTERP:
1327 1426                          if (ptload)
1328 1427                                  goto bad;
1329      -                        *dyphdr = phdr;
     1428 +                        *intphdr = phdr;
1330 1429                          break;
1331 1430  
1332 1431                  case PT_SHLIB:
1333 1432                          *stphdr = phdr;
1334 1433                          break;
1335 1434  
1336 1435                  case PT_PHDR:
1337 1436                          if (ptload)
1338 1437                                  goto bad;
1339 1438                          *uphdr = phdr;
↓ open down ↓ 13 lines elided ↑ open up ↑
1353 1452                          break;
1354 1453                  }
1355 1454                  phdr = (Phdr *)((caddr_t)phdr + hsize);
1356 1455          }
1357 1456  
1358 1457          if (minaddr != NULL) {
1359 1458                  ASSERT(mintmp != (caddr_t)-1);
1360 1459                  *minaddr = (intptr_t)mintmp;
1361 1460          }
1362 1461  
     1462 +        if (brkbase != NULL && secflag_enabled(curproc, PROC_SEC_ASLR)) {
     1463 +                size_t off;
     1464 +                uintptr_t base = (uintptr_t)*brkbase;
     1465 +                uintptr_t oend = base + *brksize;
     1466 +
     1467 +                ASSERT(ISP2(aslr_max_brk_skew));
     1468 +
     1469 +                (void) random_get_pseudo_bytes((uint8_t *)&off, sizeof (off));
     1470 +                base += P2PHASE(off, aslr_max_brk_skew);
     1471 +                base = P2ROUNDUP(base, PAGESIZE);
     1472 +                *brkbase = (caddr_t)base;
     1473 +                /*
     1474 +                 * Above, we set *brksize to account for the possibility we
     1475 +                 * had to grow the 'brk' in padding out the BSS to a page
     1476 +                 * boundary.
     1477 +                 *
     1478 +                 * We now need to adjust that based on where we now are
     1479 +                 * actually putting the brk.
     1480 +                 */
     1481 +                if (oend > base)
     1482 +                        *brksize = oend - base;
     1483 +                else
     1484 +                        *brksize = 0;
     1485 +        }
     1486 +
1363 1487          return (0);
1364 1488  bad:
1365 1489          if (error == 0)
1366 1490                  error = EINVAL;
1367 1491          return (error);
1368 1492  }
1369 1493  
1370 1494  int
1371 1495  elfnote(vnode_t *vp, offset_t *offsetp, int type, int descsz, void *desc,
1372 1496      rlim64_t rlimit, cred_t *credp)
↓ open down ↓ 860 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX