Skip to content

Commit 439a846

Browse files
committed
binfmt_elf: Avoid total_mapping_size for ET_EXEC
Partially revert commit 5f501d5 ("binfmt_elf: reintroduce using MAP_FIXED_NOREPLACE"), which applied the ET_DYN "total_mapping_size" logic also to ET_EXEC. At least ia64 has ET_EXEC PT_LOAD segments that are not virtual-address contiguous (but _are_ file-offset contiguous). This would result in a giant mapping attempting to cover the entire span, including the virtual address range hole, and well beyond the size of the ELF file itself, causing the kernel to refuse to load it. For example: $ readelf -lW /usr/bin/gcc ... Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz ... ... LOAD 0x000000 0x4000000000000000 0x4000000000000000 0x00b5a0 0x00b5a0 ... LOAD 0x00b5a0 0x600000000000b5a0 0x600000000000b5a0 0x0005ac 0x000710 ... ... ^^^^^^^^ ^^^^^^^^^^^^^^^^^^ ^^^^^^^^ ^^^^^^^^ File offset range : 0x000000-0x00bb4c 0x00bb4c bytes Virtual address range : 0x4000000000000000-0x600000000000bcb0 0x200000000000bcb0 bytes Remove the total_mapping_size logic for ET_EXEC, which reduces the ET_EXEC MAP_FIXED_NOREPLACE coverage to only the first PT_LOAD (better than nothing), and retains it for ET_DYN. Ironically, this is the reverse of the problem that originally caused problems with MAP_FIXED_NOREPLACE: overlapping PT_LOAD segments. Future work could restore full coverage if load_elf_binary() were to perform mappings in a separate phase from the loading (where it could resolve both overlaps and holes). Cc: Eric Biederman <[email protected]> Cc: Alexander Viro <[email protected]> Cc: [email protected] Cc: [email protected] Reported-by: matoro <[email protected]> Fixes: 5f501d5 ("binfmt_elf: reintroduce using MAP_FIXED_NOREPLACE") Link: https://lore.kernel.org/r/[email protected] Tested-by: matoro <[email protected]> Link: https://lore.kernel.org/lkml/[email protected] Tested-By: John Paul Adrian Glaubitz <[email protected]> Link: https://lore.kernel.org/lkml/[email protected] Cc: [email protected] Signed-off-by: Kees Cook <[email protected]>
1 parent dfd42fa commit 439a846

File tree

1 file changed

+18
-7
lines changed

1 file changed

+18
-7
lines changed

fs/binfmt_elf.c

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1135,14 +1135,25 @@ static int load_elf_binary(struct linux_binprm *bprm)
11351135
* is then page aligned.
11361136
*/
11371137
load_bias = ELF_PAGESTART(load_bias - vaddr);
1138-
}
11391138

1140-
/*
1141-
* Calculate the entire size of the ELF mapping (total_size).
1142-
* (Note that load_addr_set is set to true later once the
1143-
* initial mapping is performed.)
1144-
*/
1145-
if (!load_addr_set) {
1139+
/*
1140+
* Calculate the entire size of the ELF mapping
1141+
* (total_size), used for the initial mapping,
1142+
* due to load_addr_set which is set to true later
1143+
* once the initial mapping is performed.
1144+
*
1145+
* Note that this is only sensible when the LOAD
1146+
* segments are contiguous (or overlapping). If
1147+
* used for LOADs that are far apart, this would
1148+
* cause the holes between LOADs to be mapped,
1149+
* running the risk of having the mapping fail,
1150+
* as it would be larger than the ELF file itself.
1151+
*
1152+
* As a result, only ET_DYN does this, since
1153+
* some ET_EXEC (e.g. ia64) may have large virtual
1154+
* memory holes between LOADs.
1155+
*
1156+
*/
11461157
total_size = total_mapping_size(elf_phdata,
11471158
elf_ex->e_phnum);
11481159
if (!total_size) {

0 commit comments

Comments
 (0)