execve fix for v6.15-rc7

- binfmt_elf: Move brk for static PIE even if ASLR disabled
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYKAB0WIQRSPkdeREjth1dHnSE2KwveOeQkuwUCaCS8WQAKCRA2KwveOeQk
 u2XQAQDmhWxSh1m16/N3Utlph0h1+YpzJaJltYmrb4IV7w/WKgD/W7o1359gzhw4
 VfDc6nEbjpf678pAUc+seLnX82OYwwI=
 =da0V
 -----END PGP SIGNATURE-----

Merge tag 'execve-v6.15-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux

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
This commit is contained in:
Linus Torvalds 2025-05-14 09:15:16 -07:00
commit 1a80a098c6

View File

@ -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)) {
/**
* 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_COMPAT_BRK) &&
IS_ENABLED(CONFIG_ARCH_HAS_ELF_RANDOMIZE) &&
elf_ex->e_type == ET_DYN && !interpreter) {
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) {
/*
* 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.
* If we didn't move the brk to ELF_ET_DYN_BASE (above),
* leave a gap between .bss and brk.
*/
if (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. */
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,