Print this page
uts: Allow for address space randomisation.
Randomise the base addresses of shared objects, non-fixed mappings, the
stack and the heap.  Introduce a service, svc:/system/process-security,
and a tool psecflags(1) to control and observe it


  48 #include <sys/vmsystm.h>
  49 #include <sys/debug.h>
  50 #include <sys/auxv.h>
  51 #include <sys/exec.h>
  52 #include <sys/prsystm.h>
  53 #include <vm/as.h>
  54 #include <vm/rm.h>
  55 #include <vm/seg.h>
  56 #include <vm/seg_vn.h>
  57 #include <sys/modctl.h>
  58 #include <sys/systeminfo.h>
  59 #include <sys/vmparam.h>
  60 #include <sys/machelf.h>
  61 #include <sys/shm_impl.h>
  62 #include <sys/archsystm.h>
  63 #include <sys/fasttrap.h>
  64 #include <sys/brand.h>
  65 #include "elf_impl.h"
  66 #include <sys/sdt.h>
  67 #include <sys/siginfo.h>

  68 
  69 extern int at_flags;

  70 
  71 #define ORIGIN_STR      "ORIGIN"
  72 #define ORIGIN_STR_SIZE 6
  73 
  74 static int getelfhead(vnode_t *, cred_t *, Ehdr *, int *, int *, int *);
  75 static int getelfphdr(vnode_t *, cred_t *, const Ehdr *, int, caddr_t *,
  76     ssize_t *);
  77 static int getelfshdr(vnode_t *, cred_t *, const Ehdr *, int, int, caddr_t *,
  78     ssize_t *, caddr_t *, ssize_t *);
  79 static size_t elfsize(Ehdr *, int, caddr_t, uintptr_t *);
  80 static int mapelfexec(vnode_t *, Ehdr *, int, caddr_t,
  81     Phdr **, Phdr **, Phdr **, Phdr **, Phdr *,
  82     caddr_t *, caddr_t *, intptr_t *, intptr_t *, size_t, long *, size_t *);
  83 
  84 typedef enum {
  85         STR_CTF,
  86         STR_SYMTAB,
  87         STR_DYNSYM,
  88         STR_STRTAB,
  89         STR_DYNSTR,


 238         kmem_free(phdrbase, phdrsize);
 239         return (error);
 240 }
 241 
 242 /*ARGSUSED*/
 243 int
 244 elfexec(vnode_t *vp, execa_t *uap, uarg_t *args, intpdata_t *idatap,
 245     int level, long *execsz, int setid, caddr_t exec_file, cred_t *cred,
 246     int brand_action)
 247 {
 248         caddr_t         phdrbase = NULL;
 249         caddr_t         bssbase = 0;
 250         caddr_t         brkbase = 0;
 251         size_t          brksize = 0;
 252         ssize_t         dlnsize;
 253         aux_entry_t     *aux;
 254         int             error;
 255         ssize_t         resid;
 256         int             fd = -1;
 257         intptr_t        voffset;
 258         Phdr            *dyphdr = NULL;

 259         Phdr            *stphdr = NULL;
 260         Phdr            *uphdr = NULL;
 261         Phdr            *junk = NULL;
 262         size_t          len;
 263         ssize_t         phdrsize;
 264         int             postfixsize = 0;
 265         int             i, hsize;
 266         Phdr            *phdrp;
 267         Phdr            *dataphdrp = NULL;
 268         Phdr            *dtrphdr;
 269         Phdr            *capphdr = NULL;
 270         Cap             *cap = NULL;
 271         ssize_t         capsize;


 272         int             hasu = 0;
 273         int             hasauxv = 0;
 274         int             hasdy = 0;
 275         int             branded = 0;
 276 
 277         struct proc *p = ttoproc(curthread);
 278         struct user *up = PTOU(p);
 279         struct bigwad {
 280                 Ehdr    ehdr;
 281                 aux_entry_t     elfargs[__KERN_NAUXV_IMPL];
 282                 char            dl_name[MAXPATHLEN];
 283                 char            pathbuf[MAXPATHLEN];
 284                 struct vattr    vattr;
 285                 struct execenv  exenv;
 286         } *bigwad;      /* kmem_alloc this behemoth so we don't blow stack */
 287         Ehdr            *ehdrp;
 288         int             nshdrs, shstrndx, nphdrs;
 289         char            *dlnp;
 290         char            *pathbufp;
 291         rlim64_t        limit;
 292         rlim64_t        roundlimit;
 293 
 294         ASSERT(p->p_model == DATAMODEL_ILP32 || p->p_model == DATAMODEL_LP64);


 347          */
 348         if ((level < 2) &&
 349             (brand_action != EBA_NATIVE) && (PROC_IS_BRANDED(p))) {
 350                 error = BROP(p)->b_elfexec(vp, uap, args,
 351                     idatap, level + 1, execsz, setid, exec_file, cred,
 352                     brand_action);
 353                 goto out;
 354         }
 355 
 356         /*
 357          * Determine aux size now so that stack can be built
 358          * in one shot (except actual copyout of aux image),
 359          * determine any non-default stack protections,
 360          * and still have this code be machine independent.
 361          */
 362         hsize = ehdrp->e_phentsize;
 363         phdrp = (Phdr *)phdrbase;
 364         for (i = nphdrs; i > 0; i--) {
 365                 switch (phdrp->p_type) {
 366                 case PT_INTERP:
 367                         hasauxv = hasdy = 1;
 368                         break;
 369                 case PT_PHDR:
 370                         hasu = 1;
 371                         break;
 372                 case PT_SUNWSTACK:
 373                         args->stk_prot = PROT_USER;
 374                         if (phdrp->p_flags & PF_R)
 375                                 args->stk_prot |= PROT_READ;
 376                         if (phdrp->p_flags & PF_W)
 377                                 args->stk_prot |= PROT_WRITE;
 378                         if (phdrp->p_flags & PF_X)
 379                                 args->stk_prot |= PROT_EXEC;
 380                         break;
 381                 case PT_LOAD:
 382                         dataphdrp = phdrp;
 383                         break;
 384                 case PT_SUNWCAP:
 385                         capphdr = phdrp;
 386                         break;



 387                 }
 388                 phdrp = (Phdr *)((caddr_t)phdrp + hsize);
 389         }
 390 
 391         if (ehdrp->e_type != ET_EXEC) {
 392                 dataphdrp = NULL;
 393                 hasauxv = 1;
 394         }
 395 
 396         /* Copy BSS permissions to args->dat_prot */
 397         if (dataphdrp != NULL) {
 398                 args->dat_prot = PROT_USER;
 399                 if (dataphdrp->p_flags & PF_R)
 400                         args->dat_prot |= PROT_READ;
 401                 if (dataphdrp->p_flags & PF_W)
 402                         args->dat_prot |= PROT_WRITE;
 403                 if (dataphdrp->p_flags & PF_X)
 404                         args->dat_prot |= PROT_EXEC;
 405         }
 406 
 407         /*
 408          * If a auxvector will be required - reserve the space for
 409          * it now.  This may be increased by exec_args if there are
 410          * ISA-specific types (included in __KERN_NAUXV_IMPL).
 411          */
 412         if (hasauxv) {
 413                 /*
 414                  * If a AUX vector is being built - the base AUX
 415                  * entries are:
 416                  *
 417                  *      AT_BASE
 418                  *      AT_FLAGS
 419                  *      AT_PAGESZ
 420                  *      AT_SUN_AUXFLAGS
 421                  *      AT_SUN_HWCAP
 422                  *      AT_SUN_HWCAP2

 423                  *      AT_SUN_PLATFORM (added in stk_copyout)
 424                  *      AT_SUN_EXECNAME (added in stk_copyout)
 425                  *      AT_NULL
 426                  *
 427                  * total == 9
 428                  */
 429                 if (hasdy && hasu) {
 430                         /*
 431                          * Has PT_INTERP & PT_PHDR - the auxvectors that
 432                          * will be built are:
 433                          *
 434                          *      AT_PHDR
 435                          *      AT_PHENT
 436                          *      AT_PHNUM
 437                          *      AT_ENTRY
 438                          *      AT_LDDATA
 439                          *
 440                          * total = 5
 441                          */
 442                         args->auxsize = (9 + 5) * sizeof (aux_entry_t);
 443                 } else if (hasdy) {
 444                         /*
 445                          * Has PT_INTERP but no PT_PHDR
 446                          *
 447                          *      AT_EXECFD
 448                          *      AT_LDDATA
 449                          *
 450                          * total = 2
 451                          */
 452                         args->auxsize = (9 + 2) * sizeof (aux_entry_t);
 453                 } else {
 454                         args->auxsize = 9 * sizeof (aux_entry_t);
 455                 }
 456         } else {
 457                 args->auxsize = 0;
 458         }
 459 
 460         /*
 461          * If this binary is using an emulator, we need to add an
 462          * AT_SUN_EMULATOR aux entry.
 463          */
 464         if (args->emulator != NULL)
 465                 args->auxsize += sizeof (aux_entry_t);
 466 
 467         if ((brand_action != EBA_NATIVE) && (PROC_IS_BRANDED(p))) {
 468                 branded = 1;
 469                 /*
 470                  * We will be adding 4 entries to the aux vectors.  One for
 471                  * the the brandname and 3 for the brand specific aux vectors.
 472                  */
 473                 args->auxsize += 4 * sizeof (aux_entry_t);
 474         }
 475 






































 476         /* Hardware/Software capabilities */
 477         if (capphdr != NULL &&
 478             (capsize = capphdr->p_filesz) > 0 &&
 479             capsize <= 16 * sizeof (*cap)) {
 480                 int ncaps = capsize / sizeof (*cap);
 481                 Cap *cp;
 482 
 483                 cap = kmem_alloc(capsize, KM_SLEEP);
 484                 if ((error = vn_rdwr(UIO_READ, vp, (caddr_t)cap,
 485                     capsize, (offset_t)capphdr->p_offset,
 486                     UIO_SYSSPACE, 0, (rlim64_t)0, CRED(), &resid)) != 0) {
 487                         uprintf("%s: Cannot read capabilities section\n",
 488                             exec_file);
 489                         goto out;
 490                 }
 491                 for (cp = cap; cp < cap + ncaps; cp++) {
 492                         if (cp->c_tag == CA_SUNW_SF_1 &&
 493                             (cp->c_un.c_val & SF1_SUNW_ADDR32)) {
 494                                 if (args->to_model == DATAMODEL_LP64)
 495                                         args->addr32 = 1;


 506         if ((error = exec_args(uap, args, idatap, (void **)&aux)) != 0) {
 507                 if (error == -1) {
 508                         error = ENOEXEC;
 509                         goto bad;
 510                 }
 511                 goto out;
 512         }
 513         /* we're single threaded after this point */
 514 
 515         /*
 516          * If this is an ET_DYN executable (shared object),
 517          * determine its memory size so that mapelfexec() can load it.
 518          */
 519         if (ehdrp->e_type == ET_DYN)
 520                 len = elfsize(ehdrp, nphdrs, phdrbase, NULL);
 521         else
 522                 len = 0;
 523 
 524         dtrphdr = NULL;
 525 
 526         if ((error = mapelfexec(vp, ehdrp, nphdrs, phdrbase, &uphdr, &dyphdr,
 527             &stphdr, &dtrphdr, dataphdrp, &bssbase, &brkbase, &voffset, NULL,
 528             len, execsz, &brksize)) != 0)
 529                 goto bad;
 530 
 531         if (uphdr != NULL && dyphdr == NULL)
 532                 goto bad;
 533 
 534         if (dtrphdr != NULL && dtrace_safe_phdr(dtrphdr, args, voffset) != 0) {
 535                 uprintf("%s: Bad DTrace phdr in %s\n", exec_file, exec_file);
 536                 goto bad;
 537         }
 538 
 539         if (dyphdr != NULL) {
 540                 size_t          len;
 541                 uintptr_t       lddata;
 542                 char            *p;
 543                 struct vnode    *nvp;
 544 
 545                 dlnsize = dyphdr->p_filesz;
 546 
 547                 if (dlnsize > MAXPATHLEN || dlnsize <= 0)
 548                         goto bad;
 549 
 550                 /*
 551                  * Read in "interpreter" pathname.
 552                  */
 553                 if ((error = vn_rdwr(UIO_READ, vp, dlnp, dyphdr->p_filesz,
 554                     (offset_t)dyphdr->p_offset, UIO_SYSSPACE, 0, (rlim64_t)0,
 555                     CRED(), &resid)) != 0) {
 556                         uprintf("%s: Cannot obtain interpreter pathname\n",
 557                             exec_file);
 558                         goto bad;
 559                 }
 560 
 561                 if (resid != 0 || dlnp[dlnsize - 1] != '\0')
 562                         goto bad;
 563 
 564                 /*
 565                  * Search for '$ORIGIN' token in interpreter path.
 566                  * If found, expand it.
 567                  */
 568                 for (p = dlnp; p = strchr(p, '$'); ) {
 569                         uint_t  len, curlen;
 570                         char    *_ptr;
 571 
 572                         if (strncmp(++p, ORIGIN_STR, ORIGIN_STR_SIZE))
 573                                 continue;
 574 


 743                  * libraries instead of using the brand libraries that are
 744                  * installed in the zone.  We only do this for processes
 745                  * which we trust because we see they are already running
 746                  * under pfexec (where uid != euid).  This prevents a
 747                  * malicious user within the zone from crafting a wrapper to
 748                  * run native suid commands with unsecure libraries interposed.
 749                  */
 750                 if ((brand_action == EBA_NATIVE) && (PROC_IS_BRANDED(p) &&
 751                     (setid &= ~EXECSETID_SETID) != 0))
 752                         auxf &= ~AF_SUN_SETUGID;
 753 
 754                 /*
 755                  * Record the user addr of the auxflags aux vector entry
 756                  * since brands may optionally want to manipulate this field.
 757                  */
 758                 args->auxp_auxflags =
 759                     (char *)((char *)args->stackend +
 760                     ((char *)&aux->a_type -
 761                     (char *)bigwad->elfargs));
 762                 ADDAUX(aux, AT_SUN_AUXFLAGS, auxf);







 763                 /*
 764                  * Hardware capability flag word (performance hints)
 765                  * Used for choosing faster library routines.
 766                  * (Potentially different between 32-bit and 64-bit ABIs)
 767                  */
 768 #if defined(_LP64)
 769                 if (args->to_model == DATAMODEL_NATIVE) {
 770                         ADDAUX(aux, AT_SUN_HWCAP, auxv_hwcap)
 771                         ADDAUX(aux, AT_SUN_HWCAP2, auxv_hwcap_2)
 772                 } else {
 773                         ADDAUX(aux, AT_SUN_HWCAP, auxv_hwcap32)
 774                         ADDAUX(aux, AT_SUN_HWCAP2, auxv_hwcap32_2)
 775                 }
 776 #else
 777                 ADDAUX(aux, AT_SUN_HWCAP, auxv_hwcap)
 778                 ADDAUX(aux, AT_SUN_HWCAP2, auxv_hwcap_2)
 779 #endif
 780                 if (branded) {
 781                         /*
 782                          * Reserve space for the brand-private aux vectors,


 883                 bigwad->exenv.ex_vp = vp;
 884                 setexecenv(&bigwad->exenv);
 885         }
 886 
 887         ASSERT(error == 0);
 888         goto out;
 889 
 890 bad:
 891         if (fd != -1)           /* did we open the a.out yet */
 892                 (void) execclose(fd);
 893 
 894         psignal(p, SIGKILL);
 895 
 896         if (error == 0)
 897                 error = ENOEXEC;
 898 out:
 899         if (phdrbase != NULL)
 900                 kmem_free(phdrbase, phdrsize);
 901         if (cap != NULL)
 902                 kmem_free(cap, capsize);


 903         kmem_free(bigwad, sizeof (struct bigwad));
 904         return (error);
 905 }
 906 
 907 /*
 908  * Compute the memory size requirement for the ELF file.
 909  */
 910 static size_t
 911 elfsize(Ehdr *ehdrp, int nphdrs, caddr_t phdrbase, uintptr_t *lddata)
 912 {
 913         size_t  len;
 914         Phdr    *phdrp = (Phdr *)phdrbase;
 915         int     hsize = ehdrp->e_phentsize;
 916         int     first = 1;
 917         int     dfirst = 1;     /* first data segment */
 918         uintptr_t loaddr = 0;
 919         uintptr_t hiaddr = 0;
 920         uintptr_t lo, hi;
 921         int     i;
 922 


1152                 kmem_free(*shstrbasep, *shstrsizep);
1153                 return (err);
1154         }
1155 
1156         /*
1157          * Make sure the strtab is null-terminated to make sure we
1158          * don't run off the end of the table.
1159          */
1160         (*shstrbasep)[*shstrsizep - 1] = '\0';
1161 
1162         return (0);
1163 }
1164 
1165 static int
1166 mapelfexec(
1167         vnode_t *vp,
1168         Ehdr *ehdr,
1169         int nphdrs,
1170         caddr_t phdrbase,
1171         Phdr **uphdr,
1172         Phdr **dyphdr,
1173         Phdr **stphdr,
1174         Phdr **dtphdr,
1175         Phdr *dataphdrp,
1176         caddr_t *bssbase,
1177         caddr_t *brkbase,
1178         intptr_t *voffset,
1179         intptr_t *minaddr,
1180         size_t len,
1181         long *execsz,
1182         size_t *brksize)
1183 {
1184         Phdr *phdr;
1185         int i, prot, error;
1186         caddr_t addr = NULL;
1187         size_t zfodsz;
1188         int ptload = 0;
1189         int page;
1190         off_t offset;
1191         int hsize = ehdr->e_phentsize;
1192         caddr_t mintmp = (caddr_t)-1;
1193         extern int use_brk_lpg;
1194 
1195         if (ehdr->e_type == ET_DYN) {

1196                 /*
1197                  * Obtain the virtual address of a hole in the
1198                  * address space to map the "interpreter".
1199                  */
1200                 map_addr(&addr, len, (offset_t)0, 1, 0);



1201                 if (addr == NULL)
1202                         return (ENOMEM);
1203                 *voffset = (intptr_t)addr;
1204 
1205                 /*
1206                  * Calculate the minimum vaddr so it can be subtracted out.
1207                  * According to the ELF specification, since PT_LOAD sections
1208                  * must be sorted by increasing p_vaddr values, this is
1209                  * guaranteed to be the first PT_LOAD section.
1210                  */
1211                 phdr = (Phdr *)phdrbase;
1212                 for (i = nphdrs; i > 0; i--) {
1213                         if (phdr->p_type == PT_LOAD) {
1214                                 *voffset -= (uintptr_t)phdr->p_vaddr;
1215                                 break;
1216                         }
1217                         phdr = (Phdr *)((caddr_t)phdr + hsize);
1218                 }
1219 
1220         } else {
1221                 *voffset = 0;
1222         }
1223         phdr = (Phdr *)phdrbase;
1224         for (i = nphdrs; i > 0; i--) {
1225                 switch (phdr->p_type) {
1226                 case PT_LOAD:
1227                         if ((*dyphdr != NULL) && (*uphdr == NULL))
1228                                 return (0);
1229 
1230                         ptload = 1;
1231                         prot = PROT_USER;
1232                         if (phdr->p_flags & PF_R)
1233                                 prot |= PROT_READ;
1234                         if (phdr->p_flags & PF_W)
1235                                 prot |= PROT_WRITE;
1236                         if (phdr->p_flags & PF_X)
1237                                 prot |= PROT_EXEC;
1238 
1239                         addr = (caddr_t)((uintptr_t)phdr->p_vaddr + *voffset);
1240 
1241                         /*
1242                          * Keep track of the segment with the lowest starting
1243                          * address.
1244                          */
1245                         if (addr < mintmp)
1246                                 mintmp = addr;
1247 


1262                          */
1263                         if (brksize != NULL && use_brk_lpg &&
1264                             zfodsz != 0 && phdr == dataphdrp &&
1265                             (prot & PROT_WRITE)) {
1266                                 size_t tlen = P2NPHASE((uintptr_t)addr +
1267                                     phdr->p_filesz, PAGESIZE);
1268 
1269                                 if (zfodsz > tlen) {
1270                                         curproc->p_brkpageszc =
1271                                             page_szc(map_pgsz(MAPPGSZ_HEAP,
1272                                             curproc, addr + phdr->p_filesz +
1273                                             tlen, zfodsz - tlen, 0));
1274                                 }
1275                         }
1276 
1277                         if (curproc->p_brkpageszc != 0 && phdr == dataphdrp &&
1278                             (prot & PROT_WRITE)) {
1279                                 uint_t  szc = curproc->p_brkpageszc;
1280                                 size_t pgsz = page_get_pagesize(szc);
1281                                 caddr_t ebss = addr + phdr->p_memsz;







1282                                 size_t extra_zfodsz;
1283 
1284                                 ASSERT(pgsz > PAGESIZE);
1285 
1286                                 extra_zfodsz = P2NPHASE((uintptr_t)ebss, pgsz);
1287 
1288                                 if (error = execmap(vp, addr, phdr->p_filesz,
1289                                     zfodsz + extra_zfodsz, phdr->p_offset,
1290                                     prot, page, szc))
1291                                         goto bad;
1292                                 if (brksize != NULL)
1293                                         *brksize = extra_zfodsz;
1294                         } else {
1295                                 if (error = execmap(vp, addr, phdr->p_filesz,
1296                                     zfodsz, phdr->p_offset, prot, page, 0))
1297                                         goto bad;
1298                         }
1299 
1300                         if (bssbase != NULL && addr >= *bssbase &&
1301                             phdr == dataphdrp) {
1302                                 *bssbase = addr + phdr->p_filesz;
1303                         }
1304                         if (brkbase != NULL && addr >= *brkbase) {
1305                                 *brkbase = addr + phdr->p_memsz;
1306                         }
1307 
1308                         *execsz += btopr(phdr->p_memsz);
1309                         break;
1310 
1311                 case PT_INTERP:
1312                         if (ptload)
1313                                 goto bad;
1314                         *dyphdr = phdr;
1315                         break;
1316 
1317                 case PT_SHLIB:
1318                         *stphdr = phdr;
1319                         break;
1320 
1321                 case PT_PHDR:
1322                         if (ptload)
1323                                 goto bad;
1324                         *uphdr = phdr;
1325                         break;
1326 
1327                 case PT_NULL:
1328                 case PT_DYNAMIC:
1329                 case PT_NOTE:
1330                         break;
1331 
1332                 case PT_SUNWDTRACE:
1333                         if (dtphdr != NULL)
1334                                 *dtphdr = phdr;
1335                         break;
1336 
1337                 default:
1338                         break;
1339                 }
1340                 phdr = (Phdr *)((caddr_t)phdr + hsize);
1341         }
1342 
1343         if (minaddr != NULL) {
1344                 ASSERT(mintmp != (caddr_t)-1);
1345                 *minaddr = (intptr_t)mintmp;
1346         }
1347 

























1348         return (0);
1349 bad:
1350         if (error == 0)
1351                 error = EINVAL;
1352         return (error);
1353 }
1354 
1355 int
1356 elfnote(vnode_t *vp, offset_t *offsetp, int type, int descsz, void *desc,
1357     rlim64_t rlimit, cred_t *credp)
1358 {
1359         Note note;
1360         int error;
1361 
1362         bzero(&note, sizeof (note));
1363         bcopy("CORE", note.name, 4);
1364         note.nhdr.n_type = type;
1365         /*
1366          * The System V ABI states that n_namesz must be the length of the
1367          * string that follows the Nhdr structure including the terminating




  48 #include <sys/vmsystm.h>
  49 #include <sys/debug.h>
  50 #include <sys/auxv.h>
  51 #include <sys/exec.h>
  52 #include <sys/prsystm.h>
  53 #include <vm/as.h>
  54 #include <vm/rm.h>
  55 #include <vm/seg.h>
  56 #include <vm/seg_vn.h>
  57 #include <sys/modctl.h>
  58 #include <sys/systeminfo.h>
  59 #include <sys/vmparam.h>
  60 #include <sys/machelf.h>
  61 #include <sys/shm_impl.h>
  62 #include <sys/archsystm.h>
  63 #include <sys/fasttrap.h>
  64 #include <sys/brand.h>
  65 #include "elf_impl.h"
  66 #include <sys/sdt.h>
  67 #include <sys/siginfo.h>
  68 #include <sys/random.h>
  69 
  70 extern int at_flags;
  71 extern volatile size_t aslr_max_brk_skew;
  72 
  73 #define ORIGIN_STR      "ORIGIN"
  74 #define ORIGIN_STR_SIZE 6
  75 
  76 static int getelfhead(vnode_t *, cred_t *, Ehdr *, int *, int *, int *);
  77 static int getelfphdr(vnode_t *, cred_t *, const Ehdr *, int, caddr_t *,
  78     ssize_t *);
  79 static int getelfshdr(vnode_t *, cred_t *, const Ehdr *, int, int, caddr_t *,
  80     ssize_t *, caddr_t *, ssize_t *);
  81 static size_t elfsize(Ehdr *, int, caddr_t, uintptr_t *);
  82 static int mapelfexec(vnode_t *, Ehdr *, int, caddr_t,
  83     Phdr **, Phdr **, Phdr **, Phdr **, Phdr *,
  84     caddr_t *, caddr_t *, intptr_t *, intptr_t *, size_t, long *, size_t *);
  85 
  86 typedef enum {
  87         STR_CTF,
  88         STR_SYMTAB,
  89         STR_DYNSYM,
  90         STR_STRTAB,
  91         STR_DYNSTR,


 240         kmem_free(phdrbase, phdrsize);
 241         return (error);
 242 }
 243 
 244 /*ARGSUSED*/
 245 int
 246 elfexec(vnode_t *vp, execa_t *uap, uarg_t *args, intpdata_t *idatap,
 247     int level, long *execsz, int setid, caddr_t exec_file, cred_t *cred,
 248     int brand_action)
 249 {
 250         caddr_t         phdrbase = NULL;
 251         caddr_t         bssbase = 0;
 252         caddr_t         brkbase = 0;
 253         size_t          brksize = 0;
 254         ssize_t         dlnsize;
 255         aux_entry_t     *aux;
 256         int             error;
 257         ssize_t         resid;
 258         int             fd = -1;
 259         intptr_t        voffset;
 260         Phdr            *intphdr = NULL;
 261         Phdr            *dynamicphdr = NULL;
 262         Phdr            *stphdr = NULL;
 263         Phdr            *uphdr = NULL;
 264         Phdr            *junk = NULL;
 265         size_t          len;
 266         ssize_t         phdrsize;
 267         int             postfixsize = 0;
 268         int             i, hsize;
 269         Phdr            *phdrp;
 270         Phdr            *dataphdrp = NULL;
 271         Phdr            *dtrphdr;
 272         Phdr            *capphdr = NULL;
 273         Cap             *cap = NULL;
 274         ssize_t         capsize;
 275         Dyn             *dyn = NULL;
 276         ssize_t         dynsize;
 277         int             hasu = 0;
 278         int             hasauxv = 0;
 279         int             hasintp = 0;
 280         int             branded = 0;
 281 
 282         struct proc *p = ttoproc(curthread);
 283         struct user *up = PTOU(p);
 284         struct bigwad {
 285                 Ehdr    ehdr;
 286                 aux_entry_t     elfargs[__KERN_NAUXV_IMPL];
 287                 char            dl_name[MAXPATHLEN];
 288                 char            pathbuf[MAXPATHLEN];
 289                 struct vattr    vattr;
 290                 struct execenv  exenv;
 291         } *bigwad;      /* kmem_alloc this behemoth so we don't blow stack */
 292         Ehdr            *ehdrp;
 293         int             nshdrs, shstrndx, nphdrs;
 294         char            *dlnp;
 295         char            *pathbufp;
 296         rlim64_t        limit;
 297         rlim64_t        roundlimit;
 298 
 299         ASSERT(p->p_model == DATAMODEL_ILP32 || p->p_model == DATAMODEL_LP64);


 352          */
 353         if ((level < 2) &&
 354             (brand_action != EBA_NATIVE) && (PROC_IS_BRANDED(p))) {
 355                 error = BROP(p)->b_elfexec(vp, uap, args,
 356                     idatap, level + 1, execsz, setid, exec_file, cred,
 357                     brand_action);
 358                 goto out;
 359         }
 360 
 361         /*
 362          * Determine aux size now so that stack can be built
 363          * in one shot (except actual copyout of aux image),
 364          * determine any non-default stack protections,
 365          * and still have this code be machine independent.
 366          */
 367         hsize = ehdrp->e_phentsize;
 368         phdrp = (Phdr *)phdrbase;
 369         for (i = nphdrs; i > 0; i--) {
 370                 switch (phdrp->p_type) {
 371                 case PT_INTERP:
 372                         hasauxv = hasintp = 1;
 373                         break;
 374                 case PT_PHDR:
 375                         hasu = 1;
 376                         break;
 377                 case PT_SUNWSTACK:
 378                         args->stk_prot = PROT_USER;
 379                         if (phdrp->p_flags & PF_R)
 380                                 args->stk_prot |= PROT_READ;
 381                         if (phdrp->p_flags & PF_W)
 382                                 args->stk_prot |= PROT_WRITE;
 383                         if (phdrp->p_flags & PF_X)
 384                                 args->stk_prot |= PROT_EXEC;
 385                         break;
 386                 case PT_LOAD:
 387                         dataphdrp = phdrp;
 388                         break;
 389                 case PT_SUNWCAP:
 390                         capphdr = phdrp;
 391                         break;
 392                 case PT_DYNAMIC:
 393                         dynamicphdr = phdrp;
 394                         break;
 395                 }
 396                 phdrp = (Phdr *)((caddr_t)phdrp + hsize);
 397         }
 398 
 399         if (ehdrp->e_type != ET_EXEC) {
 400                 dataphdrp = NULL;
 401                 hasauxv = 1;
 402         }
 403 
 404         /* Copy BSS permissions to args->dat_prot */
 405         if (dataphdrp != NULL) {
 406                 args->dat_prot = PROT_USER;
 407                 if (dataphdrp->p_flags & PF_R)
 408                         args->dat_prot |= PROT_READ;
 409                 if (dataphdrp->p_flags & PF_W)
 410                         args->dat_prot |= PROT_WRITE;
 411                 if (dataphdrp->p_flags & PF_X)
 412                         args->dat_prot |= PROT_EXEC;
 413         }
 414 
 415         /*
 416          * If a auxvector will be required - reserve the space for
 417          * it now.  This may be increased by exec_args if there are
 418          * ISA-specific types (included in __KERN_NAUXV_IMPL).
 419          */
 420         if (hasauxv) {
 421                 /*
 422                  * If a AUX vector is being built - the base AUX
 423                  * entries are:
 424                  *
 425                  *      AT_BASE
 426                  *      AT_FLAGS
 427                  *      AT_PAGESZ
 428                  *      AT_SUN_AUXFLAGS
 429                  *      AT_SUN_HWCAP
 430                  *      AT_SUN_HWCAP2
 431                  *      AT_SUN_SECFLAGS
 432                  *      AT_SUN_PLATFORM (added in stk_copyout)
 433                  *      AT_SUN_EXECNAME (added in stk_copyout)
 434                  *      AT_NULL
 435                  *
 436                  * total == 10
 437                  */
 438                 if (hasintp && hasu) {
 439                         /*
 440                          * Has PT_INTERP & PT_PHDR - the auxvectors that
 441                          * will be built are:
 442                          *
 443                          *      AT_PHDR
 444                          *      AT_PHENT
 445                          *      AT_PHNUM
 446                          *      AT_ENTRY
 447                          *      AT_LDDATA
 448                          *
 449                          * total = 5
 450                          */
 451                         args->auxsize = (10 + 5) * sizeof (aux_entry_t);
 452                 } else if (hasintp) {
 453                         /*
 454                          * Has PT_INTERP but no PT_PHDR
 455                          *
 456                          *      AT_EXECFD
 457                          *      AT_LDDATA
 458                          *
 459                          * total = 2
 460                          */
 461                         args->auxsize = (10 + 2) * sizeof (aux_entry_t);
 462                 } else {
 463                         args->auxsize = 10 * sizeof (aux_entry_t);
 464                 }
 465         } else {
 466                 args->auxsize = 0;
 467         }
 468 
 469         /*
 470          * If this binary is using an emulator, we need to add an
 471          * AT_SUN_EMULATOR aux entry.
 472          */
 473         if (args->emulator != NULL)
 474                 args->auxsize += sizeof (aux_entry_t);
 475 
 476         if ((brand_action != EBA_NATIVE) && (PROC_IS_BRANDED(p))) {
 477                 branded = 1;
 478                 /*
 479                  * We will be adding 4 entries to the aux vectors.  One for
 480                  * the the brandname and 3 for the brand specific aux vectors.
 481                  */
 482                 args->auxsize += 4 * sizeof (aux_entry_t);
 483         }
 484 
 485         /* If the binary has an explicit ASLR flag, it must be honoured */
 486         if (dynamicphdr != NULL) {
 487                 Dyn *dp;
 488 
 489                 dynsize = dynamicphdr->p_filesz;
 490                 dyn = kmem_alloc(dynsize, KM_SLEEP);
 491 
 492                 if ((error = vn_rdwr(UIO_READ, vp, (caddr_t)dyn, dynsize,
 493                     (offset_t)dynamicphdr->p_offset, UIO_SYSSPACE, 0, (rlim64_t)0,
 494                     CRED(), &resid)) != 0) {
 495                         uprintf("%s: cannot read .dynamic section\n",
 496                             exec_file);
 497                         goto out;
 498                 }
 499 
 500                 if (resid != 0)
 501                         goto out;
 502 
 503                 dp = dyn;
 504                 while (dp->d_tag != DT_NULL) {
 505                         if (dp->d_tag == DT_SUNW_ASLR) {
 506                                 if (dp->d_un.d_val != 0) {
 507                                         curproc->p_secflags.psf_effective |=
 508                                             PROC_SEC_ASLR;
 509                                         curproc->p_secflags.psf_inherit |=
 510                                             PROC_SEC_ASLR;
 511 
 512                                 } else {
 513                                         curproc->p_secflags.psf_effective &=
 514                                             ~PROC_SEC_ASLR;
 515                                         curproc->p_secflags.psf_inherit &=
 516                                             ~PROC_SEC_ASLR;
 517                                 }
 518                         }
 519                         dp++;
 520                 }
 521         }
 522 
 523         /* Hardware/Software capabilities */
 524         if (capphdr != NULL &&
 525             (capsize = capphdr->p_filesz) > 0 &&
 526             capsize <= 16 * sizeof (*cap)) {
 527                 int ncaps = capsize / sizeof (*cap);
 528                 Cap *cp;
 529 
 530                 cap = kmem_alloc(capsize, KM_SLEEP);
 531                 if ((error = vn_rdwr(UIO_READ, vp, (caddr_t)cap,
 532                     capsize, (offset_t)capphdr->p_offset,
 533                     UIO_SYSSPACE, 0, (rlim64_t)0, CRED(), &resid)) != 0) {
 534                         uprintf("%s: Cannot read capabilities section\n",
 535                             exec_file);
 536                         goto out;
 537                 }
 538                 for (cp = cap; cp < cap + ncaps; cp++) {
 539                         if (cp->c_tag == CA_SUNW_SF_1 &&
 540                             (cp->c_un.c_val & SF1_SUNW_ADDR32)) {
 541                                 if (args->to_model == DATAMODEL_LP64)
 542                                         args->addr32 = 1;


 553         if ((error = exec_args(uap, args, idatap, (void **)&aux)) != 0) {
 554                 if (error == -1) {
 555                         error = ENOEXEC;
 556                         goto bad;
 557                 }
 558                 goto out;
 559         }
 560         /* we're single threaded after this point */
 561 
 562         /*
 563          * If this is an ET_DYN executable (shared object),
 564          * determine its memory size so that mapelfexec() can load it.
 565          */
 566         if (ehdrp->e_type == ET_DYN)
 567                 len = elfsize(ehdrp, nphdrs, phdrbase, NULL);
 568         else
 569                 len = 0;
 570 
 571         dtrphdr = NULL;
 572 
 573         if ((error = mapelfexec(vp, ehdrp, nphdrs, phdrbase, &uphdr, &intphdr,
 574             &stphdr, &dtrphdr, dataphdrp, &bssbase, &brkbase, &voffset, NULL,
 575             len, execsz, &brksize)) != 0)
 576                 goto bad;
 577 
 578         if (uphdr != NULL && intphdr == NULL)
 579                 goto bad;
 580 
 581         if (dtrphdr != NULL && dtrace_safe_phdr(dtrphdr, args, voffset) != 0) {
 582                 uprintf("%s: Bad DTrace phdr in %s\n", exec_file, exec_file);
 583                 goto bad;
 584         }
 585 
 586         if (intphdr != NULL) {
 587                 size_t          len;
 588                 uintptr_t       lddata;
 589                 char            *p;
 590                 struct vnode    *nvp;
 591 
 592                 dlnsize = intphdr->p_filesz;
 593 
 594                 if (dlnsize > MAXPATHLEN || dlnsize <= 0)
 595                         goto bad;
 596 
 597                 /*
 598                  * Read in "interpreter" pathname.
 599                  */
 600                 if ((error = vn_rdwr(UIO_READ, vp, dlnp, intphdr->p_filesz,
 601                     (offset_t)intphdr->p_offset, UIO_SYSSPACE, 0, (rlim64_t)0,
 602                     CRED(), &resid)) != 0) {
 603                         uprintf("%s: Cannot obtain interpreter pathname\n",
 604                             exec_file);
 605                         goto bad;
 606                 }
 607 
 608                 if (resid != 0 || dlnp[dlnsize - 1] != '\0')
 609                         goto bad;
 610 
 611                 /*
 612                  * Search for '$ORIGIN' token in interpreter path.
 613                  * If found, expand it.
 614                  */
 615                 for (p = dlnp; p = strchr(p, '$'); ) {
 616                         uint_t  len, curlen;
 617                         char    *_ptr;
 618 
 619                         if (strncmp(++p, ORIGIN_STR, ORIGIN_STR_SIZE))
 620                                 continue;
 621 


 790                  * libraries instead of using the brand libraries that are
 791                  * installed in the zone.  We only do this for processes
 792                  * which we trust because we see they are already running
 793                  * under pfexec (where uid != euid).  This prevents a
 794                  * malicious user within the zone from crafting a wrapper to
 795                  * run native suid commands with unsecure libraries interposed.
 796                  */
 797                 if ((brand_action == EBA_NATIVE) && (PROC_IS_BRANDED(p) &&
 798                     (setid &= ~EXECSETID_SETID) != 0))
 799                         auxf &= ~AF_SUN_SETUGID;
 800 
 801                 /*
 802                  * Record the user addr of the auxflags aux vector entry
 803                  * since brands may optionally want to manipulate this field.
 804                  */
 805                 args->auxp_auxflags =
 806                     (char *)((char *)args->stackend +
 807                     ((char *)&aux->a_type -
 808                     (char *)bigwad->elfargs));
 809                 ADDAUX(aux, AT_SUN_AUXFLAGS, auxf);
 810 
 811                 /*
 812                  * Put the effective security-flags into the aux vector, for
 813                  * the sake of flags that need partial (or complete)
 814                  * implementation in userland.
 815                  */
 816                 ADDAUX(aux, AT_SUN_SECFLAGS, p->p_secflags.psf_effective);
 817                 /*
 818                  * Hardware capability flag word (performance hints)
 819                  * Used for choosing faster library routines.
 820                  * (Potentially different between 32-bit and 64-bit ABIs)
 821                  */
 822 #if defined(_LP64)
 823                 if (args->to_model == DATAMODEL_NATIVE) {
 824                         ADDAUX(aux, AT_SUN_HWCAP, auxv_hwcap)
 825                         ADDAUX(aux, AT_SUN_HWCAP2, auxv_hwcap_2)
 826                 } else {
 827                         ADDAUX(aux, AT_SUN_HWCAP, auxv_hwcap32)
 828                         ADDAUX(aux, AT_SUN_HWCAP2, auxv_hwcap32_2)
 829                 }
 830 #else
 831                 ADDAUX(aux, AT_SUN_HWCAP, auxv_hwcap)
 832                 ADDAUX(aux, AT_SUN_HWCAP2, auxv_hwcap_2)
 833 #endif
 834                 if (branded) {
 835                         /*
 836                          * Reserve space for the brand-private aux vectors,


 937                 bigwad->exenv.ex_vp = vp;
 938                 setexecenv(&bigwad->exenv);
 939         }
 940 
 941         ASSERT(error == 0);
 942         goto out;
 943 
 944 bad:
 945         if (fd != -1)           /* did we open the a.out yet */
 946                 (void) execclose(fd);
 947 
 948         psignal(p, SIGKILL);
 949 
 950         if (error == 0)
 951                 error = ENOEXEC;
 952 out:
 953         if (phdrbase != NULL)
 954                 kmem_free(phdrbase, phdrsize);
 955         if (cap != NULL)
 956                 kmem_free(cap, capsize);
 957         if (dyn != NULL)
 958                 kmem_free(dyn, dynsize);
 959         kmem_free(bigwad, sizeof (struct bigwad));
 960         return (error);
 961 }
 962 
 963 /*
 964  * Compute the memory size requirement for the ELF file.
 965  */
 966 static size_t
 967 elfsize(Ehdr *ehdrp, int nphdrs, caddr_t phdrbase, uintptr_t *lddata)
 968 {
 969         size_t  len;
 970         Phdr    *phdrp = (Phdr *)phdrbase;
 971         int     hsize = ehdrp->e_phentsize;
 972         int     first = 1;
 973         int     dfirst = 1;     /* first data segment */
 974         uintptr_t loaddr = 0;
 975         uintptr_t hiaddr = 0;
 976         uintptr_t lo, hi;
 977         int     i;
 978 


1208                 kmem_free(*shstrbasep, *shstrsizep);
1209                 return (err);
1210         }
1211 
1212         /*
1213          * Make sure the strtab is null-terminated to make sure we
1214          * don't run off the end of the table.
1215          */
1216         (*shstrbasep)[*shstrsizep - 1] = '\0';
1217 
1218         return (0);
1219 }
1220 
1221 static int
1222 mapelfexec(
1223         vnode_t *vp,
1224         Ehdr *ehdr,
1225         int nphdrs,
1226         caddr_t phdrbase,
1227         Phdr **uphdr,
1228         Phdr **intphdr,
1229         Phdr **stphdr,
1230         Phdr **dtphdr,
1231         Phdr *dataphdrp,
1232         caddr_t *bssbase,
1233         caddr_t *brkbase,
1234         intptr_t *voffset,
1235         intptr_t *minaddr,
1236         size_t len,
1237         long *execsz,
1238         size_t *brksize)
1239 {
1240         Phdr *phdr;
1241         int i, prot, error;
1242         caddr_t addr = NULL;
1243         size_t zfodsz;
1244         int ptload = 0;
1245         int page;
1246         off_t offset;
1247         int hsize = ehdr->e_phentsize;
1248         caddr_t mintmp = (caddr_t)-1;
1249         extern int use_brk_lpg;
1250 
1251         if (ehdr->e_type == ET_DYN) {
1252                 uint_t flags = 0;
1253                 /*
1254                  * Obtain the virtual address of a hole in the
1255                  * address space to map the "interpreter".
1256                  */
1257                 if (secflag_enabled(curproc, PROC_SEC_ASLR))
1258                         flags |= _MAP_RANDOMIZE;
1259 
1260                 map_addr(&addr, len, (offset_t)0, 1, flags);
1261                 if (addr == NULL)
1262                         return (ENOMEM);
1263                 *voffset = (intptr_t)addr;
1264 
1265                 /*
1266                  * Calculate the minimum vaddr so it can be subtracted out.
1267                  * According to the ELF specification, since PT_LOAD sections
1268                  * must be sorted by increasing p_vaddr values, this is
1269                  * guaranteed to be the first PT_LOAD section.
1270                  */
1271                 phdr = (Phdr *)phdrbase;
1272                 for (i = nphdrs; i > 0; i--) {
1273                         if (phdr->p_type == PT_LOAD) {
1274                                 *voffset -= (uintptr_t)phdr->p_vaddr;
1275                                 break;
1276                         }
1277                         phdr = (Phdr *)((caddr_t)phdr + hsize);
1278                 }
1279 
1280         } else {
1281                 *voffset = 0;
1282         }
1283         phdr = (Phdr *)phdrbase;
1284         for (i = nphdrs; i > 0; i--) {
1285                 switch (phdr->p_type) {
1286                 case PT_LOAD:
1287                         if ((*intphdr != NULL) && (*uphdr == NULL))
1288                                 return (0);
1289 
1290                         ptload = 1;
1291                         prot = PROT_USER;
1292                         if (phdr->p_flags & PF_R)
1293                                 prot |= PROT_READ;
1294                         if (phdr->p_flags & PF_W)
1295                                 prot |= PROT_WRITE;
1296                         if (phdr->p_flags & PF_X)
1297                                 prot |= PROT_EXEC;
1298 
1299                         addr = (caddr_t)((uintptr_t)phdr->p_vaddr + *voffset);
1300 
1301                         /*
1302                          * Keep track of the segment with the lowest starting
1303                          * address.
1304                          */
1305                         if (addr < mintmp)
1306                                 mintmp = addr;
1307 


1322                          */
1323                         if (brksize != NULL && use_brk_lpg &&
1324                             zfodsz != 0 && phdr == dataphdrp &&
1325                             (prot & PROT_WRITE)) {
1326                                 size_t tlen = P2NPHASE((uintptr_t)addr +
1327                                     phdr->p_filesz, PAGESIZE);
1328 
1329                                 if (zfodsz > tlen) {
1330                                         curproc->p_brkpageszc =
1331                                             page_szc(map_pgsz(MAPPGSZ_HEAP,
1332                                             curproc, addr + phdr->p_filesz +
1333                                             tlen, zfodsz - tlen, 0));
1334                                 }
1335                         }
1336 
1337                         if (curproc->p_brkpageszc != 0 && phdr == dataphdrp &&
1338                             (prot & PROT_WRITE)) {
1339                                 uint_t  szc = curproc->p_brkpageszc;
1340                                 size_t pgsz = page_get_pagesize(szc);
1341                                 caddr_t ebss = addr + phdr->p_memsz;
1342                                 /*
1343                                  * If we need extra space to keep the BSS an
1344                                  * integral number of pages in size, some of
1345                                  * that space may fall beyond p_brkbase, so we
1346                                  * need to set p_brksize to account for it
1347                                  * being (logically) part of the brk.
1348                                  */
1349                                 size_t extra_zfodsz;
1350 
1351                                 ASSERT(pgsz > PAGESIZE);
1352 
1353                                 extra_zfodsz = P2NPHASE((uintptr_t)ebss, pgsz);
1354 
1355                                 if (error = execmap(vp, addr, phdr->p_filesz,
1356                                     zfodsz + extra_zfodsz, phdr->p_offset,
1357                                     prot, page, szc))
1358                                         goto bad;
1359                                 if (brksize != NULL)
1360                                         *brksize = extra_zfodsz;
1361                         } else {
1362                                 if (error = execmap(vp, addr, phdr->p_filesz,
1363                                     zfodsz, phdr->p_offset, prot, page, 0))
1364                                         goto bad;
1365                         }
1366 
1367                         if (bssbase != NULL && addr >= *bssbase &&
1368                             phdr == dataphdrp) {
1369                                 *bssbase = addr + phdr->p_filesz;
1370                         }
1371                         if (brkbase != NULL && addr >= *brkbase) {
1372                                 *brkbase = addr + phdr->p_memsz;
1373                         }
1374 
1375                         *execsz += btopr(phdr->p_memsz);
1376                         break;
1377 
1378                 case PT_INTERP:
1379                         if (ptload)
1380                                 goto bad;
1381                         *intphdr = phdr;
1382                         break;
1383 
1384                 case PT_SHLIB:
1385                         *stphdr = phdr;
1386                         break;
1387 
1388                 case PT_PHDR:
1389                         if (ptload)
1390                                 goto bad;
1391                         *uphdr = phdr;
1392                         break;
1393 
1394                 case PT_NULL:
1395                 case PT_DYNAMIC:
1396                 case PT_NOTE:
1397                         break;
1398 
1399                 case PT_SUNWDTRACE:
1400                         if (dtphdr != NULL)
1401                                 *dtphdr = phdr;
1402                         break;
1403 
1404                 default:
1405                         break;
1406                 }
1407                 phdr = (Phdr *)((caddr_t)phdr + hsize);
1408         }
1409 
1410         if (minaddr != NULL) {
1411                 ASSERT(mintmp != (caddr_t)-1);
1412                 *minaddr = (intptr_t)mintmp;
1413         }
1414 
1415         if (brkbase != NULL && secflag_enabled(curproc, PROC_SEC_ASLR)) {
1416                 size_t off;
1417                 uintptr_t base = (uintptr_t)*brkbase;
1418                 uintptr_t oend = base + *brksize;
1419 
1420                 ASSERT(ISP2(aslr_max_brk_skew));
1421 
1422                 (void) random_get_pseudo_bytes((uint8_t *)&off, sizeof (off));
1423                 base += P2PHASE(off, aslr_max_brk_skew);
1424                 base = P2ROUNDUP(base, PAGESIZE);
1425                 *brkbase = (caddr_t)base;
1426                 /*
1427                  * Above, we set *brksize to account for the possibility we
1428                  * had to grow the 'brk' in padding out the BSS to a page
1429                  * boundary.
1430                  *
1431                  * We now need to adjust that based on where we now are
1432                  * actually putting the brk.
1433                  */
1434                 if (oend > base)
1435                         *brksize = oend - base;
1436                 else
1437                         *brksize = 0;
1438         }
1439 
1440         return (0);
1441 bad:
1442         if (error == 0)
1443                 error = EINVAL;
1444         return (error);
1445 }
1446 
1447 int
1448 elfnote(vnode_t *vp, offset_t *offsetp, int type, int descsz, void *desc,
1449     rlim64_t rlimit, cred_t *credp)
1450 {
1451         Note note;
1452         int error;
1453 
1454         bzero(&note, sizeof (note));
1455         bcopy("CORE", note.name, 4);
1456         note.nhdr.n_type = type;
1457         /*
1458          * The System V ABI states that n_namesz must be the length of the
1459          * string that follows the Nhdr structure including the terminating