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 <kaleshsingh@google.com>
This commit is contained in:
Kalesh Singh 2024-04-09 11:48:52 -07:00
parent f390fbca3e
commit e1e747984f

View file

@ -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;
}