|
@@ -927,17 +927,60 @@ static int load_elf_binary(struct linux_binprm *bprm)
|
|
|
elf_flags = MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE;
|
|
|
|
|
|
vaddr = elf_ppnt->p_vaddr;
|
|
|
+ /*
|
|
|
+ * If we are loading ET_EXEC or we have already performed
|
|
|
+ * the ET_DYN load_addr calculations, proceed normally.
|
|
|
+ */
|
|
|
if (loc->elf_ex.e_type == ET_EXEC || load_addr_set) {
|
|
|
elf_flags |= MAP_FIXED;
|
|
|
} else if (loc->elf_ex.e_type == ET_DYN) {
|
|
|
- /* Try and get dynamic programs out of the way of the
|
|
|
- * default mmap base, as well as whatever program they
|
|
|
- * might try to exec. This is because the brk will
|
|
|
- * follow the loader, and is not movable. */
|
|
|
- load_bias = ELF_ET_DYN_BASE - vaddr;
|
|
|
- if (current->flags & PF_RANDOMIZE)
|
|
|
- load_bias += arch_mmap_rnd();
|
|
|
- load_bias = ELF_PAGESTART(load_bias);
|
|
|
+ /*
|
|
|
+ * This logic is run once for the first LOAD Program
|
|
|
+ * Header for ET_DYN binaries to calculate the
|
|
|
+ * randomization (load_bias) for all the LOAD
|
|
|
+ * Program Headers, and to calculate the entire
|
|
|
+ * size of the ELF mapping (total_size). (Note that
|
|
|
+ * load_addr_set is set to true later once the
|
|
|
+ * initial mapping is performed.)
|
|
|
+ *
|
|
|
+ * There are effectively two types of ET_DYN
|
|
|
+ * binaries: programs (i.e. PIE: ET_DYN with INTERP)
|
|
|
+ * and loaders (ET_DYN without INTERP, since they
|
|
|
+ * _are_ the ELF interpreter). The loaders must
|
|
|
+ * be loaded away from programs since the program
|
|
|
+ * may otherwise collide with the loader (especially
|
|
|
+ * for ET_EXEC which does not have a randomized
|
|
|
+ * position). For example to handle invocations of
|
|
|
+ * "./ld.so someprog" to test out a new version of
|
|
|
+ * the loader, the subsequent program that the
|
|
|
+ * loader loads must avoid the loader itself, so
|
|
|
+ * they cannot share the same load range. Sufficient
|
|
|
+ * room for the brk must be allocated with the
|
|
|
+ * loader as well, since brk must be available with
|
|
|
+ * the loader.
|
|
|
+ *
|
|
|
+ * Therefore, programs are loaded offset from
|
|
|
+ * ELF_ET_DYN_BASE and loaders are loaded into the
|
|
|
+ * independently randomized mmap region (0 load_bias
|
|
|
+ * without MAP_FIXED).
|
|
|
+ */
|
|
|
+ if (elf_interpreter) {
|
|
|
+ load_bias = ELF_ET_DYN_BASE;
|
|
|
+ if (current->flags & PF_RANDOMIZE)
|
|
|
+ load_bias += arch_mmap_rnd();
|
|
|
+ elf_flags |= MAP_FIXED;
|
|
|
+ } else
|
|
|
+ load_bias = 0;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Since load_bias is used for all subsequent loading
|
|
|
+ * calculations, we must lower it by the first vaddr
|
|
|
+ * so that the remaining calculations based on the
|
|
|
+ * ELF vaddrs will be correctly offset. The result
|
|
|
+ * is then page aligned.
|
|
|
+ */
|
|
|
+ load_bias = ELF_PAGESTART(load_bias - vaddr);
|
|
|
+
|
|
|
total_size = total_mapping_size(elf_phdata,
|
|
|
loc->elf_ex.e_phnum);
|
|
|
if (!total_size) {
|