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/i86pc/vm/vm_machdep.c
          +++ new/usr/src/uts/i86pc/vm/vm_machdep.c
↓ open down ↓ 51 lines elided ↑ open up ↑
  52   52  #include <sys/vm.h>
  53   53  #include <sys/mman.h>
  54   54  #include <sys/vnode.h>
  55   55  #include <sys/cred.h>
  56   56  #include <sys/exec.h>
  57   57  #include <sys/exechdr.h>
  58   58  #include <sys/debug.h>
  59   59  #include <sys/vmsystm.h>
  60   60  #include <sys/swap.h>
  61   61  #include <sys/dumphdr.h>
       62 +#include <sys/random.h>
  62   63  
  63   64  #include <vm/hat.h>
  64   65  #include <vm/as.h>
  65   66  #include <vm/seg.h>
  66   67  #include <vm/seg_kp.h>
  67   68  #include <vm/seg_vn.h>
  68   69  #include <vm/page.h>
  69   70  #include <vm/seg_kmem.h>
  70   71  #include <vm/seg_kpm.h>
  71   72  #include <vm/vm_dep.h>
↓ open down ↓ 558 lines elided ↑ open up ↑
 630  631  }
 631  632  
 632  633  /*ARGSUSED*/
 633  634  int
 634  635  map_addr_vacalign_check(caddr_t addr, u_offset_t off)
 635  636  {
 636  637          return (0);
 637  638  }
 638  639  
 639  640  /*
      641 + * The maximum amount a randomized mapping will be slewed.  We should perhaps
      642 + * arrange things so these tunables can be separate for mmap, mmapobj, and
      643 + * ld.so
      644 + */
      645 +volatile size_t aslr_max_map_skew = 256 * 1024 * 1024; /* 256MB */
      646 +
      647 +/*
 640  648   * map_addr_proc() is the routine called when the system is to
 641  649   * choose an address for the user.  We will pick an address
 642  650   * range which is the highest available below userlimit.
 643  651   *
 644  652   * Every mapping will have a redzone of a single page on either side of
 645  653   * the request. This is done to leave one page unmapped between segments.
 646  654   * This is not required, but it's useful for the user because if their
 647  655   * program strays across a segment boundary, it will catch a fault
 648  656   * immediately making debugging a little easier.  Currently the redzone
 649  657   * is mandatory.
↓ open down ↓ 95 lines elided ↑ open up ↑
 745  753  
 746  754                  align_amount = LEVEL_SIZE(lvl);
 747  755          }
 748  756          if ((flags & MAP_ALIGN) && ((uintptr_t)*addrp > align_amount))
 749  757                  align_amount = (uintptr_t)*addrp;
 750  758  
 751  759          ASSERT(ISP2(align_amount));
 752  760          ASSERT(align_amount == 0 || align_amount >= PAGESIZE);
 753  761  
 754  762          off = off & (align_amount - 1);
      763 +
 755  764          /*
 756  765           * Look for a large enough hole starting below userlimit.
 757  766           * After finding it, use the upper part.
 758  767           */
 759  768          if (as_gap_aligned(as, len, &base, &slen, AH_HI, NULL, align_amount,
 760  769              PAGESIZE, off) == 0) {
 761  770                  caddr_t as_addr;
 762  771  
 763  772                  /*
 764  773                   * addr is the highest possible address to use since we have
↓ open down ↓ 7 lines elided ↑ open up ↑
 772  781                   * If addr is greater than as_addr, len would not be large
 773  782                   * enough to include the redzone, so we must adjust down
 774  783                   * by the alignment amount.
 775  784                   */
 776  785                  addr = (caddr_t)((uintptr_t)addr & (~(align_amount - 1)));
 777  786                  addr += (uintptr_t)off;
 778  787                  if (addr > as_addr) {
 779  788                          addr -= align_amount;
 780  789                  }
 781  790  
      791 +                /*
      792 +                 * If randomization is requested, slew the allocation
      793 +                 * backwards, within the same gap, by a random amount.
      794 +                 *
      795 +                 * XXX: This will fall over in processes like Java, which
      796 +                 * commonly have a great many small mappings.
      797 +                 */
      798 +                if (flags & _MAP_RANDOMIZE) {
      799 +                        uint32_t slew;
      800 +
      801 +                        (void) random_get_pseudo_bytes((uint8_t *)&slew,
      802 +                            sizeof (slew));
      803 +
      804 +                        slew = slew % MIN(aslr_max_map_skew, (addr - base));
      805 +                        addr -= P2ALIGN(slew, align_amount);
      806 +                }
      807 +
 782  808                  ASSERT(addr > base);
 783  809                  ASSERT(addr + len < base + slen);
 784  810                  ASSERT(((uintptr_t)addr & (align_amount - 1)) ==
 785  811                      ((uintptr_t)(off)));
 786  812                  *addrp = addr;
 787  813          } else {
 788  814                  *addrp = NULL;  /* no more virtual space */
 789  815          }
 790  816  }
 791  817  
↓ open down ↓ 3127 lines elided ↑ open up ↑
3919 3945  }
3920 3946  
3921 3947  /*
3922 3948   * Function for flushing D-cache when performing module relocations
3923 3949   * to an alternate mapping.  Unnecessary on Intel / AMD platforms.
3924 3950   */
3925 3951  void
3926 3952  dcache_flushall()
3927 3953  {}
3928 3954  
3929      -size_t
3930      -exec_get_spslew(void)
3931      -{
3932      -        return (0);
3933      -}
3934      -
3935 3955  /*
3936 3956   * Allocate a memory page.  The argument 'seed' can be any pseudo-random
3937 3957   * number to vary where the pages come from.  This is quite a hacked up
3938 3958   * method -- it works for now, but really needs to be fixed up a bit.
3939 3959   *
3940 3960   * We currently use page_create_va() on the kvp with fake offsets,
3941 3961   * segments and virt address.  This is pretty bogus, but was copied from the
3942 3962   * old hat_i86.c code.  A better approach would be to specify either mnode
3943 3963   * random or mnode local and takes a page from whatever color has the MOST
3944 3964   * available - this would have a minimal impact on page coloring.
↓ open down ↓ 44 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX