blob: ffd4de28a8e670043c382e289b82a8abbec77a56 [file] [log] [blame]
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +02001/*
2 * Copyright (C) 2012 The Android Open Source Project
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in
12 * the documentation and/or other materials provided with the
13 * distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
Elliott Hughes650be4e2013-03-05 18:47:58 -080029#include "linker_phdr.h"
30
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +020031#include <errno.h>
32#include <sys/mman.h>
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +000033#include <sys/types.h>
34#include <sys/stat.h>
35#include <unistd.h>
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +020036
Elliott Hughes650be4e2013-03-05 18:47:58 -080037#include "linker.h"
38#include "linker_debug.h"
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +020039
Elliott Hughesb5140262014-12-02 16:16:29 -080040static int GetTargetElfMachine() {
41#if defined(__arm__)
42 return EM_ARM;
43#elif defined(__aarch64__)
44 return EM_AARCH64;
45#elif defined(__i386__)
46 return EM_386;
47#elif defined(__mips__)
48 return EM_MIPS;
49#elif defined(__x86_64__)
50 return EM_X86_64;
51#endif
52}
53
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +020054/**
55 TECHNICAL NOTE ON ELF LOADING.
56
57 An ELF file's program header table contains one or more PT_LOAD
58 segments, which corresponds to portions of the file that need to
59 be mapped into the process' address space.
60
61 Each loadable segment has the following important properties:
62
63 p_offset -> segment file offset
64 p_filesz -> segment file size
65 p_memsz -> segment memory size (always >= p_filesz)
66 p_vaddr -> segment's virtual address
67 p_flags -> segment flags (e.g. readable, writable, executable)
68
Elliott Hughes0266ae52014-02-10 17:46:57 -080069 We will ignore the p_paddr and p_align fields of ElfW(Phdr) for now.
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +020070
71 The loadable segments can be seen as a list of [p_vaddr ... p_vaddr+p_memsz)
72 ranges of virtual addresses. A few rules apply:
73
74 - the virtual address ranges should not overlap.
75
76 - if a segment's p_filesz is smaller than its p_memsz, the extra bytes
77 between them should always be initialized to 0.
78
79 - ranges do not necessarily start or end at page boundaries. Two distinct
80 segments can have their start and end on the same page. In this case, the
81 page inherits the mapping flags of the latter segment.
82
83 Finally, the real load addrs of each segment is not p_vaddr. Instead the
84 loader decides where to load the first segment, then will load all others
85 relative to the first one to respect the initial range layout.
86
87 For example, consider the following list:
88
89 [ offset:0, filesz:0x4000, memsz:0x4000, vaddr:0x30000 ],
90 [ offset:0x4000, filesz:0x2000, memsz:0x8000, vaddr:0x40000 ],
91
92 This corresponds to two segments that cover these virtual address ranges:
93
94 0x30000...0x34000
95 0x40000...0x48000
96
97 If the loader decides to load the first segment at address 0xa0000000
98 then the segments' load address ranges will be:
99
100 0xa0030000...0xa0034000
101 0xa0040000...0xa0048000
102
103 In other words, all segments must be loaded at an address that has the same
104 constant offset from their p_vaddr value. This offset is computed as the
105 difference between the first segment's load address, and its p_vaddr value.
106
107 However, in practice, segments do _not_ start at page boundaries. Since we
108 can only memory-map at page boundaries, this means that the bias is
109 computed as:
110
111 load_bias = phdr0_load_address - PAGE_START(phdr0->p_vaddr)
112
113 (NOTE: The value must be used as a 32-bit unsigned integer, to deal with
114 possible wrap around UINT32_MAX for possible large p_vaddr values).
115
116 And that the phdr0_load_address must start at a page boundary, with
117 the segment's real content starting at:
118
119 phdr0_load_address + PAGE_OFFSET(phdr0->p_vaddr)
120
121 Note that ELF requires the following condition to make the mmap()-ing work:
122
123 PAGE_OFFSET(phdr0->p_vaddr) == PAGE_OFFSET(phdr0->p_offset)
124
125 The load_bias must be added to any p_vaddr value read from the ELF file to
126 determine the corresponding memory address.
127
128 **/
129
Elliott Hughesfaf05ba2014-02-11 16:59:37 -0800130#define MAYBE_MAP_FLAG(x, from, to) (((x) & (from)) ? (to) : 0)
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200131#define PFLAGS_TO_PROT(x) (MAYBE_MAP_FLAG((x), PF_X, PROT_EXEC) | \
132 MAYBE_MAP_FLAG((x), PF_R, PROT_READ) | \
133 MAYBE_MAP_FLAG((x), PF_W, PROT_WRITE))
134
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -0700135ElfReader::ElfReader(const char* name, int fd, off64_t file_offset)
136 : name_(name), fd_(fd), file_offset_(file_offset),
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700137 phdr_num_(0), phdr_mmap_(nullptr), phdr_table_(nullptr), phdr_size_(0),
138 load_start_(nullptr), load_size_(0), load_bias_(0),
139 loaded_phdr_(nullptr) {
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200140}
141
Elliott Hughes650be4e2013-03-05 18:47:58 -0800142ElfReader::~ElfReader() {
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700143 if (phdr_mmap_ != nullptr) {
Elliott Hughes650be4e2013-03-05 18:47:58 -0800144 munmap(phdr_mmap_, phdr_size_);
145 }
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200146}
147
Torne (Richard Coles)12bbb912014-02-06 14:34:21 +0000148bool ElfReader::Load(const android_dlextinfo* extinfo) {
Elliott Hughes650be4e2013-03-05 18:47:58 -0800149 return ReadElfHeader() &&
150 VerifyElfHeader() &&
151 ReadProgramHeader() &&
Torne (Richard Coles)12bbb912014-02-06 14:34:21 +0000152 ReserveAddressSpace(extinfo) &&
Elliott Hughes650be4e2013-03-05 18:47:58 -0800153 LoadSegments() &&
154 FindPhdr();
155}
156
157bool ElfReader::ReadElfHeader() {
Dmitriy Ivanova6c12792014-10-21 12:09:18 -0700158 ssize_t rc = TEMP_FAILURE_RETRY(pread64(fd_, &header_, sizeof(header_), file_offset_));
Elliott Hughes650be4e2013-03-05 18:47:58 -0800159 if (rc < 0) {
160 DL_ERR("can't read file \"%s\": %s", name_, strerror(errno));
161 return false;
162 }
Dmitriy Ivanova6c12792014-10-21 12:09:18 -0700163
Elliott Hughes650be4e2013-03-05 18:47:58 -0800164 if (rc != sizeof(header_)) {
Elliott Hughesc6200592013-09-30 18:43:46 -0700165 DL_ERR("\"%s\" is too small to be an ELF executable: only found %zd bytes", name_,
166 static_cast<size_t>(rc));
Elliott Hughes650be4e2013-03-05 18:47:58 -0800167 return false;
168 }
169 return true;
170}
171
172bool ElfReader::VerifyElfHeader() {
Elliott Hughes625993d2014-07-15 16:53:13 -0700173 if (memcmp(header_.e_ident, ELFMAG, SELFMAG) != 0) {
Elliott Hughes650be4e2013-03-05 18:47:58 -0800174 DL_ERR("\"%s\" has bad ELF magic", name_);
175 return false;
176 }
177
Elliott Hughesc00f2cb2013-10-04 17:01:33 -0700178 // Try to give a clear diagnostic for ELF class mismatches, since they're
179 // an easy mistake to make during the 32-bit/64-bit transition period.
180 int elf_class = header_.e_ident[EI_CLASS];
181#if defined(__LP64__)
182 if (elf_class != ELFCLASS64) {
183 if (elf_class == ELFCLASS32) {
184 DL_ERR("\"%s\" is 32-bit instead of 64-bit", name_);
185 } else {
186 DL_ERR("\"%s\" has unknown ELF class: %d", name_, elf_class);
187 }
Elliott Hughes650be4e2013-03-05 18:47:58 -0800188 return false;
189 }
Elliott Hughesc00f2cb2013-10-04 17:01:33 -0700190#else
191 if (elf_class != ELFCLASS32) {
192 if (elf_class == ELFCLASS64) {
193 DL_ERR("\"%s\" is 64-bit instead of 32-bit", name_);
194 } else {
195 DL_ERR("\"%s\" has unknown ELF class: %d", name_, elf_class);
196 }
197 return false;
198 }
199#endif
200
Elliott Hughes650be4e2013-03-05 18:47:58 -0800201 if (header_.e_ident[EI_DATA] != ELFDATA2LSB) {
202 DL_ERR("\"%s\" not little-endian: %d", name_, header_.e_ident[EI_DATA]);
203 return false;
204 }
205
206 if (header_.e_type != ET_DYN) {
207 DL_ERR("\"%s\" has unexpected e_type: %d", name_, header_.e_type);
208 return false;
209 }
210
211 if (header_.e_version != EV_CURRENT) {
212 DL_ERR("\"%s\" has unexpected e_version: %d", name_, header_.e_version);
213 return false;
214 }
215
Elliott Hughesb5140262014-12-02 16:16:29 -0800216 if (header_.e_machine != GetTargetElfMachine()) {
Elliott Hughes650be4e2013-03-05 18:47:58 -0800217 DL_ERR("\"%s\" has unexpected e_machine: %d", name_, header_.e_machine);
218 return false;
219 }
220
221 return true;
222}
223
224// Loads the program header table from an ELF file into a read-only private
225// anonymous mmap-ed block.
226bool ElfReader::ReadProgramHeader() {
227 phdr_num_ = header_.e_phnum;
228
229 // Like the kernel, we only accept program header tables that
230 // are smaller than 64KiB.
Elliott Hughes0266ae52014-02-10 17:46:57 -0800231 if (phdr_num_ < 1 || phdr_num_ > 65536/sizeof(ElfW(Phdr))) {
Elliott Hughesc6200592013-09-30 18:43:46 -0700232 DL_ERR("\"%s\" has invalid e_phnum: %zd", name_, phdr_num_);
Elliott Hughes650be4e2013-03-05 18:47:58 -0800233 return false;
234 }
235
Elliott Hughes0266ae52014-02-10 17:46:57 -0800236 ElfW(Addr) page_min = PAGE_START(header_.e_phoff);
237 ElfW(Addr) page_max = PAGE_END(header_.e_phoff + (phdr_num_ * sizeof(ElfW(Phdr))));
238 ElfW(Addr) page_offset = PAGE_OFFSET(header_.e_phoff);
Elliott Hughes650be4e2013-03-05 18:47:58 -0800239
240 phdr_size_ = page_max - page_min;
241
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -0700242 void* mmap_result = mmap64(nullptr, phdr_size_, PROT_READ, MAP_PRIVATE, fd_, file_offset_ + page_min);
Elliott Hughes650be4e2013-03-05 18:47:58 -0800243 if (mmap_result == MAP_FAILED) {
244 DL_ERR("\"%s\" phdr mmap failed: %s", name_, strerror(errno));
245 return false;
246 }
247
248 phdr_mmap_ = mmap_result;
Elliott Hughes0266ae52014-02-10 17:46:57 -0800249 phdr_table_ = reinterpret_cast<ElfW(Phdr)*>(reinterpret_cast<char*>(mmap_result) + page_offset);
Elliott Hughes650be4e2013-03-05 18:47:58 -0800250 return true;
251}
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200252
Brian Carlstrome7dffe12013-01-10 16:39:58 -0800253/* Returns the size of the extent of all the possibly non-contiguous
254 * loadable segments in an ELF program header table. This corresponds
255 * to the page-aligned size in bytes that needs to be reserved in the
256 * process' address space. If there are no loadable segments, 0 is
257 * returned.
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200258 *
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700259 * If out_min_vaddr or out_max_vaddr are not null, they will be
Brian Carlstrome7dffe12013-01-10 16:39:58 -0800260 * set to the minimum and maximum addresses of pages to be reserved,
261 * or 0 if there is nothing to load.
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200262 */
Elliott Hughes0266ae52014-02-10 17:46:57 -0800263size_t phdr_table_get_load_size(const ElfW(Phdr)* phdr_table, size_t phdr_count,
264 ElfW(Addr)* out_min_vaddr,
265 ElfW(Addr)* out_max_vaddr) {
266 ElfW(Addr) min_vaddr = UINTPTR_MAX;
267 ElfW(Addr) max_vaddr = 0;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200268
Elliott Hughes0266ae52014-02-10 17:46:57 -0800269 bool found_pt_load = false;
270 for (size_t i = 0; i < phdr_count; ++i) {
271 const ElfW(Phdr)* phdr = &phdr_table[i];
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200272
Elliott Hughes0266ae52014-02-10 17:46:57 -0800273 if (phdr->p_type != PT_LOAD) {
274 continue;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200275 }
Elliott Hughes0266ae52014-02-10 17:46:57 -0800276 found_pt_load = true;
277
278 if (phdr->p_vaddr < min_vaddr) {
279 min_vaddr = phdr->p_vaddr;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200280 }
281
Elliott Hughes0266ae52014-02-10 17:46:57 -0800282 if (phdr->p_vaddr + phdr->p_memsz > max_vaddr) {
283 max_vaddr = phdr->p_vaddr + phdr->p_memsz;
284 }
285 }
286 if (!found_pt_load) {
287 min_vaddr = 0;
288 }
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200289
Elliott Hughes0266ae52014-02-10 17:46:57 -0800290 min_vaddr = PAGE_START(min_vaddr);
291 max_vaddr = PAGE_END(max_vaddr);
292
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700293 if (out_min_vaddr != nullptr) {
Elliott Hughes0266ae52014-02-10 17:46:57 -0800294 *out_min_vaddr = min_vaddr;
295 }
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700296 if (out_max_vaddr != nullptr) {
Elliott Hughes0266ae52014-02-10 17:46:57 -0800297 *out_max_vaddr = max_vaddr;
298 }
299 return max_vaddr - min_vaddr;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200300}
301
Elliott Hughes650be4e2013-03-05 18:47:58 -0800302// Reserve a virtual address range big enough to hold all loadable
303// segments of a program header table. This is done by creating a
304// private anonymous mmap() with PROT_NONE.
Torne (Richard Coles)12bbb912014-02-06 14:34:21 +0000305bool ElfReader::ReserveAddressSpace(const android_dlextinfo* extinfo) {
Elliott Hughes0266ae52014-02-10 17:46:57 -0800306 ElfW(Addr) min_vaddr;
Brian Carlstrome7dffe12013-01-10 16:39:58 -0800307 load_size_ = phdr_table_get_load_size(phdr_table_, phdr_num_, &min_vaddr);
Elliott Hughes650be4e2013-03-05 18:47:58 -0800308 if (load_size_ == 0) {
309 DL_ERR("\"%s\" has no loadable segments", name_);
310 return false;
311 }
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200312
Brian Carlstrome7dffe12013-01-10 16:39:58 -0800313 uint8_t* addr = reinterpret_cast<uint8_t*>(min_vaddr);
Torne (Richard Coles)12bbb912014-02-06 14:34:21 +0000314 void* start;
315 size_t reserved_size = 0;
316 bool reserved_hint = true;
317
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700318 if (extinfo != nullptr) {
Torne (Richard Coles)12bbb912014-02-06 14:34:21 +0000319 if (extinfo->flags & ANDROID_DLEXT_RESERVED_ADDRESS) {
320 reserved_size = extinfo->reserved_size;
321 reserved_hint = false;
322 } else if (extinfo->flags & ANDROID_DLEXT_RESERVED_ADDRESS_HINT) {
323 reserved_size = extinfo->reserved_size;
324 }
325 }
326
327 if (load_size_ > reserved_size) {
328 if (!reserved_hint) {
329 DL_ERR("reserved address space %zd smaller than %zd bytes needed for \"%s\"",
330 reserved_size - load_size_, load_size_, name_);
331 return false;
332 }
333 int mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS;
334 start = mmap(addr, load_size_, PROT_NONE, mmap_flags, -1, 0);
335 if (start == MAP_FAILED) {
336 DL_ERR("couldn't reserve %zd bytes of address space for \"%s\"", load_size_, name_);
337 return false;
338 }
339 } else {
340 start = extinfo->reserved_addr;
Elliott Hughes650be4e2013-03-05 18:47:58 -0800341 }
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200342
Elliott Hughes650be4e2013-03-05 18:47:58 -0800343 load_start_ = start;
Brian Carlstrome7dffe12013-01-10 16:39:58 -0800344 load_bias_ = reinterpret_cast<uint8_t*>(start) - addr;
Elliott Hughes650be4e2013-03-05 18:47:58 -0800345 return true;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200346}
347
Elliott Hughes650be4e2013-03-05 18:47:58 -0800348bool ElfReader::LoadSegments() {
349 for (size_t i = 0; i < phdr_num_; ++i) {
Elliott Hughes0266ae52014-02-10 17:46:57 -0800350 const ElfW(Phdr)* phdr = &phdr_table_[i];
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200351
Elliott Hughes650be4e2013-03-05 18:47:58 -0800352 if (phdr->p_type != PT_LOAD) {
353 continue;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200354 }
Elliott Hughes650be4e2013-03-05 18:47:58 -0800355
356 // Segment addresses in memory.
Elliott Hughes0266ae52014-02-10 17:46:57 -0800357 ElfW(Addr) seg_start = phdr->p_vaddr + load_bias_;
358 ElfW(Addr) seg_end = seg_start + phdr->p_memsz;
Elliott Hughes650be4e2013-03-05 18:47:58 -0800359
Elliott Hughes0266ae52014-02-10 17:46:57 -0800360 ElfW(Addr) seg_page_start = PAGE_START(seg_start);
361 ElfW(Addr) seg_page_end = PAGE_END(seg_end);
Elliott Hughes650be4e2013-03-05 18:47:58 -0800362
Elliott Hughes0266ae52014-02-10 17:46:57 -0800363 ElfW(Addr) seg_file_end = seg_start + phdr->p_filesz;
Elliott Hughes650be4e2013-03-05 18:47:58 -0800364
365 // File offsets.
Elliott Hughes0266ae52014-02-10 17:46:57 -0800366 ElfW(Addr) file_start = phdr->p_offset;
367 ElfW(Addr) file_end = file_start + phdr->p_filesz;
Elliott Hughes650be4e2013-03-05 18:47:58 -0800368
Elliott Hughes0266ae52014-02-10 17:46:57 -0800369 ElfW(Addr) file_page_start = PAGE_START(file_start);
370 ElfW(Addr) file_length = file_end - file_page_start;
Elliott Hughes650be4e2013-03-05 18:47:58 -0800371
Brian Carlstrom82dcc792013-05-21 16:49:24 -0700372 if (file_length != 0) {
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -0700373 void* seg_addr = mmap64(reinterpret_cast<void*>(seg_page_start),
Brian Carlstrom82dcc792013-05-21 16:49:24 -0700374 file_length,
375 PFLAGS_TO_PROT(phdr->p_flags),
376 MAP_FIXED|MAP_PRIVATE,
377 fd_,
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -0700378 file_offset_ + file_page_start);
Brian Carlstrom82dcc792013-05-21 16:49:24 -0700379 if (seg_addr == MAP_FAILED) {
Elliott Hughesc6200592013-09-30 18:43:46 -0700380 DL_ERR("couldn't map \"%s\" segment %zd: %s", name_, i, strerror(errno));
Brian Carlstrom82dcc792013-05-21 16:49:24 -0700381 return false;
382 }
Elliott Hughes650be4e2013-03-05 18:47:58 -0800383 }
384
385 // if the segment is writable, and does not end on a page boundary,
386 // zero-fill it until the page limit.
387 if ((phdr->p_flags & PF_W) != 0 && PAGE_OFFSET(seg_file_end) > 0) {
Elliott Hughesfaf05ba2014-02-11 16:59:37 -0800388 memset(reinterpret_cast<void*>(seg_file_end), 0, PAGE_SIZE - PAGE_OFFSET(seg_file_end));
Elliott Hughes650be4e2013-03-05 18:47:58 -0800389 }
390
391 seg_file_end = PAGE_END(seg_file_end);
392
393 // seg_file_end is now the first page address after the file
394 // content. If seg_end is larger, we need to zero anything
395 // between them. This is done by using a private anonymous
396 // map for all extra pages.
397 if (seg_page_end > seg_file_end) {
Elliott Hughesfaf05ba2014-02-11 16:59:37 -0800398 void* zeromap = mmap(reinterpret_cast<void*>(seg_file_end),
Elliott Hughes650be4e2013-03-05 18:47:58 -0800399 seg_page_end - seg_file_end,
400 PFLAGS_TO_PROT(phdr->p_flags),
401 MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE,
402 -1,
403 0);
404 if (zeromap == MAP_FAILED) {
405 DL_ERR("couldn't zero fill \"%s\" gap: %s", name_, strerror(errno));
406 return false;
407 }
408 }
409 }
410 return true;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200411}
412
Elliott Hughes105bc262012-08-15 16:56:00 -0700413/* Used internally. Used to set the protection bits of all loaded segments
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200414 * with optional extra flags (i.e. really PROT_WRITE). Used by
415 * phdr_table_protect_segments and phdr_table_unprotect_segments.
416 */
Elliott Hughes0266ae52014-02-10 17:46:57 -0800417static int _phdr_table_set_load_prot(const ElfW(Phdr)* phdr_table, size_t phdr_count,
418 ElfW(Addr) load_bias, int extra_prot_flags) {
419 const ElfW(Phdr)* phdr = phdr_table;
420 const ElfW(Phdr)* phdr_limit = phdr + phdr_count;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200421
Elliott Hughes0266ae52014-02-10 17:46:57 -0800422 for (; phdr < phdr_limit; phdr++) {
423 if (phdr->p_type != PT_LOAD || (phdr->p_flags & PF_W) != 0) {
424 continue;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200425 }
Elliott Hughes0266ae52014-02-10 17:46:57 -0800426
427 ElfW(Addr) seg_page_start = PAGE_START(phdr->p_vaddr) + load_bias;
428 ElfW(Addr) seg_page_end = PAGE_END(phdr->p_vaddr + phdr->p_memsz) + load_bias;
429
Elliott Hughesfaf05ba2014-02-11 16:59:37 -0800430 int ret = mprotect(reinterpret_cast<void*>(seg_page_start),
Elliott Hughes0266ae52014-02-10 17:46:57 -0800431 seg_page_end - seg_page_start,
432 PFLAGS_TO_PROT(phdr->p_flags) | extra_prot_flags);
433 if (ret < 0) {
434 return -1;
435 }
436 }
437 return 0;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200438}
439
440/* Restore the original protection modes for all loadable segments.
441 * You should only call this after phdr_table_unprotect_segments and
442 * applying all relocations.
443 *
444 * Input:
445 * phdr_table -> program header table
Elliott Hughes105bc262012-08-15 16:56:00 -0700446 * phdr_count -> number of entries in tables
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200447 * load_bias -> load bias
448 * Return:
449 * 0 on error, -1 on failure (error code in errno).
450 */
Elliott Hughes0266ae52014-02-10 17:46:57 -0800451int phdr_table_protect_segments(const ElfW(Phdr)* phdr_table, size_t phdr_count, ElfW(Addr) load_bias) {
452 return _phdr_table_set_load_prot(phdr_table, phdr_count, load_bias, 0);
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200453}
454
455/* Change the protection of all loaded segments in memory to writable.
456 * This is useful before performing relocations. Once completed, you
457 * will have to call phdr_table_protect_segments to restore the original
458 * protection flags on all segments.
459 *
460 * Note that some writable segments can also have their content turned
461 * to read-only by calling phdr_table_protect_gnu_relro. This is no
462 * performed here.
463 *
464 * Input:
465 * phdr_table -> program header table
Elliott Hughes105bc262012-08-15 16:56:00 -0700466 * phdr_count -> number of entries in tables
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200467 * load_bias -> load bias
468 * Return:
469 * 0 on error, -1 on failure (error code in errno).
470 */
Elliott Hughes0266ae52014-02-10 17:46:57 -0800471int phdr_table_unprotect_segments(const ElfW(Phdr)* phdr_table, size_t phdr_count, ElfW(Addr) load_bias) {
472 return _phdr_table_set_load_prot(phdr_table, phdr_count, load_bias, PROT_WRITE);
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200473}
474
475/* Used internally by phdr_table_protect_gnu_relro and
476 * phdr_table_unprotect_gnu_relro.
477 */
Elliott Hughes0266ae52014-02-10 17:46:57 -0800478static int _phdr_table_set_gnu_relro_prot(const ElfW(Phdr)* phdr_table, size_t phdr_count,
479 ElfW(Addr) load_bias, int prot_flags) {
480 const ElfW(Phdr)* phdr = phdr_table;
481 const ElfW(Phdr)* phdr_limit = phdr + phdr_count;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200482
Elliott Hughes0266ae52014-02-10 17:46:57 -0800483 for (phdr = phdr_table; phdr < phdr_limit; phdr++) {
484 if (phdr->p_type != PT_GNU_RELRO) {
485 continue;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200486 }
Elliott Hughes0266ae52014-02-10 17:46:57 -0800487
488 // Tricky: what happens when the relro segment does not start
489 // or end at page boundaries? We're going to be over-protective
490 // here and put every page touched by the segment as read-only.
491
492 // This seems to match Ian Lance Taylor's description of the
493 // feature at http://www.airs.com/blog/archives/189.
494
495 // Extract:
496 // Note that the current dynamic linker code will only work
497 // correctly if the PT_GNU_RELRO segment starts on a page
498 // boundary. This is because the dynamic linker rounds the
499 // p_vaddr field down to the previous page boundary. If
500 // there is anything on the page which should not be read-only,
501 // the program is likely to fail at runtime. So in effect the
502 // linker must only emit a PT_GNU_RELRO segment if it ensures
503 // that it starts on a page boundary.
504 ElfW(Addr) seg_page_start = PAGE_START(phdr->p_vaddr) + load_bias;
505 ElfW(Addr) seg_page_end = PAGE_END(phdr->p_vaddr + phdr->p_memsz) + load_bias;
506
Elliott Hughesfaf05ba2014-02-11 16:59:37 -0800507 int ret = mprotect(reinterpret_cast<void*>(seg_page_start),
Elliott Hughes0266ae52014-02-10 17:46:57 -0800508 seg_page_end - seg_page_start,
509 prot_flags);
510 if (ret < 0) {
511 return -1;
512 }
513 }
514 return 0;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200515}
516
517/* Apply GNU relro protection if specified by the program header. This will
518 * turn some of the pages of a writable PT_LOAD segment to read-only, as
519 * specified by one or more PT_GNU_RELRO segments. This must be always
520 * performed after relocations.
521 *
Ard Biesheuvel12c78bb2012-08-14 12:30:09 +0200522 * The areas typically covered are .got and .data.rel.ro, these are
523 * read-only from the program's POV, but contain absolute addresses
524 * that need to be relocated before use.
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200525 *
526 * Input:
527 * phdr_table -> program header table
Elliott Hughes105bc262012-08-15 16:56:00 -0700528 * phdr_count -> number of entries in tables
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200529 * load_bias -> load bias
530 * Return:
531 * 0 on error, -1 on failure (error code in errno).
532 */
Elliott Hughes0266ae52014-02-10 17:46:57 -0800533int phdr_table_protect_gnu_relro(const ElfW(Phdr)* phdr_table, size_t phdr_count, ElfW(Addr) load_bias) {
534 return _phdr_table_set_gnu_relro_prot(phdr_table, phdr_count, load_bias, PROT_READ);
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200535}
536
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +0000537/* Serialize the GNU relro segments to the given file descriptor. This can be
538 * performed after relocations to allow another process to later share the
539 * relocated segment, if it was loaded at the same address.
540 *
541 * Input:
542 * phdr_table -> program header table
543 * phdr_count -> number of entries in tables
544 * load_bias -> load bias
545 * fd -> writable file descriptor to use
546 * Return:
547 * 0 on error, -1 on failure (error code in errno).
548 */
549int phdr_table_serialize_gnu_relro(const ElfW(Phdr)* phdr_table, size_t phdr_count, ElfW(Addr) load_bias,
550 int fd) {
551 const ElfW(Phdr)* phdr = phdr_table;
552 const ElfW(Phdr)* phdr_limit = phdr + phdr_count;
553 ssize_t file_offset = 0;
554
555 for (phdr = phdr_table; phdr < phdr_limit; phdr++) {
556 if (phdr->p_type != PT_GNU_RELRO) {
557 continue;
558 }
559
560 ElfW(Addr) seg_page_start = PAGE_START(phdr->p_vaddr) + load_bias;
561 ElfW(Addr) seg_page_end = PAGE_END(phdr->p_vaddr + phdr->p_memsz) + load_bias;
562 ssize_t size = seg_page_end - seg_page_start;
563
564 ssize_t written = TEMP_FAILURE_RETRY(write(fd, reinterpret_cast<void*>(seg_page_start), size));
565 if (written != size) {
566 return -1;
567 }
568 void* map = mmap(reinterpret_cast<void*>(seg_page_start), size, PROT_READ,
569 MAP_PRIVATE|MAP_FIXED, fd, file_offset);
570 if (map == MAP_FAILED) {
571 return -1;
572 }
573 file_offset += size;
574 }
575 return 0;
576}
577
578/* Where possible, replace the GNU relro segments with mappings of the given
579 * file descriptor. This can be performed after relocations to allow a file
580 * previously created by phdr_table_serialize_gnu_relro in another process to
581 * replace the dirty relocated pages, saving memory, if it was loaded at the
582 * same address. We have to compare the data before we map over it, since some
583 * parts of the relro segment may not be identical due to other libraries in
584 * the process being loaded at different addresses.
585 *
586 * Input:
587 * phdr_table -> program header table
588 * phdr_count -> number of entries in tables
589 * load_bias -> load bias
590 * fd -> readable file descriptor to use
591 * Return:
592 * 0 on error, -1 on failure (error code in errno).
593 */
594int phdr_table_map_gnu_relro(const ElfW(Phdr)* phdr_table, size_t phdr_count, ElfW(Addr) load_bias,
595 int fd) {
596 // Map the file at a temporary location so we can compare its contents.
597 struct stat file_stat;
598 if (TEMP_FAILURE_RETRY(fstat(fd, &file_stat)) != 0) {
599 return -1;
600 }
601 off_t file_size = file_stat.st_size;
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700602 void* temp_mapping = nullptr;
Torne (Richard Coles)26ec9672014-04-30 15:48:40 +0100603 if (file_size > 0) {
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700604 temp_mapping = mmap(nullptr, file_size, PROT_READ, MAP_PRIVATE, fd, 0);
Torne (Richard Coles)26ec9672014-04-30 15:48:40 +0100605 if (temp_mapping == MAP_FAILED) {
606 return -1;
607 }
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +0000608 }
609 size_t file_offset = 0;
610
611 // Iterate over the relro segments and compare/remap the pages.
612 const ElfW(Phdr)* phdr = phdr_table;
613 const ElfW(Phdr)* phdr_limit = phdr + phdr_count;
614
615 for (phdr = phdr_table; phdr < phdr_limit; phdr++) {
616 if (phdr->p_type != PT_GNU_RELRO) {
617 continue;
618 }
619
620 ElfW(Addr) seg_page_start = PAGE_START(phdr->p_vaddr) + load_bias;
621 ElfW(Addr) seg_page_end = PAGE_END(phdr->p_vaddr + phdr->p_memsz) + load_bias;
622
623 char* file_base = static_cast<char*>(temp_mapping) + file_offset;
624 char* mem_base = reinterpret_cast<char*>(seg_page_start);
625 size_t match_offset = 0;
626 size_t size = seg_page_end - seg_page_start;
627
Torne (Richard Coles)26ec9672014-04-30 15:48:40 +0100628 if (file_size - file_offset < size) {
629 // File is too short to compare to this segment. The contents are likely
630 // different as well (it's probably for a different library version) so
631 // just don't bother checking.
632 break;
633 }
634
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +0000635 while (match_offset < size) {
636 // Skip over dissimilar pages.
637 while (match_offset < size &&
638 memcmp(mem_base + match_offset, file_base + match_offset, PAGE_SIZE) != 0) {
639 match_offset += PAGE_SIZE;
640 }
641
642 // Count similar pages.
643 size_t mismatch_offset = match_offset;
644 while (mismatch_offset < size &&
645 memcmp(mem_base + mismatch_offset, file_base + mismatch_offset, PAGE_SIZE) == 0) {
646 mismatch_offset += PAGE_SIZE;
647 }
648
649 // Map over similar pages.
650 if (mismatch_offset > match_offset) {
651 void* map = mmap(mem_base + match_offset, mismatch_offset - match_offset,
652 PROT_READ, MAP_PRIVATE|MAP_FIXED, fd, match_offset);
653 if (map == MAP_FAILED) {
654 munmap(temp_mapping, file_size);
655 return -1;
656 }
657 }
658
659 match_offset = mismatch_offset;
660 }
661
662 // Add to the base file offset in case there are multiple relro segments.
663 file_offset += size;
664 }
665 munmap(temp_mapping, file_size);
666 return 0;
667}
668
669
Elliott Hughes4eeb1f12013-10-25 17:38:02 -0700670#if defined(__arm__)
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200671
672# ifndef PT_ARM_EXIDX
673# define PT_ARM_EXIDX 0x70000001 /* .ARM.exidx segment */
674# endif
675
676/* Return the address and size of the .ARM.exidx section in memory,
677 * if present.
678 *
679 * Input:
680 * phdr_table -> program header table
Elliott Hughes105bc262012-08-15 16:56:00 -0700681 * phdr_count -> number of entries in tables
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200682 * load_bias -> load bias
683 * Output:
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700684 * arm_exidx -> address of table in memory (null on failure).
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200685 * arm_exidx_count -> number of items in table (0 on failure).
686 * Return:
687 * 0 on error, -1 on failure (_no_ error code in errno)
688 */
Elliott Hughes0266ae52014-02-10 17:46:57 -0800689int phdr_table_get_arm_exidx(const ElfW(Phdr)* phdr_table, size_t phdr_count,
690 ElfW(Addr) load_bias,
691 ElfW(Addr)** arm_exidx, unsigned* arm_exidx_count) {
692 const ElfW(Phdr)* phdr = phdr_table;
693 const ElfW(Phdr)* phdr_limit = phdr + phdr_count;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200694
Elliott Hughes0266ae52014-02-10 17:46:57 -0800695 for (phdr = phdr_table; phdr < phdr_limit; phdr++) {
696 if (phdr->p_type != PT_ARM_EXIDX) {
697 continue;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200698 }
Elliott Hughes0266ae52014-02-10 17:46:57 -0800699
700 *arm_exidx = reinterpret_cast<ElfW(Addr)*>(load_bias + phdr->p_vaddr);
701 *arm_exidx_count = (unsigned)(phdr->p_memsz / 8);
702 return 0;
703 }
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700704 *arm_exidx = nullptr;
Elliott Hughes0266ae52014-02-10 17:46:57 -0800705 *arm_exidx_count = 0;
706 return -1;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200707}
Elliott Hughes4eeb1f12013-10-25 17:38:02 -0700708#endif
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200709
Ard Biesheuvel12c78bb2012-08-14 12:30:09 +0200710/* Return the address and size of the ELF file's .dynamic section in memory,
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700711 * or null if missing.
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200712 *
713 * Input:
714 * phdr_table -> program header table
Elliott Hughes105bc262012-08-15 16:56:00 -0700715 * phdr_count -> number of entries in tables
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200716 * load_bias -> load bias
Ard Biesheuvel12c78bb2012-08-14 12:30:09 +0200717 * Output:
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700718 * dynamic -> address of table in memory (null on failure).
Ningsheng Jiane93be992014-09-16 15:22:10 +0800719 * dynamic_flags -> protection flags for section (unset on failure)
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200720 * Return:
Ard Biesheuvel12c78bb2012-08-14 12:30:09 +0200721 * void
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200722 */
Elliott Hughes0266ae52014-02-10 17:46:57 -0800723void phdr_table_get_dynamic_section(const ElfW(Phdr)* phdr_table, size_t phdr_count,
Ningsheng Jiane93be992014-09-16 15:22:10 +0800724 ElfW(Addr) load_bias, ElfW(Dyn)** dynamic,
725 ElfW(Word)* dynamic_flags) {
Dmitriy Ivanov498eb182014-09-05 14:57:59 -0700726 *dynamic = nullptr;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700727 for (const ElfW(Phdr)* phdr = phdr_table, *phdr_limit = phdr + phdr_count; phdr < phdr_limit; phdr++) {
728 if (phdr->p_type == PT_DYNAMIC) {
729 *dynamic = reinterpret_cast<ElfW(Dyn)*>(load_bias + phdr->p_vaddr);
Ningsheng Jiane93be992014-09-16 15:22:10 +0800730 if (dynamic_flags) {
731 *dynamic_flags = phdr->p_flags;
732 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700733 return;
734 }
Elliott Hughes0266ae52014-02-10 17:46:57 -0800735 }
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200736}
737
Robert Grosse4544d9f2014-10-15 14:32:19 -0700738// Sets loaded_phdr_ to the address of the program header table as it appears
739// in the loaded segments in memory. This is in contrast with phdr_table_,
740// which is temporary and will be released before the library is relocated.
Elliott Hughes650be4e2013-03-05 18:47:58 -0800741bool ElfReader::FindPhdr() {
Elliott Hughes0266ae52014-02-10 17:46:57 -0800742 const ElfW(Phdr)* phdr_limit = phdr_table_ + phdr_num_;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200743
Elliott Hughes650be4e2013-03-05 18:47:58 -0800744 // If there is a PT_PHDR, use it directly.
Elliott Hughes0266ae52014-02-10 17:46:57 -0800745 for (const ElfW(Phdr)* phdr = phdr_table_; phdr < phdr_limit; ++phdr) {
Elliott Hughes650be4e2013-03-05 18:47:58 -0800746 if (phdr->p_type == PT_PHDR) {
747 return CheckPhdr(load_bias_ + phdr->p_vaddr);
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200748 }
Elliott Hughes650be4e2013-03-05 18:47:58 -0800749 }
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200750
Elliott Hughes650be4e2013-03-05 18:47:58 -0800751 // Otherwise, check the first loadable segment. If its file offset
752 // is 0, it starts with the ELF header, and we can trivially find the
753 // loaded program header from it.
Elliott Hughes0266ae52014-02-10 17:46:57 -0800754 for (const ElfW(Phdr)* phdr = phdr_table_; phdr < phdr_limit; ++phdr) {
Elliott Hughes650be4e2013-03-05 18:47:58 -0800755 if (phdr->p_type == PT_LOAD) {
756 if (phdr->p_offset == 0) {
Elliott Hughes0266ae52014-02-10 17:46:57 -0800757 ElfW(Addr) elf_addr = load_bias_ + phdr->p_vaddr;
Elliott Hughesfaf05ba2014-02-11 16:59:37 -0800758 const ElfW(Ehdr)* ehdr = reinterpret_cast<const ElfW(Ehdr)*>(elf_addr);
Elliott Hughes0266ae52014-02-10 17:46:57 -0800759 ElfW(Addr) offset = ehdr->e_phoff;
760 return CheckPhdr((ElfW(Addr))ehdr + offset);
Elliott Hughes650be4e2013-03-05 18:47:58 -0800761 }
762 break;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200763 }
Elliott Hughes650be4e2013-03-05 18:47:58 -0800764 }
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200765
Elliott Hughes650be4e2013-03-05 18:47:58 -0800766 DL_ERR("can't find loaded phdr for \"%s\"", name_);
767 return false;
768}
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200769
Elliott Hughes650be4e2013-03-05 18:47:58 -0800770// Ensures that our program header is actually within a loadable
771// segment. This should help catch badly-formed ELF files that
772// would cause the linker to crash later when trying to access it.
Elliott Hughes0266ae52014-02-10 17:46:57 -0800773bool ElfReader::CheckPhdr(ElfW(Addr) loaded) {
774 const ElfW(Phdr)* phdr_limit = phdr_table_ + phdr_num_;
775 ElfW(Addr) loaded_end = loaded + (phdr_num_ * sizeof(ElfW(Phdr)));
776 for (ElfW(Phdr)* phdr = phdr_table_; phdr < phdr_limit; ++phdr) {
Elliott Hughes650be4e2013-03-05 18:47:58 -0800777 if (phdr->p_type != PT_LOAD) {
778 continue;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200779 }
Elliott Hughes0266ae52014-02-10 17:46:57 -0800780 ElfW(Addr) seg_start = phdr->p_vaddr + load_bias_;
781 ElfW(Addr) seg_end = phdr->p_filesz + seg_start;
Elliott Hughes650be4e2013-03-05 18:47:58 -0800782 if (seg_start <= loaded && loaded_end <= seg_end) {
Elliott Hughes0266ae52014-02-10 17:46:57 -0800783 loaded_phdr_ = reinterpret_cast<const ElfW(Phdr)*>(loaded);
Elliott Hughes650be4e2013-03-05 18:47:58 -0800784 return true;
785 }
786 }
Elliott Hughesc00f2cb2013-10-04 17:01:33 -0700787 DL_ERR("\"%s\" loaded phdr %p not in loadable segment", name_, reinterpret_cast<void*>(loaded));
Elliott Hughes650be4e2013-03-05 18:47:58 -0800788 return false;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200789}