From e1e747984f6d6f71435da1606101940cf4b9dbac Mon Sep 17 00:00:00 2001 From: Kalesh Singh Date: Tue, 9 Apr 2024 11:48:52 -0700 Subject: [PATCH] bionic: loader: Don't extend LOAD segments for p_aligns > 64KiB Loader segment extension was introduced to fix kernel slab memory regressions in page-agnostic Android. This reression was due to required VMAs for the gap VMAs that exist when the elf-max-page-size > runtime-page-size. This issue already existed for some libraries like libart.so and libhwui.so which use 2mB alignment to make use of THPs (transparent huge pages). Later it was found that this optimization could break in-field apps due to dependencies and the address ranges in /proc/*/[s]maps. To avoid breaking the in-field apps, the kernel can work around the compatibility issues if made aware of where the padding regions exist. However, the kernel can only represent padding for p_align up to 64KiB. This is because the kernel uses 4 available bits in the vm_area_struct to represent padding extent; and so cannot enable mitigations to avoid breaking app compatibility for p_aligns > 64KiB. For ELFs with p_align > 64KiB, don't do segment extension, to avoid issues with app compatibility -- these ELFs already exist with gap mappings and are not part of the page size transition VMA slab regression. Bug: 330117029 Bug: 327600007 Bug: 330767927 Bug: 328266487 Bug: 329803029 Test: Manual - Launch Free Fire Chaos app Change-Id: Id4dcced4632dce67adab6348816f85847ce1de58 Signed-off-by: Kalesh Singh --- linker/linker_phdr.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/linker/linker_phdr.cpp b/linker/linker_phdr.cpp index ef7671cee..685ae7082 100644 --- a/linker/linker_phdr.cpp +++ b/linker/linker_phdr.cpp @@ -773,7 +773,16 @@ static inline void _extend_load_segment_vma(const ElfW(Phdr)* phdr_table, size_t const ElfW(Phdr)* next = nullptr; size_t next_idx = phdr_idx + 1; - if (phdr->p_align == kPageSize || !should_pad_segments) { + // Don't do segment extension for p_align > 64KiB, such ELFs already existed in the + // field e.g. 2MiB p_align for THPs and are relatively small in number. + // + // The kernel can only represent padding for p_align up to 64KiB. This is because + // the kernel uses 4 available bits in the vm_area_struct to represent padding + // extent; and so cannot enable mitigations to avoid breaking app compatibility for + // p_aligns > 64KiB. + // + // Don't perform segment extension on these to avoid app compatibility issues. + if (phdr->p_align <= kPageSize || phdr->p_align > 64*1024 || !should_pad_segments) { return; }