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

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 ↓ 57 lines elided ↑ open up ↑
  58   58  #include <sys/systeminfo.h>
  59   59  #include <sys/vmparam.h>
  60   60  #include <sys/machelf.h>
  61   61  #include <sys/shm_impl.h>
  62   62  #include <sys/archsystm.h>
  63   63  #include <sys/fasttrap.h>
  64   64  #include <sys/brand.h>
  65   65  #include "elf_impl.h"
  66   66  #include <sys/sdt.h>
  67   67  #include <sys/siginfo.h>
       68 +#include <sys/random.h>
  68   69  
  69   70  extern int at_flags;
       71 +extern volatile size_t aslr_max_brk_skew;
  70   72  
  71   73  #define ORIGIN_STR      "ORIGIN"
  72   74  #define ORIGIN_STR_SIZE 6
  73   75  
  74   76  static int getelfhead(vnode_t *, cred_t *, Ehdr *, int *, int *, int *);
  75   77  static int getelfphdr(vnode_t *, cred_t *, const Ehdr *, int, caddr_t *,
  76   78      ssize_t *);
  77   79  static int getelfshdr(vnode_t *, cred_t *, const Ehdr *, int, int, caddr_t *,
  78   80      ssize_t *, caddr_t *, ssize_t *);
  79   81  static size_t elfsize(Ehdr *, int, caddr_t, uintptr_t *);
↓ open down ↓ 168 lines elided ↑ open up ↑
 248  250          caddr_t         phdrbase = NULL;
 249  251          caddr_t         bssbase = 0;
 250  252          caddr_t         brkbase = 0;
 251  253          size_t          brksize = 0;
 252  254          ssize_t         dlnsize;
 253  255          aux_entry_t     *aux;
 254  256          int             error;
 255  257          ssize_t         resid;
 256  258          int             fd = -1;
 257  259          intptr_t        voffset;
 258      -        Phdr            *dyphdr = NULL;
      260 +        Phdr            *intphdr = NULL;
      261 +        Phdr            *dynamicphdr = NULL;
 259  262          Phdr            *stphdr = NULL;
 260  263          Phdr            *uphdr = NULL;
 261  264          Phdr            *junk = NULL;
 262  265          size_t          len;
 263  266          ssize_t         phdrsize;
 264  267          int             postfixsize = 0;
 265  268          int             i, hsize;
 266  269          Phdr            *phdrp;
 267  270          Phdr            *dataphdrp = NULL;
 268  271          Phdr            *dtrphdr;
 269  272          Phdr            *capphdr = NULL;
 270  273          Cap             *cap = NULL;
 271  274          ssize_t         capsize;
      275 +        Dyn             *dyn = NULL;
      276 +        ssize_t         dynsize;
 272  277          int             hasu = 0;
 273  278          int             hasauxv = 0;
 274      -        int             hasdy = 0;
      279 +        int             hasintp = 0;
 275  280          int             branded = 0;
 276  281  
 277  282          struct proc *p = ttoproc(curthread);
 278  283          struct user *up = PTOU(p);
 279  284          struct bigwad {
 280  285                  Ehdr    ehdr;
 281  286                  aux_entry_t     elfargs[__KERN_NAUXV_IMPL];
 282  287                  char            dl_name[MAXPATHLEN];
 283  288                  char            pathbuf[MAXPATHLEN];
 284  289                  struct vattr    vattr;
↓ open down ↓ 72 lines elided ↑ open up ↑
 357  362           * Determine aux size now so that stack can be built
 358  363           * in one shot (except actual copyout of aux image),
 359  364           * determine any non-default stack protections,
 360  365           * and still have this code be machine independent.
 361  366           */
 362  367          hsize = ehdrp->e_phentsize;
 363  368          phdrp = (Phdr *)phdrbase;
 364  369          for (i = nphdrs; i > 0; i--) {
 365  370                  switch (phdrp->p_type) {
 366  371                  case PT_INTERP:
 367      -                        hasauxv = hasdy = 1;
      372 +                        hasauxv = hasintp = 1;
 368  373                          break;
 369  374                  case PT_PHDR:
 370  375                          hasu = 1;
 371  376                          break;
 372  377                  case PT_SUNWSTACK:
 373  378                          args->stk_prot = PROT_USER;
 374  379                          if (phdrp->p_flags & PF_R)
 375  380                                  args->stk_prot |= PROT_READ;
 376  381                          if (phdrp->p_flags & PF_W)
 377  382                                  args->stk_prot |= PROT_WRITE;
 378  383                          if (phdrp->p_flags & PF_X)
 379  384                                  args->stk_prot |= PROT_EXEC;
 380  385                          break;
 381  386                  case PT_LOAD:
 382  387                          dataphdrp = phdrp;
 383  388                          break;
 384  389                  case PT_SUNWCAP:
 385  390                          capphdr = phdrp;
 386  391                          break;
      392 +                case PT_DYNAMIC:
      393 +                        dynamicphdr = phdrp;
      394 +                        break;
 387  395                  }
 388  396                  phdrp = (Phdr *)((caddr_t)phdrp + hsize);
 389  397          }
 390  398  
 391  399          if (ehdrp->e_type != ET_EXEC) {
 392  400                  dataphdrp = NULL;
 393  401                  hasauxv = 1;
 394  402          }
 395  403  
 396  404          /* Copy BSS permissions to args->dat_prot */
↓ open down ↓ 16 lines elided ↑ open up ↑
 413  421                  /*
 414  422                   * If a AUX vector is being built - the base AUX
 415  423                   * entries are:
 416  424                   *
 417  425                   *      AT_BASE
 418  426                   *      AT_FLAGS
 419  427                   *      AT_PAGESZ
 420  428                   *      AT_SUN_AUXFLAGS
 421  429                   *      AT_SUN_HWCAP
 422  430                   *      AT_SUN_HWCAP2
      431 +                 *      AT_SUN_SECFLAGS
 423  432                   *      AT_SUN_PLATFORM (added in stk_copyout)
 424  433                   *      AT_SUN_EXECNAME (added in stk_copyout)
 425  434                   *      AT_NULL
 426  435                   *
 427      -                 * total == 9
      436 +                 * total == 10
 428  437                   */
 429      -                if (hasdy && hasu) {
      438 +                if (hasintp && hasu) {
 430  439                          /*
 431  440                           * Has PT_INTERP & PT_PHDR - the auxvectors that
 432  441                           * will be built are:
 433  442                           *
 434  443                           *      AT_PHDR
 435  444                           *      AT_PHENT
 436  445                           *      AT_PHNUM
 437  446                           *      AT_ENTRY
 438  447                           *      AT_LDDATA
 439  448                           *
 440  449                           * total = 5
 441  450                           */
 442      -                        args->auxsize = (9 + 5) * sizeof (aux_entry_t);
 443      -                } else if (hasdy) {
      451 +                        args->auxsize = (10 + 5) * sizeof (aux_entry_t);
      452 +                } else if (hasintp) {
 444  453                          /*
 445  454                           * Has PT_INTERP but no PT_PHDR
 446  455                           *
 447  456                           *      AT_EXECFD
 448  457                           *      AT_LDDATA
 449  458                           *
 450  459                           * total = 2
 451  460                           */
 452      -                        args->auxsize = (9 + 2) * sizeof (aux_entry_t);
      461 +                        args->auxsize = (10 + 2) * sizeof (aux_entry_t);
 453  462                  } else {
 454      -                        args->auxsize = 9 * sizeof (aux_entry_t);
      463 +                        args->auxsize = 10 * sizeof (aux_entry_t);
 455  464                  }
 456  465          } else {
 457  466                  args->auxsize = 0;
 458  467          }
 459  468  
 460  469          /*
 461  470           * If this binary is using an emulator, we need to add an
 462  471           * AT_SUN_EMULATOR aux entry.
 463  472           */
 464  473          if (args->emulator != NULL)
↓ open down ↓ 1 lines elided ↑ open up ↑
 466  475  
 467  476          if ((brand_action != EBA_NATIVE) && (PROC_IS_BRANDED(p))) {
 468  477                  branded = 1;
 469  478                  /*
 470  479                   * We will be adding 4 entries to the aux vectors.  One for
 471  480                   * the the brandname and 3 for the brand specific aux vectors.
 472  481                   */
 473  482                  args->auxsize += 4 * sizeof (aux_entry_t);
 474  483          }
 475  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 +
 476  523          /* Hardware/Software capabilities */
 477  524          if (capphdr != NULL &&
 478  525              (capsize = capphdr->p_filesz) > 0 &&
 479  526              capsize <= 16 * sizeof (*cap)) {
 480  527                  int ncaps = capsize / sizeof (*cap);
 481  528                  Cap *cp;
 482  529  
 483  530                  cap = kmem_alloc(capsize, KM_SLEEP);
 484  531                  if ((error = vn_rdwr(UIO_READ, vp, (caddr_t)cap,
 485  532                      capsize, (offset_t)capphdr->p_offset,
↓ open down ↓ 30 lines elided ↑ open up ↑
 516  563           * If this is an ET_DYN executable (shared object),
 517  564           * determine its memory size so that mapelfexec() can load it.
 518  565           */
 519  566          if (ehdrp->e_type == ET_DYN)
 520  567                  len = elfsize(ehdrp, nphdrs, phdrbase, NULL);
 521  568          else
 522  569                  len = 0;
 523  570  
 524  571          dtrphdr = NULL;
 525  572  
 526      -        if ((error = mapelfexec(vp, ehdrp, nphdrs, phdrbase, &uphdr, &dyphdr,
      573 +        if ((error = mapelfexec(vp, ehdrp, nphdrs, phdrbase, &uphdr, &intphdr,
 527  574              &stphdr, &dtrphdr, dataphdrp, &bssbase, &brkbase, &voffset, NULL,
 528  575              len, execsz, &brksize)) != 0)
 529  576                  goto bad;
 530  577  
 531      -        if (uphdr != NULL && dyphdr == NULL)
      578 +        if (uphdr != NULL && intphdr == NULL)
 532  579                  goto bad;
 533  580  
 534  581          if (dtrphdr != NULL && dtrace_safe_phdr(dtrphdr, args, voffset) != 0) {
 535  582                  uprintf("%s: Bad DTrace phdr in %s\n", exec_file, exec_file);
 536  583                  goto bad;
 537  584          }
 538  585  
 539      -        if (dyphdr != NULL) {
      586 +        if (intphdr != NULL) {
 540  587                  size_t          len;
 541  588                  uintptr_t       lddata;
 542  589                  char            *p;
 543  590                  struct vnode    *nvp;
 544  591  
 545      -                dlnsize = dyphdr->p_filesz;
      592 +                dlnsize = intphdr->p_filesz;
 546  593  
 547  594                  if (dlnsize > MAXPATHLEN || dlnsize <= 0)
 548  595                          goto bad;
 549  596  
 550  597                  /*
 551  598                   * Read in "interpreter" pathname.
 552  599                   */
 553      -                if ((error = vn_rdwr(UIO_READ, vp, dlnp, dyphdr->p_filesz,
 554      -                    (offset_t)dyphdr->p_offset, UIO_SYSSPACE, 0, (rlim64_t)0,
      600 +                if ((error = vn_rdwr(UIO_READ, vp, dlnp, intphdr->p_filesz,
      601 +                    (offset_t)intphdr->p_offset, UIO_SYSSPACE, 0, (rlim64_t)0,
 555  602                      CRED(), &resid)) != 0) {
 556  603                          uprintf("%s: Cannot obtain interpreter pathname\n",
 557  604                              exec_file);
 558  605                          goto bad;
 559  606                  }
 560  607  
 561  608                  if (resid != 0 || dlnp[dlnsize - 1] != '\0')
 562  609                          goto bad;
 563  610  
 564  611                  /*
↓ open down ↓ 188 lines elided ↑ open up ↑
 753  800  
 754  801                  /*
 755  802                   * Record the user addr of the auxflags aux vector entry
 756  803                   * since brands may optionally want to manipulate this field.
 757  804                   */
 758  805                  args->auxp_auxflags =
 759  806                      (char *)((char *)args->stackend +
 760  807                      ((char *)&aux->a_type -
 761  808                      (char *)bigwad->elfargs));
 762  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);
 763  817                  /*
 764  818                   * Hardware capability flag word (performance hints)
 765  819                   * Used for choosing faster library routines.
 766  820                   * (Potentially different between 32-bit and 64-bit ABIs)
 767  821                   */
 768  822  #if defined(_LP64)
 769  823                  if (args->to_model == DATAMODEL_NATIVE) {
 770  824                          ADDAUX(aux, AT_SUN_HWCAP, auxv_hwcap)
 771  825                          ADDAUX(aux, AT_SUN_HWCAP2, auxv_hwcap_2)
 772  826                  } else {
↓ open down ↓ 120 lines elided ↑ open up ↑
 893  947  
 894  948          psignal(p, SIGKILL);
 895  949  
 896  950          if (error == 0)
 897  951                  error = ENOEXEC;
 898  952  out:
 899  953          if (phdrbase != NULL)
 900  954                  kmem_free(phdrbase, phdrsize);
 901  955          if (cap != NULL)
 902  956                  kmem_free(cap, capsize);
      957 +        if (dyn != NULL)
      958 +                kmem_free(dyn, dynsize);
 903  959          kmem_free(bigwad, sizeof (struct bigwad));
 904  960          return (error);
 905  961  }
 906  962  
 907  963  /*
 908  964   * Compute the memory size requirement for the ELF file.
 909  965   */
 910  966  static size_t
 911  967  elfsize(Ehdr *ehdrp, int nphdrs, caddr_t phdrbase, uintptr_t *lddata)
 912  968  {
↓ open down ↓ 249 lines elided ↑ open up ↑
1162 1218          return (0);
1163 1219  }
1164 1220  
1165 1221  static int
1166 1222  mapelfexec(
1167 1223          vnode_t *vp,
1168 1224          Ehdr *ehdr,
1169 1225          int nphdrs,
1170 1226          caddr_t phdrbase,
1171 1227          Phdr **uphdr,
1172      -        Phdr **dyphdr,
     1228 +        Phdr **intphdr,
1173 1229          Phdr **stphdr,
1174 1230          Phdr **dtphdr,
1175 1231          Phdr *dataphdrp,
1176 1232          caddr_t *bssbase,
1177 1233          caddr_t *brkbase,
1178 1234          intptr_t *voffset,
1179 1235          intptr_t *minaddr,
1180 1236          size_t len,
1181 1237          long *execsz,
1182 1238          size_t *brksize)
↓ open down ↓ 3 lines elided ↑ open up ↑
1186 1242          caddr_t addr = NULL;
1187 1243          size_t zfodsz;
1188 1244          int ptload = 0;
1189 1245          int page;
1190 1246          off_t offset;
1191 1247          int hsize = ehdr->e_phentsize;
1192 1248          caddr_t mintmp = (caddr_t)-1;
1193 1249          extern int use_brk_lpg;
1194 1250  
1195 1251          if (ehdr->e_type == ET_DYN) {
     1252 +                uint_t flags = 0;
1196 1253                  /*
1197 1254                   * Obtain the virtual address of a hole in the
1198 1255                   * address space to map the "interpreter".
1199 1256                   */
1200      -                map_addr(&addr, len, (offset_t)0, 1, 0);
     1257 +                if (secflag_enabled(curproc, PROC_SEC_ASLR))
     1258 +                        flags |= _MAP_RANDOMIZE;
     1259 +
     1260 +                map_addr(&addr, len, (offset_t)0, 1, flags);
1201 1261                  if (addr == NULL)
1202 1262                          return (ENOMEM);
1203 1263                  *voffset = (intptr_t)addr;
1204 1264  
1205 1265                  /*
1206 1266                   * Calculate the minimum vaddr so it can be subtracted out.
1207 1267                   * According to the ELF specification, since PT_LOAD sections
1208 1268                   * must be sorted by increasing p_vaddr values, this is
1209 1269                   * guaranteed to be the first PT_LOAD section.
1210 1270                   */
↓ open down ↓ 6 lines elided ↑ open up ↑
1217 1277                          phdr = (Phdr *)((caddr_t)phdr + hsize);
1218 1278                  }
1219 1279  
1220 1280          } else {
1221 1281                  *voffset = 0;
1222 1282          }
1223 1283          phdr = (Phdr *)phdrbase;
1224 1284          for (i = nphdrs; i > 0; i--) {
1225 1285                  switch (phdr->p_type) {
1226 1286                  case PT_LOAD:
1227      -                        if ((*dyphdr != NULL) && (*uphdr == NULL))
     1287 +                        if ((*intphdr != NULL) && (*uphdr == NULL))
1228 1288                                  return (0);
1229 1289  
1230 1290                          ptload = 1;
1231 1291                          prot = PROT_USER;
1232 1292                          if (phdr->p_flags & PF_R)
1233 1293                                  prot |= PROT_READ;
1234 1294                          if (phdr->p_flags & PF_W)
1235 1295                                  prot |= PROT_WRITE;
1236 1296                          if (phdr->p_flags & PF_X)
1237 1297                                  prot |= PROT_EXEC;
↓ open down ↓ 34 lines elided ↑ open up ↑
1272 1332                                              curproc, addr + phdr->p_filesz +
1273 1333                                              tlen, zfodsz - tlen, 0));
1274 1334                                  }
1275 1335                          }
1276 1336  
1277 1337                          if (curproc->p_brkpageszc != 0 && phdr == dataphdrp &&
1278 1338                              (prot & PROT_WRITE)) {
1279 1339                                  uint_t  szc = curproc->p_brkpageszc;
1280 1340                                  size_t pgsz = page_get_pagesize(szc);
1281 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 +                                 */
1282 1349                                  size_t extra_zfodsz;
1283 1350  
1284 1351                                  ASSERT(pgsz > PAGESIZE);
1285 1352  
1286 1353                                  extra_zfodsz = P2NPHASE((uintptr_t)ebss, pgsz);
1287 1354  
1288 1355                                  if (error = execmap(vp, addr, phdr->p_filesz,
1289 1356                                      zfodsz + extra_zfodsz, phdr->p_offset,
1290 1357                                      prot, page, szc))
1291 1358                                          goto bad;
↓ open down ↓ 12 lines elided ↑ open up ↑
1304 1371                          if (brkbase != NULL && addr >= *brkbase) {
1305 1372                                  *brkbase = addr + phdr->p_memsz;
1306 1373                          }
1307 1374  
1308 1375                          *execsz += btopr(phdr->p_memsz);
1309 1376                          break;
1310 1377  
1311 1378                  case PT_INTERP:
1312 1379                          if (ptload)
1313 1380                                  goto bad;
1314      -                        *dyphdr = phdr;
     1381 +                        *intphdr = phdr;
1315 1382                          break;
1316 1383  
1317 1384                  case PT_SHLIB:
1318 1385                          *stphdr = phdr;
1319 1386                          break;
1320 1387  
1321 1388                  case PT_PHDR:
1322 1389                          if (ptload)
1323 1390                                  goto bad;
1324 1391                          *uphdr = phdr;
↓ open down ↓ 13 lines elided ↑ open up ↑
1338 1405                          break;
1339 1406                  }
1340 1407                  phdr = (Phdr *)((caddr_t)phdr + hsize);
1341 1408          }
1342 1409  
1343 1410          if (minaddr != NULL) {
1344 1411                  ASSERT(mintmp != (caddr_t)-1);
1345 1412                  *minaddr = (intptr_t)mintmp;
1346 1413          }
1347 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 +
1348 1440          return (0);
1349 1441  bad:
1350 1442          if (error == 0)
1351 1443                  error = EINVAL;
1352 1444          return (error);
1353 1445  }
1354 1446  
1355 1447  int
1356 1448  elfnote(vnode_t *vp, offset_t *offsetp, int type, int descsz, void *desc,
1357 1449      rlim64_t rlimit, cred_t *credp)
↓ open down ↓ 860 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX