Commit 1a80a098 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull execve fix from Kees Cook:
 "This fixes a corner case for ASLR-disabled static-PIE brk collision
  with vdso allocations:

   - binfmt_elf: Move brk for static PIE even if ASLR disabled"

* tag 'execve-v6.15-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux:
  binfmt_elf: Move brk for static PIE even if ASLR disabled
parents 00f281fd 11854fe2
Loading
Loading
Loading
Loading
+47 −24
Original line number Diff line number Diff line
@@ -830,6 +830,7 @@ static int load_elf_binary(struct linux_binprm *bprm)
	struct elf_phdr *elf_ppnt, *elf_phdata, *interp_elf_phdata = NULL;
	struct elf_phdr *elf_property_phdata = NULL;
	unsigned long elf_brk;
	bool brk_moved = false;
	int retval, i;
	unsigned long elf_entry;
	unsigned long e_entry;
@@ -1097,15 +1098,19 @@ static int load_elf_binary(struct linux_binprm *bprm)
			/* Calculate any requested alignment. */
			alignment = maximum_alignment(elf_phdata, elf_ex->e_phnum);

			/*
			 * There are effectively two types of ET_DYN
			 * binaries: programs (i.e. PIE: ET_DYN with PT_INTERP)
			 * and loaders (ET_DYN without PT_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
			/**
			 * DOC: PIE handling
			 *
			 * There are effectively two types of ET_DYN ELF
			 * binaries: programs (i.e. PIE: ET_DYN with
			 * PT_INTERP) and loaders (i.e. static PIE: ET_DYN
			 * without PT_INTERP, usually the ELF interpreter
			 * itself). 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
@@ -1118,6 +1123,9 @@ static int load_elf_binary(struct linux_binprm *bprm)
			 * ELF_ET_DYN_BASE and loaders are loaded into the
			 * independently randomized mmap region (0 load_bias
			 * without MAP_FIXED nor MAP_FIXED_NOREPLACE).
			 *
			 * See below for "brk" handling details, which is
			 * also affected by program vs loader and ASLR.
			 */
			if (interpreter) {
				/* On ET_DYN with PT_INTERP, we do the ASLR. */
@@ -1234,8 +1242,6 @@ static int load_elf_binary(struct linux_binprm *bprm)
	start_data += load_bias;
	end_data += load_bias;

	current->mm->start_brk = current->mm->brk = ELF_PAGEALIGN(elf_brk);

	if (interpreter) {
		elf_entry = load_elf_interp(interp_elf_ex,
					    interpreter,
@@ -1291,27 +1297,44 @@ static int load_elf_binary(struct linux_binprm *bprm)
	mm->end_data = end_data;
	mm->start_stack = bprm->p;

	if ((current->flags & PF_RANDOMIZE) && (snapshot_randomize_va_space > 1)) {
		/*
		 * For architectures with ELF randomization, when executing
		 * a loader directly (i.e. no interpreter listed in ELF
		 * headers), move the brk area out of the mmap region
		 * (since it grows up, and may collide early with the stack
		 * growing down), and into the unused ELF_ET_DYN_BASE region.
	/**
	 * DOC: "brk" handling
	 *
	 * For architectures with ELF randomization, when executing a
	 * loader directly (i.e. static PIE: ET_DYN without PT_INTERP),
	 * move the brk area out of the mmap region and into the unused
	 * ELF_ET_DYN_BASE region. Since "brk" grows up it may collide
	 * early with the stack growing down or other regions being put
	 * into the mmap region by the kernel (e.g. vdso).
	 *
	 * In the CONFIG_COMPAT_BRK case, though, everything is turned
	 * off because we're not allowed to move the brk at all.
	 */
		if (IS_ENABLED(CONFIG_ARCH_HAS_ELF_RANDOMIZE) &&
	if (!IS_ENABLED(CONFIG_COMPAT_BRK) &&
	    IS_ENABLED(CONFIG_ARCH_HAS_ELF_RANDOMIZE) &&
	    elf_ex->e_type == ET_DYN && !interpreter) {
			mm->brk = mm->start_brk = ELF_ET_DYN_BASE;
		} else {
			/* Otherwise leave a gap between .bss and brk. */
			mm->brk = mm->start_brk = mm->brk + PAGE_SIZE;
		elf_brk = ELF_ET_DYN_BASE;
		/* This counts as moving the brk, so let brk(2) know. */
		brk_moved = true;
	}
	mm->start_brk = mm->brk = ELF_PAGEALIGN(elf_brk);

	if ((current->flags & PF_RANDOMIZE) && snapshot_randomize_va_space > 1) {
		/*
		 * If we didn't move the brk to ELF_ET_DYN_BASE (above),
		 * leave a gap between .bss and brk.
		 */
		if (!brk_moved)
			mm->brk = mm->start_brk = mm->brk + PAGE_SIZE;

		mm->brk = mm->start_brk = arch_randomize_brk(mm);
		brk_moved = true;
	}

#ifdef compat_brk_randomized
	if (brk_moved)
		current->brk_randomized = 1;
#endif
	}

	if (current->personality & MMAP_PAGE_ZERO) {
		/* Why this, you ask???  Well SVr4 maps page 0 as read-only,