xref: /aosp_15_r20/bionic/linker/linker_phdr.cpp (revision 8d67ca893c1523eb926b9080dbe4e2ffd2a27ba1)
1*8d67ca89SAndroid Build Coastguard Worker /*
2*8d67ca89SAndroid Build Coastguard Worker  * Copyright (C) 2012 The Android Open Source Project
3*8d67ca89SAndroid Build Coastguard Worker  * All rights reserved.
4*8d67ca89SAndroid Build Coastguard Worker  *
5*8d67ca89SAndroid Build Coastguard Worker  * Redistribution and use in source and binary forms, with or without
6*8d67ca89SAndroid Build Coastguard Worker  * modification, are permitted provided that the following conditions
7*8d67ca89SAndroid Build Coastguard Worker  * are met:
8*8d67ca89SAndroid Build Coastguard Worker  *  * Redistributions of source code must retain the above copyright
9*8d67ca89SAndroid Build Coastguard Worker  *    notice, this list of conditions and the following disclaimer.
10*8d67ca89SAndroid Build Coastguard Worker  *  * Redistributions in binary form must reproduce the above copyright
11*8d67ca89SAndroid Build Coastguard Worker  *    notice, this list of conditions and the following disclaimer in
12*8d67ca89SAndroid Build Coastguard Worker  *    the documentation and/or other materials provided with the
13*8d67ca89SAndroid Build Coastguard Worker  *    distribution.
14*8d67ca89SAndroid Build Coastguard Worker  *
15*8d67ca89SAndroid Build Coastguard Worker  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16*8d67ca89SAndroid Build Coastguard Worker  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17*8d67ca89SAndroid Build Coastguard Worker  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18*8d67ca89SAndroid Build Coastguard Worker  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19*8d67ca89SAndroid Build Coastguard Worker  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20*8d67ca89SAndroid Build Coastguard Worker  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21*8d67ca89SAndroid Build Coastguard Worker  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22*8d67ca89SAndroid Build Coastguard Worker  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23*8d67ca89SAndroid Build Coastguard Worker  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24*8d67ca89SAndroid Build Coastguard Worker  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25*8d67ca89SAndroid Build Coastguard Worker  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26*8d67ca89SAndroid Build Coastguard Worker  * SUCH DAMAGE.
27*8d67ca89SAndroid Build Coastguard Worker  */
28*8d67ca89SAndroid Build Coastguard Worker 
29*8d67ca89SAndroid Build Coastguard Worker #include "linker_phdr.h"
30*8d67ca89SAndroid Build Coastguard Worker 
31*8d67ca89SAndroid Build Coastguard Worker #include <errno.h>
32*8d67ca89SAndroid Build Coastguard Worker #include <string.h>
33*8d67ca89SAndroid Build Coastguard Worker #include <sys/mman.h>
34*8d67ca89SAndroid Build Coastguard Worker #include <sys/prctl.h>
35*8d67ca89SAndroid Build Coastguard Worker #include <sys/types.h>
36*8d67ca89SAndroid Build Coastguard Worker #include <sys/stat.h>
37*8d67ca89SAndroid Build Coastguard Worker #include <unistd.h>
38*8d67ca89SAndroid Build Coastguard Worker 
39*8d67ca89SAndroid Build Coastguard Worker #include "linker.h"
40*8d67ca89SAndroid Build Coastguard Worker #include "linker_debug.h"
41*8d67ca89SAndroid Build Coastguard Worker #include "linker_dlwarning.h"
42*8d67ca89SAndroid Build Coastguard Worker #include "linker_globals.h"
43*8d67ca89SAndroid Build Coastguard Worker #include "linker_logger.h"
44*8d67ca89SAndroid Build Coastguard Worker #include "linker_main.h"
45*8d67ca89SAndroid Build Coastguard Worker #include "linker_soinfo.h"
46*8d67ca89SAndroid Build Coastguard Worker #include "linker_utils.h"
47*8d67ca89SAndroid Build Coastguard Worker 
48*8d67ca89SAndroid Build Coastguard Worker #include "private/bionic_asm_note.h"
49*8d67ca89SAndroid Build Coastguard Worker #include "private/CFIShadow.h" // For kLibraryAlignment
50*8d67ca89SAndroid Build Coastguard Worker #include "private/elf_note.h"
51*8d67ca89SAndroid Build Coastguard Worker 
52*8d67ca89SAndroid Build Coastguard Worker #include <android-base/file.h>
53*8d67ca89SAndroid Build Coastguard Worker #include <android-base/properties.h>
54*8d67ca89SAndroid Build Coastguard Worker 
GetTargetElfMachine()55*8d67ca89SAndroid Build Coastguard Worker static int GetTargetElfMachine() {
56*8d67ca89SAndroid Build Coastguard Worker #if defined(__arm__)
57*8d67ca89SAndroid Build Coastguard Worker   return EM_ARM;
58*8d67ca89SAndroid Build Coastguard Worker #elif defined(__aarch64__)
59*8d67ca89SAndroid Build Coastguard Worker   return EM_AARCH64;
60*8d67ca89SAndroid Build Coastguard Worker #elif defined(__i386__)
61*8d67ca89SAndroid Build Coastguard Worker   return EM_386;
62*8d67ca89SAndroid Build Coastguard Worker #elif defined(__riscv)
63*8d67ca89SAndroid Build Coastguard Worker   return EM_RISCV;
64*8d67ca89SAndroid Build Coastguard Worker #elif defined(__x86_64__)
65*8d67ca89SAndroid Build Coastguard Worker   return EM_X86_64;
66*8d67ca89SAndroid Build Coastguard Worker #endif
67*8d67ca89SAndroid Build Coastguard Worker }
68*8d67ca89SAndroid Build Coastguard Worker 
69*8d67ca89SAndroid Build Coastguard Worker /**
70*8d67ca89SAndroid Build Coastguard Worker   TECHNICAL NOTE ON ELF LOADING.
71*8d67ca89SAndroid Build Coastguard Worker 
72*8d67ca89SAndroid Build Coastguard Worker   An ELF file's program header table contains one or more PT_LOAD
73*8d67ca89SAndroid Build Coastguard Worker   segments, which corresponds to portions of the file that need to
74*8d67ca89SAndroid Build Coastguard Worker   be mapped into the process' address space.
75*8d67ca89SAndroid Build Coastguard Worker 
76*8d67ca89SAndroid Build Coastguard Worker   Each loadable segment has the following important properties:
77*8d67ca89SAndroid Build Coastguard Worker 
78*8d67ca89SAndroid Build Coastguard Worker     p_offset  -> segment file offset
79*8d67ca89SAndroid Build Coastguard Worker     p_filesz  -> segment file size
80*8d67ca89SAndroid Build Coastguard Worker     p_memsz   -> segment memory size (always >= p_filesz)
81*8d67ca89SAndroid Build Coastguard Worker     p_vaddr   -> segment's virtual address
82*8d67ca89SAndroid Build Coastguard Worker     p_flags   -> segment flags (e.g. readable, writable, executable)
83*8d67ca89SAndroid Build Coastguard Worker     p_align   -> segment's in-memory and in-file alignment
84*8d67ca89SAndroid Build Coastguard Worker 
85*8d67ca89SAndroid Build Coastguard Worker   We will ignore the p_paddr field of ElfW(Phdr) for now.
86*8d67ca89SAndroid Build Coastguard Worker 
87*8d67ca89SAndroid Build Coastguard Worker   The loadable segments can be seen as a list of [p_vaddr ... p_vaddr+p_memsz)
88*8d67ca89SAndroid Build Coastguard Worker   ranges of virtual addresses. A few rules apply:
89*8d67ca89SAndroid Build Coastguard Worker 
90*8d67ca89SAndroid Build Coastguard Worker   - the virtual address ranges should not overlap.
91*8d67ca89SAndroid Build Coastguard Worker 
92*8d67ca89SAndroid Build Coastguard Worker   - if a segment's p_filesz is smaller than its p_memsz, the extra bytes
93*8d67ca89SAndroid Build Coastguard Worker     between them should always be initialized to 0.
94*8d67ca89SAndroid Build Coastguard Worker 
95*8d67ca89SAndroid Build Coastguard Worker   - ranges do not necessarily start or end at page boundaries. Two distinct
96*8d67ca89SAndroid Build Coastguard Worker     segments can have their start and end on the same page. In this case, the
97*8d67ca89SAndroid Build Coastguard Worker     page inherits the mapping flags of the latter segment.
98*8d67ca89SAndroid Build Coastguard Worker 
99*8d67ca89SAndroid Build Coastguard Worker   Finally, the real load addrs of each segment is not p_vaddr. Instead the
100*8d67ca89SAndroid Build Coastguard Worker   loader decides where to load the first segment, then will load all others
101*8d67ca89SAndroid Build Coastguard Worker   relative to the first one to respect the initial range layout.
102*8d67ca89SAndroid Build Coastguard Worker 
103*8d67ca89SAndroid Build Coastguard Worker   For example, consider the following list:
104*8d67ca89SAndroid Build Coastguard Worker 
105*8d67ca89SAndroid Build Coastguard Worker     [ offset:0,      filesz:0x4000, memsz:0x4000, vaddr:0x30000 ],
106*8d67ca89SAndroid Build Coastguard Worker     [ offset:0x4000, filesz:0x2000, memsz:0x8000, vaddr:0x40000 ],
107*8d67ca89SAndroid Build Coastguard Worker 
108*8d67ca89SAndroid Build Coastguard Worker   This corresponds to two segments that cover these virtual address ranges:
109*8d67ca89SAndroid Build Coastguard Worker 
110*8d67ca89SAndroid Build Coastguard Worker        0x30000...0x34000
111*8d67ca89SAndroid Build Coastguard Worker        0x40000...0x48000
112*8d67ca89SAndroid Build Coastguard Worker 
113*8d67ca89SAndroid Build Coastguard Worker   If the loader decides to load the first segment at address 0xa0000000
114*8d67ca89SAndroid Build Coastguard Worker   then the segments' load address ranges will be:
115*8d67ca89SAndroid Build Coastguard Worker 
116*8d67ca89SAndroid Build Coastguard Worker        0xa0030000...0xa0034000
117*8d67ca89SAndroid Build Coastguard Worker        0xa0040000...0xa0048000
118*8d67ca89SAndroid Build Coastguard Worker 
119*8d67ca89SAndroid Build Coastguard Worker   In other words, all segments must be loaded at an address that has the same
120*8d67ca89SAndroid Build Coastguard Worker   constant offset from their p_vaddr value. This offset is computed as the
121*8d67ca89SAndroid Build Coastguard Worker   difference between the first segment's load address, and its p_vaddr value.
122*8d67ca89SAndroid Build Coastguard Worker 
123*8d67ca89SAndroid Build Coastguard Worker   However, in practice, segments do _not_ start at page boundaries. Since we
124*8d67ca89SAndroid Build Coastguard Worker   can only memory-map at page boundaries, this means that the bias is
125*8d67ca89SAndroid Build Coastguard Worker   computed as:
126*8d67ca89SAndroid Build Coastguard Worker 
127*8d67ca89SAndroid Build Coastguard Worker        load_bias = phdr0_load_address - page_start(phdr0->p_vaddr)
128*8d67ca89SAndroid Build Coastguard Worker 
129*8d67ca89SAndroid Build Coastguard Worker   (NOTE: The value must be used as a 32-bit unsigned integer, to deal with
130*8d67ca89SAndroid Build Coastguard Worker           possible wrap around UINT32_MAX for possible large p_vaddr values).
131*8d67ca89SAndroid Build Coastguard Worker 
132*8d67ca89SAndroid Build Coastguard Worker   And that the phdr0_load_address must start at a page boundary, with
133*8d67ca89SAndroid Build Coastguard Worker   the segment's real content starting at:
134*8d67ca89SAndroid Build Coastguard Worker 
135*8d67ca89SAndroid Build Coastguard Worker        phdr0_load_address + page_offset(phdr0->p_vaddr)
136*8d67ca89SAndroid Build Coastguard Worker 
137*8d67ca89SAndroid Build Coastguard Worker   Note that ELF requires the following condition to make the mmap()-ing work:
138*8d67ca89SAndroid Build Coastguard Worker 
139*8d67ca89SAndroid Build Coastguard Worker       page_offset(phdr0->p_vaddr) == page_offset(phdr0->p_offset)
140*8d67ca89SAndroid Build Coastguard Worker 
141*8d67ca89SAndroid Build Coastguard Worker   The load_bias must be added to any p_vaddr value read from the ELF file to
142*8d67ca89SAndroid Build Coastguard Worker   determine the corresponding memory address.
143*8d67ca89SAndroid Build Coastguard Worker 
144*8d67ca89SAndroid Build Coastguard Worker  **/
145*8d67ca89SAndroid Build Coastguard Worker 
146*8d67ca89SAndroid Build Coastguard Worker static const size_t kPageSize = page_size();
147*8d67ca89SAndroid Build Coastguard Worker 
148*8d67ca89SAndroid Build Coastguard Worker /*
149*8d67ca89SAndroid Build Coastguard Worker  * Generic PMD size calculation:
150*8d67ca89SAndroid Build Coastguard Worker  *    - Each page table (PT) is of size 1 page.
151*8d67ca89SAndroid Build Coastguard Worker  *    - Each page table entry (PTE) is of size 64 bits.
152*8d67ca89SAndroid Build Coastguard Worker  *    - Each PTE locates one physical page frame (PFN) of size 1 page.
153*8d67ca89SAndroid Build Coastguard Worker  *    - A PMD entry locates 1 page table (PT)
154*8d67ca89SAndroid Build Coastguard Worker  *
155*8d67ca89SAndroid Build Coastguard Worker  *   PMD size = Num entries in a PT * page_size
156*8d67ca89SAndroid Build Coastguard Worker  */
157*8d67ca89SAndroid Build Coastguard Worker static const size_t kPmdSize = (kPageSize / sizeof(uint64_t)) * kPageSize;
158*8d67ca89SAndroid Build Coastguard Worker 
ElfReader()159*8d67ca89SAndroid Build Coastguard Worker ElfReader::ElfReader()
160*8d67ca89SAndroid Build Coastguard Worker     : did_read_(false), did_load_(false), fd_(-1), file_offset_(0), file_size_(0), phdr_num_(0),
161*8d67ca89SAndroid Build Coastguard Worker       phdr_table_(nullptr), shdr_table_(nullptr), shdr_num_(0), dynamic_(nullptr), strtab_(nullptr),
162*8d67ca89SAndroid Build Coastguard Worker       strtab_size_(0), load_start_(nullptr), load_size_(0), load_bias_(0), loaded_phdr_(nullptr),
163*8d67ca89SAndroid Build Coastguard Worker       mapped_by_caller_(false) {
164*8d67ca89SAndroid Build Coastguard Worker }
165*8d67ca89SAndroid Build Coastguard Worker 
Read(const char * name,int fd,off64_t file_offset,off64_t file_size)166*8d67ca89SAndroid Build Coastguard Worker bool ElfReader::Read(const char* name, int fd, off64_t file_offset, off64_t file_size) {
167*8d67ca89SAndroid Build Coastguard Worker   if (did_read_) {
168*8d67ca89SAndroid Build Coastguard Worker     return true;
169*8d67ca89SAndroid Build Coastguard Worker   }
170*8d67ca89SAndroid Build Coastguard Worker   name_ = name;
171*8d67ca89SAndroid Build Coastguard Worker   fd_ = fd;
172*8d67ca89SAndroid Build Coastguard Worker   file_offset_ = file_offset;
173*8d67ca89SAndroid Build Coastguard Worker   file_size_ = file_size;
174*8d67ca89SAndroid Build Coastguard Worker 
175*8d67ca89SAndroid Build Coastguard Worker   if (ReadElfHeader() &&
176*8d67ca89SAndroid Build Coastguard Worker       VerifyElfHeader() &&
177*8d67ca89SAndroid Build Coastguard Worker       ReadProgramHeaders() &&
178*8d67ca89SAndroid Build Coastguard Worker       ReadSectionHeaders() &&
179*8d67ca89SAndroid Build Coastguard Worker       ReadDynamicSection() &&
180*8d67ca89SAndroid Build Coastguard Worker       ReadPadSegmentNote()) {
181*8d67ca89SAndroid Build Coastguard Worker     did_read_ = true;
182*8d67ca89SAndroid Build Coastguard Worker   }
183*8d67ca89SAndroid Build Coastguard Worker 
184*8d67ca89SAndroid Build Coastguard Worker   if (kPageSize == 0x4000 && phdr_table_get_minimum_alignment(phdr_table_, phdr_num_) == 0x1000) {
185*8d67ca89SAndroid Build Coastguard Worker     // This prop needs to be read on 16KiB devices for each ELF where min_palign is 4KiB.
186*8d67ca89SAndroid Build Coastguard Worker     // It cannot be cached since the developer may toggle app compat on/off.
187*8d67ca89SAndroid Build Coastguard Worker     // This check will be removed once app compat is made the default on 16KiB devices.
188*8d67ca89SAndroid Build Coastguard Worker     should_use_16kib_app_compat_ =
189*8d67ca89SAndroid Build Coastguard Worker         ::android::base::GetBoolProperty("bionic.linker.16kb.app_compat.enabled", false) ||
190*8d67ca89SAndroid Build Coastguard Worker         get_16kb_appcompat_mode();
191*8d67ca89SAndroid Build Coastguard Worker   }
192*8d67ca89SAndroid Build Coastguard Worker 
193*8d67ca89SAndroid Build Coastguard Worker   return did_read_;
194*8d67ca89SAndroid Build Coastguard Worker }
195*8d67ca89SAndroid Build Coastguard Worker 
Load(address_space_params * address_space)196*8d67ca89SAndroid Build Coastguard Worker bool ElfReader::Load(address_space_params* address_space) {
197*8d67ca89SAndroid Build Coastguard Worker   CHECK(did_read_);
198*8d67ca89SAndroid Build Coastguard Worker   if (did_load_) {
199*8d67ca89SAndroid Build Coastguard Worker     return true;
200*8d67ca89SAndroid Build Coastguard Worker   }
201*8d67ca89SAndroid Build Coastguard Worker   bool reserveSuccess = ReserveAddressSpace(address_space);
202*8d67ca89SAndroid Build Coastguard Worker   if (reserveSuccess && LoadSegments() && FindPhdr() &&
203*8d67ca89SAndroid Build Coastguard Worker       FindGnuPropertySection()) {
204*8d67ca89SAndroid Build Coastguard Worker     did_load_ = true;
205*8d67ca89SAndroid Build Coastguard Worker #if defined(__aarch64__)
206*8d67ca89SAndroid Build Coastguard Worker     // For Armv8.5-A loaded executable segments may require PROT_BTI.
207*8d67ca89SAndroid Build Coastguard Worker     if (note_gnu_property_.IsBTICompatible()) {
208*8d67ca89SAndroid Build Coastguard Worker       did_load_ =
209*8d67ca89SAndroid Build Coastguard Worker           (phdr_table_protect_segments(phdr_table_, phdr_num_, load_bias_, should_pad_segments_,
210*8d67ca89SAndroid Build Coastguard Worker                                        should_use_16kib_app_compat_, &note_gnu_property_) == 0);
211*8d67ca89SAndroid Build Coastguard Worker     }
212*8d67ca89SAndroid Build Coastguard Worker #endif
213*8d67ca89SAndroid Build Coastguard Worker   }
214*8d67ca89SAndroid Build Coastguard Worker   if (reserveSuccess && !did_load_) {
215*8d67ca89SAndroid Build Coastguard Worker     if (load_start_ != nullptr && load_size_ != 0) {
216*8d67ca89SAndroid Build Coastguard Worker       if (!mapped_by_caller_) {
217*8d67ca89SAndroid Build Coastguard Worker         munmap(load_start_, load_size_);
218*8d67ca89SAndroid Build Coastguard Worker       }
219*8d67ca89SAndroid Build Coastguard Worker     }
220*8d67ca89SAndroid Build Coastguard Worker   }
221*8d67ca89SAndroid Build Coastguard Worker 
222*8d67ca89SAndroid Build Coastguard Worker   return did_load_;
223*8d67ca89SAndroid Build Coastguard Worker }
224*8d67ca89SAndroid Build Coastguard Worker 
get_string(ElfW (Word)index) const225*8d67ca89SAndroid Build Coastguard Worker const char* ElfReader::get_string(ElfW(Word) index) const {
226*8d67ca89SAndroid Build Coastguard Worker   CHECK(strtab_ != nullptr);
227*8d67ca89SAndroid Build Coastguard Worker   CHECK(index < strtab_size_);
228*8d67ca89SAndroid Build Coastguard Worker 
229*8d67ca89SAndroid Build Coastguard Worker   return strtab_ + index;
230*8d67ca89SAndroid Build Coastguard Worker }
231*8d67ca89SAndroid Build Coastguard Worker 
ReadElfHeader()232*8d67ca89SAndroid Build Coastguard Worker bool ElfReader::ReadElfHeader() {
233*8d67ca89SAndroid Build Coastguard Worker   ssize_t rc = TEMP_FAILURE_RETRY(pread64(fd_, &header_, sizeof(header_), file_offset_));
234*8d67ca89SAndroid Build Coastguard Worker   if (rc < 0) {
235*8d67ca89SAndroid Build Coastguard Worker     DL_ERR("can't read file \"%s\": %s", name_.c_str(), strerror(errno));
236*8d67ca89SAndroid Build Coastguard Worker     return false;
237*8d67ca89SAndroid Build Coastguard Worker   }
238*8d67ca89SAndroid Build Coastguard Worker 
239*8d67ca89SAndroid Build Coastguard Worker   if (rc != sizeof(header_)) {
240*8d67ca89SAndroid Build Coastguard Worker     DL_ERR("\"%s\" is too small to be an ELF executable: only found %zd bytes", name_.c_str(),
241*8d67ca89SAndroid Build Coastguard Worker            static_cast<size_t>(rc));
242*8d67ca89SAndroid Build Coastguard Worker     return false;
243*8d67ca89SAndroid Build Coastguard Worker   }
244*8d67ca89SAndroid Build Coastguard Worker   return true;
245*8d67ca89SAndroid Build Coastguard Worker }
246*8d67ca89SAndroid Build Coastguard Worker 
EM_to_string(int em)247*8d67ca89SAndroid Build Coastguard Worker static const char* EM_to_string(int em) {
248*8d67ca89SAndroid Build Coastguard Worker   if (em == EM_386) return "EM_386";
249*8d67ca89SAndroid Build Coastguard Worker   if (em == EM_AARCH64) return "EM_AARCH64";
250*8d67ca89SAndroid Build Coastguard Worker   if (em == EM_ARM) return "EM_ARM";
251*8d67ca89SAndroid Build Coastguard Worker   if (em == EM_RISCV) return "EM_RISCV";
252*8d67ca89SAndroid Build Coastguard Worker   if (em == EM_X86_64) return "EM_X86_64";
253*8d67ca89SAndroid Build Coastguard Worker   return "EM_???";
254*8d67ca89SAndroid Build Coastguard Worker }
255*8d67ca89SAndroid Build Coastguard Worker 
VerifyElfHeader()256*8d67ca89SAndroid Build Coastguard Worker bool ElfReader::VerifyElfHeader() {
257*8d67ca89SAndroid Build Coastguard Worker   if (memcmp(header_.e_ident, ELFMAG, SELFMAG) != 0) {
258*8d67ca89SAndroid Build Coastguard Worker     DL_ERR("\"%s\" has bad ELF magic: %02x%02x%02x%02x", name_.c_str(),
259*8d67ca89SAndroid Build Coastguard Worker            header_.e_ident[0], header_.e_ident[1], header_.e_ident[2], header_.e_ident[3]);
260*8d67ca89SAndroid Build Coastguard Worker     return false;
261*8d67ca89SAndroid Build Coastguard Worker   }
262*8d67ca89SAndroid Build Coastguard Worker 
263*8d67ca89SAndroid Build Coastguard Worker   // Try to give a clear diagnostic for ELF class mismatches, since they're
264*8d67ca89SAndroid Build Coastguard Worker   // an easy mistake to make during the 32-bit/64-bit transition period.
265*8d67ca89SAndroid Build Coastguard Worker   int elf_class = header_.e_ident[EI_CLASS];
266*8d67ca89SAndroid Build Coastguard Worker #if defined(__LP64__)
267*8d67ca89SAndroid Build Coastguard Worker   if (elf_class != ELFCLASS64) {
268*8d67ca89SAndroid Build Coastguard Worker     if (elf_class == ELFCLASS32) {
269*8d67ca89SAndroid Build Coastguard Worker       DL_ERR("\"%s\" is 32-bit instead of 64-bit", name_.c_str());
270*8d67ca89SAndroid Build Coastguard Worker     } else {
271*8d67ca89SAndroid Build Coastguard Worker       DL_ERR("\"%s\" has unknown ELF class: %d", name_.c_str(), elf_class);
272*8d67ca89SAndroid Build Coastguard Worker     }
273*8d67ca89SAndroid Build Coastguard Worker     return false;
274*8d67ca89SAndroid Build Coastguard Worker   }
275*8d67ca89SAndroid Build Coastguard Worker #else
276*8d67ca89SAndroid Build Coastguard Worker   if (elf_class != ELFCLASS32) {
277*8d67ca89SAndroid Build Coastguard Worker     if (elf_class == ELFCLASS64) {
278*8d67ca89SAndroid Build Coastguard Worker       DL_ERR("\"%s\" is 64-bit instead of 32-bit", name_.c_str());
279*8d67ca89SAndroid Build Coastguard Worker     } else {
280*8d67ca89SAndroid Build Coastguard Worker       DL_ERR("\"%s\" has unknown ELF class: %d", name_.c_str(), elf_class);
281*8d67ca89SAndroid Build Coastguard Worker     }
282*8d67ca89SAndroid Build Coastguard Worker     return false;
283*8d67ca89SAndroid Build Coastguard Worker   }
284*8d67ca89SAndroid Build Coastguard Worker #endif
285*8d67ca89SAndroid Build Coastguard Worker 
286*8d67ca89SAndroid Build Coastguard Worker   if (header_.e_ident[EI_DATA] != ELFDATA2LSB) {
287*8d67ca89SAndroid Build Coastguard Worker     DL_ERR("\"%s\" not little-endian: %d", name_.c_str(), header_.e_ident[EI_DATA]);
288*8d67ca89SAndroid Build Coastguard Worker     return false;
289*8d67ca89SAndroid Build Coastguard Worker   }
290*8d67ca89SAndroid Build Coastguard Worker 
291*8d67ca89SAndroid Build Coastguard Worker   if (header_.e_type != ET_DYN) {
292*8d67ca89SAndroid Build Coastguard Worker     DL_ERR("\"%s\" has unexpected e_type: %d", name_.c_str(), header_.e_type);
293*8d67ca89SAndroid Build Coastguard Worker     return false;
294*8d67ca89SAndroid Build Coastguard Worker   }
295*8d67ca89SAndroid Build Coastguard Worker 
296*8d67ca89SAndroid Build Coastguard Worker   if (header_.e_version != EV_CURRENT) {
297*8d67ca89SAndroid Build Coastguard Worker     DL_ERR("\"%s\" has unexpected e_version: %d", name_.c_str(), header_.e_version);
298*8d67ca89SAndroid Build Coastguard Worker     return false;
299*8d67ca89SAndroid Build Coastguard Worker   }
300*8d67ca89SAndroid Build Coastguard Worker 
301*8d67ca89SAndroid Build Coastguard Worker   if (header_.e_machine != GetTargetElfMachine()) {
302*8d67ca89SAndroid Build Coastguard Worker     DL_ERR("\"%s\" is for %s (%d) instead of %s (%d)",
303*8d67ca89SAndroid Build Coastguard Worker            name_.c_str(),
304*8d67ca89SAndroid Build Coastguard Worker            EM_to_string(header_.e_machine), header_.e_machine,
305*8d67ca89SAndroid Build Coastguard Worker            EM_to_string(GetTargetElfMachine()), GetTargetElfMachine());
306*8d67ca89SAndroid Build Coastguard Worker     return false;
307*8d67ca89SAndroid Build Coastguard Worker   }
308*8d67ca89SAndroid Build Coastguard Worker 
309*8d67ca89SAndroid Build Coastguard Worker   if (header_.e_shentsize != sizeof(ElfW(Shdr))) {
310*8d67ca89SAndroid Build Coastguard Worker     if (get_application_target_sdk_version() >= 26) {
311*8d67ca89SAndroid Build Coastguard Worker       DL_ERR_AND_LOG("\"%s\" has unsupported e_shentsize: 0x%x (expected 0x%zx)",
312*8d67ca89SAndroid Build Coastguard Worker                      name_.c_str(), header_.e_shentsize, sizeof(ElfW(Shdr)));
313*8d67ca89SAndroid Build Coastguard Worker       return false;
314*8d67ca89SAndroid Build Coastguard Worker     }
315*8d67ca89SAndroid Build Coastguard Worker     DL_WARN_documented_change(26,
316*8d67ca89SAndroid Build Coastguard Worker                               "invalid-elf-header_section-headers-enforced-for-api-level-26",
317*8d67ca89SAndroid Build Coastguard Worker                               "\"%s\" has unsupported e_shentsize 0x%x (expected 0x%zx)",
318*8d67ca89SAndroid Build Coastguard Worker                               name_.c_str(), header_.e_shentsize, sizeof(ElfW(Shdr)));
319*8d67ca89SAndroid Build Coastguard Worker     add_dlwarning(name_.c_str(), "has invalid ELF header");
320*8d67ca89SAndroid Build Coastguard Worker   }
321*8d67ca89SAndroid Build Coastguard Worker 
322*8d67ca89SAndroid Build Coastguard Worker   if (header_.e_shstrndx == 0) {
323*8d67ca89SAndroid Build Coastguard Worker     if (get_application_target_sdk_version() >= 26) {
324*8d67ca89SAndroid Build Coastguard Worker       DL_ERR_AND_LOG("\"%s\" has invalid e_shstrndx", name_.c_str());
325*8d67ca89SAndroid Build Coastguard Worker       return false;
326*8d67ca89SAndroid Build Coastguard Worker     }
327*8d67ca89SAndroid Build Coastguard Worker     DL_WARN_documented_change(26,
328*8d67ca89SAndroid Build Coastguard Worker                               "invalid-elf-header_section-headers-enforced-for-api-level-26",
329*8d67ca89SAndroid Build Coastguard Worker                               "\"%s\" has invalid e_shstrndx", name_.c_str());
330*8d67ca89SAndroid Build Coastguard Worker     add_dlwarning(name_.c_str(), "has invalid ELF header");
331*8d67ca89SAndroid Build Coastguard Worker   }
332*8d67ca89SAndroid Build Coastguard Worker 
333*8d67ca89SAndroid Build Coastguard Worker   return true;
334*8d67ca89SAndroid Build Coastguard Worker }
335*8d67ca89SAndroid Build Coastguard Worker 
CheckFileRange(ElfW (Addr)offset,size_t size,size_t alignment)336*8d67ca89SAndroid Build Coastguard Worker bool ElfReader::CheckFileRange(ElfW(Addr) offset, size_t size, size_t alignment) {
337*8d67ca89SAndroid Build Coastguard Worker   off64_t range_start;
338*8d67ca89SAndroid Build Coastguard Worker   off64_t range_end;
339*8d67ca89SAndroid Build Coastguard Worker 
340*8d67ca89SAndroid Build Coastguard Worker   // Only header can be located at the 0 offset... This function called to
341*8d67ca89SAndroid Build Coastguard Worker   // check DYNSYM and DYNAMIC sections and phdr/shdr - none of them can be
342*8d67ca89SAndroid Build Coastguard Worker   // at offset 0.
343*8d67ca89SAndroid Build Coastguard Worker 
344*8d67ca89SAndroid Build Coastguard Worker   return offset > 0 &&
345*8d67ca89SAndroid Build Coastguard Worker          safe_add(&range_start, file_offset_, offset) &&
346*8d67ca89SAndroid Build Coastguard Worker          safe_add(&range_end, range_start, size) &&
347*8d67ca89SAndroid Build Coastguard Worker          (range_start < file_size_) &&
348*8d67ca89SAndroid Build Coastguard Worker          (range_end <= file_size_) &&
349*8d67ca89SAndroid Build Coastguard Worker          ((offset % alignment) == 0);
350*8d67ca89SAndroid Build Coastguard Worker }
351*8d67ca89SAndroid Build Coastguard Worker 
352*8d67ca89SAndroid Build Coastguard Worker // Loads the program header table from an ELF file into a read-only private
353*8d67ca89SAndroid Build Coastguard Worker // anonymous mmap-ed block.
ReadProgramHeaders()354*8d67ca89SAndroid Build Coastguard Worker bool ElfReader::ReadProgramHeaders() {
355*8d67ca89SAndroid Build Coastguard Worker   phdr_num_ = header_.e_phnum;
356*8d67ca89SAndroid Build Coastguard Worker 
357*8d67ca89SAndroid Build Coastguard Worker   // Like the kernel, we only accept program header tables that
358*8d67ca89SAndroid Build Coastguard Worker   // are smaller than 64KiB.
359*8d67ca89SAndroid Build Coastguard Worker   if (phdr_num_ < 1 || phdr_num_ > 65536/sizeof(ElfW(Phdr))) {
360*8d67ca89SAndroid Build Coastguard Worker     DL_ERR("\"%s\" has invalid e_phnum: %zd", name_.c_str(), phdr_num_);
361*8d67ca89SAndroid Build Coastguard Worker     return false;
362*8d67ca89SAndroid Build Coastguard Worker   }
363*8d67ca89SAndroid Build Coastguard Worker 
364*8d67ca89SAndroid Build Coastguard Worker   // Boundary checks
365*8d67ca89SAndroid Build Coastguard Worker   size_t size = phdr_num_ * sizeof(ElfW(Phdr));
366*8d67ca89SAndroid Build Coastguard Worker   if (!CheckFileRange(header_.e_phoff, size, alignof(ElfW(Phdr)))) {
367*8d67ca89SAndroid Build Coastguard Worker     DL_ERR_AND_LOG("\"%s\" has invalid phdr offset/size: %zu/%zu",
368*8d67ca89SAndroid Build Coastguard Worker                    name_.c_str(),
369*8d67ca89SAndroid Build Coastguard Worker                    static_cast<size_t>(header_.e_phoff),
370*8d67ca89SAndroid Build Coastguard Worker                    size);
371*8d67ca89SAndroid Build Coastguard Worker     return false;
372*8d67ca89SAndroid Build Coastguard Worker   }
373*8d67ca89SAndroid Build Coastguard Worker 
374*8d67ca89SAndroid Build Coastguard Worker   if (!phdr_fragment_.Map(fd_, file_offset_, header_.e_phoff, size)) {
375*8d67ca89SAndroid Build Coastguard Worker     DL_ERR("\"%s\" phdr mmap failed: %m", name_.c_str());
376*8d67ca89SAndroid Build Coastguard Worker     return false;
377*8d67ca89SAndroid Build Coastguard Worker   }
378*8d67ca89SAndroid Build Coastguard Worker 
379*8d67ca89SAndroid Build Coastguard Worker   phdr_table_ = static_cast<ElfW(Phdr)*>(phdr_fragment_.data());
380*8d67ca89SAndroid Build Coastguard Worker   return true;
381*8d67ca89SAndroid Build Coastguard Worker }
382*8d67ca89SAndroid Build Coastguard Worker 
ReadSectionHeaders()383*8d67ca89SAndroid Build Coastguard Worker bool ElfReader::ReadSectionHeaders() {
384*8d67ca89SAndroid Build Coastguard Worker   shdr_num_ = header_.e_shnum;
385*8d67ca89SAndroid Build Coastguard Worker 
386*8d67ca89SAndroid Build Coastguard Worker   if (shdr_num_ == 0) {
387*8d67ca89SAndroid Build Coastguard Worker     DL_ERR_AND_LOG("\"%s\" has no section headers", name_.c_str());
388*8d67ca89SAndroid Build Coastguard Worker     return false;
389*8d67ca89SAndroid Build Coastguard Worker   }
390*8d67ca89SAndroid Build Coastguard Worker 
391*8d67ca89SAndroid Build Coastguard Worker   size_t size = shdr_num_ * sizeof(ElfW(Shdr));
392*8d67ca89SAndroid Build Coastguard Worker   if (!CheckFileRange(header_.e_shoff, size, alignof(const ElfW(Shdr)))) {
393*8d67ca89SAndroid Build Coastguard Worker     DL_ERR_AND_LOG("\"%s\" has invalid shdr offset/size: %zu/%zu",
394*8d67ca89SAndroid Build Coastguard Worker                    name_.c_str(),
395*8d67ca89SAndroid Build Coastguard Worker                    static_cast<size_t>(header_.e_shoff),
396*8d67ca89SAndroid Build Coastguard Worker                    size);
397*8d67ca89SAndroid Build Coastguard Worker     return false;
398*8d67ca89SAndroid Build Coastguard Worker   }
399*8d67ca89SAndroid Build Coastguard Worker 
400*8d67ca89SAndroid Build Coastguard Worker   if (!shdr_fragment_.Map(fd_, file_offset_, header_.e_shoff, size)) {
401*8d67ca89SAndroid Build Coastguard Worker     DL_ERR("\"%s\" shdr mmap failed: %m", name_.c_str());
402*8d67ca89SAndroid Build Coastguard Worker     return false;
403*8d67ca89SAndroid Build Coastguard Worker   }
404*8d67ca89SAndroid Build Coastguard Worker 
405*8d67ca89SAndroid Build Coastguard Worker   shdr_table_ = static_cast<const ElfW(Shdr)*>(shdr_fragment_.data());
406*8d67ca89SAndroid Build Coastguard Worker   return true;
407*8d67ca89SAndroid Build Coastguard Worker }
408*8d67ca89SAndroid Build Coastguard Worker 
ReadDynamicSection()409*8d67ca89SAndroid Build Coastguard Worker bool ElfReader::ReadDynamicSection() {
410*8d67ca89SAndroid Build Coastguard Worker   // 1. Find .dynamic section (in section headers)
411*8d67ca89SAndroid Build Coastguard Worker   const ElfW(Shdr)* dynamic_shdr = nullptr;
412*8d67ca89SAndroid Build Coastguard Worker   for (size_t i = 0; i < shdr_num_; ++i) {
413*8d67ca89SAndroid Build Coastguard Worker     if (shdr_table_[i].sh_type == SHT_DYNAMIC) {
414*8d67ca89SAndroid Build Coastguard Worker       dynamic_shdr = &shdr_table_ [i];
415*8d67ca89SAndroid Build Coastguard Worker       break;
416*8d67ca89SAndroid Build Coastguard Worker     }
417*8d67ca89SAndroid Build Coastguard Worker   }
418*8d67ca89SAndroid Build Coastguard Worker 
419*8d67ca89SAndroid Build Coastguard Worker   if (dynamic_shdr == nullptr) {
420*8d67ca89SAndroid Build Coastguard Worker     DL_ERR_AND_LOG("\"%s\" .dynamic section header was not found", name_.c_str());
421*8d67ca89SAndroid Build Coastguard Worker     return false;
422*8d67ca89SAndroid Build Coastguard Worker   }
423*8d67ca89SAndroid Build Coastguard Worker 
424*8d67ca89SAndroid Build Coastguard Worker   // Make sure dynamic_shdr offset and size matches PT_DYNAMIC phdr
425*8d67ca89SAndroid Build Coastguard Worker   size_t pt_dynamic_offset = 0;
426*8d67ca89SAndroid Build Coastguard Worker   size_t pt_dynamic_filesz = 0;
427*8d67ca89SAndroid Build Coastguard Worker   for (size_t i = 0; i < phdr_num_; ++i) {
428*8d67ca89SAndroid Build Coastguard Worker     const ElfW(Phdr)* phdr = &phdr_table_[i];
429*8d67ca89SAndroid Build Coastguard Worker     if (phdr->p_type == PT_DYNAMIC) {
430*8d67ca89SAndroid Build Coastguard Worker       pt_dynamic_offset = phdr->p_offset;
431*8d67ca89SAndroid Build Coastguard Worker       pt_dynamic_filesz = phdr->p_filesz;
432*8d67ca89SAndroid Build Coastguard Worker     }
433*8d67ca89SAndroid Build Coastguard Worker   }
434*8d67ca89SAndroid Build Coastguard Worker 
435*8d67ca89SAndroid Build Coastguard Worker   if (pt_dynamic_offset != dynamic_shdr->sh_offset) {
436*8d67ca89SAndroid Build Coastguard Worker     if (get_application_target_sdk_version() >= 26) {
437*8d67ca89SAndroid Build Coastguard Worker       DL_ERR_AND_LOG("\"%s\" .dynamic section has invalid offset: 0x%zx, "
438*8d67ca89SAndroid Build Coastguard Worker                      "expected to match PT_DYNAMIC offset: 0x%zx",
439*8d67ca89SAndroid Build Coastguard Worker                      name_.c_str(),
440*8d67ca89SAndroid Build Coastguard Worker                      static_cast<size_t>(dynamic_shdr->sh_offset),
441*8d67ca89SAndroid Build Coastguard Worker                      pt_dynamic_offset);
442*8d67ca89SAndroid Build Coastguard Worker       return false;
443*8d67ca89SAndroid Build Coastguard Worker     }
444*8d67ca89SAndroid Build Coastguard Worker     DL_WARN_documented_change(26,
445*8d67ca89SAndroid Build Coastguard Worker                               "invalid-elf-header_section-headers-enforced-for-api-level-26",
446*8d67ca89SAndroid Build Coastguard Worker                               "\"%s\" .dynamic section has invalid offset: 0x%zx "
447*8d67ca89SAndroid Build Coastguard Worker                               "(expected to match PT_DYNAMIC offset 0x%zx)",
448*8d67ca89SAndroid Build Coastguard Worker                               name_.c_str(),
449*8d67ca89SAndroid Build Coastguard Worker                               static_cast<size_t>(dynamic_shdr->sh_offset),
450*8d67ca89SAndroid Build Coastguard Worker                               pt_dynamic_offset);
451*8d67ca89SAndroid Build Coastguard Worker     add_dlwarning(name_.c_str(), "invalid .dynamic section");
452*8d67ca89SAndroid Build Coastguard Worker   }
453*8d67ca89SAndroid Build Coastguard Worker 
454*8d67ca89SAndroid Build Coastguard Worker   if (pt_dynamic_filesz != dynamic_shdr->sh_size) {
455*8d67ca89SAndroid Build Coastguard Worker     if (get_application_target_sdk_version() >= 26) {
456*8d67ca89SAndroid Build Coastguard Worker       DL_ERR_AND_LOG("\"%s\" .dynamic section has invalid size: 0x%zx, "
457*8d67ca89SAndroid Build Coastguard Worker                      "expected to match PT_DYNAMIC filesz: 0x%zx",
458*8d67ca89SAndroid Build Coastguard Worker                      name_.c_str(),
459*8d67ca89SAndroid Build Coastguard Worker                      static_cast<size_t>(dynamic_shdr->sh_size),
460*8d67ca89SAndroid Build Coastguard Worker                      pt_dynamic_filesz);
461*8d67ca89SAndroid Build Coastguard Worker       return false;
462*8d67ca89SAndroid Build Coastguard Worker     }
463*8d67ca89SAndroid Build Coastguard Worker     DL_WARN_documented_change(26,
464*8d67ca89SAndroid Build Coastguard Worker                               "invalid-elf-header_section-headers-enforced-for-api-level-26",
465*8d67ca89SAndroid Build Coastguard Worker                               "\"%s\" .dynamic section has invalid size: 0x%zx "
466*8d67ca89SAndroid Build Coastguard Worker                               "(expected to match PT_DYNAMIC filesz 0x%zx)",
467*8d67ca89SAndroid Build Coastguard Worker                               name_.c_str(),
468*8d67ca89SAndroid Build Coastguard Worker                               static_cast<size_t>(dynamic_shdr->sh_size),
469*8d67ca89SAndroid Build Coastguard Worker                               pt_dynamic_filesz);
470*8d67ca89SAndroid Build Coastguard Worker     add_dlwarning(name_.c_str(), "invalid .dynamic section");
471*8d67ca89SAndroid Build Coastguard Worker   }
472*8d67ca89SAndroid Build Coastguard Worker 
473*8d67ca89SAndroid Build Coastguard Worker   if (dynamic_shdr->sh_link >= shdr_num_) {
474*8d67ca89SAndroid Build Coastguard Worker     DL_ERR_AND_LOG("\"%s\" .dynamic section has invalid sh_link: %d",
475*8d67ca89SAndroid Build Coastguard Worker                    name_.c_str(),
476*8d67ca89SAndroid Build Coastguard Worker                    dynamic_shdr->sh_link);
477*8d67ca89SAndroid Build Coastguard Worker     return false;
478*8d67ca89SAndroid Build Coastguard Worker   }
479*8d67ca89SAndroid Build Coastguard Worker 
480*8d67ca89SAndroid Build Coastguard Worker   const ElfW(Shdr)* strtab_shdr = &shdr_table_[dynamic_shdr->sh_link];
481*8d67ca89SAndroid Build Coastguard Worker 
482*8d67ca89SAndroid Build Coastguard Worker   if (strtab_shdr->sh_type != SHT_STRTAB) {
483*8d67ca89SAndroid Build Coastguard Worker     DL_ERR_AND_LOG("\"%s\" .dynamic section has invalid link(%d) sh_type: %d (expected SHT_STRTAB)",
484*8d67ca89SAndroid Build Coastguard Worker                    name_.c_str(), dynamic_shdr->sh_link, strtab_shdr->sh_type);
485*8d67ca89SAndroid Build Coastguard Worker     return false;
486*8d67ca89SAndroid Build Coastguard Worker   }
487*8d67ca89SAndroid Build Coastguard Worker 
488*8d67ca89SAndroid Build Coastguard Worker   if (!CheckFileRange(dynamic_shdr->sh_offset, dynamic_shdr->sh_size, alignof(const ElfW(Dyn)))) {
489*8d67ca89SAndroid Build Coastguard Worker     DL_ERR_AND_LOG("\"%s\" has invalid offset/size of .dynamic section", name_.c_str());
490*8d67ca89SAndroid Build Coastguard Worker     return false;
491*8d67ca89SAndroid Build Coastguard Worker   }
492*8d67ca89SAndroid Build Coastguard Worker 
493*8d67ca89SAndroid Build Coastguard Worker   if (!dynamic_fragment_.Map(fd_, file_offset_, dynamic_shdr->sh_offset, dynamic_shdr->sh_size)) {
494*8d67ca89SAndroid Build Coastguard Worker     DL_ERR("\"%s\" dynamic section mmap failed: %m", name_.c_str());
495*8d67ca89SAndroid Build Coastguard Worker     return false;
496*8d67ca89SAndroid Build Coastguard Worker   }
497*8d67ca89SAndroid Build Coastguard Worker 
498*8d67ca89SAndroid Build Coastguard Worker   dynamic_ = static_cast<const ElfW(Dyn)*>(dynamic_fragment_.data());
499*8d67ca89SAndroid Build Coastguard Worker 
500*8d67ca89SAndroid Build Coastguard Worker   if (!CheckFileRange(strtab_shdr->sh_offset, strtab_shdr->sh_size, alignof(const char))) {
501*8d67ca89SAndroid Build Coastguard Worker     DL_ERR_AND_LOG("\"%s\" has invalid offset/size of the .strtab section linked from .dynamic section",
502*8d67ca89SAndroid Build Coastguard Worker                    name_.c_str());
503*8d67ca89SAndroid Build Coastguard Worker     return false;
504*8d67ca89SAndroid Build Coastguard Worker   }
505*8d67ca89SAndroid Build Coastguard Worker 
506*8d67ca89SAndroid Build Coastguard Worker   if (!strtab_fragment_.Map(fd_, file_offset_, strtab_shdr->sh_offset, strtab_shdr->sh_size)) {
507*8d67ca89SAndroid Build Coastguard Worker     DL_ERR("\"%s\" strtab section mmap failed: %m", name_.c_str());
508*8d67ca89SAndroid Build Coastguard Worker     return false;
509*8d67ca89SAndroid Build Coastguard Worker   }
510*8d67ca89SAndroid Build Coastguard Worker 
511*8d67ca89SAndroid Build Coastguard Worker   strtab_ = static_cast<const char*>(strtab_fragment_.data());
512*8d67ca89SAndroid Build Coastguard Worker   strtab_size_ = strtab_fragment_.size();
513*8d67ca89SAndroid Build Coastguard Worker   return true;
514*8d67ca89SAndroid Build Coastguard Worker }
515*8d67ca89SAndroid Build Coastguard Worker 
516*8d67ca89SAndroid Build Coastguard Worker /* Returns the size of the extent of all the possibly non-contiguous
517*8d67ca89SAndroid Build Coastguard Worker  * loadable segments in an ELF program header table. This corresponds
518*8d67ca89SAndroid Build Coastguard Worker  * to the page-aligned size in bytes that needs to be reserved in the
519*8d67ca89SAndroid Build Coastguard Worker  * process' address space. If there are no loadable segments, 0 is
520*8d67ca89SAndroid Build Coastguard Worker  * returned.
521*8d67ca89SAndroid Build Coastguard Worker  *
522*8d67ca89SAndroid Build Coastguard Worker  * If out_min_vaddr or out_max_vaddr are not null, they will be
523*8d67ca89SAndroid Build Coastguard Worker  * set to the minimum and maximum addresses of pages to be reserved,
524*8d67ca89SAndroid Build Coastguard Worker  * or 0 if there is nothing to load.
525*8d67ca89SAndroid Build Coastguard Worker  */
phdr_table_get_load_size(const ElfW (Phdr)* phdr_table,size_t phdr_count,ElfW (Addr)* out_min_vaddr,ElfW (Addr)* out_max_vaddr)526*8d67ca89SAndroid Build Coastguard Worker size_t phdr_table_get_load_size(const ElfW(Phdr)* phdr_table, size_t phdr_count,
527*8d67ca89SAndroid Build Coastguard Worker                                 ElfW(Addr)* out_min_vaddr,
528*8d67ca89SAndroid Build Coastguard Worker                                 ElfW(Addr)* out_max_vaddr) {
529*8d67ca89SAndroid Build Coastguard Worker   ElfW(Addr) min_vaddr = UINTPTR_MAX;
530*8d67ca89SAndroid Build Coastguard Worker   ElfW(Addr) max_vaddr = 0;
531*8d67ca89SAndroid Build Coastguard Worker 
532*8d67ca89SAndroid Build Coastguard Worker   bool found_pt_load = false;
533*8d67ca89SAndroid Build Coastguard Worker   for (size_t i = 0; i < phdr_count; ++i) {
534*8d67ca89SAndroid Build Coastguard Worker     const ElfW(Phdr)* phdr = &phdr_table[i];
535*8d67ca89SAndroid Build Coastguard Worker 
536*8d67ca89SAndroid Build Coastguard Worker     if (phdr->p_type != PT_LOAD) {
537*8d67ca89SAndroid Build Coastguard Worker       continue;
538*8d67ca89SAndroid Build Coastguard Worker     }
539*8d67ca89SAndroid Build Coastguard Worker     found_pt_load = true;
540*8d67ca89SAndroid Build Coastguard Worker 
541*8d67ca89SAndroid Build Coastguard Worker     if (phdr->p_vaddr < min_vaddr) {
542*8d67ca89SAndroid Build Coastguard Worker       min_vaddr = phdr->p_vaddr;
543*8d67ca89SAndroid Build Coastguard Worker     }
544*8d67ca89SAndroid Build Coastguard Worker 
545*8d67ca89SAndroid Build Coastguard Worker     if (phdr->p_vaddr + phdr->p_memsz > max_vaddr) {
546*8d67ca89SAndroid Build Coastguard Worker       max_vaddr = phdr->p_vaddr + phdr->p_memsz;
547*8d67ca89SAndroid Build Coastguard Worker     }
548*8d67ca89SAndroid Build Coastguard Worker   }
549*8d67ca89SAndroid Build Coastguard Worker   if (!found_pt_load) {
550*8d67ca89SAndroid Build Coastguard Worker     min_vaddr = 0;
551*8d67ca89SAndroid Build Coastguard Worker   }
552*8d67ca89SAndroid Build Coastguard Worker 
553*8d67ca89SAndroid Build Coastguard Worker   min_vaddr = page_start(min_vaddr);
554*8d67ca89SAndroid Build Coastguard Worker   max_vaddr = page_end(max_vaddr);
555*8d67ca89SAndroid Build Coastguard Worker 
556*8d67ca89SAndroid Build Coastguard Worker   if (out_min_vaddr != nullptr) {
557*8d67ca89SAndroid Build Coastguard Worker     *out_min_vaddr = min_vaddr;
558*8d67ca89SAndroid Build Coastguard Worker   }
559*8d67ca89SAndroid Build Coastguard Worker   if (out_max_vaddr != nullptr) {
560*8d67ca89SAndroid Build Coastguard Worker     *out_max_vaddr = max_vaddr;
561*8d67ca89SAndroid Build Coastguard Worker   }
562*8d67ca89SAndroid Build Coastguard Worker   return max_vaddr - min_vaddr;
563*8d67ca89SAndroid Build Coastguard Worker }
564*8d67ca89SAndroid Build Coastguard Worker 
565*8d67ca89SAndroid Build Coastguard Worker // Returns the maximum p_align associated with a loadable segment in the ELF
566*8d67ca89SAndroid Build Coastguard Worker // program header table. Used to determine whether the file should be loaded at
567*8d67ca89SAndroid Build Coastguard Worker // a specific virtual address alignment for use with huge pages.
phdr_table_get_maximum_alignment(const ElfW (Phdr)* phdr_table,size_t phdr_count)568*8d67ca89SAndroid Build Coastguard Worker size_t phdr_table_get_maximum_alignment(const ElfW(Phdr)* phdr_table, size_t phdr_count) {
569*8d67ca89SAndroid Build Coastguard Worker   size_t maximum_alignment = page_size();
570*8d67ca89SAndroid Build Coastguard Worker 
571*8d67ca89SAndroid Build Coastguard Worker   for (size_t i = 0; i < phdr_count; ++i) {
572*8d67ca89SAndroid Build Coastguard Worker     const ElfW(Phdr)* phdr = &phdr_table[i];
573*8d67ca89SAndroid Build Coastguard Worker 
574*8d67ca89SAndroid Build Coastguard Worker     // p_align must be 0, 1, or a positive, integral power of two.
575*8d67ca89SAndroid Build Coastguard Worker     if (phdr->p_type != PT_LOAD || ((phdr->p_align & (phdr->p_align - 1)) != 0)) {
576*8d67ca89SAndroid Build Coastguard Worker       continue;
577*8d67ca89SAndroid Build Coastguard Worker     }
578*8d67ca89SAndroid Build Coastguard Worker 
579*8d67ca89SAndroid Build Coastguard Worker     maximum_alignment = std::max(maximum_alignment, static_cast<size_t>(phdr->p_align));
580*8d67ca89SAndroid Build Coastguard Worker   }
581*8d67ca89SAndroid Build Coastguard Worker 
582*8d67ca89SAndroid Build Coastguard Worker #if defined(__LP64__)
583*8d67ca89SAndroid Build Coastguard Worker   return maximum_alignment;
584*8d67ca89SAndroid Build Coastguard Worker #else
585*8d67ca89SAndroid Build Coastguard Worker   return page_size();
586*8d67ca89SAndroid Build Coastguard Worker #endif
587*8d67ca89SAndroid Build Coastguard Worker }
588*8d67ca89SAndroid Build Coastguard Worker 
589*8d67ca89SAndroid Build Coastguard Worker // Returns the minimum p_align associated with a loadable segment in the ELF
590*8d67ca89SAndroid Build Coastguard Worker // program header table. Used to determine if the program alignment is compatible
591*8d67ca89SAndroid Build Coastguard Worker // with the page size of this system.
phdr_table_get_minimum_alignment(const ElfW (Phdr)* phdr_table,size_t phdr_count)592*8d67ca89SAndroid Build Coastguard Worker size_t phdr_table_get_minimum_alignment(const ElfW(Phdr)* phdr_table, size_t phdr_count) {
593*8d67ca89SAndroid Build Coastguard Worker   size_t minimum_alignment = page_size();
594*8d67ca89SAndroid Build Coastguard Worker 
595*8d67ca89SAndroid Build Coastguard Worker   for (size_t i = 0; i < phdr_count; ++i) {
596*8d67ca89SAndroid Build Coastguard Worker     const ElfW(Phdr)* phdr = &phdr_table[i];
597*8d67ca89SAndroid Build Coastguard Worker 
598*8d67ca89SAndroid Build Coastguard Worker     // p_align must be 0, 1, or a positive, integral power of two.
599*8d67ca89SAndroid Build Coastguard Worker     if (phdr->p_type != PT_LOAD || ((phdr->p_align & (phdr->p_align - 1)) != 0)) {
600*8d67ca89SAndroid Build Coastguard Worker       continue;
601*8d67ca89SAndroid Build Coastguard Worker     }
602*8d67ca89SAndroid Build Coastguard Worker 
603*8d67ca89SAndroid Build Coastguard Worker     if (phdr->p_align <= 1) {
604*8d67ca89SAndroid Build Coastguard Worker       continue;
605*8d67ca89SAndroid Build Coastguard Worker     }
606*8d67ca89SAndroid Build Coastguard Worker 
607*8d67ca89SAndroid Build Coastguard Worker     minimum_alignment = std::min(minimum_alignment, static_cast<size_t>(phdr->p_align));
608*8d67ca89SAndroid Build Coastguard Worker   }
609*8d67ca89SAndroid Build Coastguard Worker 
610*8d67ca89SAndroid Build Coastguard Worker   return minimum_alignment;
611*8d67ca89SAndroid Build Coastguard Worker }
612*8d67ca89SAndroid Build Coastguard Worker 
613*8d67ca89SAndroid Build Coastguard Worker // Reserve a virtual address range such that if it's limits were extended to the next 2**align
614*8d67ca89SAndroid Build Coastguard Worker // boundary, it would not overlap with any existing mappings.
ReserveWithAlignmentPadding(size_t size,size_t mapping_align,size_t start_align,void ** out_gap_start,size_t * out_gap_size)615*8d67ca89SAndroid Build Coastguard Worker static void* ReserveWithAlignmentPadding(size_t size, size_t mapping_align, size_t start_align,
616*8d67ca89SAndroid Build Coastguard Worker                                          void** out_gap_start, size_t* out_gap_size) {
617*8d67ca89SAndroid Build Coastguard Worker   int mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS;
618*8d67ca89SAndroid Build Coastguard Worker   // Reserve enough space to properly align the library's start address.
619*8d67ca89SAndroid Build Coastguard Worker   mapping_align = std::max(mapping_align, start_align);
620*8d67ca89SAndroid Build Coastguard Worker   if (mapping_align == page_size()) {
621*8d67ca89SAndroid Build Coastguard Worker     void* mmap_ptr = mmap(nullptr, size, PROT_NONE, mmap_flags, -1, 0);
622*8d67ca89SAndroid Build Coastguard Worker     if (mmap_ptr == MAP_FAILED) {
623*8d67ca89SAndroid Build Coastguard Worker       return nullptr;
624*8d67ca89SAndroid Build Coastguard Worker     }
625*8d67ca89SAndroid Build Coastguard Worker     return mmap_ptr;
626*8d67ca89SAndroid Build Coastguard Worker   }
627*8d67ca89SAndroid Build Coastguard Worker 
628*8d67ca89SAndroid Build Coastguard Worker   // Minimum alignment of shared library gap. For efficiency, this should match the second level
629*8d67ca89SAndroid Build Coastguard Worker   // page size of the platform.
630*8d67ca89SAndroid Build Coastguard Worker #if defined(__LP64__)
631*8d67ca89SAndroid Build Coastguard Worker   constexpr size_t kGapAlignment = 1ul << 21;  // 2MB
632*8d67ca89SAndroid Build Coastguard Worker #else
633*8d67ca89SAndroid Build Coastguard Worker   constexpr size_t kGapAlignment = 0;
634*8d67ca89SAndroid Build Coastguard Worker #endif
635*8d67ca89SAndroid Build Coastguard Worker   // Maximum gap size, in the units of kGapAlignment.
636*8d67ca89SAndroid Build Coastguard Worker   constexpr size_t kMaxGapUnits = 32;
637*8d67ca89SAndroid Build Coastguard Worker   // Allocate enough space so that the end of the desired region aligned up is still inside the
638*8d67ca89SAndroid Build Coastguard Worker   // mapping.
639*8d67ca89SAndroid Build Coastguard Worker   size_t mmap_size = align_up(size, mapping_align) + mapping_align - page_size();
640*8d67ca89SAndroid Build Coastguard Worker   uint8_t* mmap_ptr =
641*8d67ca89SAndroid Build Coastguard Worker       reinterpret_cast<uint8_t*>(mmap(nullptr, mmap_size, PROT_NONE, mmap_flags, -1, 0));
642*8d67ca89SAndroid Build Coastguard Worker   if (mmap_ptr == MAP_FAILED) {
643*8d67ca89SAndroid Build Coastguard Worker     return nullptr;
644*8d67ca89SAndroid Build Coastguard Worker   }
645*8d67ca89SAndroid Build Coastguard Worker   size_t gap_size = 0;
646*8d67ca89SAndroid Build Coastguard Worker   size_t first_byte = reinterpret_cast<size_t>(align_up(mmap_ptr, mapping_align));
647*8d67ca89SAndroid Build Coastguard Worker   size_t last_byte = reinterpret_cast<size_t>(align_down(mmap_ptr + mmap_size, mapping_align) - 1);
648*8d67ca89SAndroid Build Coastguard Worker   if (kGapAlignment && first_byte / kGapAlignment != last_byte / kGapAlignment) {
649*8d67ca89SAndroid Build Coastguard Worker     // This library crosses a 2MB boundary and will fragment a new huge page.
650*8d67ca89SAndroid Build Coastguard Worker     // Lets take advantage of that and insert a random number of inaccessible huge pages before that
651*8d67ca89SAndroid Build Coastguard Worker     // to improve address randomization and make it harder to locate this library code by probing.
652*8d67ca89SAndroid Build Coastguard Worker     munmap(mmap_ptr, mmap_size);
653*8d67ca89SAndroid Build Coastguard Worker     mapping_align = std::max(mapping_align, kGapAlignment);
654*8d67ca89SAndroid Build Coastguard Worker     gap_size =
655*8d67ca89SAndroid Build Coastguard Worker         kGapAlignment * (is_first_stage_init() ? 1 : arc4random_uniform(kMaxGapUnits - 1) + 1);
656*8d67ca89SAndroid Build Coastguard Worker     mmap_size = align_up(size + gap_size, mapping_align) + mapping_align - page_size();
657*8d67ca89SAndroid Build Coastguard Worker     mmap_ptr = reinterpret_cast<uint8_t*>(mmap(nullptr, mmap_size, PROT_NONE, mmap_flags, -1, 0));
658*8d67ca89SAndroid Build Coastguard Worker     if (mmap_ptr == MAP_FAILED) {
659*8d67ca89SAndroid Build Coastguard Worker       return nullptr;
660*8d67ca89SAndroid Build Coastguard Worker     }
661*8d67ca89SAndroid Build Coastguard Worker   }
662*8d67ca89SAndroid Build Coastguard Worker 
663*8d67ca89SAndroid Build Coastguard Worker   uint8_t *gap_end, *gap_start;
664*8d67ca89SAndroid Build Coastguard Worker   if (gap_size) {
665*8d67ca89SAndroid Build Coastguard Worker     gap_end = align_down(mmap_ptr + mmap_size, kGapAlignment);
666*8d67ca89SAndroid Build Coastguard Worker     gap_start = gap_end - gap_size;
667*8d67ca89SAndroid Build Coastguard Worker   } else {
668*8d67ca89SAndroid Build Coastguard Worker     gap_start = gap_end = mmap_ptr + mmap_size;
669*8d67ca89SAndroid Build Coastguard Worker   }
670*8d67ca89SAndroid Build Coastguard Worker 
671*8d67ca89SAndroid Build Coastguard Worker   uint8_t* first = align_up(mmap_ptr, mapping_align);
672*8d67ca89SAndroid Build Coastguard Worker   uint8_t* last = align_down(gap_start, mapping_align) - size;
673*8d67ca89SAndroid Build Coastguard Worker 
674*8d67ca89SAndroid Build Coastguard Worker   // arc4random* is not available in first stage init because /dev/urandom hasn't yet been
675*8d67ca89SAndroid Build Coastguard Worker   // created. Don't randomize then.
676*8d67ca89SAndroid Build Coastguard Worker   size_t n = is_first_stage_init() ? 0 : arc4random_uniform((last - first) / start_align + 1);
677*8d67ca89SAndroid Build Coastguard Worker   uint8_t* start = first + n * start_align;
678*8d67ca89SAndroid Build Coastguard Worker   // Unmap the extra space around the allocation.
679*8d67ca89SAndroid Build Coastguard Worker   // Keep it mapped PROT_NONE on 64-bit targets where address space is plentiful to make it harder
680*8d67ca89SAndroid Build Coastguard Worker   // to defeat ASLR by probing for readable memory mappings.
681*8d67ca89SAndroid Build Coastguard Worker   munmap(mmap_ptr, start - mmap_ptr);
682*8d67ca89SAndroid Build Coastguard Worker   munmap(start + size, gap_start - (start + size));
683*8d67ca89SAndroid Build Coastguard Worker   if (gap_end != mmap_ptr + mmap_size) {
684*8d67ca89SAndroid Build Coastguard Worker     munmap(gap_end, mmap_ptr + mmap_size - gap_end);
685*8d67ca89SAndroid Build Coastguard Worker   }
686*8d67ca89SAndroid Build Coastguard Worker   *out_gap_start = gap_start;
687*8d67ca89SAndroid Build Coastguard Worker   *out_gap_size = gap_size;
688*8d67ca89SAndroid Build Coastguard Worker   return start;
689*8d67ca89SAndroid Build Coastguard Worker }
690*8d67ca89SAndroid Build Coastguard Worker 
691*8d67ca89SAndroid Build Coastguard Worker // Reserve a virtual address range big enough to hold all loadable
692*8d67ca89SAndroid Build Coastguard Worker // segments of a program header table. This is done by creating a
693*8d67ca89SAndroid Build Coastguard Worker // private anonymous mmap() with PROT_NONE.
ReserveAddressSpace(address_space_params * address_space)694*8d67ca89SAndroid Build Coastguard Worker bool ElfReader::ReserveAddressSpace(address_space_params* address_space) {
695*8d67ca89SAndroid Build Coastguard Worker   ElfW(Addr) min_vaddr;
696*8d67ca89SAndroid Build Coastguard Worker   load_size_ = phdr_table_get_load_size(phdr_table_, phdr_num_, &min_vaddr);
697*8d67ca89SAndroid Build Coastguard Worker   if (load_size_ == 0) {
698*8d67ca89SAndroid Build Coastguard Worker     DL_ERR("\"%s\" has no loadable segments", name_.c_str());
699*8d67ca89SAndroid Build Coastguard Worker     return false;
700*8d67ca89SAndroid Build Coastguard Worker   }
701*8d67ca89SAndroid Build Coastguard Worker 
702*8d67ca89SAndroid Build Coastguard Worker   if (should_use_16kib_app_compat_) {
703*8d67ca89SAndroid Build Coastguard Worker     // Reserve additional space for aligning the permission boundary in compat loading
704*8d67ca89SAndroid Build Coastguard Worker     // Up to kPageSize-kCompatPageSize additional space is needed, but reservation
705*8d67ca89SAndroid Build Coastguard Worker     // is done with mmap which gives kPageSize multiple-sized reservations.
706*8d67ca89SAndroid Build Coastguard Worker     load_size_ += kPageSize;
707*8d67ca89SAndroid Build Coastguard Worker   }
708*8d67ca89SAndroid Build Coastguard Worker 
709*8d67ca89SAndroid Build Coastguard Worker   uint8_t* addr = reinterpret_cast<uint8_t*>(min_vaddr);
710*8d67ca89SAndroid Build Coastguard Worker   void* start;
711*8d67ca89SAndroid Build Coastguard Worker 
712*8d67ca89SAndroid Build Coastguard Worker   if (load_size_ > address_space->reserved_size) {
713*8d67ca89SAndroid Build Coastguard Worker     if (address_space->must_use_address) {
714*8d67ca89SAndroid Build Coastguard Worker       DL_ERR("reserved address space %zd smaller than %zd bytes needed for \"%s\"",
715*8d67ca89SAndroid Build Coastguard Worker              load_size_ - address_space->reserved_size, load_size_, name_.c_str());
716*8d67ca89SAndroid Build Coastguard Worker       return false;
717*8d67ca89SAndroid Build Coastguard Worker     }
718*8d67ca89SAndroid Build Coastguard Worker     size_t start_alignment = page_size();
719*8d67ca89SAndroid Build Coastguard Worker     if (get_transparent_hugepages_supported() && get_application_target_sdk_version() >= 31) {
720*8d67ca89SAndroid Build Coastguard Worker       size_t maximum_alignment = phdr_table_get_maximum_alignment(phdr_table_, phdr_num_);
721*8d67ca89SAndroid Build Coastguard Worker       // Limit alignment to PMD size as other alignments reduce the number of
722*8d67ca89SAndroid Build Coastguard Worker       // bits available for ASLR for no benefit.
723*8d67ca89SAndroid Build Coastguard Worker       start_alignment = maximum_alignment == kPmdSize ? kPmdSize : page_size();
724*8d67ca89SAndroid Build Coastguard Worker     }
725*8d67ca89SAndroid Build Coastguard Worker     start = ReserveWithAlignmentPadding(load_size_, kLibraryAlignment, start_alignment, &gap_start_,
726*8d67ca89SAndroid Build Coastguard Worker                                         &gap_size_);
727*8d67ca89SAndroid Build Coastguard Worker     if (start == nullptr) {
728*8d67ca89SAndroid Build Coastguard Worker       DL_ERR("couldn't reserve %zd bytes of address space for \"%s\"", load_size_, name_.c_str());
729*8d67ca89SAndroid Build Coastguard Worker       return false;
730*8d67ca89SAndroid Build Coastguard Worker     }
731*8d67ca89SAndroid Build Coastguard Worker   } else {
732*8d67ca89SAndroid Build Coastguard Worker     start = address_space->start_addr;
733*8d67ca89SAndroid Build Coastguard Worker     gap_start_ = nullptr;
734*8d67ca89SAndroid Build Coastguard Worker     gap_size_ = 0;
735*8d67ca89SAndroid Build Coastguard Worker     mapped_by_caller_ = true;
736*8d67ca89SAndroid Build Coastguard Worker 
737*8d67ca89SAndroid Build Coastguard Worker     // Update the reserved address space to subtract the space used by this library.
738*8d67ca89SAndroid Build Coastguard Worker     address_space->start_addr = reinterpret_cast<uint8_t*>(address_space->start_addr) + load_size_;
739*8d67ca89SAndroid Build Coastguard Worker     address_space->reserved_size -= load_size_;
740*8d67ca89SAndroid Build Coastguard Worker   }
741*8d67ca89SAndroid Build Coastguard Worker 
742*8d67ca89SAndroid Build Coastguard Worker   load_start_ = start;
743*8d67ca89SAndroid Build Coastguard Worker   load_bias_ = reinterpret_cast<uint8_t*>(start) - addr;
744*8d67ca89SAndroid Build Coastguard Worker 
745*8d67ca89SAndroid Build Coastguard Worker   if (should_use_16kib_app_compat_) {
746*8d67ca89SAndroid Build Coastguard Worker     // In compat mode make the initial mapping RW since the ELF contents will be read
747*8d67ca89SAndroid Build Coastguard Worker     // into it; instead of mapped over it.
748*8d67ca89SAndroid Build Coastguard Worker     mprotect(reinterpret_cast<void*>(start), load_size_, PROT_READ | PROT_WRITE);
749*8d67ca89SAndroid Build Coastguard Worker   }
750*8d67ca89SAndroid Build Coastguard Worker 
751*8d67ca89SAndroid Build Coastguard Worker   return true;
752*8d67ca89SAndroid Build Coastguard Worker }
753*8d67ca89SAndroid Build Coastguard Worker 
754*8d67ca89SAndroid Build Coastguard Worker /*
755*8d67ca89SAndroid Build Coastguard Worker  * Returns true if the kernel supports page size migration for this process.
756*8d67ca89SAndroid Build Coastguard Worker  */
page_size_migration_supported()757*8d67ca89SAndroid Build Coastguard Worker bool page_size_migration_supported() {
758*8d67ca89SAndroid Build Coastguard Worker #if defined(__LP64__)
759*8d67ca89SAndroid Build Coastguard Worker   static bool pgsize_migration_enabled = []() {
760*8d67ca89SAndroid Build Coastguard Worker     std::string enabled;
761*8d67ca89SAndroid Build Coastguard Worker     if (!android::base::ReadFileToString("/sys/kernel/mm/pgsize_migration/enabled", &enabled)) {
762*8d67ca89SAndroid Build Coastguard Worker       return false;
763*8d67ca89SAndroid Build Coastguard Worker     }
764*8d67ca89SAndroid Build Coastguard Worker     return enabled.find("1") != std::string::npos;
765*8d67ca89SAndroid Build Coastguard Worker   }();
766*8d67ca89SAndroid Build Coastguard Worker   return pgsize_migration_enabled;
767*8d67ca89SAndroid Build Coastguard Worker #else
768*8d67ca89SAndroid Build Coastguard Worker   return false;
769*8d67ca89SAndroid Build Coastguard Worker #endif
770*8d67ca89SAndroid Build Coastguard Worker }
771*8d67ca89SAndroid Build Coastguard Worker 
772*8d67ca89SAndroid Build Coastguard Worker // Find the ELF note of type NT_ANDROID_TYPE_PAD_SEGMENT and check that the desc value is 1.
ReadPadSegmentNote()773*8d67ca89SAndroid Build Coastguard Worker bool ElfReader::ReadPadSegmentNote() {
774*8d67ca89SAndroid Build Coastguard Worker   if (!page_size_migration_supported()) {
775*8d67ca89SAndroid Build Coastguard Worker     // Don't attempt to read the note, since segment extension isn't
776*8d67ca89SAndroid Build Coastguard Worker     // supported; but return true so that loading can continue normally.
777*8d67ca89SAndroid Build Coastguard Worker     return true;
778*8d67ca89SAndroid Build Coastguard Worker   }
779*8d67ca89SAndroid Build Coastguard Worker 
780*8d67ca89SAndroid Build Coastguard Worker   // The ELF can have multiple PT_NOTE's, check them all
781*8d67ca89SAndroid Build Coastguard Worker   for (size_t i = 0; i < phdr_num_; ++i) {
782*8d67ca89SAndroid Build Coastguard Worker     const ElfW(Phdr)* phdr = &phdr_table_[i];
783*8d67ca89SAndroid Build Coastguard Worker 
784*8d67ca89SAndroid Build Coastguard Worker     if (phdr->p_type != PT_NOTE) {
785*8d67ca89SAndroid Build Coastguard Worker       continue;
786*8d67ca89SAndroid Build Coastguard Worker     }
787*8d67ca89SAndroid Build Coastguard Worker 
788*8d67ca89SAndroid Build Coastguard Worker     // Some obfuscated ELFs may contain "empty" PT_NOTE program headers that don't
789*8d67ca89SAndroid Build Coastguard Worker     // point to any part of the ELF (p_memsz == 0). Skip these since there is
790*8d67ca89SAndroid Build Coastguard Worker     // nothing to decode. See: b/324468126
791*8d67ca89SAndroid Build Coastguard Worker     if (phdr->p_memsz == 0) {
792*8d67ca89SAndroid Build Coastguard Worker       continue;
793*8d67ca89SAndroid Build Coastguard Worker     }
794*8d67ca89SAndroid Build Coastguard Worker 
795*8d67ca89SAndroid Build Coastguard Worker     // If the PT_NOTE extends beyond the file. The ELF is doing something
796*8d67ca89SAndroid Build Coastguard Worker     // strange -- obfuscation, embedding hidden loaders, ...
797*8d67ca89SAndroid Build Coastguard Worker     //
798*8d67ca89SAndroid Build Coastguard Worker     // It doesn't contain the pad_segment note. Skip it to avoid SIGBUS
799*8d67ca89SAndroid Build Coastguard Worker     // by accesses beyond the file.
800*8d67ca89SAndroid Build Coastguard Worker     off64_t note_end_off = file_offset_ + phdr->p_offset + phdr->p_filesz;
801*8d67ca89SAndroid Build Coastguard Worker     if (note_end_off > file_size_) {
802*8d67ca89SAndroid Build Coastguard Worker       continue;
803*8d67ca89SAndroid Build Coastguard Worker     }
804*8d67ca89SAndroid Build Coastguard Worker 
805*8d67ca89SAndroid Build Coastguard Worker     // note_fragment is scoped to within the loop so that there is
806*8d67ca89SAndroid Build Coastguard Worker     // at most 1 PT_NOTE mapped at anytime during this search.
807*8d67ca89SAndroid Build Coastguard Worker     MappedFileFragment note_fragment;
808*8d67ca89SAndroid Build Coastguard Worker     if (!note_fragment.Map(fd_, file_offset_, phdr->p_offset, phdr->p_memsz)) {
809*8d67ca89SAndroid Build Coastguard Worker       DL_ERR("\"%s\": PT_NOTE mmap(nullptr, %p, PROT_READ, MAP_PRIVATE, %d, %p) failed: %m",
810*8d67ca89SAndroid Build Coastguard Worker              name_.c_str(), reinterpret_cast<void*>(phdr->p_memsz), fd_,
811*8d67ca89SAndroid Build Coastguard Worker              reinterpret_cast<void*>(page_start(file_offset_ + phdr->p_offset)));
812*8d67ca89SAndroid Build Coastguard Worker       return false;
813*8d67ca89SAndroid Build Coastguard Worker     }
814*8d67ca89SAndroid Build Coastguard Worker 
815*8d67ca89SAndroid Build Coastguard Worker     const ElfW(Nhdr)* note_hdr = nullptr;
816*8d67ca89SAndroid Build Coastguard Worker     const char* note_desc = nullptr;
817*8d67ca89SAndroid Build Coastguard Worker     if (!__get_elf_note(NT_ANDROID_TYPE_PAD_SEGMENT, "Android",
818*8d67ca89SAndroid Build Coastguard Worker                         reinterpret_cast<ElfW(Addr)>(note_fragment.data()),
819*8d67ca89SAndroid Build Coastguard Worker                         phdr, &note_hdr, &note_desc)) {
820*8d67ca89SAndroid Build Coastguard Worker       continue;
821*8d67ca89SAndroid Build Coastguard Worker     }
822*8d67ca89SAndroid Build Coastguard Worker 
823*8d67ca89SAndroid Build Coastguard Worker     if (note_hdr->n_descsz != sizeof(ElfW(Word))) {
824*8d67ca89SAndroid Build Coastguard Worker       DL_ERR("\"%s\" NT_ANDROID_TYPE_PAD_SEGMENT note has unexpected n_descsz: %u",
825*8d67ca89SAndroid Build Coastguard Worker              name_.c_str(), reinterpret_cast<unsigned int>(note_hdr->n_descsz));
826*8d67ca89SAndroid Build Coastguard Worker       return false;
827*8d67ca89SAndroid Build Coastguard Worker     }
828*8d67ca89SAndroid Build Coastguard Worker 
829*8d67ca89SAndroid Build Coastguard Worker     // 1 == enabled, 0 == disabled
830*8d67ca89SAndroid Build Coastguard Worker     should_pad_segments_ = *reinterpret_cast<const ElfW(Word)*>(note_desc) == 1;
831*8d67ca89SAndroid Build Coastguard Worker     return true;
832*8d67ca89SAndroid Build Coastguard Worker   }
833*8d67ca89SAndroid Build Coastguard Worker 
834*8d67ca89SAndroid Build Coastguard Worker   return true;
835*8d67ca89SAndroid Build Coastguard Worker }
836*8d67ca89SAndroid Build Coastguard Worker 
_extend_load_segment_vma(const ElfW (Phdr)* phdr_table,size_t phdr_count,size_t phdr_idx,ElfW (Addr)* p_memsz,ElfW (Addr)* p_filesz,bool should_pad_segments,bool should_use_16kib_app_compat)837*8d67ca89SAndroid Build Coastguard Worker static inline void _extend_load_segment_vma(const ElfW(Phdr)* phdr_table, size_t phdr_count,
838*8d67ca89SAndroid Build Coastguard Worker                                             size_t phdr_idx, ElfW(Addr)* p_memsz,
839*8d67ca89SAndroid Build Coastguard Worker                                             ElfW(Addr)* p_filesz, bool should_pad_segments,
840*8d67ca89SAndroid Build Coastguard Worker                                             bool should_use_16kib_app_compat) {
841*8d67ca89SAndroid Build Coastguard Worker   // NOTE: Segment extension is only applicable where the ELF's max-page-size > runtime page size;
842*8d67ca89SAndroid Build Coastguard Worker   // to save kernel VMA slab memory. 16KiB compat mode is the exact opposite scenario.
843*8d67ca89SAndroid Build Coastguard Worker   if (should_use_16kib_app_compat) {
844*8d67ca89SAndroid Build Coastguard Worker     return;
845*8d67ca89SAndroid Build Coastguard Worker   }
846*8d67ca89SAndroid Build Coastguard Worker 
847*8d67ca89SAndroid Build Coastguard Worker   const ElfW(Phdr)* phdr = &phdr_table[phdr_idx];
848*8d67ca89SAndroid Build Coastguard Worker   const ElfW(Phdr)* next = nullptr;
849*8d67ca89SAndroid Build Coastguard Worker   size_t next_idx = phdr_idx + 1;
850*8d67ca89SAndroid Build Coastguard Worker 
851*8d67ca89SAndroid Build Coastguard Worker   // Don't do segment extension for p_align > 64KiB, such ELFs already existed in the
852*8d67ca89SAndroid Build Coastguard Worker   // field e.g. 2MiB p_align for THPs and are relatively small in number.
853*8d67ca89SAndroid Build Coastguard Worker   //
854*8d67ca89SAndroid Build Coastguard Worker   // The kernel can only represent padding for p_align up to 64KiB. This is because
855*8d67ca89SAndroid Build Coastguard Worker   // the kernel uses 4 available bits in the vm_area_struct to represent padding
856*8d67ca89SAndroid Build Coastguard Worker   // extent; and so cannot enable mitigations to avoid breaking app compatibility for
857*8d67ca89SAndroid Build Coastguard Worker   // p_aligns > 64KiB.
858*8d67ca89SAndroid Build Coastguard Worker   //
859*8d67ca89SAndroid Build Coastguard Worker   // Don't perform segment extension on these to avoid app compatibility issues.
860*8d67ca89SAndroid Build Coastguard Worker   if (phdr->p_align <= kPageSize || phdr->p_align > 64*1024 || !should_pad_segments) {
861*8d67ca89SAndroid Build Coastguard Worker     return;
862*8d67ca89SAndroid Build Coastguard Worker   }
863*8d67ca89SAndroid Build Coastguard Worker 
864*8d67ca89SAndroid Build Coastguard Worker   if (next_idx < phdr_count && phdr_table[next_idx].p_type == PT_LOAD) {
865*8d67ca89SAndroid Build Coastguard Worker     next = &phdr_table[next_idx];
866*8d67ca89SAndroid Build Coastguard Worker   }
867*8d67ca89SAndroid Build Coastguard Worker 
868*8d67ca89SAndroid Build Coastguard Worker   // If this is the last LOAD segment, no extension is needed
869*8d67ca89SAndroid Build Coastguard Worker   if (!next || *p_memsz != *p_filesz) {
870*8d67ca89SAndroid Build Coastguard Worker     return;
871*8d67ca89SAndroid Build Coastguard Worker   }
872*8d67ca89SAndroid Build Coastguard Worker 
873*8d67ca89SAndroid Build Coastguard Worker   ElfW(Addr) next_start = page_start(next->p_vaddr);
874*8d67ca89SAndroid Build Coastguard Worker   ElfW(Addr) curr_end = page_end(phdr->p_vaddr + *p_memsz);
875*8d67ca89SAndroid Build Coastguard Worker 
876*8d67ca89SAndroid Build Coastguard Worker   // If adjacent segment mappings overlap, no extension is needed.
877*8d67ca89SAndroid Build Coastguard Worker   if (curr_end >= next_start) {
878*8d67ca89SAndroid Build Coastguard Worker     return;
879*8d67ca89SAndroid Build Coastguard Worker   }
880*8d67ca89SAndroid Build Coastguard Worker 
881*8d67ca89SAndroid Build Coastguard Worker   // Extend the LOAD segment mapping to be contiguous with that of
882*8d67ca89SAndroid Build Coastguard Worker   // the next LOAD segment.
883*8d67ca89SAndroid Build Coastguard Worker   ElfW(Addr) extend = next_start - curr_end;
884*8d67ca89SAndroid Build Coastguard Worker   *p_memsz += extend;
885*8d67ca89SAndroid Build Coastguard Worker   *p_filesz += extend;
886*8d67ca89SAndroid Build Coastguard Worker }
887*8d67ca89SAndroid Build Coastguard Worker 
MapSegment(size_t seg_idx,size_t len)888*8d67ca89SAndroid Build Coastguard Worker bool ElfReader::MapSegment(size_t seg_idx, size_t len) {
889*8d67ca89SAndroid Build Coastguard Worker   const ElfW(Phdr)* phdr = &phdr_table_[seg_idx];
890*8d67ca89SAndroid Build Coastguard Worker 
891*8d67ca89SAndroid Build Coastguard Worker   void* start = reinterpret_cast<void*>(page_start(phdr->p_vaddr + load_bias_));
892*8d67ca89SAndroid Build Coastguard Worker 
893*8d67ca89SAndroid Build Coastguard Worker   // The ELF could be being loaded directly from a zipped APK,
894*8d67ca89SAndroid Build Coastguard Worker   // the zip offset must be added to find the segment offset.
895*8d67ca89SAndroid Build Coastguard Worker   const ElfW(Addr) offset = file_offset_ + page_start(phdr->p_offset);
896*8d67ca89SAndroid Build Coastguard Worker 
897*8d67ca89SAndroid Build Coastguard Worker   int prot = PFLAGS_TO_PROT(phdr->p_flags);
898*8d67ca89SAndroid Build Coastguard Worker 
899*8d67ca89SAndroid Build Coastguard Worker   void* seg_addr = mmap64(start, len, prot, MAP_FIXED | MAP_PRIVATE, fd_, offset);
900*8d67ca89SAndroid Build Coastguard Worker 
901*8d67ca89SAndroid Build Coastguard Worker   if (seg_addr == MAP_FAILED) {
902*8d67ca89SAndroid Build Coastguard Worker     DL_ERR("couldn't map \"%s\" segment %zd: %m", name_.c_str(), seg_idx);
903*8d67ca89SAndroid Build Coastguard Worker     return false;
904*8d67ca89SAndroid Build Coastguard Worker   }
905*8d67ca89SAndroid Build Coastguard Worker 
906*8d67ca89SAndroid Build Coastguard Worker   // Mark segments as huge page eligible if they meet the requirements
907*8d67ca89SAndroid Build Coastguard Worker   if ((phdr->p_flags & PF_X) && phdr->p_align == kPmdSize &&
908*8d67ca89SAndroid Build Coastguard Worker       get_transparent_hugepages_supported()) {
909*8d67ca89SAndroid Build Coastguard Worker     madvise(seg_addr, len, MADV_HUGEPAGE);
910*8d67ca89SAndroid Build Coastguard Worker   }
911*8d67ca89SAndroid Build Coastguard Worker 
912*8d67ca89SAndroid Build Coastguard Worker   return true;
913*8d67ca89SAndroid Build Coastguard Worker }
914*8d67ca89SAndroid Build Coastguard Worker 
ZeroFillSegment(const ElfW (Phdr)* phdr)915*8d67ca89SAndroid Build Coastguard Worker void ElfReader::ZeroFillSegment(const ElfW(Phdr)* phdr) {
916*8d67ca89SAndroid Build Coastguard Worker   // NOTE: In 16KiB app compat mode, the ELF mapping is anonymous, meaning that
917*8d67ca89SAndroid Build Coastguard Worker   // RW segments are COW-ed from the kernel's zero page. So there is no need to
918*8d67ca89SAndroid Build Coastguard Worker   // explicitly zero-fill until the last page's limit.
919*8d67ca89SAndroid Build Coastguard Worker   if (should_use_16kib_app_compat_) {
920*8d67ca89SAndroid Build Coastguard Worker     return;
921*8d67ca89SAndroid Build Coastguard Worker   }
922*8d67ca89SAndroid Build Coastguard Worker 
923*8d67ca89SAndroid Build Coastguard Worker   ElfW(Addr) seg_start = phdr->p_vaddr + load_bias_;
924*8d67ca89SAndroid Build Coastguard Worker   uint64_t unextended_seg_file_end = seg_start + phdr->p_filesz;
925*8d67ca89SAndroid Build Coastguard Worker 
926*8d67ca89SAndroid Build Coastguard Worker   // If the segment is writable, and does not end on a page boundary,
927*8d67ca89SAndroid Build Coastguard Worker   // zero-fill it until the page limit.
928*8d67ca89SAndroid Build Coastguard Worker   //
929*8d67ca89SAndroid Build Coastguard Worker   // Do not attempt to zero the extended region past the first partial page,
930*8d67ca89SAndroid Build Coastguard Worker   // since doing so may:
931*8d67ca89SAndroid Build Coastguard Worker   //   1) Result in a SIGBUS, as the region is not backed by the underlying
932*8d67ca89SAndroid Build Coastguard Worker   //      file.
933*8d67ca89SAndroid Build Coastguard Worker   //   2) Break the COW backing, faulting in new anon pages for a region
934*8d67ca89SAndroid Build Coastguard Worker   //      that will not be used.
935*8d67ca89SAndroid Build Coastguard Worker   if ((phdr->p_flags & PF_W) != 0 && page_offset(unextended_seg_file_end) > 0) {
936*8d67ca89SAndroid Build Coastguard Worker     memset(reinterpret_cast<void*>(unextended_seg_file_end), 0,
937*8d67ca89SAndroid Build Coastguard Worker            kPageSize - page_offset(unextended_seg_file_end));
938*8d67ca89SAndroid Build Coastguard Worker   }
939*8d67ca89SAndroid Build Coastguard Worker }
940*8d67ca89SAndroid Build Coastguard Worker 
DropPaddingPages(const ElfW (Phdr)* phdr,uint64_t seg_file_end)941*8d67ca89SAndroid Build Coastguard Worker void ElfReader::DropPaddingPages(const ElfW(Phdr)* phdr, uint64_t seg_file_end) {
942*8d67ca89SAndroid Build Coastguard Worker   // NOTE: Padding pages are only applicable where the ELF's max-page-size > runtime page size;
943*8d67ca89SAndroid Build Coastguard Worker   // 16KiB compat mode is the exact opposite scenario.
944*8d67ca89SAndroid Build Coastguard Worker   if (should_use_16kib_app_compat_) {
945*8d67ca89SAndroid Build Coastguard Worker     return;
946*8d67ca89SAndroid Build Coastguard Worker   }
947*8d67ca89SAndroid Build Coastguard Worker 
948*8d67ca89SAndroid Build Coastguard Worker   ElfW(Addr) seg_start = phdr->p_vaddr + load_bias_;
949*8d67ca89SAndroid Build Coastguard Worker   uint64_t unextended_seg_file_end = seg_start + phdr->p_filesz;
950*8d67ca89SAndroid Build Coastguard Worker 
951*8d67ca89SAndroid Build Coastguard Worker   uint64_t pad_start = page_end(unextended_seg_file_end);
952*8d67ca89SAndroid Build Coastguard Worker   uint64_t pad_end = page_end(seg_file_end);
953*8d67ca89SAndroid Build Coastguard Worker   CHECK(pad_start <= pad_end);
954*8d67ca89SAndroid Build Coastguard Worker 
955*8d67ca89SAndroid Build Coastguard Worker   uint64_t pad_len = pad_end - pad_start;
956*8d67ca89SAndroid Build Coastguard Worker   if (pad_len == 0 || !page_size_migration_supported()) {
957*8d67ca89SAndroid Build Coastguard Worker     return;
958*8d67ca89SAndroid Build Coastguard Worker   }
959*8d67ca89SAndroid Build Coastguard Worker 
960*8d67ca89SAndroid Build Coastguard Worker   // Pages may be brought in due to readahead.
961*8d67ca89SAndroid Build Coastguard Worker   // Drop the padding (zero) pages, to avoid reclaim work later.
962*8d67ca89SAndroid Build Coastguard Worker   //
963*8d67ca89SAndroid Build Coastguard Worker   // NOTE: The madvise() here is special, as it also serves to hint to the
964*8d67ca89SAndroid Build Coastguard Worker   // kernel the portion of the LOAD segment that is padding.
965*8d67ca89SAndroid Build Coastguard Worker   //
966*8d67ca89SAndroid Build Coastguard Worker   // See: [1] https://android-review.googlesource.com/c/kernel/common/+/3032411
967*8d67ca89SAndroid Build Coastguard Worker   //      [2] https://android-review.googlesource.com/c/kernel/common/+/3048835
968*8d67ca89SAndroid Build Coastguard Worker   if (madvise(reinterpret_cast<void*>(pad_start), pad_len, MADV_DONTNEED)) {
969*8d67ca89SAndroid Build Coastguard Worker     DL_WARN("\"%s\": madvise(0x%" PRIx64 ", 0x%" PRIx64 ", MADV_DONTNEED) failed: %m",
970*8d67ca89SAndroid Build Coastguard Worker             name_.c_str(), pad_start, pad_len);
971*8d67ca89SAndroid Build Coastguard Worker   }
972*8d67ca89SAndroid Build Coastguard Worker }
973*8d67ca89SAndroid Build Coastguard Worker 
MapBssSection(const ElfW (Phdr)* phdr,ElfW (Addr)seg_page_end,ElfW (Addr)seg_file_end)974*8d67ca89SAndroid Build Coastguard Worker bool ElfReader::MapBssSection(const ElfW(Phdr)* phdr, ElfW(Addr) seg_page_end,
975*8d67ca89SAndroid Build Coastguard Worker                               ElfW(Addr) seg_file_end) {
976*8d67ca89SAndroid Build Coastguard Worker   // NOTE: We do not need to handle .bss in 16KiB compat mode since the mapping
977*8d67ca89SAndroid Build Coastguard Worker   // reservation is anonymous and RW to begin with.
978*8d67ca89SAndroid Build Coastguard Worker   if (should_use_16kib_app_compat_) {
979*8d67ca89SAndroid Build Coastguard Worker     return true;
980*8d67ca89SAndroid Build Coastguard Worker   }
981*8d67ca89SAndroid Build Coastguard Worker 
982*8d67ca89SAndroid Build Coastguard Worker   // seg_file_end is now the first page address after the file content.
983*8d67ca89SAndroid Build Coastguard Worker   seg_file_end = page_end(seg_file_end);
984*8d67ca89SAndroid Build Coastguard Worker 
985*8d67ca89SAndroid Build Coastguard Worker   if (seg_page_end <= seg_file_end) {
986*8d67ca89SAndroid Build Coastguard Worker     return true;
987*8d67ca89SAndroid Build Coastguard Worker   }
988*8d67ca89SAndroid Build Coastguard Worker 
989*8d67ca89SAndroid Build Coastguard Worker   // If seg_page_end is larger than seg_file_end, we need to zero
990*8d67ca89SAndroid Build Coastguard Worker   // anything between them. This is done by using a private anonymous
991*8d67ca89SAndroid Build Coastguard Worker   // map for all extra pages
992*8d67ca89SAndroid Build Coastguard Worker   size_t zeromap_size = seg_page_end - seg_file_end;
993*8d67ca89SAndroid Build Coastguard Worker   void* zeromap =
994*8d67ca89SAndroid Build Coastguard Worker       mmap(reinterpret_cast<void*>(seg_file_end), zeromap_size, PFLAGS_TO_PROT(phdr->p_flags),
995*8d67ca89SAndroid Build Coastguard Worker            MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
996*8d67ca89SAndroid Build Coastguard Worker   if (zeromap == MAP_FAILED) {
997*8d67ca89SAndroid Build Coastguard Worker     DL_ERR("couldn't map .bss section for \"%s\": %m", name_.c_str());
998*8d67ca89SAndroid Build Coastguard Worker     return false;
999*8d67ca89SAndroid Build Coastguard Worker   }
1000*8d67ca89SAndroid Build Coastguard Worker 
1001*8d67ca89SAndroid Build Coastguard Worker   // Set the VMA name using prctl
1002*8d67ca89SAndroid Build Coastguard Worker   prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, zeromap, zeromap_size, ".bss");
1003*8d67ca89SAndroid Build Coastguard Worker 
1004*8d67ca89SAndroid Build Coastguard Worker   return true;
1005*8d67ca89SAndroid Build Coastguard Worker }
1006*8d67ca89SAndroid Build Coastguard Worker 
LoadSegments()1007*8d67ca89SAndroid Build Coastguard Worker bool ElfReader::LoadSegments() {
1008*8d67ca89SAndroid Build Coastguard Worker   // NOTE: The compat(legacy) page size (4096) must be used when aligning
1009*8d67ca89SAndroid Build Coastguard Worker   // the 4KiB segments for loading in compat mode. The larger 16KiB page size
1010*8d67ca89SAndroid Build Coastguard Worker   // will lead to overwriting adjacent segments since the ELF's segment(s)
1011*8d67ca89SAndroid Build Coastguard Worker   // are not 16KiB aligned.
1012*8d67ca89SAndroid Build Coastguard Worker   size_t seg_align = should_use_16kib_app_compat_ ? kCompatPageSize : kPageSize;
1013*8d67ca89SAndroid Build Coastguard Worker 
1014*8d67ca89SAndroid Build Coastguard Worker   size_t min_palign = phdr_table_get_minimum_alignment(phdr_table_, phdr_num_);
1015*8d67ca89SAndroid Build Coastguard Worker   // Only enforce this on 16 KB systems with app compat disabled.
1016*8d67ca89SAndroid Build Coastguard Worker   // Apps may rely on undefined behavior here on 4 KB systems,
1017*8d67ca89SAndroid Build Coastguard Worker   // which is the norm before this change is introduced
1018*8d67ca89SAndroid Build Coastguard Worker   if (kPageSize >= 16384 && min_palign < kPageSize && !should_use_16kib_app_compat_) {
1019*8d67ca89SAndroid Build Coastguard Worker     DL_ERR("\"%s\" program alignment (%zu) cannot be smaller than system page size (%zu)",
1020*8d67ca89SAndroid Build Coastguard Worker            name_.c_str(), min_palign, kPageSize);
1021*8d67ca89SAndroid Build Coastguard Worker     return false;
1022*8d67ca89SAndroid Build Coastguard Worker   }
1023*8d67ca89SAndroid Build Coastguard Worker 
1024*8d67ca89SAndroid Build Coastguard Worker   if (!Setup16KiBAppCompat()) {
1025*8d67ca89SAndroid Build Coastguard Worker     DL_ERR("\"%s\" failed to setup 16KiB App Compat", name_.c_str());
1026*8d67ca89SAndroid Build Coastguard Worker     return false;
1027*8d67ca89SAndroid Build Coastguard Worker   }
1028*8d67ca89SAndroid Build Coastguard Worker 
1029*8d67ca89SAndroid Build Coastguard Worker   for (size_t i = 0; i < phdr_num_; ++i) {
1030*8d67ca89SAndroid Build Coastguard Worker     const ElfW(Phdr)* phdr = &phdr_table_[i];
1031*8d67ca89SAndroid Build Coastguard Worker 
1032*8d67ca89SAndroid Build Coastguard Worker     if (phdr->p_type != PT_LOAD) {
1033*8d67ca89SAndroid Build Coastguard Worker       continue;
1034*8d67ca89SAndroid Build Coastguard Worker     }
1035*8d67ca89SAndroid Build Coastguard Worker 
1036*8d67ca89SAndroid Build Coastguard Worker     ElfW(Addr) p_memsz = phdr->p_memsz;
1037*8d67ca89SAndroid Build Coastguard Worker     ElfW(Addr) p_filesz = phdr->p_filesz;
1038*8d67ca89SAndroid Build Coastguard Worker     _extend_load_segment_vma(phdr_table_, phdr_num_, i, &p_memsz, &p_filesz, should_pad_segments_,
1039*8d67ca89SAndroid Build Coastguard Worker                              should_use_16kib_app_compat_);
1040*8d67ca89SAndroid Build Coastguard Worker 
1041*8d67ca89SAndroid Build Coastguard Worker     // Segment addresses in memory.
1042*8d67ca89SAndroid Build Coastguard Worker     ElfW(Addr) seg_start = phdr->p_vaddr + load_bias_;
1043*8d67ca89SAndroid Build Coastguard Worker     ElfW(Addr) seg_end = seg_start + p_memsz;
1044*8d67ca89SAndroid Build Coastguard Worker 
1045*8d67ca89SAndroid Build Coastguard Worker     ElfW(Addr) seg_page_end = align_up(seg_end, seg_align);
1046*8d67ca89SAndroid Build Coastguard Worker 
1047*8d67ca89SAndroid Build Coastguard Worker     ElfW(Addr) seg_file_end = seg_start + p_filesz;
1048*8d67ca89SAndroid Build Coastguard Worker 
1049*8d67ca89SAndroid Build Coastguard Worker     // File offsets.
1050*8d67ca89SAndroid Build Coastguard Worker     ElfW(Addr) file_start = phdr->p_offset;
1051*8d67ca89SAndroid Build Coastguard Worker     ElfW(Addr) file_end = file_start + p_filesz;
1052*8d67ca89SAndroid Build Coastguard Worker 
1053*8d67ca89SAndroid Build Coastguard Worker     ElfW(Addr) file_page_start = align_down(file_start, seg_align);
1054*8d67ca89SAndroid Build Coastguard Worker     ElfW(Addr) file_length = file_end - file_page_start;
1055*8d67ca89SAndroid Build Coastguard Worker 
1056*8d67ca89SAndroid Build Coastguard Worker     if (file_size_ <= 0) {
1057*8d67ca89SAndroid Build Coastguard Worker       DL_ERR("\"%s\" invalid file size: %" PRId64, name_.c_str(), file_size_);
1058*8d67ca89SAndroid Build Coastguard Worker       return false;
1059*8d67ca89SAndroid Build Coastguard Worker     }
1060*8d67ca89SAndroid Build Coastguard Worker 
1061*8d67ca89SAndroid Build Coastguard Worker     if (file_start + phdr->p_filesz > static_cast<size_t>(file_size_)) {
1062*8d67ca89SAndroid Build Coastguard Worker       DL_ERR("invalid ELF file \"%s\" load segment[%zd]:"
1063*8d67ca89SAndroid Build Coastguard Worker           " p_offset (%p) + p_filesz (%p) ( = %p) past end of file (0x%" PRIx64 ")",
1064*8d67ca89SAndroid Build Coastguard Worker           name_.c_str(), i, reinterpret_cast<void*>(phdr->p_offset),
1065*8d67ca89SAndroid Build Coastguard Worker           reinterpret_cast<void*>(phdr->p_filesz),
1066*8d67ca89SAndroid Build Coastguard Worker           reinterpret_cast<void*>(file_start + phdr->p_filesz), file_size_);
1067*8d67ca89SAndroid Build Coastguard Worker       return false;
1068*8d67ca89SAndroid Build Coastguard Worker     }
1069*8d67ca89SAndroid Build Coastguard Worker 
1070*8d67ca89SAndroid Build Coastguard Worker     if (file_length != 0) {
1071*8d67ca89SAndroid Build Coastguard Worker       int prot = PFLAGS_TO_PROT(phdr->p_flags);
1072*8d67ca89SAndroid Build Coastguard Worker       if ((prot & (PROT_EXEC | PROT_WRITE)) == (PROT_EXEC | PROT_WRITE)) {
1073*8d67ca89SAndroid Build Coastguard Worker         // W + E PT_LOAD segments are not allowed in O.
1074*8d67ca89SAndroid Build Coastguard Worker         if (get_application_target_sdk_version() >= 26) {
1075*8d67ca89SAndroid Build Coastguard Worker           DL_ERR_AND_LOG("\"%s\": W+E load segments are not allowed", name_.c_str());
1076*8d67ca89SAndroid Build Coastguard Worker           return false;
1077*8d67ca89SAndroid Build Coastguard Worker         }
1078*8d67ca89SAndroid Build Coastguard Worker         DL_WARN_documented_change(26,
1079*8d67ca89SAndroid Build Coastguard Worker                                   "writable-and-executable-segments-enforced-for-api-level-26",
1080*8d67ca89SAndroid Build Coastguard Worker                                   "\"%s\" has load segments that are both writable and executable",
1081*8d67ca89SAndroid Build Coastguard Worker                                   name_.c_str());
1082*8d67ca89SAndroid Build Coastguard Worker         add_dlwarning(name_.c_str(), "W+E load segments");
1083*8d67ca89SAndroid Build Coastguard Worker       }
1084*8d67ca89SAndroid Build Coastguard Worker 
1085*8d67ca89SAndroid Build Coastguard Worker       // Pass the file_length, since it may have been extended by _extend_load_segment_vma().
1086*8d67ca89SAndroid Build Coastguard Worker       if (should_use_16kib_app_compat_) {
1087*8d67ca89SAndroid Build Coastguard Worker         if (!CompatMapSegment(i, file_length)) {
1088*8d67ca89SAndroid Build Coastguard Worker           return false;
1089*8d67ca89SAndroid Build Coastguard Worker         }
1090*8d67ca89SAndroid Build Coastguard Worker       } else {
1091*8d67ca89SAndroid Build Coastguard Worker         if (!MapSegment(i, file_length)) {
1092*8d67ca89SAndroid Build Coastguard Worker           return false;
1093*8d67ca89SAndroid Build Coastguard Worker         }
1094*8d67ca89SAndroid Build Coastguard Worker       }
1095*8d67ca89SAndroid Build Coastguard Worker     }
1096*8d67ca89SAndroid Build Coastguard Worker 
1097*8d67ca89SAndroid Build Coastguard Worker     ZeroFillSegment(phdr);
1098*8d67ca89SAndroid Build Coastguard Worker 
1099*8d67ca89SAndroid Build Coastguard Worker     DropPaddingPages(phdr, seg_file_end);
1100*8d67ca89SAndroid Build Coastguard Worker 
1101*8d67ca89SAndroid Build Coastguard Worker     if (!MapBssSection(phdr, seg_page_end, seg_file_end)) {
1102*8d67ca89SAndroid Build Coastguard Worker       return false;
1103*8d67ca89SAndroid Build Coastguard Worker     }
1104*8d67ca89SAndroid Build Coastguard Worker   }
1105*8d67ca89SAndroid Build Coastguard Worker   return true;
1106*8d67ca89SAndroid Build Coastguard Worker }
1107*8d67ca89SAndroid Build Coastguard Worker 
1108*8d67ca89SAndroid Build Coastguard Worker /* Used internally. Used to set the protection bits of all loaded segments
1109*8d67ca89SAndroid Build Coastguard Worker  * with optional extra flags (i.e. really PROT_WRITE). Used by
1110*8d67ca89SAndroid Build Coastguard Worker  * phdr_table_protect_segments and phdr_table_unprotect_segments.
1111*8d67ca89SAndroid Build Coastguard Worker  */
_phdr_table_set_load_prot(const ElfW (Phdr)* phdr_table,size_t phdr_count,ElfW (Addr)load_bias,int extra_prot_flags,bool should_pad_segments,bool should_use_16kib_app_compat)1112*8d67ca89SAndroid Build Coastguard Worker static int _phdr_table_set_load_prot(const ElfW(Phdr)* phdr_table, size_t phdr_count,
1113*8d67ca89SAndroid Build Coastguard Worker                                      ElfW(Addr) load_bias, int extra_prot_flags,
1114*8d67ca89SAndroid Build Coastguard Worker                                      bool should_pad_segments, bool should_use_16kib_app_compat) {
1115*8d67ca89SAndroid Build Coastguard Worker   for (size_t i = 0; i < phdr_count; ++i) {
1116*8d67ca89SAndroid Build Coastguard Worker     const ElfW(Phdr)* phdr = &phdr_table[i];
1117*8d67ca89SAndroid Build Coastguard Worker 
1118*8d67ca89SAndroid Build Coastguard Worker     if (phdr->p_type != PT_LOAD || (phdr->p_flags & PF_W) != 0) {
1119*8d67ca89SAndroid Build Coastguard Worker       continue;
1120*8d67ca89SAndroid Build Coastguard Worker     }
1121*8d67ca89SAndroid Build Coastguard Worker 
1122*8d67ca89SAndroid Build Coastguard Worker     ElfW(Addr) p_memsz = phdr->p_memsz;
1123*8d67ca89SAndroid Build Coastguard Worker     ElfW(Addr) p_filesz = phdr->p_filesz;
1124*8d67ca89SAndroid Build Coastguard Worker     _extend_load_segment_vma(phdr_table, phdr_count, i, &p_memsz, &p_filesz, should_pad_segments,
1125*8d67ca89SAndroid Build Coastguard Worker                              should_use_16kib_app_compat);
1126*8d67ca89SAndroid Build Coastguard Worker 
1127*8d67ca89SAndroid Build Coastguard Worker     ElfW(Addr) seg_page_start = page_start(phdr->p_vaddr + load_bias);
1128*8d67ca89SAndroid Build Coastguard Worker     ElfW(Addr) seg_page_end = page_end(phdr->p_vaddr + p_memsz + load_bias);
1129*8d67ca89SAndroid Build Coastguard Worker 
1130*8d67ca89SAndroid Build Coastguard Worker     int prot = PFLAGS_TO_PROT(phdr->p_flags) | extra_prot_flags;
1131*8d67ca89SAndroid Build Coastguard Worker     if ((prot & PROT_WRITE) != 0) {
1132*8d67ca89SAndroid Build Coastguard Worker       // make sure we're never simultaneously writable / executable
1133*8d67ca89SAndroid Build Coastguard Worker       prot &= ~PROT_EXEC;
1134*8d67ca89SAndroid Build Coastguard Worker     }
1135*8d67ca89SAndroid Build Coastguard Worker #if defined(__aarch64__)
1136*8d67ca89SAndroid Build Coastguard Worker     if ((prot & PROT_EXEC) == 0) {
1137*8d67ca89SAndroid Build Coastguard Worker       // Though it is not specified don't add PROT_BTI if segment is not
1138*8d67ca89SAndroid Build Coastguard Worker       // executable.
1139*8d67ca89SAndroid Build Coastguard Worker       prot &= ~PROT_BTI;
1140*8d67ca89SAndroid Build Coastguard Worker     }
1141*8d67ca89SAndroid Build Coastguard Worker #endif
1142*8d67ca89SAndroid Build Coastguard Worker 
1143*8d67ca89SAndroid Build Coastguard Worker     int ret =
1144*8d67ca89SAndroid Build Coastguard Worker         mprotect(reinterpret_cast<void*>(seg_page_start), seg_page_end - seg_page_start, prot);
1145*8d67ca89SAndroid Build Coastguard Worker     if (ret < 0) {
1146*8d67ca89SAndroid Build Coastguard Worker       return -1;
1147*8d67ca89SAndroid Build Coastguard Worker     }
1148*8d67ca89SAndroid Build Coastguard Worker   }
1149*8d67ca89SAndroid Build Coastguard Worker   return 0;
1150*8d67ca89SAndroid Build Coastguard Worker }
1151*8d67ca89SAndroid Build Coastguard Worker 
1152*8d67ca89SAndroid Build Coastguard Worker /* Restore the original protection modes for all loadable segments.
1153*8d67ca89SAndroid Build Coastguard Worker  * You should only call this after phdr_table_unprotect_segments and
1154*8d67ca89SAndroid Build Coastguard Worker  * applying all relocations.
1155*8d67ca89SAndroid Build Coastguard Worker  *
1156*8d67ca89SAndroid Build Coastguard Worker  * AArch64: also called from linker_main and ElfReader::Load to apply
1157*8d67ca89SAndroid Build Coastguard Worker  *     PROT_BTI for loaded main so and other so-s.
1158*8d67ca89SAndroid Build Coastguard Worker  *
1159*8d67ca89SAndroid Build Coastguard Worker  * Input:
1160*8d67ca89SAndroid Build Coastguard Worker  *   phdr_table  -> program header table
1161*8d67ca89SAndroid Build Coastguard Worker  *   phdr_count  -> number of entries in tables
1162*8d67ca89SAndroid Build Coastguard Worker  *   load_bias   -> load bias
1163*8d67ca89SAndroid Build Coastguard Worker  *   should_pad_segments -> Are segments extended to avoid gaps in the memory map
1164*8d67ca89SAndroid Build Coastguard Worker  *   should_use_16kib_app_compat -> Is the ELF being loaded in 16KiB app compat mode.
1165*8d67ca89SAndroid Build Coastguard Worker  *   prop        -> GnuPropertySection or nullptr
1166*8d67ca89SAndroid Build Coastguard Worker  * Return:
1167*8d67ca89SAndroid Build Coastguard Worker  *   0 on success, -1 on failure (error code in errno).
1168*8d67ca89SAndroid Build Coastguard Worker  */
phdr_table_protect_segments(const ElfW (Phdr)* phdr_table,size_t phdr_count,ElfW (Addr)load_bias,bool should_pad_segments,bool should_use_16kib_app_compat,const GnuPropertySection * prop __unused)1169*8d67ca89SAndroid Build Coastguard Worker int phdr_table_protect_segments(const ElfW(Phdr)* phdr_table, size_t phdr_count,
1170*8d67ca89SAndroid Build Coastguard Worker                                 ElfW(Addr) load_bias, bool should_pad_segments,
1171*8d67ca89SAndroid Build Coastguard Worker                                 bool should_use_16kib_app_compat,
1172*8d67ca89SAndroid Build Coastguard Worker                                 const GnuPropertySection* prop __unused) {
1173*8d67ca89SAndroid Build Coastguard Worker   int prot = 0;
1174*8d67ca89SAndroid Build Coastguard Worker #if defined(__aarch64__)
1175*8d67ca89SAndroid Build Coastguard Worker   if ((prop != nullptr) && prop->IsBTICompatible()) {
1176*8d67ca89SAndroid Build Coastguard Worker     prot |= PROT_BTI;
1177*8d67ca89SAndroid Build Coastguard Worker   }
1178*8d67ca89SAndroid Build Coastguard Worker #endif
1179*8d67ca89SAndroid Build Coastguard Worker   return _phdr_table_set_load_prot(phdr_table, phdr_count, load_bias, prot, should_pad_segments,
1180*8d67ca89SAndroid Build Coastguard Worker                                    should_use_16kib_app_compat);
1181*8d67ca89SAndroid Build Coastguard Worker }
1182*8d67ca89SAndroid Build Coastguard Worker 
segment_needs_memtag_globals_remapping(const ElfW (Phdr)* phdr)1183*8d67ca89SAndroid Build Coastguard Worker static bool segment_needs_memtag_globals_remapping(const ElfW(Phdr) * phdr) {
1184*8d67ca89SAndroid Build Coastguard Worker   // For now, MTE globals is only supported on writeable data segments.
1185*8d67ca89SAndroid Build Coastguard Worker   return phdr->p_type == PT_LOAD && !(phdr->p_flags & PF_X) && (phdr->p_flags & PF_W);
1186*8d67ca89SAndroid Build Coastguard Worker }
1187*8d67ca89SAndroid Build Coastguard Worker 
1188*8d67ca89SAndroid Build Coastguard Worker /* When MTE globals are requested by the binary, and when the hardware supports
1189*8d67ca89SAndroid Build Coastguard Worker  * it, remap the executable's PT_LOAD data pages to have PROT_MTE.
1190*8d67ca89SAndroid Build Coastguard Worker  *
1191*8d67ca89SAndroid Build Coastguard Worker  * Returns 0 on success, -1 on failure (error code in errno).
1192*8d67ca89SAndroid Build Coastguard Worker  */
remap_memtag_globals_segments(const ElfW (Phdr)* phdr_table __unused,size_t phdr_count __unused,ElfW (Addr)load_bias __unused)1193*8d67ca89SAndroid Build Coastguard Worker int remap_memtag_globals_segments(const ElfW(Phdr) * phdr_table __unused,
1194*8d67ca89SAndroid Build Coastguard Worker                                   size_t phdr_count __unused, ElfW(Addr) load_bias __unused) {
1195*8d67ca89SAndroid Build Coastguard Worker #if defined(__aarch64__)
1196*8d67ca89SAndroid Build Coastguard Worker   for (const ElfW(Phdr)* phdr = phdr_table; phdr < phdr_table + phdr_count; phdr++) {
1197*8d67ca89SAndroid Build Coastguard Worker     if (!segment_needs_memtag_globals_remapping(phdr)) {
1198*8d67ca89SAndroid Build Coastguard Worker       continue;
1199*8d67ca89SAndroid Build Coastguard Worker     }
1200*8d67ca89SAndroid Build Coastguard Worker 
1201*8d67ca89SAndroid Build Coastguard Worker     uintptr_t seg_page_start = page_start(phdr->p_vaddr) + load_bias;
1202*8d67ca89SAndroid Build Coastguard Worker     uintptr_t seg_page_end = page_end(phdr->p_vaddr + phdr->p_memsz) + load_bias;
1203*8d67ca89SAndroid Build Coastguard Worker     size_t seg_page_aligned_size = seg_page_end - seg_page_start;
1204*8d67ca89SAndroid Build Coastguard Worker 
1205*8d67ca89SAndroid Build Coastguard Worker     int prot = PFLAGS_TO_PROT(phdr->p_flags);
1206*8d67ca89SAndroid Build Coastguard Worker     // For anonymous private mappings, it may be possible to simply mprotect()
1207*8d67ca89SAndroid Build Coastguard Worker     // the PROT_MTE flag over the top. For file-based mappings, this will fail,
1208*8d67ca89SAndroid Build Coastguard Worker     // and we'll need to fall back. We also allow PROT_WRITE here to allow
1209*8d67ca89SAndroid Build Coastguard Worker     // writing memory tags (in `soinfo::tag_globals()`), and set these sections
1210*8d67ca89SAndroid Build Coastguard Worker     // back to read-only after tags are applied (similar to RELRO).
1211*8d67ca89SAndroid Build Coastguard Worker     prot |= PROT_MTE;
1212*8d67ca89SAndroid Build Coastguard Worker     if (mprotect(reinterpret_cast<void*>(seg_page_start), seg_page_aligned_size,
1213*8d67ca89SAndroid Build Coastguard Worker                  prot | PROT_WRITE) == 0) {
1214*8d67ca89SAndroid Build Coastguard Worker       continue;
1215*8d67ca89SAndroid Build Coastguard Worker     }
1216*8d67ca89SAndroid Build Coastguard Worker 
1217*8d67ca89SAndroid Build Coastguard Worker     void* mapping_copy = mmap(nullptr, seg_page_aligned_size, PROT_READ | PROT_WRITE,
1218*8d67ca89SAndroid Build Coastguard Worker                               MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
1219*8d67ca89SAndroid Build Coastguard Worker     linker_memcpy(mapping_copy, reinterpret_cast<void*>(seg_page_start), seg_page_aligned_size);
1220*8d67ca89SAndroid Build Coastguard Worker 
1221*8d67ca89SAndroid Build Coastguard Worker     void* seg_addr = mmap(reinterpret_cast<void*>(seg_page_start), seg_page_aligned_size,
1222*8d67ca89SAndroid Build Coastguard Worker                           prot | PROT_WRITE, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
1223*8d67ca89SAndroid Build Coastguard Worker     if (seg_addr == MAP_FAILED) return -1;
1224*8d67ca89SAndroid Build Coastguard Worker 
1225*8d67ca89SAndroid Build Coastguard Worker     linker_memcpy(seg_addr, mapping_copy, seg_page_aligned_size);
1226*8d67ca89SAndroid Build Coastguard Worker     munmap(mapping_copy, seg_page_aligned_size);
1227*8d67ca89SAndroid Build Coastguard Worker   }
1228*8d67ca89SAndroid Build Coastguard Worker #endif  // defined(__aarch64__)
1229*8d67ca89SAndroid Build Coastguard Worker   return 0;
1230*8d67ca89SAndroid Build Coastguard Worker }
1231*8d67ca89SAndroid Build Coastguard Worker 
protect_memtag_globals_ro_segments(const ElfW (Phdr)* phdr_table __unused,size_t phdr_count __unused,ElfW (Addr)load_bias __unused)1232*8d67ca89SAndroid Build Coastguard Worker void protect_memtag_globals_ro_segments(const ElfW(Phdr) * phdr_table __unused,
1233*8d67ca89SAndroid Build Coastguard Worker                                         size_t phdr_count __unused, ElfW(Addr) load_bias __unused) {
1234*8d67ca89SAndroid Build Coastguard Worker #if defined(__aarch64__)
1235*8d67ca89SAndroid Build Coastguard Worker   for (const ElfW(Phdr)* phdr = phdr_table; phdr < phdr_table + phdr_count; phdr++) {
1236*8d67ca89SAndroid Build Coastguard Worker     int prot = PFLAGS_TO_PROT(phdr->p_flags);
1237*8d67ca89SAndroid Build Coastguard Worker     if (!segment_needs_memtag_globals_remapping(phdr) || (prot & PROT_WRITE)) {
1238*8d67ca89SAndroid Build Coastguard Worker       continue;
1239*8d67ca89SAndroid Build Coastguard Worker     }
1240*8d67ca89SAndroid Build Coastguard Worker 
1241*8d67ca89SAndroid Build Coastguard Worker     prot |= PROT_MTE;
1242*8d67ca89SAndroid Build Coastguard Worker 
1243*8d67ca89SAndroid Build Coastguard Worker     uintptr_t seg_page_start = page_start(phdr->p_vaddr) + load_bias;
1244*8d67ca89SAndroid Build Coastguard Worker     uintptr_t seg_page_end = page_end(phdr->p_vaddr + phdr->p_memsz) + load_bias;
1245*8d67ca89SAndroid Build Coastguard Worker     size_t seg_page_aligned_size = seg_page_end - seg_page_start;
1246*8d67ca89SAndroid Build Coastguard Worker     mprotect(reinterpret_cast<void*>(seg_page_start), seg_page_aligned_size, prot);
1247*8d67ca89SAndroid Build Coastguard Worker   }
1248*8d67ca89SAndroid Build Coastguard Worker #endif  // defined(__aarch64__)
1249*8d67ca89SAndroid Build Coastguard Worker }
1250*8d67ca89SAndroid Build Coastguard Worker 
name_memtag_globals_segments(const ElfW (Phdr)* phdr_table,size_t phdr_count,ElfW (Addr)load_bias,const char * soname,std::list<std::string> * vma_names)1251*8d67ca89SAndroid Build Coastguard Worker void name_memtag_globals_segments(const ElfW(Phdr) * phdr_table, size_t phdr_count,
1252*8d67ca89SAndroid Build Coastguard Worker                                   ElfW(Addr) load_bias, const char* soname,
1253*8d67ca89SAndroid Build Coastguard Worker                                   std::list<std::string>* vma_names) {
1254*8d67ca89SAndroid Build Coastguard Worker   for (const ElfW(Phdr)* phdr = phdr_table; phdr < phdr_table + phdr_count; phdr++) {
1255*8d67ca89SAndroid Build Coastguard Worker     if (!segment_needs_memtag_globals_remapping(phdr)) {
1256*8d67ca89SAndroid Build Coastguard Worker       continue;
1257*8d67ca89SAndroid Build Coastguard Worker     }
1258*8d67ca89SAndroid Build Coastguard Worker 
1259*8d67ca89SAndroid Build Coastguard Worker     uintptr_t seg_page_start = page_start(phdr->p_vaddr) + load_bias;
1260*8d67ca89SAndroid Build Coastguard Worker     uintptr_t seg_page_end = page_end(phdr->p_vaddr + phdr->p_memsz) + load_bias;
1261*8d67ca89SAndroid Build Coastguard Worker     size_t seg_page_aligned_size = seg_page_end - seg_page_start;
1262*8d67ca89SAndroid Build Coastguard Worker 
1263*8d67ca89SAndroid Build Coastguard Worker     // For file-based mappings that we're now forcing to be anonymous mappings, set the VMA name to
1264*8d67ca89SAndroid Build Coastguard Worker     // make debugging easier.
1265*8d67ca89SAndroid Build Coastguard Worker     // Once we are targeting only devices that run kernel 5.10 or newer (and thus include
1266*8d67ca89SAndroid Build Coastguard Worker     // https://android-review.git.corp.google.com/c/kernel/common/+/1934723 which causes the
1267*8d67ca89SAndroid Build Coastguard Worker     // VMA_ANON_NAME to be copied into the kernel), we can get rid of the storage here.
1268*8d67ca89SAndroid Build Coastguard Worker     // For now, that is not the case:
1269*8d67ca89SAndroid Build Coastguard Worker     // https://source.android.com/docs/core/architecture/kernel/android-common#compatibility-matrix
1270*8d67ca89SAndroid Build Coastguard Worker     constexpr int kVmaNameLimit = 80;
1271*8d67ca89SAndroid Build Coastguard Worker     std::string& vma_name = vma_names->emplace_back(kVmaNameLimit, '\0');
1272*8d67ca89SAndroid Build Coastguard Worker     int full_vma_length =
1273*8d67ca89SAndroid Build Coastguard Worker         async_safe_format_buffer(vma_name.data(), kVmaNameLimit, "mt:%s+%" PRIxPTR, soname,
1274*8d67ca89SAndroid Build Coastguard Worker                                  page_start(phdr->p_vaddr)) +
1275*8d67ca89SAndroid Build Coastguard Worker         /* include the null terminator */ 1;
1276*8d67ca89SAndroid Build Coastguard Worker     // There's an upper limit of 80 characters, including the null terminator, in the anonymous VMA
1277*8d67ca89SAndroid Build Coastguard Worker     // name. If we run over that limit, we end up truncating the segment offset and parts of the
1278*8d67ca89SAndroid Build Coastguard Worker     // DSO's name, starting on the right hand side of the basename. Because the basename is the most
1279*8d67ca89SAndroid Build Coastguard Worker     // important thing, chop off the soname from the left hand side first.
1280*8d67ca89SAndroid Build Coastguard Worker     //
1281*8d67ca89SAndroid Build Coastguard Worker     // Example (with '#' as the null terminator):
1282*8d67ca89SAndroid Build Coastguard Worker     //   - "mt:/data/nativetest64/bionic-unit-tests/bionic-loader-test-libs/libdlext_test.so+e000#"
1283*8d67ca89SAndroid Build Coastguard Worker     //     is a `full_vma_length` == 86.
1284*8d67ca89SAndroid Build Coastguard Worker     //
1285*8d67ca89SAndroid Build Coastguard Worker     // We need to left-truncate (86 - 80) 6 characters from the soname, plus the
1286*8d67ca89SAndroid Build Coastguard Worker     // `vma_truncation_prefix`, so 9 characters total.
1287*8d67ca89SAndroid Build Coastguard Worker     if (full_vma_length > kVmaNameLimit) {
1288*8d67ca89SAndroid Build Coastguard Worker       const char vma_truncation_prefix[] = "...";
1289*8d67ca89SAndroid Build Coastguard Worker       int soname_truncated_bytes =
1290*8d67ca89SAndroid Build Coastguard Worker           full_vma_length - kVmaNameLimit + sizeof(vma_truncation_prefix) - 1;
1291*8d67ca89SAndroid Build Coastguard Worker       async_safe_format_buffer(vma_name.data(), kVmaNameLimit, "mt:%s%s+%" PRIxPTR,
1292*8d67ca89SAndroid Build Coastguard Worker                                vma_truncation_prefix, soname + soname_truncated_bytes,
1293*8d67ca89SAndroid Build Coastguard Worker                                page_start(phdr->p_vaddr));
1294*8d67ca89SAndroid Build Coastguard Worker     }
1295*8d67ca89SAndroid Build Coastguard Worker     if (prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, reinterpret_cast<void*>(seg_page_start),
1296*8d67ca89SAndroid Build Coastguard Worker               seg_page_aligned_size, vma_name.data()) != 0) {
1297*8d67ca89SAndroid Build Coastguard Worker       DL_WARN("Failed to rename memtag global segment: %m");
1298*8d67ca89SAndroid Build Coastguard Worker     }
1299*8d67ca89SAndroid Build Coastguard Worker   }
1300*8d67ca89SAndroid Build Coastguard Worker }
1301*8d67ca89SAndroid Build Coastguard Worker 
1302*8d67ca89SAndroid Build Coastguard Worker /* Change the protection of all loaded segments in memory to writable.
1303*8d67ca89SAndroid Build Coastguard Worker  * This is useful before performing relocations. Once completed, you
1304*8d67ca89SAndroid Build Coastguard Worker  * will have to call phdr_table_protect_segments to restore the original
1305*8d67ca89SAndroid Build Coastguard Worker  * protection flags on all segments.
1306*8d67ca89SAndroid Build Coastguard Worker  *
1307*8d67ca89SAndroid Build Coastguard Worker  * Note that some writable segments can also have their content turned
1308*8d67ca89SAndroid Build Coastguard Worker  * to read-only by calling phdr_table_protect_gnu_relro. This is no
1309*8d67ca89SAndroid Build Coastguard Worker  * performed here.
1310*8d67ca89SAndroid Build Coastguard Worker  *
1311*8d67ca89SAndroid Build Coastguard Worker  * Input:
1312*8d67ca89SAndroid Build Coastguard Worker  *   phdr_table  -> program header table
1313*8d67ca89SAndroid Build Coastguard Worker  *   phdr_count  -> number of entries in tables
1314*8d67ca89SAndroid Build Coastguard Worker  *   load_bias   -> load bias
1315*8d67ca89SAndroid Build Coastguard Worker  *   should_pad_segments -> Are segments extended to avoid gaps in the memory map
1316*8d67ca89SAndroid Build Coastguard Worker  *   should_use_16kib_app_compat -> Is the ELF being loaded in 16KiB app compat mode.
1317*8d67ca89SAndroid Build Coastguard Worker  * Return:
1318*8d67ca89SAndroid Build Coastguard Worker  *   0 on success, -1 on failure (error code in errno).
1319*8d67ca89SAndroid Build Coastguard Worker  */
phdr_table_unprotect_segments(const ElfW (Phdr)* phdr_table,size_t phdr_count,ElfW (Addr)load_bias,bool should_pad_segments,bool should_use_16kib_app_compat)1320*8d67ca89SAndroid Build Coastguard Worker int phdr_table_unprotect_segments(const ElfW(Phdr)* phdr_table, size_t phdr_count,
1321*8d67ca89SAndroid Build Coastguard Worker                                   ElfW(Addr) load_bias, bool should_pad_segments,
1322*8d67ca89SAndroid Build Coastguard Worker                                   bool should_use_16kib_app_compat) {
1323*8d67ca89SAndroid Build Coastguard Worker   return _phdr_table_set_load_prot(phdr_table, phdr_count, load_bias, PROT_WRITE,
1324*8d67ca89SAndroid Build Coastguard Worker                                    should_pad_segments, should_use_16kib_app_compat);
1325*8d67ca89SAndroid Build Coastguard Worker }
1326*8d67ca89SAndroid Build Coastguard Worker 
_extend_gnu_relro_prot_end(const ElfW (Phdr)* relro_phdr,const ElfW (Phdr)* phdr_table,size_t phdr_count,ElfW (Addr)load_bias,ElfW (Addr)* seg_page_end,bool should_pad_segments,bool should_use_16kib_app_compat)1327*8d67ca89SAndroid Build Coastguard Worker static inline void _extend_gnu_relro_prot_end(const ElfW(Phdr)* relro_phdr,
1328*8d67ca89SAndroid Build Coastguard Worker                                               const ElfW(Phdr)* phdr_table, size_t phdr_count,
1329*8d67ca89SAndroid Build Coastguard Worker                                               ElfW(Addr) load_bias, ElfW(Addr)* seg_page_end,
1330*8d67ca89SAndroid Build Coastguard Worker                                               bool should_pad_segments,
1331*8d67ca89SAndroid Build Coastguard Worker                                               bool should_use_16kib_app_compat) {
1332*8d67ca89SAndroid Build Coastguard Worker   // Find the index and phdr of the LOAD containing the GNU_RELRO segment
1333*8d67ca89SAndroid Build Coastguard Worker   for (size_t index = 0; index < phdr_count; ++index) {
1334*8d67ca89SAndroid Build Coastguard Worker     const ElfW(Phdr)* phdr = &phdr_table[index];
1335*8d67ca89SAndroid Build Coastguard Worker 
1336*8d67ca89SAndroid Build Coastguard Worker     if (phdr->p_type == PT_LOAD && phdr->p_vaddr == relro_phdr->p_vaddr) {
1337*8d67ca89SAndroid Build Coastguard Worker       // If the PT_GNU_RELRO mem size is not at least as large as the corresponding
1338*8d67ca89SAndroid Build Coastguard Worker       // LOAD segment mem size, we need to protect only a partial region of the
1339*8d67ca89SAndroid Build Coastguard Worker       // LOAD segment and therefore cannot avoid a VMA split.
1340*8d67ca89SAndroid Build Coastguard Worker       //
1341*8d67ca89SAndroid Build Coastguard Worker       // Note: Don't check the page-aligned mem sizes since the extended protection
1342*8d67ca89SAndroid Build Coastguard Worker       // may incorrectly write protect non-relocation data.
1343*8d67ca89SAndroid Build Coastguard Worker       //
1344*8d67ca89SAndroid Build Coastguard Worker       // Example:
1345*8d67ca89SAndroid Build Coastguard Worker       //
1346*8d67ca89SAndroid Build Coastguard Worker       //               |---- 3K ----|-- 1K --|---- 3K ---- |-- 1K --|
1347*8d67ca89SAndroid Build Coastguard Worker       //       ----------------------------------------------------------------
1348*8d67ca89SAndroid Build Coastguard Worker       //               |            |        |             |        |
1349*8d67ca89SAndroid Build Coastguard Worker       //        SEG X  |     RO     |   RO   |     RW      |        |   SEG Y
1350*8d67ca89SAndroid Build Coastguard Worker       //               |            |        |             |        |
1351*8d67ca89SAndroid Build Coastguard Worker       //       ----------------------------------------------------------------
1352*8d67ca89SAndroid Build Coastguard Worker       //                            |        |             |
1353*8d67ca89SAndroid Build Coastguard Worker       //                            |        |             |
1354*8d67ca89SAndroid Build Coastguard Worker       //                            |        |             |
1355*8d67ca89SAndroid Build Coastguard Worker       //                    relro_vaddr   relro_vaddr   relro_vaddr
1356*8d67ca89SAndroid Build Coastguard Worker       //                    (load_vaddr)       +            +
1357*8d67ca89SAndroid Build Coastguard Worker       //                                  relro_memsz   load_memsz
1358*8d67ca89SAndroid Build Coastguard Worker       //
1359*8d67ca89SAndroid Build Coastguard Worker       //       ----------------------------------------------------------------
1360*8d67ca89SAndroid Build Coastguard Worker       //               |         PAGE        |         PAGE         |
1361*8d67ca89SAndroid Build Coastguard Worker       //       ----------------------------------------------------------------
1362*8d67ca89SAndroid Build Coastguard Worker       //                                     |       Potential      |
1363*8d67ca89SAndroid Build Coastguard Worker       //                                     |----- Extended RO ----|
1364*8d67ca89SAndroid Build Coastguard Worker       //                                     |      Protection      |
1365*8d67ca89SAndroid Build Coastguard Worker       //
1366*8d67ca89SAndroid Build Coastguard Worker       // If the check below uses  page aligned mem sizes it will cause incorrect write
1367*8d67ca89SAndroid Build Coastguard Worker       // protection of the 3K RW part of the LOAD segment containing the GNU_RELRO.
1368*8d67ca89SAndroid Build Coastguard Worker       if (relro_phdr->p_memsz < phdr->p_memsz) {
1369*8d67ca89SAndroid Build Coastguard Worker         return;
1370*8d67ca89SAndroid Build Coastguard Worker       }
1371*8d67ca89SAndroid Build Coastguard Worker 
1372*8d67ca89SAndroid Build Coastguard Worker       ElfW(Addr) p_memsz = phdr->p_memsz;
1373*8d67ca89SAndroid Build Coastguard Worker       ElfW(Addr) p_filesz = phdr->p_filesz;
1374*8d67ca89SAndroid Build Coastguard Worker 
1375*8d67ca89SAndroid Build Coastguard Worker       // Attempt extending the VMA (mprotect range). Without extending the range,
1376*8d67ca89SAndroid Build Coastguard Worker       // mprotect will only RO protect a part of the extended RW LOAD segment, which
1377*8d67ca89SAndroid Build Coastguard Worker       // will leave an extra split RW VMA (the gap).
1378*8d67ca89SAndroid Build Coastguard Worker       _extend_load_segment_vma(phdr_table, phdr_count, index, &p_memsz, &p_filesz,
1379*8d67ca89SAndroid Build Coastguard Worker                                should_pad_segments, should_use_16kib_app_compat);
1380*8d67ca89SAndroid Build Coastguard Worker 
1381*8d67ca89SAndroid Build Coastguard Worker       *seg_page_end = page_end(phdr->p_vaddr + p_memsz + load_bias);
1382*8d67ca89SAndroid Build Coastguard Worker       return;
1383*8d67ca89SAndroid Build Coastguard Worker     }
1384*8d67ca89SAndroid Build Coastguard Worker   }
1385*8d67ca89SAndroid Build Coastguard Worker }
1386*8d67ca89SAndroid Build Coastguard Worker 
1387*8d67ca89SAndroid Build Coastguard Worker /* Used internally by phdr_table_protect_gnu_relro and
1388*8d67ca89SAndroid Build Coastguard Worker  * phdr_table_unprotect_gnu_relro.
1389*8d67ca89SAndroid Build Coastguard Worker  */
_phdr_table_set_gnu_relro_prot(const ElfW (Phdr)* phdr_table,size_t phdr_count,ElfW (Addr)load_bias,int prot_flags,bool should_pad_segments,bool should_use_16kib_app_compat)1390*8d67ca89SAndroid Build Coastguard Worker static int _phdr_table_set_gnu_relro_prot(const ElfW(Phdr)* phdr_table, size_t phdr_count,
1391*8d67ca89SAndroid Build Coastguard Worker                                           ElfW(Addr) load_bias, int prot_flags,
1392*8d67ca89SAndroid Build Coastguard Worker                                           bool should_pad_segments,
1393*8d67ca89SAndroid Build Coastguard Worker                                           bool should_use_16kib_app_compat) {
1394*8d67ca89SAndroid Build Coastguard Worker   const ElfW(Phdr)* phdr = phdr_table;
1395*8d67ca89SAndroid Build Coastguard Worker   const ElfW(Phdr)* phdr_limit = phdr + phdr_count;
1396*8d67ca89SAndroid Build Coastguard Worker 
1397*8d67ca89SAndroid Build Coastguard Worker   for (phdr = phdr_table; phdr < phdr_limit; phdr++) {
1398*8d67ca89SAndroid Build Coastguard Worker     if (phdr->p_type != PT_GNU_RELRO) {
1399*8d67ca89SAndroid Build Coastguard Worker       continue;
1400*8d67ca89SAndroid Build Coastguard Worker     }
1401*8d67ca89SAndroid Build Coastguard Worker 
1402*8d67ca89SAndroid Build Coastguard Worker     // Tricky: what happens when the relro segment does not start
1403*8d67ca89SAndroid Build Coastguard Worker     // or end at page boundaries? We're going to be over-protective
1404*8d67ca89SAndroid Build Coastguard Worker     // here and put every page touched by the segment as read-only.
1405*8d67ca89SAndroid Build Coastguard Worker 
1406*8d67ca89SAndroid Build Coastguard Worker     // This seems to match Ian Lance Taylor's description of the
1407*8d67ca89SAndroid Build Coastguard Worker     // feature at http://www.airs.com/blog/archives/189.
1408*8d67ca89SAndroid Build Coastguard Worker 
1409*8d67ca89SAndroid Build Coastguard Worker     //    Extract:
1410*8d67ca89SAndroid Build Coastguard Worker     //       Note that the current dynamic linker code will only work
1411*8d67ca89SAndroid Build Coastguard Worker     //       correctly if the PT_GNU_RELRO segment starts on a page
1412*8d67ca89SAndroid Build Coastguard Worker     //       boundary. This is because the dynamic linker rounds the
1413*8d67ca89SAndroid Build Coastguard Worker     //       p_vaddr field down to the previous page boundary. If
1414*8d67ca89SAndroid Build Coastguard Worker     //       there is anything on the page which should not be read-only,
1415*8d67ca89SAndroid Build Coastguard Worker     //       the program is likely to fail at runtime. So in effect the
1416*8d67ca89SAndroid Build Coastguard Worker     //       linker must only emit a PT_GNU_RELRO segment if it ensures
1417*8d67ca89SAndroid Build Coastguard Worker     //       that it starts on a page boundary.
1418*8d67ca89SAndroid Build Coastguard Worker     ElfW(Addr) seg_page_start = page_start(phdr->p_vaddr) + load_bias;
1419*8d67ca89SAndroid Build Coastguard Worker     ElfW(Addr) seg_page_end = page_end(phdr->p_vaddr + phdr->p_memsz) + load_bias;
1420*8d67ca89SAndroid Build Coastguard Worker     _extend_gnu_relro_prot_end(phdr, phdr_table, phdr_count, load_bias, &seg_page_end,
1421*8d67ca89SAndroid Build Coastguard Worker                                should_pad_segments, should_use_16kib_app_compat);
1422*8d67ca89SAndroid Build Coastguard Worker 
1423*8d67ca89SAndroid Build Coastguard Worker     int ret = mprotect(reinterpret_cast<void*>(seg_page_start),
1424*8d67ca89SAndroid Build Coastguard Worker                        seg_page_end - seg_page_start,
1425*8d67ca89SAndroid Build Coastguard Worker                        prot_flags);
1426*8d67ca89SAndroid Build Coastguard Worker     if (ret < 0) {
1427*8d67ca89SAndroid Build Coastguard Worker       return -1;
1428*8d67ca89SAndroid Build Coastguard Worker     }
1429*8d67ca89SAndroid Build Coastguard Worker   }
1430*8d67ca89SAndroid Build Coastguard Worker   return 0;
1431*8d67ca89SAndroid Build Coastguard Worker }
1432*8d67ca89SAndroid Build Coastguard Worker 
1433*8d67ca89SAndroid Build Coastguard Worker /* Apply GNU relro protection if specified by the program header. This will
1434*8d67ca89SAndroid Build Coastguard Worker  * turn some of the pages of a writable PT_LOAD segment to read-only, as
1435*8d67ca89SAndroid Build Coastguard Worker  * specified by one or more PT_GNU_RELRO segments. This must be always
1436*8d67ca89SAndroid Build Coastguard Worker  * performed after relocations.
1437*8d67ca89SAndroid Build Coastguard Worker  *
1438*8d67ca89SAndroid Build Coastguard Worker  * The areas typically covered are .got and .data.rel.ro, these are
1439*8d67ca89SAndroid Build Coastguard Worker  * read-only from the program's POV, but contain absolute addresses
1440*8d67ca89SAndroid Build Coastguard Worker  * that need to be relocated before use.
1441*8d67ca89SAndroid Build Coastguard Worker  *
1442*8d67ca89SAndroid Build Coastguard Worker  * Input:
1443*8d67ca89SAndroid Build Coastguard Worker  *   phdr_table  -> program header table
1444*8d67ca89SAndroid Build Coastguard Worker  *   phdr_count  -> number of entries in tables
1445*8d67ca89SAndroid Build Coastguard Worker  *   load_bias   -> load bias
1446*8d67ca89SAndroid Build Coastguard Worker  *   should_pad_segments -> Were segments extended to avoid gaps in the memory map
1447*8d67ca89SAndroid Build Coastguard Worker  *   should_use_16kib_app_compat -> Is the ELF being loaded in 16KiB app compat mode.
1448*8d67ca89SAndroid Build Coastguard Worker  * Return:
1449*8d67ca89SAndroid Build Coastguard Worker  *   0 on success, -1 on failure (error code in errno).
1450*8d67ca89SAndroid Build Coastguard Worker  */
phdr_table_protect_gnu_relro(const ElfW (Phdr)* phdr_table,size_t phdr_count,ElfW (Addr)load_bias,bool should_pad_segments,bool should_use_16kib_app_compat)1451*8d67ca89SAndroid Build Coastguard Worker int phdr_table_protect_gnu_relro(const ElfW(Phdr)* phdr_table, size_t phdr_count,
1452*8d67ca89SAndroid Build Coastguard Worker                                  ElfW(Addr) load_bias, bool should_pad_segments,
1453*8d67ca89SAndroid Build Coastguard Worker                                  bool should_use_16kib_app_compat) {
1454*8d67ca89SAndroid Build Coastguard Worker   return _phdr_table_set_gnu_relro_prot(phdr_table, phdr_count, load_bias, PROT_READ,
1455*8d67ca89SAndroid Build Coastguard Worker                                         should_pad_segments, should_use_16kib_app_compat);
1456*8d67ca89SAndroid Build Coastguard Worker }
1457*8d67ca89SAndroid Build Coastguard Worker 
1458*8d67ca89SAndroid Build Coastguard Worker /*
1459*8d67ca89SAndroid Build Coastguard Worker  * Apply RX protection to the compat relro region of the ELF being loaded in
1460*8d67ca89SAndroid Build Coastguard Worker  * 16KiB compat mode.
1461*8d67ca89SAndroid Build Coastguard Worker  *
1462*8d67ca89SAndroid Build Coastguard Worker  * Input:
1463*8d67ca89SAndroid Build Coastguard Worker  *   start  -> start address of the compat relro region.
1464*8d67ca89SAndroid Build Coastguard Worker  *   size   -> size of the compat relro region in bytes.
1465*8d67ca89SAndroid Build Coastguard Worker  * Return:
1466*8d67ca89SAndroid Build Coastguard Worker  *   0 on success, -1 on failure (error code in errno).
1467*8d67ca89SAndroid Build Coastguard Worker  */
phdr_table_protect_gnu_relro_16kib_compat(ElfW (Addr)start,ElfW (Addr)size)1468*8d67ca89SAndroid Build Coastguard Worker int phdr_table_protect_gnu_relro_16kib_compat(ElfW(Addr) start, ElfW(Addr) size) {
1469*8d67ca89SAndroid Build Coastguard Worker   return mprotect(reinterpret_cast<void*>(start), size, PROT_READ | PROT_EXEC);
1470*8d67ca89SAndroid Build Coastguard Worker }
1471*8d67ca89SAndroid Build Coastguard Worker 
1472*8d67ca89SAndroid Build Coastguard Worker /* Serialize the GNU relro segments to the given file descriptor. This can be
1473*8d67ca89SAndroid Build Coastguard Worker  * performed after relocations to allow another process to later share the
1474*8d67ca89SAndroid Build Coastguard Worker  * relocated segment, if it was loaded at the same address.
1475*8d67ca89SAndroid Build Coastguard Worker  *
1476*8d67ca89SAndroid Build Coastguard Worker  * Input:
1477*8d67ca89SAndroid Build Coastguard Worker  *   phdr_table  -> program header table
1478*8d67ca89SAndroid Build Coastguard Worker  *   phdr_count  -> number of entries in tables
1479*8d67ca89SAndroid Build Coastguard Worker  *   load_bias   -> load bias
1480*8d67ca89SAndroid Build Coastguard Worker  *   fd          -> writable file descriptor to use
1481*8d67ca89SAndroid Build Coastguard Worker  *   file_offset -> pointer to offset into file descriptor to use/update
1482*8d67ca89SAndroid Build Coastguard Worker  * Return:
1483*8d67ca89SAndroid Build Coastguard Worker  *   0 on success, -1 on failure (error code in errno).
1484*8d67ca89SAndroid Build Coastguard Worker  */
phdr_table_serialize_gnu_relro(const ElfW (Phdr)* phdr_table,size_t phdr_count,ElfW (Addr)load_bias,int fd,size_t * file_offset)1485*8d67ca89SAndroid Build Coastguard Worker int phdr_table_serialize_gnu_relro(const ElfW(Phdr)* phdr_table,
1486*8d67ca89SAndroid Build Coastguard Worker                                    size_t phdr_count,
1487*8d67ca89SAndroid Build Coastguard Worker                                    ElfW(Addr) load_bias,
1488*8d67ca89SAndroid Build Coastguard Worker                                    int fd,
1489*8d67ca89SAndroid Build Coastguard Worker                                    size_t* file_offset) {
1490*8d67ca89SAndroid Build Coastguard Worker   const ElfW(Phdr)* phdr = phdr_table;
1491*8d67ca89SAndroid Build Coastguard Worker   const ElfW(Phdr)* phdr_limit = phdr + phdr_count;
1492*8d67ca89SAndroid Build Coastguard Worker 
1493*8d67ca89SAndroid Build Coastguard Worker   for (phdr = phdr_table; phdr < phdr_limit; phdr++) {
1494*8d67ca89SAndroid Build Coastguard Worker     if (phdr->p_type != PT_GNU_RELRO) {
1495*8d67ca89SAndroid Build Coastguard Worker       continue;
1496*8d67ca89SAndroid Build Coastguard Worker     }
1497*8d67ca89SAndroid Build Coastguard Worker 
1498*8d67ca89SAndroid Build Coastguard Worker     ElfW(Addr) seg_page_start = page_start(phdr->p_vaddr) + load_bias;
1499*8d67ca89SAndroid Build Coastguard Worker     ElfW(Addr) seg_page_end = page_end(phdr->p_vaddr + phdr->p_memsz) + load_bias;
1500*8d67ca89SAndroid Build Coastguard Worker     ssize_t size = seg_page_end - seg_page_start;
1501*8d67ca89SAndroid Build Coastguard Worker 
1502*8d67ca89SAndroid Build Coastguard Worker     ssize_t written = TEMP_FAILURE_RETRY(write(fd, reinterpret_cast<void*>(seg_page_start), size));
1503*8d67ca89SAndroid Build Coastguard Worker     if (written != size) {
1504*8d67ca89SAndroid Build Coastguard Worker       return -1;
1505*8d67ca89SAndroid Build Coastguard Worker     }
1506*8d67ca89SAndroid Build Coastguard Worker     void* map = mmap(reinterpret_cast<void*>(seg_page_start), size, PROT_READ,
1507*8d67ca89SAndroid Build Coastguard Worker                      MAP_PRIVATE|MAP_FIXED, fd, *file_offset);
1508*8d67ca89SAndroid Build Coastguard Worker     if (map == MAP_FAILED) {
1509*8d67ca89SAndroid Build Coastguard Worker       return -1;
1510*8d67ca89SAndroid Build Coastguard Worker     }
1511*8d67ca89SAndroid Build Coastguard Worker     *file_offset += size;
1512*8d67ca89SAndroid Build Coastguard Worker   }
1513*8d67ca89SAndroid Build Coastguard Worker   return 0;
1514*8d67ca89SAndroid Build Coastguard Worker }
1515*8d67ca89SAndroid Build Coastguard Worker 
1516*8d67ca89SAndroid Build Coastguard Worker /* Where possible, replace the GNU relro segments with mappings of the given
1517*8d67ca89SAndroid Build Coastguard Worker  * file descriptor. This can be performed after relocations to allow a file
1518*8d67ca89SAndroid Build Coastguard Worker  * previously created by phdr_table_serialize_gnu_relro in another process to
1519*8d67ca89SAndroid Build Coastguard Worker  * replace the dirty relocated pages, saving memory, if it was loaded at the
1520*8d67ca89SAndroid Build Coastguard Worker  * same address. We have to compare the data before we map over it, since some
1521*8d67ca89SAndroid Build Coastguard Worker  * parts of the relro segment may not be identical due to other libraries in
1522*8d67ca89SAndroid Build Coastguard Worker  * the process being loaded at different addresses.
1523*8d67ca89SAndroid Build Coastguard Worker  *
1524*8d67ca89SAndroid Build Coastguard Worker  * Input:
1525*8d67ca89SAndroid Build Coastguard Worker  *   phdr_table  -> program header table
1526*8d67ca89SAndroid Build Coastguard Worker  *   phdr_count  -> number of entries in tables
1527*8d67ca89SAndroid Build Coastguard Worker  *   load_bias   -> load bias
1528*8d67ca89SAndroid Build Coastguard Worker  *   fd          -> readable file descriptor to use
1529*8d67ca89SAndroid Build Coastguard Worker  *   file_offset -> pointer to offset into file descriptor to use/update
1530*8d67ca89SAndroid Build Coastguard Worker  * Return:
1531*8d67ca89SAndroid Build Coastguard Worker  *   0 on success, -1 on failure (error code in errno).
1532*8d67ca89SAndroid Build Coastguard Worker  */
phdr_table_map_gnu_relro(const ElfW (Phdr)* phdr_table,size_t phdr_count,ElfW (Addr)load_bias,int fd,size_t * file_offset)1533*8d67ca89SAndroid Build Coastguard Worker int phdr_table_map_gnu_relro(const ElfW(Phdr)* phdr_table,
1534*8d67ca89SAndroid Build Coastguard Worker                              size_t phdr_count,
1535*8d67ca89SAndroid Build Coastguard Worker                              ElfW(Addr) load_bias,
1536*8d67ca89SAndroid Build Coastguard Worker                              int fd,
1537*8d67ca89SAndroid Build Coastguard Worker                              size_t* file_offset) {
1538*8d67ca89SAndroid Build Coastguard Worker   // Map the file at a temporary location so we can compare its contents.
1539*8d67ca89SAndroid Build Coastguard Worker   struct stat file_stat;
1540*8d67ca89SAndroid Build Coastguard Worker   if (TEMP_FAILURE_RETRY(fstat(fd, &file_stat)) != 0) {
1541*8d67ca89SAndroid Build Coastguard Worker     return -1;
1542*8d67ca89SAndroid Build Coastguard Worker   }
1543*8d67ca89SAndroid Build Coastguard Worker   off_t file_size = file_stat.st_size;
1544*8d67ca89SAndroid Build Coastguard Worker   void* temp_mapping = nullptr;
1545*8d67ca89SAndroid Build Coastguard Worker   if (file_size > 0) {
1546*8d67ca89SAndroid Build Coastguard Worker     temp_mapping = mmap(nullptr, file_size, PROT_READ, MAP_PRIVATE, fd, 0);
1547*8d67ca89SAndroid Build Coastguard Worker     if (temp_mapping == MAP_FAILED) {
1548*8d67ca89SAndroid Build Coastguard Worker       return -1;
1549*8d67ca89SAndroid Build Coastguard Worker     }
1550*8d67ca89SAndroid Build Coastguard Worker   }
1551*8d67ca89SAndroid Build Coastguard Worker 
1552*8d67ca89SAndroid Build Coastguard Worker   // Iterate over the relro segments and compare/remap the pages.
1553*8d67ca89SAndroid Build Coastguard Worker   const ElfW(Phdr)* phdr = phdr_table;
1554*8d67ca89SAndroid Build Coastguard Worker   const ElfW(Phdr)* phdr_limit = phdr + phdr_count;
1555*8d67ca89SAndroid Build Coastguard Worker 
1556*8d67ca89SAndroid Build Coastguard Worker   for (phdr = phdr_table; phdr < phdr_limit; phdr++) {
1557*8d67ca89SAndroid Build Coastguard Worker     if (phdr->p_type != PT_GNU_RELRO) {
1558*8d67ca89SAndroid Build Coastguard Worker       continue;
1559*8d67ca89SAndroid Build Coastguard Worker     }
1560*8d67ca89SAndroid Build Coastguard Worker 
1561*8d67ca89SAndroid Build Coastguard Worker     ElfW(Addr) seg_page_start = page_start(phdr->p_vaddr) + load_bias;
1562*8d67ca89SAndroid Build Coastguard Worker     ElfW(Addr) seg_page_end = page_end(phdr->p_vaddr + phdr->p_memsz) + load_bias;
1563*8d67ca89SAndroid Build Coastguard Worker 
1564*8d67ca89SAndroid Build Coastguard Worker     char* file_base = static_cast<char*>(temp_mapping) + *file_offset;
1565*8d67ca89SAndroid Build Coastguard Worker     char* mem_base = reinterpret_cast<char*>(seg_page_start);
1566*8d67ca89SAndroid Build Coastguard Worker     size_t match_offset = 0;
1567*8d67ca89SAndroid Build Coastguard Worker     size_t size = seg_page_end - seg_page_start;
1568*8d67ca89SAndroid Build Coastguard Worker 
1569*8d67ca89SAndroid Build Coastguard Worker     if (file_size - *file_offset < size) {
1570*8d67ca89SAndroid Build Coastguard Worker       // File is too short to compare to this segment. The contents are likely
1571*8d67ca89SAndroid Build Coastguard Worker       // different as well (it's probably for a different library version) so
1572*8d67ca89SAndroid Build Coastguard Worker       // just don't bother checking.
1573*8d67ca89SAndroid Build Coastguard Worker       break;
1574*8d67ca89SAndroid Build Coastguard Worker     }
1575*8d67ca89SAndroid Build Coastguard Worker 
1576*8d67ca89SAndroid Build Coastguard Worker     while (match_offset < size) {
1577*8d67ca89SAndroid Build Coastguard Worker       // Skip over dissimilar pages.
1578*8d67ca89SAndroid Build Coastguard Worker       while (match_offset < size &&
1579*8d67ca89SAndroid Build Coastguard Worker              memcmp(mem_base + match_offset, file_base + match_offset, page_size()) != 0) {
1580*8d67ca89SAndroid Build Coastguard Worker         match_offset += page_size();
1581*8d67ca89SAndroid Build Coastguard Worker       }
1582*8d67ca89SAndroid Build Coastguard Worker 
1583*8d67ca89SAndroid Build Coastguard Worker       // Count similar pages.
1584*8d67ca89SAndroid Build Coastguard Worker       size_t mismatch_offset = match_offset;
1585*8d67ca89SAndroid Build Coastguard Worker       while (mismatch_offset < size &&
1586*8d67ca89SAndroid Build Coastguard Worker              memcmp(mem_base + mismatch_offset, file_base + mismatch_offset, page_size()) == 0) {
1587*8d67ca89SAndroid Build Coastguard Worker         mismatch_offset += page_size();
1588*8d67ca89SAndroid Build Coastguard Worker       }
1589*8d67ca89SAndroid Build Coastguard Worker 
1590*8d67ca89SAndroid Build Coastguard Worker       // Map over similar pages.
1591*8d67ca89SAndroid Build Coastguard Worker       if (mismatch_offset > match_offset) {
1592*8d67ca89SAndroid Build Coastguard Worker         void* map = mmap(mem_base + match_offset, mismatch_offset - match_offset,
1593*8d67ca89SAndroid Build Coastguard Worker                          PROT_READ, MAP_PRIVATE|MAP_FIXED, fd, *file_offset + match_offset);
1594*8d67ca89SAndroid Build Coastguard Worker         if (map == MAP_FAILED) {
1595*8d67ca89SAndroid Build Coastguard Worker           munmap(temp_mapping, file_size);
1596*8d67ca89SAndroid Build Coastguard Worker           return -1;
1597*8d67ca89SAndroid Build Coastguard Worker         }
1598*8d67ca89SAndroid Build Coastguard Worker       }
1599*8d67ca89SAndroid Build Coastguard Worker 
1600*8d67ca89SAndroid Build Coastguard Worker       match_offset = mismatch_offset;
1601*8d67ca89SAndroid Build Coastguard Worker     }
1602*8d67ca89SAndroid Build Coastguard Worker 
1603*8d67ca89SAndroid Build Coastguard Worker     // Add to the base file offset in case there are multiple relro segments.
1604*8d67ca89SAndroid Build Coastguard Worker     *file_offset += size;
1605*8d67ca89SAndroid Build Coastguard Worker   }
1606*8d67ca89SAndroid Build Coastguard Worker   munmap(temp_mapping, file_size);
1607*8d67ca89SAndroid Build Coastguard Worker   return 0;
1608*8d67ca89SAndroid Build Coastguard Worker }
1609*8d67ca89SAndroid Build Coastguard Worker 
1610*8d67ca89SAndroid Build Coastguard Worker 
1611*8d67ca89SAndroid Build Coastguard Worker #if defined(__arm__)
1612*8d67ca89SAndroid Build Coastguard Worker /* Return the address and size of the .ARM.exidx section in memory,
1613*8d67ca89SAndroid Build Coastguard Worker  * if present.
1614*8d67ca89SAndroid Build Coastguard Worker  *
1615*8d67ca89SAndroid Build Coastguard Worker  * Input:
1616*8d67ca89SAndroid Build Coastguard Worker  *   phdr_table  -> program header table
1617*8d67ca89SAndroid Build Coastguard Worker  *   phdr_count  -> number of entries in tables
1618*8d67ca89SAndroid Build Coastguard Worker  *   load_bias   -> load bias
1619*8d67ca89SAndroid Build Coastguard Worker  * Output:
1620*8d67ca89SAndroid Build Coastguard Worker  *   arm_exidx       -> address of table in memory (null on failure).
1621*8d67ca89SAndroid Build Coastguard Worker  *   arm_exidx_count -> number of items in table (0 on failure).
1622*8d67ca89SAndroid Build Coastguard Worker  * Return:
1623*8d67ca89SAndroid Build Coastguard Worker  *   0 on success, -1 on failure (_no_ error code in errno)
1624*8d67ca89SAndroid Build Coastguard Worker  */
phdr_table_get_arm_exidx(const ElfW (Phdr)* phdr_table,size_t phdr_count,ElfW (Addr)load_bias,ElfW (Addr)** arm_exidx,size_t * arm_exidx_count)1625*8d67ca89SAndroid Build Coastguard Worker int phdr_table_get_arm_exidx(const ElfW(Phdr)* phdr_table, size_t phdr_count,
1626*8d67ca89SAndroid Build Coastguard Worker                              ElfW(Addr) load_bias,
1627*8d67ca89SAndroid Build Coastguard Worker                              ElfW(Addr)** arm_exidx, size_t* arm_exidx_count) {
1628*8d67ca89SAndroid Build Coastguard Worker   const ElfW(Phdr)* phdr = phdr_table;
1629*8d67ca89SAndroid Build Coastguard Worker   const ElfW(Phdr)* phdr_limit = phdr + phdr_count;
1630*8d67ca89SAndroid Build Coastguard Worker 
1631*8d67ca89SAndroid Build Coastguard Worker   for (phdr = phdr_table; phdr < phdr_limit; phdr++) {
1632*8d67ca89SAndroid Build Coastguard Worker     if (phdr->p_type != PT_ARM_EXIDX) {
1633*8d67ca89SAndroid Build Coastguard Worker       continue;
1634*8d67ca89SAndroid Build Coastguard Worker     }
1635*8d67ca89SAndroid Build Coastguard Worker 
1636*8d67ca89SAndroid Build Coastguard Worker     *arm_exidx = reinterpret_cast<ElfW(Addr)*>(load_bias + phdr->p_vaddr);
1637*8d67ca89SAndroid Build Coastguard Worker     *arm_exidx_count = phdr->p_memsz / 8;
1638*8d67ca89SAndroid Build Coastguard Worker     return 0;
1639*8d67ca89SAndroid Build Coastguard Worker   }
1640*8d67ca89SAndroid Build Coastguard Worker   *arm_exidx = nullptr;
1641*8d67ca89SAndroid Build Coastguard Worker   *arm_exidx_count = 0;
1642*8d67ca89SAndroid Build Coastguard Worker   return -1;
1643*8d67ca89SAndroid Build Coastguard Worker }
1644*8d67ca89SAndroid Build Coastguard Worker #endif
1645*8d67ca89SAndroid Build Coastguard Worker 
1646*8d67ca89SAndroid Build Coastguard Worker /* Return the address and size of the ELF file's .dynamic section in memory,
1647*8d67ca89SAndroid Build Coastguard Worker  * or null if missing.
1648*8d67ca89SAndroid Build Coastguard Worker  *
1649*8d67ca89SAndroid Build Coastguard Worker  * Input:
1650*8d67ca89SAndroid Build Coastguard Worker  *   phdr_table  -> program header table
1651*8d67ca89SAndroid Build Coastguard Worker  *   phdr_count  -> number of entries in tables
1652*8d67ca89SAndroid Build Coastguard Worker  *   load_bias   -> load bias
1653*8d67ca89SAndroid Build Coastguard Worker  * Output:
1654*8d67ca89SAndroid Build Coastguard Worker  *   dynamic       -> address of table in memory (null on failure).
1655*8d67ca89SAndroid Build Coastguard Worker  *   dynamic_flags -> protection flags for section (unset on failure)
1656*8d67ca89SAndroid Build Coastguard Worker  * Return:
1657*8d67ca89SAndroid Build Coastguard Worker  *   void
1658*8d67ca89SAndroid Build Coastguard Worker  */
phdr_table_get_dynamic_section(const ElfW (Phdr)* phdr_table,size_t phdr_count,ElfW (Addr)load_bias,ElfW (Dyn)** dynamic,ElfW (Word)* dynamic_flags)1659*8d67ca89SAndroid Build Coastguard Worker void phdr_table_get_dynamic_section(const ElfW(Phdr)* phdr_table, size_t phdr_count,
1660*8d67ca89SAndroid Build Coastguard Worker                                     ElfW(Addr) load_bias, ElfW(Dyn)** dynamic,
1661*8d67ca89SAndroid Build Coastguard Worker                                     ElfW(Word)* dynamic_flags) {
1662*8d67ca89SAndroid Build Coastguard Worker   *dynamic = nullptr;
1663*8d67ca89SAndroid Build Coastguard Worker   for (size_t i = 0; i<phdr_count; ++i) {
1664*8d67ca89SAndroid Build Coastguard Worker     const ElfW(Phdr)& phdr = phdr_table[i];
1665*8d67ca89SAndroid Build Coastguard Worker     if (phdr.p_type == PT_DYNAMIC) {
1666*8d67ca89SAndroid Build Coastguard Worker       *dynamic = reinterpret_cast<ElfW(Dyn)*>(load_bias + phdr.p_vaddr);
1667*8d67ca89SAndroid Build Coastguard Worker       if (dynamic_flags) {
1668*8d67ca89SAndroid Build Coastguard Worker         *dynamic_flags = phdr.p_flags;
1669*8d67ca89SAndroid Build Coastguard Worker       }
1670*8d67ca89SAndroid Build Coastguard Worker       return;
1671*8d67ca89SAndroid Build Coastguard Worker     }
1672*8d67ca89SAndroid Build Coastguard Worker   }
1673*8d67ca89SAndroid Build Coastguard Worker }
1674*8d67ca89SAndroid Build Coastguard Worker 
1675*8d67ca89SAndroid Build Coastguard Worker /* Return the program interpreter string, or nullptr if missing.
1676*8d67ca89SAndroid Build Coastguard Worker  *
1677*8d67ca89SAndroid Build Coastguard Worker  * Input:
1678*8d67ca89SAndroid Build Coastguard Worker  *   phdr_table  -> program header table
1679*8d67ca89SAndroid Build Coastguard Worker  *   phdr_count  -> number of entries in tables
1680*8d67ca89SAndroid Build Coastguard Worker  *   load_bias   -> load bias
1681*8d67ca89SAndroid Build Coastguard Worker  * Return:
1682*8d67ca89SAndroid Build Coastguard Worker  *   pointer to the program interpreter string.
1683*8d67ca89SAndroid Build Coastguard Worker  */
phdr_table_get_interpreter_name(const ElfW (Phdr)* phdr_table,size_t phdr_count,ElfW (Addr)load_bias)1684*8d67ca89SAndroid Build Coastguard Worker const char* phdr_table_get_interpreter_name(const ElfW(Phdr)* phdr_table, size_t phdr_count,
1685*8d67ca89SAndroid Build Coastguard Worker                                             ElfW(Addr) load_bias) {
1686*8d67ca89SAndroid Build Coastguard Worker   for (size_t i = 0; i<phdr_count; ++i) {
1687*8d67ca89SAndroid Build Coastguard Worker     const ElfW(Phdr)& phdr = phdr_table[i];
1688*8d67ca89SAndroid Build Coastguard Worker     if (phdr.p_type == PT_INTERP) {
1689*8d67ca89SAndroid Build Coastguard Worker       return reinterpret_cast<const char*>(load_bias + phdr.p_vaddr);
1690*8d67ca89SAndroid Build Coastguard Worker     }
1691*8d67ca89SAndroid Build Coastguard Worker   }
1692*8d67ca89SAndroid Build Coastguard Worker   return nullptr;
1693*8d67ca89SAndroid Build Coastguard Worker }
1694*8d67ca89SAndroid Build Coastguard Worker 
1695*8d67ca89SAndroid Build Coastguard Worker // Sets loaded_phdr_ to the address of the program header table as it appears
1696*8d67ca89SAndroid Build Coastguard Worker // in the loaded segments in memory. This is in contrast with phdr_table_,
1697*8d67ca89SAndroid Build Coastguard Worker // which is temporary and will be released before the library is relocated.
FindPhdr()1698*8d67ca89SAndroid Build Coastguard Worker bool ElfReader::FindPhdr() {
1699*8d67ca89SAndroid Build Coastguard Worker   const ElfW(Phdr)* phdr_limit = phdr_table_ + phdr_num_;
1700*8d67ca89SAndroid Build Coastguard Worker 
1701*8d67ca89SAndroid Build Coastguard Worker   // If there is a PT_PHDR, use it directly.
1702*8d67ca89SAndroid Build Coastguard Worker   for (const ElfW(Phdr)* phdr = phdr_table_; phdr < phdr_limit; ++phdr) {
1703*8d67ca89SAndroid Build Coastguard Worker     if (phdr->p_type == PT_PHDR) {
1704*8d67ca89SAndroid Build Coastguard Worker       return CheckPhdr(load_bias_ + phdr->p_vaddr);
1705*8d67ca89SAndroid Build Coastguard Worker     }
1706*8d67ca89SAndroid Build Coastguard Worker   }
1707*8d67ca89SAndroid Build Coastguard Worker 
1708*8d67ca89SAndroid Build Coastguard Worker   // Otherwise, check the first loadable segment. If its file offset
1709*8d67ca89SAndroid Build Coastguard Worker   // is 0, it starts with the ELF header, and we can trivially find the
1710*8d67ca89SAndroid Build Coastguard Worker   // loaded program header from it.
1711*8d67ca89SAndroid Build Coastguard Worker   for (const ElfW(Phdr)* phdr = phdr_table_; phdr < phdr_limit; ++phdr) {
1712*8d67ca89SAndroid Build Coastguard Worker     if (phdr->p_type == PT_LOAD) {
1713*8d67ca89SAndroid Build Coastguard Worker       if (phdr->p_offset == 0) {
1714*8d67ca89SAndroid Build Coastguard Worker         ElfW(Addr)  elf_addr = load_bias_ + phdr->p_vaddr;
1715*8d67ca89SAndroid Build Coastguard Worker         const ElfW(Ehdr)* ehdr = reinterpret_cast<const ElfW(Ehdr)*>(elf_addr);
1716*8d67ca89SAndroid Build Coastguard Worker         ElfW(Addr)  offset = ehdr->e_phoff;
1717*8d67ca89SAndroid Build Coastguard Worker         return CheckPhdr(reinterpret_cast<ElfW(Addr)>(ehdr) + offset);
1718*8d67ca89SAndroid Build Coastguard Worker       }
1719*8d67ca89SAndroid Build Coastguard Worker       break;
1720*8d67ca89SAndroid Build Coastguard Worker     }
1721*8d67ca89SAndroid Build Coastguard Worker   }
1722*8d67ca89SAndroid Build Coastguard Worker 
1723*8d67ca89SAndroid Build Coastguard Worker   DL_ERR("can't find loaded phdr for \"%s\"", name_.c_str());
1724*8d67ca89SAndroid Build Coastguard Worker   return false;
1725*8d67ca89SAndroid Build Coastguard Worker }
1726*8d67ca89SAndroid Build Coastguard Worker 
1727*8d67ca89SAndroid Build Coastguard Worker // Tries to find .note.gnu.property section.
1728*8d67ca89SAndroid Build Coastguard Worker // It is not considered an error if such section is missing.
FindGnuPropertySection()1729*8d67ca89SAndroid Build Coastguard Worker bool ElfReader::FindGnuPropertySection() {
1730*8d67ca89SAndroid Build Coastguard Worker #if defined(__aarch64__)
1731*8d67ca89SAndroid Build Coastguard Worker   note_gnu_property_ = GnuPropertySection(phdr_table_, phdr_num_, load_start(), name_.c_str());
1732*8d67ca89SAndroid Build Coastguard Worker #endif
1733*8d67ca89SAndroid Build Coastguard Worker   return true;
1734*8d67ca89SAndroid Build Coastguard Worker }
1735*8d67ca89SAndroid Build Coastguard Worker 
1736*8d67ca89SAndroid Build Coastguard Worker // Ensures that our program header is actually within a loadable
1737*8d67ca89SAndroid Build Coastguard Worker // segment. This should help catch badly-formed ELF files that
1738*8d67ca89SAndroid Build Coastguard Worker // would cause the linker to crash later when trying to access it.
CheckPhdr(ElfW (Addr)loaded)1739*8d67ca89SAndroid Build Coastguard Worker bool ElfReader::CheckPhdr(ElfW(Addr) loaded) {
1740*8d67ca89SAndroid Build Coastguard Worker   const ElfW(Phdr)* phdr_limit = phdr_table_ + phdr_num_;
1741*8d67ca89SAndroid Build Coastguard Worker   ElfW(Addr) loaded_end = loaded + (phdr_num_ * sizeof(ElfW(Phdr)));
1742*8d67ca89SAndroid Build Coastguard Worker   for (const ElfW(Phdr)* phdr = phdr_table_; phdr < phdr_limit; ++phdr) {
1743*8d67ca89SAndroid Build Coastguard Worker     if (phdr->p_type != PT_LOAD) {
1744*8d67ca89SAndroid Build Coastguard Worker       continue;
1745*8d67ca89SAndroid Build Coastguard Worker     }
1746*8d67ca89SAndroid Build Coastguard Worker     ElfW(Addr) seg_start = phdr->p_vaddr + load_bias_;
1747*8d67ca89SAndroid Build Coastguard Worker     ElfW(Addr) seg_end = phdr->p_filesz + seg_start;
1748*8d67ca89SAndroid Build Coastguard Worker     if (seg_start <= loaded && loaded_end <= seg_end) {
1749*8d67ca89SAndroid Build Coastguard Worker       loaded_phdr_ = reinterpret_cast<const ElfW(Phdr)*>(loaded);
1750*8d67ca89SAndroid Build Coastguard Worker       return true;
1751*8d67ca89SAndroid Build Coastguard Worker     }
1752*8d67ca89SAndroid Build Coastguard Worker   }
1753*8d67ca89SAndroid Build Coastguard Worker   DL_ERR("\"%s\" loaded phdr %p not in loadable segment",
1754*8d67ca89SAndroid Build Coastguard Worker          name_.c_str(), reinterpret_cast<void*>(loaded));
1755*8d67ca89SAndroid Build Coastguard Worker   return false;
1756*8d67ca89SAndroid Build Coastguard Worker }
1757