1 # Address Space Layout Randomisation
   2 
   3 Briefly, see: `psecflags(1)`, `security-flags(5)`
   4 
   5 ## Administration
   6 
   7 ASLR is implemented via process security-flags (which we introduce), there are
   8 four sets of flags per-process: The effective, inheritable, upper, and lower
   9 sets (see `security-flags(5)`).  The effective set is immutable, it can only
  10 change when the process calls `exec(2)`, at which point the effective set is
  11 replaced by the inheritable set (with one exception).  Security flags are
  12 inherited upon `fork(2)` (but the inheritable set is not promoted until
  13 `exec(2)`, as mentioned).  The upper and lower sets bound the permitted values
  14 of the inheritable set.
  15 
  16 This is such that a given execution of an executable has a constant set of
  17 security-flags, which simplifies things for everyone.
  18 
  19 This unfortunately means that to enable ASLR fully system-wide, requires a
  20 reboot or at least restart of a majority of services.
  21 
  22 The system-wide ASLR flag is an SMF property on the new service
  23 `svc:/system/process-security`, which contains `default`, `upper`, and `lower`
  24 property groups, with one boolean property per implemented flag (see, again,
  25 `security-flags(5)`).  These will only affect services (and their children)
  26 started via SMF after the values have been changed.
  27 
  28 Per-process setting (and inspecting) of security-flags is done via
  29 `psecflags(1)`.
  30 
  31 Per-service setting of security-flags is achievable by the `security_flags`
  32 property on the service `method_context`.  A `default` pseudo-flag specifies
  33 the flags from `svc:/system/process-security`, and flags can be
  34 added/subtracted from there much the same as with `privileges(5)`.
  35 
  36 ## Privilege
  37 
  38 A process may change the security-flags of any process to which it could send
  39 a signal with `kill(2)`, as long as the process also has the
  40 `PRIV_PROC_SECFLAGS` privilege.  This privilege is granted by default, but is
  41 not a `basic` privilege.  If you have configured custom privileges for certain
  42 users or services, they will not automatically gain the new
  43 `PRIV_PROC_SECFLAGS` (unfortunately).
  44 
  45 ## Executable tagging
  46 
  47 There is a somewhat compatible property of dynamic executables, `DT_SUNW_ASLR`
  48 which controls the ASLR behaviour of a given executable.  If this dynamic tag
  49 has a value of 1, ASLR is always enabled for an execution of this process.  If
  50 the tag has a value of 0, ASLR is never enabled for an execution of this
  51 process.  The default is to inherit the ASLR flag as normal.
  52 
  53 This allows a process for which ASLR is known to be problematic to explicitly
  54 forbid it, and for processes of special sensitivity to mandate it.
  55 
  56 This is controlled via the `-z aslr` flag to `ld(1)`.
  57 
  58  
  59 ## Per-zone configuration
  60 
  61 The default security flags for a zone, and the upper and lower limits, may be
  62 specified with the security-flags resource in zonecfg(1M).  These are applied
  63 to every process in NGZs (unlike the GZ, where there are a small number of
  64 processes we must miss)
  65 
  66 
  67 ## Missing bits/Problems/Worries
  68 
  69 ### The stack skewing may skew too much of the stack
  70 
  71 At present, we skew the absolute base of the stack, which means the gap
  72 between a user stack frame and the process environment is constant.  I have
  73 this vague memory that that's sub-par, and that we want to skew the stack
  74 _after_ the environment, etc.  I could be entirely wrong about that though.
  75 
  76 ### We skew each mapping separately
  77 
  78 Some systems calculate a random skew for the various parts of a process at
  79 execution time, and apply that same skew to each mapping.  That obviously
  80 minimises the performance impact of this significantly for processes that
  81 perform many mappings.
  82 
  83 Due to some unfortunate aspects of how we manage the user address space and
  84 mappings, we don't do that right now.  We calculate a separate random skew for
  85 each mapping we attempt.
  86 
  87 ### The way we skew mappings is problematic
  88 
  89 The user address space is currently managed somewhat unfortunately (from our
  90 point of view, at least).  When attempting a mapping we first determine the
  91 highest gap into which the requested mapping can fit, and then we place the
  92 mapping at the highest address in that gap.  This is how we manage user
  93 fragmentation.
  94 
  95 The current ASLR implementation works in basically the same way.  We still
  96 find the highest gap into which the given mapping may fit, and choose the
  97 highest address at which it may fit.  The only difference is that we then slew
  98 it backward by a random (but co-aligned), amount.
  99 
 100 This is obviously not as random as it could be, but is the easiest way I've
 101 found in the current code base for introducing uncertainty while also
 102 preserving any attempt at preventing unbounded user fragmentation.  
 103 
 104 It is not impossible to imagine a long-lived process that makes many mappings
 105 being in a position where mappings later in its life are 100% predictable
 106 given this implementation, however.  In fact, I think it is fairly likely.
 107 
 108 I think the most at risk would be a process which makes many mappings, and
 109 uses `dlopen(3c)` at unpredictable times (rather than, as is most common, during
 110 setup).  Dynamic objects tend to have strict (and high) alignment requirements
 111 which in such a process are likely to only be fulfillable at a single location
 112 in the address space gap we choose, and thus be entirely predictable.
 113 
 114 ### Randomisation of executable base addresses requires PIE
 115 
 116 To randomise the executable base address, we need position independent
 117 executables, which appears like it would turn into a whole separate project
 118 (though perhaps not too large a project).  That code isn't here, so the
 119 executable base is fixed.
 120 
 121 This means that rather than return-to-libc one could return-to-executable
 122 trivially and successfully, I think.  (That would include using the
 123 executable's PLT to vector yourself to libc.  Should the executable have a PLT
 124 entry for something useful to you).