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


  42 #include <sys/param.h>
  43 #include <sys/systm.h>
  44 #include <sys/user.h>
  45 #include <sys/proc.h>
  46 #include <sys/kmem.h>
  47 #include <sys/vmem.h>
  48 #include <sys/buf.h>
  49 #include <sys/cpuvar.h>
  50 #include <sys/lgrp.h>
  51 #include <sys/disp.h>
  52 #include <sys/vm.h>
  53 #include <sys/mman.h>
  54 #include <sys/vnode.h>
  55 #include <sys/cred.h>
  56 #include <sys/exec.h>
  57 #include <sys/exechdr.h>
  58 #include <sys/debug.h>
  59 #include <sys/vmsystm.h>
  60 #include <sys/swap.h>
  61 #include <sys/dumphdr.h>

  62 
  63 #include <vm/hat.h>
  64 #include <vm/as.h>
  65 #include <vm/seg.h>
  66 #include <vm/seg_kp.h>
  67 #include <vm/seg_vn.h>
  68 #include <vm/page.h>
  69 #include <vm/seg_kmem.h>
  70 #include <vm/seg_kpm.h>
  71 #include <vm/vm_dep.h>
  72 
  73 #include <sys/cpu.h>
  74 #include <sys/vm_machparam.h>
  75 #include <sys/memlist.h>
  76 #include <sys/bootconf.h> /* XXX the memlist stuff belongs in memlist_plat.h */
  77 #include <vm/hat_i86.h>
  78 #include <sys/x86_archext.h>
  79 #include <sys/elf_386.h>
  80 #include <sys/cmn_err.h>
  81 #include <sys/archsystm.h>


 620 }
 621 
 622 void
 623 map_addr(caddr_t *addrp, size_t len, offset_t off, int vacalign, uint_t flags)
 624 {
 625         struct proc *p = curproc;
 626         caddr_t userlimit = (flags & _MAP_LOW32) ?
 627             (caddr_t)_userlimit32 : p->p_as->a_userlimit;
 628 
 629         map_addr_proc(addrp, len, off, vacalign, userlimit, curproc, flags);
 630 }
 631 
 632 /*ARGSUSED*/
 633 int
 634 map_addr_vacalign_check(caddr_t addr, u_offset_t off)
 635 {
 636         return (0);
 637 }
 638 
 639 /*







 640  * map_addr_proc() is the routine called when the system is to
 641  * choose an address for the user.  We will pick an address
 642  * range which is the highest available below userlimit.
 643  *
 644  * Every mapping will have a redzone of a single page on either side of
 645  * the request. This is done to leave one page unmapped between segments.
 646  * This is not required, but it's useful for the user because if their
 647  * program strays across a segment boundary, it will catch a fault
 648  * immediately making debugging a little easier.  Currently the redzone
 649  * is mandatory.
 650  *
 651  * addrp is a value/result parameter.
 652  *      On input it is a hint from the user to be used in a completely
 653  *      machine dependent fashion.  We decide to completely ignore this hint.
 654  *      If MAP_ALIGN was specified, addrp contains the minimal alignment, which
 655  *      must be some "power of two" multiple of pagesize.
 656  *
 657  *      On output it is NULL if no address can be found in the current
 658  *      processes address space or else an address that is currently
 659  *      not mapped for len bytes with a page of red zone on either side.


 735                  * For 32-bit processes, only those which have specified
 736                  * MAP_ALIGN and an addr will be aligned on a larger page size.
 737                  * Not doing so can potentially waste up to 1G of process
 738                  * address space.
 739                  */
 740                 int lvl = (p->p_model == DATAMODEL_ILP32) ? 1 :
 741                     mmu.umax_page_level;
 742 
 743                 while (lvl && len < LEVEL_SIZE(lvl))
 744                         --lvl;
 745 
 746                 align_amount = LEVEL_SIZE(lvl);
 747         }
 748         if ((flags & MAP_ALIGN) && ((uintptr_t)*addrp > align_amount))
 749                 align_amount = (uintptr_t)*addrp;
 750 
 751         ASSERT(ISP2(align_amount));
 752         ASSERT(align_amount == 0 || align_amount >= PAGESIZE);
 753 
 754         off = off & (align_amount - 1);

 755         /*
 756          * Look for a large enough hole starting below userlimit.
 757          * After finding it, use the upper part.
 758          */
 759         if (as_gap_aligned(as, len, &base, &slen, AH_HI, NULL, align_amount,
 760             PAGESIZE, off) == 0) {
 761                 caddr_t as_addr;
 762 
 763                 /*
 764                  * addr is the highest possible address to use since we have
 765                  * a PAGESIZE redzone at the beginning and end.
 766                  */
 767                 addr = base + slen - (PAGESIZE + len);
 768                 as_addr = addr;
 769                 /*
 770                  * Round address DOWN to the alignment amount and
 771                  * add the offset in.
 772                  * If addr is greater than as_addr, len would not be large
 773                  * enough to include the redzone, so we must adjust down
 774                  * by the alignment amount.
 775                  */
 776                 addr = (caddr_t)((uintptr_t)addr & (~(align_amount - 1)));
 777                 addr += (uintptr_t)off;
 778                 if (addr > as_addr) {
 779                         addr -= align_amount;
 780                 }
 781 

















 782                 ASSERT(addr > base);
 783                 ASSERT(addr + len < base + slen);
 784                 ASSERT(((uintptr_t)addr & (align_amount - 1)) ==
 785                     ((uintptr_t)(off)));
 786                 *addrp = addr;
 787         } else {
 788                 *addrp = NULL;  /* no more virtual space */
 789         }
 790 }
 791 
 792 int valid_va_range_aligned_wraparound;
 793 
 794 /*
 795  * Determine whether [*basep, *basep + *lenp) contains a mappable range of
 796  * addresses at least "minlen" long, where the base of the range is at "off"
 797  * phase from an "align" boundary and there is space for a "redzone"-sized
 798  * redzone on either side of the range.  On success, 1 is returned and *basep
 799  * and *lenp are adjusted to describe the acceptable range (including
 800  * the redzone).  On failure, 0 is returned.
 801  */


3909 
3910         hat_mempte_release(cpup->cpu_caddr2, cpup->cpu_caddr2pte);
3911         cpup->cpu_caddr2pte = 0;
3912         vmem_free(heap_arena, cpup->cpu_caddr2, mmu_ptob(1));
3913         cpup->cpu_caddr2 = 0;
3914 
3915         hat_mempte_release(cpup->cpu_caddr1, cpup->cpu_caddr1pte);
3916         cpup->cpu_caddr1pte = 0;
3917         vmem_free(heap_arena, cpup->cpu_caddr1, mmu_ptob(1));
3918         cpup->cpu_caddr1 = 0;
3919 }
3920 
3921 /*
3922  * Function for flushing D-cache when performing module relocations
3923  * to an alternate mapping.  Unnecessary on Intel / AMD platforms.
3924  */
3925 void
3926 dcache_flushall()
3927 {}
3928 
3929 size_t
3930 exec_get_spslew(void)
3931 {
3932         return (0);
3933 }
3934 
3935 /*
3936  * Allocate a memory page.  The argument 'seed' can be any pseudo-random
3937  * number to vary where the pages come from.  This is quite a hacked up
3938  * method -- it works for now, but really needs to be fixed up a bit.
3939  *
3940  * We currently use page_create_va() on the kvp with fake offsets,
3941  * segments and virt address.  This is pretty bogus, but was copied from the
3942  * old hat_i86.c code.  A better approach would be to specify either mnode
3943  * random or mnode local and takes a page from whatever color has the MOST
3944  * available - this would have a minimal impact on page coloring.
3945  */
3946 page_t *
3947 page_get_physical(uintptr_t seed)
3948 {
3949         page_t *pp;
3950         u_offset_t offset;
3951         static struct seg tmpseg;
3952         static uintptr_t ctr = 0;
3953 
3954         /*




  42 #include <sys/param.h>
  43 #include <sys/systm.h>
  44 #include <sys/user.h>
  45 #include <sys/proc.h>
  46 #include <sys/kmem.h>
  47 #include <sys/vmem.h>
  48 #include <sys/buf.h>
  49 #include <sys/cpuvar.h>
  50 #include <sys/lgrp.h>
  51 #include <sys/disp.h>
  52 #include <sys/vm.h>
  53 #include <sys/mman.h>
  54 #include <sys/vnode.h>
  55 #include <sys/cred.h>
  56 #include <sys/exec.h>
  57 #include <sys/exechdr.h>
  58 #include <sys/debug.h>
  59 #include <sys/vmsystm.h>
  60 #include <sys/swap.h>
  61 #include <sys/dumphdr.h>
  62 #include <sys/random.h>
  63 
  64 #include <vm/hat.h>
  65 #include <vm/as.h>
  66 #include <vm/seg.h>
  67 #include <vm/seg_kp.h>
  68 #include <vm/seg_vn.h>
  69 #include <vm/page.h>
  70 #include <vm/seg_kmem.h>
  71 #include <vm/seg_kpm.h>
  72 #include <vm/vm_dep.h>
  73 
  74 #include <sys/cpu.h>
  75 #include <sys/vm_machparam.h>
  76 #include <sys/memlist.h>
  77 #include <sys/bootconf.h> /* XXX the memlist stuff belongs in memlist_plat.h */
  78 #include <vm/hat_i86.h>
  79 #include <sys/x86_archext.h>
  80 #include <sys/elf_386.h>
  81 #include <sys/cmn_err.h>
  82 #include <sys/archsystm.h>


 621 }
 622 
 623 void
 624 map_addr(caddr_t *addrp, size_t len, offset_t off, int vacalign, uint_t flags)
 625 {
 626         struct proc *p = curproc;
 627         caddr_t userlimit = (flags & _MAP_LOW32) ?
 628             (caddr_t)_userlimit32 : p->p_as->a_userlimit;
 629 
 630         map_addr_proc(addrp, len, off, vacalign, userlimit, curproc, flags);
 631 }
 632 
 633 /*ARGSUSED*/
 634 int
 635 map_addr_vacalign_check(caddr_t addr, u_offset_t off)
 636 {
 637         return (0);
 638 }
 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 /*
 648  * map_addr_proc() is the routine called when the system is to
 649  * choose an address for the user.  We will pick an address
 650  * range which is the highest available below userlimit.
 651  *
 652  * Every mapping will have a redzone of a single page on either side of
 653  * the request. This is done to leave one page unmapped between segments.
 654  * This is not required, but it's useful for the user because if their
 655  * program strays across a segment boundary, it will catch a fault
 656  * immediately making debugging a little easier.  Currently the redzone
 657  * is mandatory.
 658  *
 659  * addrp is a value/result parameter.
 660  *      On input it is a hint from the user to be used in a completely
 661  *      machine dependent fashion.  We decide to completely ignore this hint.
 662  *      If MAP_ALIGN was specified, addrp contains the minimal alignment, which
 663  *      must be some "power of two" multiple of pagesize.
 664  *
 665  *      On output it is NULL if no address can be found in the current
 666  *      processes address space or else an address that is currently
 667  *      not mapped for len bytes with a page of red zone on either side.


 743                  * For 32-bit processes, only those which have specified
 744                  * MAP_ALIGN and an addr will be aligned on a larger page size.
 745                  * Not doing so can potentially waste up to 1G of process
 746                  * address space.
 747                  */
 748                 int lvl = (p->p_model == DATAMODEL_ILP32) ? 1 :
 749                     mmu.umax_page_level;
 750 
 751                 while (lvl && len < LEVEL_SIZE(lvl))
 752                         --lvl;
 753 
 754                 align_amount = LEVEL_SIZE(lvl);
 755         }
 756         if ((flags & MAP_ALIGN) && ((uintptr_t)*addrp > align_amount))
 757                 align_amount = (uintptr_t)*addrp;
 758 
 759         ASSERT(ISP2(align_amount));
 760         ASSERT(align_amount == 0 || align_amount >= PAGESIZE);
 761 
 762         off = off & (align_amount - 1);
 763 
 764         /*
 765          * Look for a large enough hole starting below userlimit.
 766          * After finding it, use the upper part.
 767          */
 768         if (as_gap_aligned(as, len, &base, &slen, AH_HI, NULL, align_amount,
 769             PAGESIZE, off) == 0) {
 770                 caddr_t as_addr;
 771 
 772                 /*
 773                  * addr is the highest possible address to use since we have
 774                  * a PAGESIZE redzone at the beginning and end.
 775                  */
 776                 addr = base + slen - (PAGESIZE + len);
 777                 as_addr = addr;
 778                 /*
 779                  * Round address DOWN to the alignment amount and
 780                  * add the offset in.
 781                  * If addr is greater than as_addr, len would not be large
 782                  * enough to include the redzone, so we must adjust down
 783                  * by the alignment amount.
 784                  */
 785                 addr = (caddr_t)((uintptr_t)addr & (~(align_amount - 1)));
 786                 addr += (uintptr_t)off;
 787                 if (addr > as_addr) {
 788                         addr -= align_amount;
 789                 }
 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 
 808                 ASSERT(addr > base);
 809                 ASSERT(addr + len < base + slen);
 810                 ASSERT(((uintptr_t)addr & (align_amount - 1)) ==
 811                     ((uintptr_t)(off)));
 812                 *addrp = addr;
 813         } else {
 814                 *addrp = NULL;  /* no more virtual space */
 815         }
 816 }
 817 
 818 int valid_va_range_aligned_wraparound;
 819 
 820 /*
 821  * Determine whether [*basep, *basep + *lenp) contains a mappable range of
 822  * addresses at least "minlen" long, where the base of the range is at "off"
 823  * phase from an "align" boundary and there is space for a "redzone"-sized
 824  * redzone on either side of the range.  On success, 1 is returned and *basep
 825  * and *lenp are adjusted to describe the acceptable range (including
 826  * the redzone).  On failure, 0 is returned.
 827  */


3935 
3936         hat_mempte_release(cpup->cpu_caddr2, cpup->cpu_caddr2pte);
3937         cpup->cpu_caddr2pte = 0;
3938         vmem_free(heap_arena, cpup->cpu_caddr2, mmu_ptob(1));
3939         cpup->cpu_caddr2 = 0;
3940 
3941         hat_mempte_release(cpup->cpu_caddr1, cpup->cpu_caddr1pte);
3942         cpup->cpu_caddr1pte = 0;
3943         vmem_free(heap_arena, cpup->cpu_caddr1, mmu_ptob(1));
3944         cpup->cpu_caddr1 = 0;
3945 }
3946 
3947 /*
3948  * Function for flushing D-cache when performing module relocations
3949  * to an alternate mapping.  Unnecessary on Intel / AMD platforms.
3950  */
3951 void
3952 dcache_flushall()
3953 {}
3954 






3955 /*
3956  * Allocate a memory page.  The argument 'seed' can be any pseudo-random
3957  * number to vary where the pages come from.  This is quite a hacked up
3958  * method -- it works for now, but really needs to be fixed up a bit.
3959  *
3960  * We currently use page_create_va() on the kvp with fake offsets,
3961  * segments and virt address.  This is pretty bogus, but was copied from the
3962  * old hat_i86.c code.  A better approach would be to specify either mnode
3963  * random or mnode local and takes a page from whatever color has the MOST
3964  * available - this would have a minimal impact on page coloring.
3965  */
3966 page_t *
3967 page_get_physical(uintptr_t seed)
3968 {
3969         page_t *pp;
3970         u_offset_t offset;
3971         static struct seg tmpseg;
3972         static uintptr_t ctr = 0;
3973 
3974         /*