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 two sets of flags per-process:  The effective set and the inheritable set (see
   9 `security-flags(5)`).  The effective set is immutable, it can only change when
  10 the process calls `exec(2)`, at which point the effective set is replaced by
  11 the inheritable set (with one exception).  Security flags are inherited upon
  12 `fork(2)` (but the inheritable set is not promoted until `exec(2)`, as
  13 mentioned).
  14 
  15 This is such that a given execution of an executable has a constant set of
  16 security-flags, which simplifies things for everyone.
  17 
  18 This unfortunately means that to enable ASLR fully system-wide, requires a
  19 reboot or at least restart of a majority of services.
  20 
  21 The system-wide ASLR flag is an SMF property on the new service
  22 `svc:/system/process-security`, which contains a `secflags` property group,
  23 with one boolean property per implemented flag (see, again,
  24 `security-flags(5)`).  At present, this will not take effect (at all) until a
  25 reboot.
  26 
  27 Per-process setting (and inspecting) of security-flags is done via
  28 `psecflags(1)`.
  29 
  30 ## Privilege
  31 
  32 A process may change the security-flags of any process to which it could send
  33 a signal with `kill(2)`, as long as the process also has the
  34 `PRIV_PROC_SECFLAGS` privilege.  This privilege is granted by default, but is
  35 not a `basic` privilege.  If you have configured custom privileges for certain
  36 users or services, they will not automatically gain the new
  37 `PRIV_PROC_SECFLAGS` (unfortunately).
  38 
  39 ## Executable tagging
  40 
  41 There is a somewhat compatible property of dynamic executables, `DT_SUNW_ASLR`
  42 which controls the ASLR behaviour of a given executable.  If this dynamic tag
  43 has a value of 1, ASLR is always enabled for an execution of this process.  If
  44 the tag has a value of 0, ASLR is never enabled for an execution of this
  45 process.  The default is to inherit the ASLR flag as normal.
  46 
  47 This allows a process for which ASLR is known to be problematic to explicitly
  48 forbid it, and for processes of special sensitivity to mandate it.
  49 
  50 This is controlled via the `-z aslr` flag to `ld(1)`.
  51 
  52 ## Missing bits/Problems/Worries
  53 
  54 ### The stack skewing may skew too much of the stack
  55 
  56 At present, we skew the absolute base of the stack, which means the gap
  57 between a user stack frame and the process environment is constant.  I have
  58 this vague memory that that's sub-par, and that we want to skew the stack
  59 _after_ the environment, etc.  I could be entirely wrong about that though.
  60 
  61 ### We skew each mapping separately
  62 
  63 Some systems calculate a random skew for the various parts of a process at
  64 execution time, and apply that same skew to each mapping.  That obviously
  65 minimises the performance impact of this significantly for processes that
  66 perform many mappings.
  67 
  68 Due to some unfortunate aspects of how we manage the user address space and
  69 mappings, we don't do that right now.  We calculate a separate random skew for
  70 each mapping we attempt.
  71 
  72 ### The way we skew mappings is problematic
  73 
  74 The user address space is currently managed somewhat unfortunately (from our
  75 point of view, at least).  When attempting a mapping we first determine the
  76 highest gap into which the requested mapping can fit, and then we place the
  77 mapping at the highest address in that gap.  This is how we manage user
  78 fragmentation.
  79 
  80 The current ASLR implementation works in basically the same way.  We still
  81 find the highest gap into which the given mapping may fit, and choose the
  82 highest address at which it may fit.  The only difference is that we then slew
  83 it backward by a random (but co-aligned), amount.
  84 
  85 This is obviously not as random as it could be, but is the easiest way I've
  86 found in the current code base for introducing uncertainty while also
  87 preserving any attempt at preventing unbounded user fragmentation.  
  88 
  89 It is not impossible to imagine a long-lived process that makes many mappings
  90 being in a position where mappings later in its life are 100% predictable
  91 given this implementation, however.  In fact, I think it is fairly likely.
  92 
  93 I think the most at risk would be a process which makes many mappings, and
  94 uses `dlopen(3c)` at unpredictable times (rather than, as is most common, during
  95 setup).  Dynamic objects tend to have strict (and high) alignment requirements
  96 which in such a process are likely to only be fulfillable at a single location
  97 in the address space gap we choose, and thus be entirely predictable.
  98  
  99 ### We want a per-zone configuration item, but it's not implemented yet
 100 
 101 I plan to implement a per-zone configuration item similar to `limitpriv` which
 102 describes a zones default security-flags.  This will be set during
 103 `zone_create` and apply to _every_ process in a zone (rather than the GZ
 104 implementation, from which `svc.startd(1M)`, `svc.configd(1M)`, and `init(1M)`
 105 are immune unless tagged).
 106 
 107 This will also allow a global zone administrator to configure the
 108 security-flags of a zone, and then take `PRIV_PROC_SECFLAGS` away from that
 109 zone, such that the security-flag configuration of the zone is forced upon it.
 110 
 111 This is somewhat ugly though, since `svc:/system/process-security` and its
 112 settings in the zone will thus be inoperative.
 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).