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


  29 /*
  30  * Portions of this source code were derived from Berkeley 4.3 BSD
  31  * under license from the Regents of the University of California.
  32  */
  33 
  34 /*
  35  * UNIX machine dependent virtual memory support.
  36  */
  37 
  38 #include <sys/vm.h>
  39 #include <sys/exec.h>
  40 #include <sys/cmn_err.h>
  41 #include <sys/cpu_module.h>
  42 #include <sys/cpu.h>
  43 #include <sys/elf_SPARC.h>
  44 #include <sys/archsystm.h>
  45 #include <vm/hat_sfmmu.h>
  46 #include <sys/memnode.h>
  47 #include <sys/mem_cage.h>
  48 #include <vm/vm_dep.h>

  49 
  50 #if defined(__sparcv9) && defined(SF_ERRATA_57)
  51 caddr_t errata57_limit;
  52 #endif
  53 
  54 uint_t page_colors = 0;
  55 uint_t page_colors_mask = 0;
  56 uint_t page_coloring_shift = 0;
  57 int consistent_coloring;
  58 int update_proc_pgcolorbase_after_fork = 0;
  59 
  60 uint_t mmu_page_sizes = DEFAULT_MMU_PAGE_SIZES;
  61 uint_t max_mmu_page_sizes = MMU_PAGE_SIZES;
  62 uint_t mmu_hashcnt = DEFAULT_MAX_HASHCNT;
  63 uint_t max_mmu_hashcnt = MAX_HASHCNT;
  64 size_t mmu_ism_pagesize = DEFAULT_ISM_PAGESIZE;
  65 
  66 /*
  67  * The sun4u hardware mapping sizes which will always be supported are
  68  * 8K, 64K, 512K and 4M.  If sun4u based machines need to support other


 120 size_t max_shm_lpsize = MMU_PAGESIZE4M;
 121 
 122 void
 123 adjust_data_maxlpsize(size_t ismpagesize)
 124 {
 125         if (max_uheap_lpsize == MMU_PAGESIZE4M) {
 126                 max_uheap_lpsize = ismpagesize;
 127         }
 128         if (max_ustack_lpsize == MMU_PAGESIZE4M) {
 129                 max_ustack_lpsize = ismpagesize;
 130         }
 131         if (max_privmap_lpsize == MMU_PAGESIZE4M) {
 132                 max_privmap_lpsize = ismpagesize;
 133         }
 134         if (max_shm_lpsize == MMU_PAGESIZE4M) {
 135                 max_shm_lpsize = ismpagesize;
 136         }
 137 }
 138 
 139 /*







 140  * map_addr_proc() is the routine called when the system is to
 141  * choose an address for the user.  We will pick an address
 142  * range which is just below the current stack limit.  The
 143  * algorithm used for cache consistency on machines with virtual
 144  * address caches is such that offset 0 in the vnode is always
 145  * on a shm_alignment'ed aligned address.  Unfortunately, this
 146  * means that vnodes which are demand paged will not be mapped
 147  * cache consistently with the executable images.  When the
 148  * cache alignment for a given object is inconsistent, the
 149  * lower level code must manage the translations so that this
 150  * is not seen here (at the cost of efficiency, of course).
 151  *
 152  * Every mapping will have a redzone of a single page on either side of
 153  * the request. This is done to leave one page unmapped between segments.
 154  * This is not required, but it's useful for the user because if their
 155  * program strays across a segment boundary, it will catch a fault
 156  * immediately making debugging a little easier.  Currently the redzone
 157  * is mandatory.
 158  *
 159  *


 248         if (p->p_model == DATAMODEL_LP64)
 249                 align_amount = MAX(align_amount, ELF_SPARCV9_MAXPGSZ);
 250 #ifdef VAC
 251         if (vac && vacalign && (align_amount < shm_alignment))
 252                 align_amount = shm_alignment;
 253 #endif
 254 
 255         if ((flags & MAP_ALIGN) && ((uintptr_t)*addrp > align_amount)) {
 256                 align_amount = (uintptr_t)*addrp;
 257         }
 258 
 259         ASSERT(ISP2(align_amount));
 260         ASSERT(align_amount == 0 || align_amount >= PAGESIZE);
 261 
 262         /*
 263          * Look for a large enough hole starting below the stack limit.
 264          * After finding it, use the upper part.
 265          */
 266         as_purge(as);
 267         off = off & (align_amount - 1);

 268         if (as_gap_aligned(as, len, &base, &slen, AH_HI, NULL, align_amount,
 269             PAGESIZE, off) == 0) {
 270                 caddr_t as_addr;
 271 
 272                 /*
 273                  * addr is the highest possible address to use since we have
 274                  * a PAGESIZE redzone at the beginning and end.
 275                  */
 276                 addr = base + slen - (PAGESIZE + len);
 277                 as_addr = addr;
 278                 /*
 279                  * Round address DOWN to the alignment amount and
 280                  * add the offset in.
 281                  * If addr is greater than as_addr, len would not be large
 282                  * enough to include the redzone, so we must adjust down
 283                  * by the alignment amount.
 284                  */
 285                 addr = (caddr_t)((uintptr_t)addr & (~(align_amount - 1l)));
 286                 addr += (long)off;
 287                 if (addr > as_addr) {
 288                         addr -= align_amount;
 289                 }
 290 


























 291                 ASSERT(addr > base);
 292                 ASSERT(addr + len < base + slen);
 293                 ASSERT(((uintptr_t)addr & (align_amount - 1l)) ==
 294                     ((uintptr_t)(off)));
 295                 *addrp = addr;
 296 
 297 #if defined(SF_ERRATA_57)
 298                 if (AS_TYPE_64BIT(as) && addr < errata57_limit) {
 299                         *addrp = NULL;
 300                 }
 301 #endif
 302         } else {
 303                 *addrp = NULL;  /* no more virtual space */
 304         }
 305 }
 306 
 307 /*
 308  * Platform-dependent page scrub call.
 309  */
 310 void


 332 {
 333         extern void set_kcontextreg();
 334 
 335         if (kcontextreg)
 336                 set_kcontextreg();
 337 }
 338 
 339 void
 340 contig_mem_init(void)
 341 {
 342         /* not applicable to sun4u */
 343 }
 344 
 345 /*ARGSUSED*/
 346 caddr_t
 347 contig_mem_prealloc(caddr_t alloc_base, pgcnt_t npages)
 348 {
 349         /* not applicable to sun4u */
 350         return (alloc_base);
 351 }
 352 
 353 size_t
 354 exec_get_spslew(void)
 355 {
 356         return (0);
 357 }


  29 /*
  30  * Portions of this source code were derived from Berkeley 4.3 BSD
  31  * under license from the Regents of the University of California.
  32  */
  33 
  34 /*
  35  * UNIX machine dependent virtual memory support.
  36  */
  37 
  38 #include <sys/vm.h>
  39 #include <sys/exec.h>
  40 #include <sys/cmn_err.h>
  41 #include <sys/cpu_module.h>
  42 #include <sys/cpu.h>
  43 #include <sys/elf_SPARC.h>
  44 #include <sys/archsystm.h>
  45 #include <vm/hat_sfmmu.h>
  46 #include <sys/memnode.h>
  47 #include <sys/mem_cage.h>
  48 #include <vm/vm_dep.h>
  49 #include <sys/random.h>
  50 
  51 #if defined(__sparcv9) && defined(SF_ERRATA_57)
  52 caddr_t errata57_limit;
  53 #endif
  54 
  55 uint_t page_colors = 0;
  56 uint_t page_colors_mask = 0;
  57 uint_t page_coloring_shift = 0;
  58 int consistent_coloring;
  59 int update_proc_pgcolorbase_after_fork = 0;
  60 
  61 uint_t mmu_page_sizes = DEFAULT_MMU_PAGE_SIZES;
  62 uint_t max_mmu_page_sizes = MMU_PAGE_SIZES;
  63 uint_t mmu_hashcnt = DEFAULT_MAX_HASHCNT;
  64 uint_t max_mmu_hashcnt = MAX_HASHCNT;
  65 size_t mmu_ism_pagesize = DEFAULT_ISM_PAGESIZE;
  66 
  67 /*
  68  * The sun4u hardware mapping sizes which will always be supported are
  69  * 8K, 64K, 512K and 4M.  If sun4u based machines need to support other


 121 size_t max_shm_lpsize = MMU_PAGESIZE4M;
 122 
 123 void
 124 adjust_data_maxlpsize(size_t ismpagesize)
 125 {
 126         if (max_uheap_lpsize == MMU_PAGESIZE4M) {
 127                 max_uheap_lpsize = ismpagesize;
 128         }
 129         if (max_ustack_lpsize == MMU_PAGESIZE4M) {
 130                 max_ustack_lpsize = ismpagesize;
 131         }
 132         if (max_privmap_lpsize == MMU_PAGESIZE4M) {
 133                 max_privmap_lpsize = ismpagesize;
 134         }
 135         if (max_shm_lpsize == MMU_PAGESIZE4M) {
 136                 max_shm_lpsize = ismpagesize;
 137         }
 138 }
 139 
 140 /*
 141  * The maximum amount a randomized mapping will be slewed.  We should perhaps
 142  * arrange things so these tunables can be separate for mmap, mmapobj, and
 143  * ld.so
 144  */
 145 volatile size_t aslr_max_map_skew = 256 * 1024 * 1024; /* 256MB */
 146 
 147 /*
 148  * map_addr_proc() is the routine called when the system is to
 149  * choose an address for the user.  We will pick an address
 150  * range which is just below the current stack limit.  The
 151  * algorithm used for cache consistency on machines with virtual
 152  * address caches is such that offset 0 in the vnode is always
 153  * on a shm_alignment'ed aligned address.  Unfortunately, this
 154  * means that vnodes which are demand paged will not be mapped
 155  * cache consistently with the executable images.  When the
 156  * cache alignment for a given object is inconsistent, the
 157  * lower level code must manage the translations so that this
 158  * is not seen here (at the cost of efficiency, of course).
 159  *
 160  * Every mapping will have a redzone of a single page on either side of
 161  * the request. This is done to leave one page unmapped between segments.
 162  * This is not required, but it's useful for the user because if their
 163  * program strays across a segment boundary, it will catch a fault
 164  * immediately making debugging a little easier.  Currently the redzone
 165  * is mandatory.
 166  *
 167  *


 256         if (p->p_model == DATAMODEL_LP64)
 257                 align_amount = MAX(align_amount, ELF_SPARCV9_MAXPGSZ);
 258 #ifdef VAC
 259         if (vac && vacalign && (align_amount < shm_alignment))
 260                 align_amount = shm_alignment;
 261 #endif
 262 
 263         if ((flags & MAP_ALIGN) && ((uintptr_t)*addrp > align_amount)) {
 264                 align_amount = (uintptr_t)*addrp;
 265         }
 266 
 267         ASSERT(ISP2(align_amount));
 268         ASSERT(align_amount == 0 || align_amount >= PAGESIZE);
 269 
 270         /*
 271          * Look for a large enough hole starting below the stack limit.
 272          * After finding it, use the upper part.
 273          */
 274         as_purge(as);
 275         off = off & (align_amount - 1);
 276 
 277         if (as_gap_aligned(as, len, &base, &slen, AH_HI, NULL, align_amount,
 278             PAGESIZE, off) == 0) {
 279                 caddr_t as_addr;
 280 
 281                 /*
 282                  * addr is the highest possible address to use since we have
 283                  * a PAGESIZE redzone at the beginning and end.
 284                  */
 285                 addr = base + slen - (PAGESIZE + len);
 286                 as_addr = addr;
 287                 /*
 288                  * Round address DOWN to the alignment amount and
 289                  * add the offset in.
 290                  * If addr is greater than as_addr, len would not be large
 291                  * enough to include the redzone, so we must adjust down
 292                  * by the alignment amount.
 293                  */
 294                 addr = (caddr_t)((uintptr_t)addr & (~(align_amount - 1l)));
 295                 addr += (long)off;
 296                 if (addr > as_addr) {
 297                         addr -= align_amount;
 298                 }
 299 
 300                 /*
 301                  * If randomization is requested, slew the allocation
 302                  * backwards, within the same gap, by a random amount.
 303                  *
 304                  * XXX: This will fall over in processes like Java, which
 305                  * commonly have a great many small mappings.
 306                  */
 307                 if (flags & _MAP_RANDOMIZE) {
 308                         uint32_t slew;
 309                         uint32_t maxslew;
 310 
 311                         (void) random_get_pseudo_bytes((uint8_t *)&slew,
 312                             sizeof (slew));
 313 
 314                         maxslew = MIN(aslr_max_map_skew, (addr - base));
 315                         /*
 316                          * Don't allow ASLR to cause mappings to fail below
 317                          * because of SF erratum #57
 318                          */
 319                         maxslew = MIN(maxslew, (addr - errata57_limit));
 320 
 321                         slew = slew % MIN(MIN(aslr_max_map_skew, (addr - base)),
 322                             addr - errata57_limit);
 323                         addr -= P2ALIGN(slew, align_amount);
 324                 }
 325 
 326                 ASSERT(addr > base);
 327                 ASSERT(addr + len < base + slen);
 328                 ASSERT(((uintptr_t)addr & (align_amount - 1l)) ==
 329                     ((uintptr_t)(off)));
 330                 *addrp = addr;
 331 
 332 #if defined(SF_ERRATA_57)
 333                 if (AS_TYPE_64BIT(as) && addr < errata57_limit) {
 334                         *addrp = NULL;
 335                 }
 336 #endif
 337         } else {
 338                 *addrp = NULL;  /* no more virtual space */
 339         }
 340 }
 341 
 342 /*
 343  * Platform-dependent page scrub call.
 344  */
 345 void


 367 {
 368         extern void set_kcontextreg();
 369 
 370         if (kcontextreg)
 371                 set_kcontextreg();
 372 }
 373 
 374 void
 375 contig_mem_init(void)
 376 {
 377         /* not applicable to sun4u */
 378 }
 379 
 380 /*ARGSUSED*/
 381 caddr_t
 382 contig_mem_prealloc(caddr_t alloc_base, pgcnt_t npages)
 383 {
 384         /* not applicable to sun4u */
 385         return (alloc_base);
 386 }