blob: cfeab967b09a1d0b40b41960fbd1f889b703f20b [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>
Marcus Oaklande365f9d2013-10-10 15:19:31 +010032#include <machine/exec.h>
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +020033#include <sys/mman.h>
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +000034#include <sys/types.h>
35#include <sys/stat.h>
36#include <unistd.h>
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +020037
Elliott Hughes650be4e2013-03-05 18:47:58 -080038#include "linker.h"
39#include "linker_debug.h"
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +020040
41/**
42 TECHNICAL NOTE ON ELF LOADING.
43
44 An ELF file's program header table contains one or more PT_LOAD
45 segments, which corresponds to portions of the file that need to
46 be mapped into the process' address space.
47
48 Each loadable segment has the following important properties:
49
50 p_offset -> segment file offset
51 p_filesz -> segment file size
52 p_memsz -> segment memory size (always >= p_filesz)
53 p_vaddr -> segment's virtual address
54 p_flags -> segment flags (e.g. readable, writable, executable)
55
Elliott Hughes0266ae52014-02-10 17:46:57 -080056 We will ignore the p_paddr and p_align fields of ElfW(Phdr) for now.
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +020057
58 The loadable segments can be seen as a list of [p_vaddr ... p_vaddr+p_memsz)
59 ranges of virtual addresses. A few rules apply:
60
61 - the virtual address ranges should not overlap.
62
63 - if a segment's p_filesz is smaller than its p_memsz, the extra bytes
64 between them should always be initialized to 0.
65
66 - ranges do not necessarily start or end at page boundaries. Two distinct
67 segments can have their start and end on the same page. In this case, the
68 page inherits the mapping flags of the latter segment.
69
70 Finally, the real load addrs of each segment is not p_vaddr. Instead the
71 loader decides where to load the first segment, then will load all others
72 relative to the first one to respect the initial range layout.
73
74 For example, consider the following list:
75
76 [ offset:0, filesz:0x4000, memsz:0x4000, vaddr:0x30000 ],
77 [ offset:0x4000, filesz:0x2000, memsz:0x8000, vaddr:0x40000 ],
78
79 This corresponds to two segments that cover these virtual address ranges:
80
81 0x30000...0x34000
82 0x40000...0x48000
83
84 If the loader decides to load the first segment at address 0xa0000000
85 then the segments' load address ranges will be:
86
87 0xa0030000...0xa0034000
88 0xa0040000...0xa0048000
89
90 In other words, all segments must be loaded at an address that has the same
91 constant offset from their p_vaddr value. This offset is computed as the
92 difference between the first segment's load address, and its p_vaddr value.
93
94 However, in practice, segments do _not_ start at page boundaries. Since we
95 can only memory-map at page boundaries, this means that the bias is
96 computed as:
97
98 load_bias = phdr0_load_address - PAGE_START(phdr0->p_vaddr)
99
100 (NOTE: The value must be used as a 32-bit unsigned integer, to deal with
101 possible wrap around UINT32_MAX for possible large p_vaddr values).
102
103 And that the phdr0_load_address must start at a page boundary, with
104 the segment's real content starting at:
105
106 phdr0_load_address + PAGE_OFFSET(phdr0->p_vaddr)
107
108 Note that ELF requires the following condition to make the mmap()-ing work:
109
110 PAGE_OFFSET(phdr0->p_vaddr) == PAGE_OFFSET(phdr0->p_offset)
111
112 The load_bias must be added to any p_vaddr value read from the ELF file to
113 determine the corresponding memory address.
114
115 **/
116
Elliott Hughesfaf05ba2014-02-11 16:59:37 -0800117#define MAYBE_MAP_FLAG(x, from, to) (((x) & (from)) ? (to) : 0)
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200118#define PFLAGS_TO_PROT(x) (MAYBE_MAP_FLAG((x), PF_X, PROT_EXEC) | \
119 MAYBE_MAP_FLAG((x), PF_R, PROT_READ) | \
120 MAYBE_MAP_FLAG((x), PF_W, PROT_WRITE))
121
Elliott Hughes650be4e2013-03-05 18:47:58 -0800122ElfReader::ElfReader(const char* name, int fd)
123 : name_(name), fd_(fd),
124 phdr_num_(0), phdr_mmap_(NULL), phdr_table_(NULL), phdr_size_(0),
125 load_start_(NULL), load_size_(0), load_bias_(0),
126 loaded_phdr_(NULL) {
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200127}
128
Elliott Hughes650be4e2013-03-05 18:47:58 -0800129ElfReader::~ElfReader() {
130 if (fd_ != -1) {
131 close(fd_);
132 }
133 if (phdr_mmap_ != NULL) {
134 munmap(phdr_mmap_, phdr_size_);
135 }
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200136}
137
Torne (Richard Coles)12bbb912014-02-06 14:34:21 +0000138bool ElfReader::Load(const android_dlextinfo* extinfo) {
Elliott Hughes650be4e2013-03-05 18:47:58 -0800139 return ReadElfHeader() &&
140 VerifyElfHeader() &&
141 ReadProgramHeader() &&
Torne (Richard Coles)12bbb912014-02-06 14:34:21 +0000142 ReserveAddressSpace(extinfo) &&
Elliott Hughes650be4e2013-03-05 18:47:58 -0800143 LoadSegments() &&
144 FindPhdr();
145}
146
147bool ElfReader::ReadElfHeader() {
148 ssize_t rc = TEMP_FAILURE_RETRY(read(fd_, &header_, sizeof(header_)));
149 if (rc < 0) {
150 DL_ERR("can't read file \"%s\": %s", name_, strerror(errno));
151 return false;
152 }
153 if (rc != sizeof(header_)) {
Elliott Hughesc6200592013-09-30 18:43:46 -0700154 DL_ERR("\"%s\" is too small to be an ELF executable: only found %zd bytes", name_,
155 static_cast<size_t>(rc));
Elliott Hughes650be4e2013-03-05 18:47:58 -0800156 return false;
157 }
158 return true;
159}
160
161bool ElfReader::VerifyElfHeader() {
162 if (header_.e_ident[EI_MAG0] != ELFMAG0 ||
163 header_.e_ident[EI_MAG1] != ELFMAG1 ||
164 header_.e_ident[EI_MAG2] != ELFMAG2 ||
165 header_.e_ident[EI_MAG3] != ELFMAG3) {
166 DL_ERR("\"%s\" has bad ELF magic", name_);
167 return false;
168 }
169
Elliott Hughesc00f2cb2013-10-04 17:01:33 -0700170 // Try to give a clear diagnostic for ELF class mismatches, since they're
171 // an easy mistake to make during the 32-bit/64-bit transition period.
172 int elf_class = header_.e_ident[EI_CLASS];
173#if defined(__LP64__)
174 if (elf_class != ELFCLASS64) {
175 if (elf_class == ELFCLASS32) {
176 DL_ERR("\"%s\" is 32-bit instead of 64-bit", name_);
177 } else {
178 DL_ERR("\"%s\" has unknown ELF class: %d", name_, elf_class);
179 }
Elliott Hughes650be4e2013-03-05 18:47:58 -0800180 return false;
181 }
Elliott Hughesc00f2cb2013-10-04 17:01:33 -0700182#else
183 if (elf_class != ELFCLASS32) {
184 if (elf_class == ELFCLASS64) {
185 DL_ERR("\"%s\" is 64-bit instead of 32-bit", name_);
186 } else {
187 DL_ERR("\"%s\" has unknown ELF class: %d", name_, elf_class);
188 }
189 return false;
190 }
191#endif
192
Elliott Hughes650be4e2013-03-05 18:47:58 -0800193 if (header_.e_ident[EI_DATA] != ELFDATA2LSB) {
194 DL_ERR("\"%s\" not little-endian: %d", name_, header_.e_ident[EI_DATA]);
195 return false;
196 }
197
198 if (header_.e_type != ET_DYN) {
199 DL_ERR("\"%s\" has unexpected e_type: %d", name_, header_.e_type);
200 return false;
201 }
202
203 if (header_.e_version != EV_CURRENT) {
204 DL_ERR("\"%s\" has unexpected e_version: %d", name_, header_.e_version);
205 return false;
206 }
207
Marcus Oaklande365f9d2013-10-10 15:19:31 +0100208 if (header_.e_machine != ELF_TARG_MACH) {
Elliott Hughes650be4e2013-03-05 18:47:58 -0800209 DL_ERR("\"%s\" has unexpected e_machine: %d", name_, header_.e_machine);
210 return false;
211 }
212
213 return true;
214}
215
216// Loads the program header table from an ELF file into a read-only private
217// anonymous mmap-ed block.
218bool ElfReader::ReadProgramHeader() {
219 phdr_num_ = header_.e_phnum;
220
221 // Like the kernel, we only accept program header tables that
222 // are smaller than 64KiB.
Elliott Hughes0266ae52014-02-10 17:46:57 -0800223 if (phdr_num_ < 1 || phdr_num_ > 65536/sizeof(ElfW(Phdr))) {
Elliott Hughesc6200592013-09-30 18:43:46 -0700224 DL_ERR("\"%s\" has invalid e_phnum: %zd", name_, phdr_num_);
Elliott Hughes650be4e2013-03-05 18:47:58 -0800225 return false;
226 }
227
Elliott Hughes0266ae52014-02-10 17:46:57 -0800228 ElfW(Addr) page_min = PAGE_START(header_.e_phoff);
229 ElfW(Addr) page_max = PAGE_END(header_.e_phoff + (phdr_num_ * sizeof(ElfW(Phdr))));
230 ElfW(Addr) page_offset = PAGE_OFFSET(header_.e_phoff);
Elliott Hughes650be4e2013-03-05 18:47:58 -0800231
232 phdr_size_ = page_max - page_min;
233
234 void* mmap_result = mmap(NULL, phdr_size_, PROT_READ, MAP_PRIVATE, fd_, page_min);
235 if (mmap_result == MAP_FAILED) {
236 DL_ERR("\"%s\" phdr mmap failed: %s", name_, strerror(errno));
237 return false;
238 }
239
240 phdr_mmap_ = mmap_result;
Elliott Hughes0266ae52014-02-10 17:46:57 -0800241 phdr_table_ = reinterpret_cast<ElfW(Phdr)*>(reinterpret_cast<char*>(mmap_result) + page_offset);
Elliott Hughes650be4e2013-03-05 18:47:58 -0800242 return true;
243}
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200244
Brian Carlstrome7dffe12013-01-10 16:39:58 -0800245/* Returns the size of the extent of all the possibly non-contiguous
246 * loadable segments in an ELF program header table. This corresponds
247 * to the page-aligned size in bytes that needs to be reserved in the
248 * process' address space. If there are no loadable segments, 0 is
249 * returned.
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200250 *
Brian Carlstrome7dffe12013-01-10 16:39:58 -0800251 * If out_min_vaddr or out_max_vaddr are non-NULL, they will be
252 * set to the minimum and maximum addresses of pages to be reserved,
253 * or 0 if there is nothing to load.
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200254 */
Elliott Hughes0266ae52014-02-10 17:46:57 -0800255size_t phdr_table_get_load_size(const ElfW(Phdr)* phdr_table, size_t phdr_count,
256 ElfW(Addr)* out_min_vaddr,
257 ElfW(Addr)* out_max_vaddr) {
258 ElfW(Addr) min_vaddr = UINTPTR_MAX;
259 ElfW(Addr) max_vaddr = 0;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200260
Elliott Hughes0266ae52014-02-10 17:46:57 -0800261 bool found_pt_load = false;
262 for (size_t i = 0; i < phdr_count; ++i) {
263 const ElfW(Phdr)* phdr = &phdr_table[i];
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200264
Elliott Hughes0266ae52014-02-10 17:46:57 -0800265 if (phdr->p_type != PT_LOAD) {
266 continue;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200267 }
Elliott Hughes0266ae52014-02-10 17:46:57 -0800268 found_pt_load = true;
269
270 if (phdr->p_vaddr < min_vaddr) {
271 min_vaddr = phdr->p_vaddr;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200272 }
273
Elliott Hughes0266ae52014-02-10 17:46:57 -0800274 if (phdr->p_vaddr + phdr->p_memsz > max_vaddr) {
275 max_vaddr = phdr->p_vaddr + phdr->p_memsz;
276 }
277 }
278 if (!found_pt_load) {
279 min_vaddr = 0;
280 }
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200281
Elliott Hughes0266ae52014-02-10 17:46:57 -0800282 min_vaddr = PAGE_START(min_vaddr);
283 max_vaddr = PAGE_END(max_vaddr);
284
285 if (out_min_vaddr != NULL) {
286 *out_min_vaddr = min_vaddr;
287 }
288 if (out_max_vaddr != NULL) {
289 *out_max_vaddr = max_vaddr;
290 }
291 return max_vaddr - min_vaddr;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200292}
293
Elliott Hughes650be4e2013-03-05 18:47:58 -0800294// Reserve a virtual address range big enough to hold all loadable
295// segments of a program header table. This is done by creating a
296// private anonymous mmap() with PROT_NONE.
Torne (Richard Coles)12bbb912014-02-06 14:34:21 +0000297bool ElfReader::ReserveAddressSpace(const android_dlextinfo* extinfo) {
Elliott Hughes0266ae52014-02-10 17:46:57 -0800298 ElfW(Addr) min_vaddr;
Brian Carlstrome7dffe12013-01-10 16:39:58 -0800299 load_size_ = phdr_table_get_load_size(phdr_table_, phdr_num_, &min_vaddr);
Elliott Hughes650be4e2013-03-05 18:47:58 -0800300 if (load_size_ == 0) {
301 DL_ERR("\"%s\" has no loadable segments", name_);
302 return false;
303 }
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200304
Brian Carlstrome7dffe12013-01-10 16:39:58 -0800305 uint8_t* addr = reinterpret_cast<uint8_t*>(min_vaddr);
Torne (Richard Coles)12bbb912014-02-06 14:34:21 +0000306 void* start;
307 size_t reserved_size = 0;
308 bool reserved_hint = true;
309
310 if (extinfo != NULL) {
311 if (extinfo->flags & ANDROID_DLEXT_RESERVED_ADDRESS) {
312 reserved_size = extinfo->reserved_size;
313 reserved_hint = false;
314 } else if (extinfo->flags & ANDROID_DLEXT_RESERVED_ADDRESS_HINT) {
315 reserved_size = extinfo->reserved_size;
316 }
317 }
318
319 if (load_size_ > reserved_size) {
320 if (!reserved_hint) {
321 DL_ERR("reserved address space %zd smaller than %zd bytes needed for \"%s\"",
322 reserved_size - load_size_, load_size_, name_);
323 return false;
324 }
325 int mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS;
326 start = mmap(addr, load_size_, PROT_NONE, mmap_flags, -1, 0);
327 if (start == MAP_FAILED) {
328 DL_ERR("couldn't reserve %zd bytes of address space for \"%s\"", load_size_, name_);
329 return false;
330 }
331 } else {
332 start = extinfo->reserved_addr;
Elliott Hughes650be4e2013-03-05 18:47:58 -0800333 }
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200334
Elliott Hughes650be4e2013-03-05 18:47:58 -0800335 load_start_ = start;
Brian Carlstrome7dffe12013-01-10 16:39:58 -0800336 load_bias_ = reinterpret_cast<uint8_t*>(start) - addr;
Elliott Hughes650be4e2013-03-05 18:47:58 -0800337 return true;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200338}
339
Elliott Hughes650be4e2013-03-05 18:47:58 -0800340bool ElfReader::LoadSegments() {
341 for (size_t i = 0; i < phdr_num_; ++i) {
Elliott Hughes0266ae52014-02-10 17:46:57 -0800342 const ElfW(Phdr)* phdr = &phdr_table_[i];
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200343
Elliott Hughes650be4e2013-03-05 18:47:58 -0800344 if (phdr->p_type != PT_LOAD) {
345 continue;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200346 }
Elliott Hughes650be4e2013-03-05 18:47:58 -0800347
348 // Segment addresses in memory.
Elliott Hughes0266ae52014-02-10 17:46:57 -0800349 ElfW(Addr) seg_start = phdr->p_vaddr + load_bias_;
350 ElfW(Addr) seg_end = seg_start + phdr->p_memsz;
Elliott Hughes650be4e2013-03-05 18:47:58 -0800351
Elliott Hughes0266ae52014-02-10 17:46:57 -0800352 ElfW(Addr) seg_page_start = PAGE_START(seg_start);
353 ElfW(Addr) seg_page_end = PAGE_END(seg_end);
Elliott Hughes650be4e2013-03-05 18:47:58 -0800354
Elliott Hughes0266ae52014-02-10 17:46:57 -0800355 ElfW(Addr) seg_file_end = seg_start + phdr->p_filesz;
Elliott Hughes650be4e2013-03-05 18:47:58 -0800356
357 // File offsets.
Elliott Hughes0266ae52014-02-10 17:46:57 -0800358 ElfW(Addr) file_start = phdr->p_offset;
359 ElfW(Addr) file_end = file_start + phdr->p_filesz;
Elliott Hughes650be4e2013-03-05 18:47:58 -0800360
Elliott Hughes0266ae52014-02-10 17:46:57 -0800361 ElfW(Addr) file_page_start = PAGE_START(file_start);
362 ElfW(Addr) file_length = file_end - file_page_start;
Elliott Hughes650be4e2013-03-05 18:47:58 -0800363
Brian Carlstrom82dcc792013-05-21 16:49:24 -0700364 if (file_length != 0) {
Elliott Hughesfaf05ba2014-02-11 16:59:37 -0800365 void* seg_addr = mmap(reinterpret_cast<void*>(seg_page_start),
Brian Carlstrom82dcc792013-05-21 16:49:24 -0700366 file_length,
367 PFLAGS_TO_PROT(phdr->p_flags),
368 MAP_FIXED|MAP_PRIVATE,
369 fd_,
370 file_page_start);
371 if (seg_addr == MAP_FAILED) {
Elliott Hughesc6200592013-09-30 18:43:46 -0700372 DL_ERR("couldn't map \"%s\" segment %zd: %s", name_, i, strerror(errno));
Brian Carlstrom82dcc792013-05-21 16:49:24 -0700373 return false;
374 }
Elliott Hughes650be4e2013-03-05 18:47:58 -0800375 }
376
377 // if the segment is writable, and does not end on a page boundary,
378 // zero-fill it until the page limit.
379 if ((phdr->p_flags & PF_W) != 0 && PAGE_OFFSET(seg_file_end) > 0) {
Elliott Hughesfaf05ba2014-02-11 16:59:37 -0800380 memset(reinterpret_cast<void*>(seg_file_end), 0, PAGE_SIZE - PAGE_OFFSET(seg_file_end));
Elliott Hughes650be4e2013-03-05 18:47:58 -0800381 }
382
383 seg_file_end = PAGE_END(seg_file_end);
384
385 // seg_file_end is now the first page address after the file
386 // content. If seg_end is larger, we need to zero anything
387 // between them. This is done by using a private anonymous
388 // map for all extra pages.
389 if (seg_page_end > seg_file_end) {
Elliott Hughesfaf05ba2014-02-11 16:59:37 -0800390 void* zeromap = mmap(reinterpret_cast<void*>(seg_file_end),
Elliott Hughes650be4e2013-03-05 18:47:58 -0800391 seg_page_end - seg_file_end,
392 PFLAGS_TO_PROT(phdr->p_flags),
393 MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE,
394 -1,
395 0);
396 if (zeromap == MAP_FAILED) {
397 DL_ERR("couldn't zero fill \"%s\" gap: %s", name_, strerror(errno));
398 return false;
399 }
400 }
401 }
402 return true;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200403}
404
Elliott Hughes105bc262012-08-15 16:56:00 -0700405/* Used internally. Used to set the protection bits of all loaded segments
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200406 * with optional extra flags (i.e. really PROT_WRITE). Used by
407 * phdr_table_protect_segments and phdr_table_unprotect_segments.
408 */
Elliott Hughes0266ae52014-02-10 17:46:57 -0800409static int _phdr_table_set_load_prot(const ElfW(Phdr)* phdr_table, size_t phdr_count,
410 ElfW(Addr) load_bias, int extra_prot_flags) {
411 const ElfW(Phdr)* phdr = phdr_table;
412 const ElfW(Phdr)* phdr_limit = phdr + phdr_count;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200413
Elliott Hughes0266ae52014-02-10 17:46:57 -0800414 for (; phdr < phdr_limit; phdr++) {
415 if (phdr->p_type != PT_LOAD || (phdr->p_flags & PF_W) != 0) {
416 continue;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200417 }
Elliott Hughes0266ae52014-02-10 17:46:57 -0800418
419 ElfW(Addr) seg_page_start = PAGE_START(phdr->p_vaddr) + load_bias;
420 ElfW(Addr) seg_page_end = PAGE_END(phdr->p_vaddr + phdr->p_memsz) + load_bias;
421
Elliott Hughesfaf05ba2014-02-11 16:59:37 -0800422 int ret = mprotect(reinterpret_cast<void*>(seg_page_start),
Elliott Hughes0266ae52014-02-10 17:46:57 -0800423 seg_page_end - seg_page_start,
424 PFLAGS_TO_PROT(phdr->p_flags) | extra_prot_flags);
425 if (ret < 0) {
426 return -1;
427 }
428 }
429 return 0;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200430}
431
432/* Restore the original protection modes for all loadable segments.
433 * You should only call this after phdr_table_unprotect_segments and
434 * applying all relocations.
435 *
436 * Input:
437 * phdr_table -> program header table
Elliott Hughes105bc262012-08-15 16:56:00 -0700438 * phdr_count -> number of entries in tables
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200439 * load_bias -> load bias
440 * Return:
441 * 0 on error, -1 on failure (error code in errno).
442 */
Elliott Hughes0266ae52014-02-10 17:46:57 -0800443int phdr_table_protect_segments(const ElfW(Phdr)* phdr_table, size_t phdr_count, ElfW(Addr) load_bias) {
444 return _phdr_table_set_load_prot(phdr_table, phdr_count, load_bias, 0);
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200445}
446
447/* Change the protection of all loaded segments in memory to writable.
448 * This is useful before performing relocations. Once completed, you
449 * will have to call phdr_table_protect_segments to restore the original
450 * protection flags on all segments.
451 *
452 * Note that some writable segments can also have their content turned
453 * to read-only by calling phdr_table_protect_gnu_relro. This is no
454 * performed here.
455 *
456 * Input:
457 * phdr_table -> program header table
Elliott Hughes105bc262012-08-15 16:56:00 -0700458 * phdr_count -> number of entries in tables
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200459 * load_bias -> load bias
460 * Return:
461 * 0 on error, -1 on failure (error code in errno).
462 */
Elliott Hughes0266ae52014-02-10 17:46:57 -0800463int phdr_table_unprotect_segments(const ElfW(Phdr)* phdr_table, size_t phdr_count, ElfW(Addr) load_bias) {
464 return _phdr_table_set_load_prot(phdr_table, phdr_count, load_bias, PROT_WRITE);
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200465}
466
467/* Used internally by phdr_table_protect_gnu_relro and
468 * phdr_table_unprotect_gnu_relro.
469 */
Elliott Hughes0266ae52014-02-10 17:46:57 -0800470static int _phdr_table_set_gnu_relro_prot(const ElfW(Phdr)* phdr_table, size_t phdr_count,
471 ElfW(Addr) load_bias, int prot_flags) {
472 const ElfW(Phdr)* phdr = phdr_table;
473 const ElfW(Phdr)* phdr_limit = phdr + phdr_count;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200474
Elliott Hughes0266ae52014-02-10 17:46:57 -0800475 for (phdr = phdr_table; phdr < phdr_limit; phdr++) {
476 if (phdr->p_type != PT_GNU_RELRO) {
477 continue;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200478 }
Elliott Hughes0266ae52014-02-10 17:46:57 -0800479
480 // Tricky: what happens when the relro segment does not start
481 // or end at page boundaries? We're going to be over-protective
482 // here and put every page touched by the segment as read-only.
483
484 // This seems to match Ian Lance Taylor's description of the
485 // feature at http://www.airs.com/blog/archives/189.
486
487 // Extract:
488 // Note that the current dynamic linker code will only work
489 // correctly if the PT_GNU_RELRO segment starts on a page
490 // boundary. This is because the dynamic linker rounds the
491 // p_vaddr field down to the previous page boundary. If
492 // there is anything on the page which should not be read-only,
493 // the program is likely to fail at runtime. So in effect the
494 // linker must only emit a PT_GNU_RELRO segment if it ensures
495 // that it starts on a page boundary.
496 ElfW(Addr) seg_page_start = PAGE_START(phdr->p_vaddr) + load_bias;
497 ElfW(Addr) seg_page_end = PAGE_END(phdr->p_vaddr + phdr->p_memsz) + load_bias;
498
Elliott Hughesfaf05ba2014-02-11 16:59:37 -0800499 int ret = mprotect(reinterpret_cast<void*>(seg_page_start),
Elliott Hughes0266ae52014-02-10 17:46:57 -0800500 seg_page_end - seg_page_start,
501 prot_flags);
502 if (ret < 0) {
503 return -1;
504 }
505 }
506 return 0;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200507}
508
509/* Apply GNU relro protection if specified by the program header. This will
510 * turn some of the pages of a writable PT_LOAD segment to read-only, as
511 * specified by one or more PT_GNU_RELRO segments. This must be always
512 * performed after relocations.
513 *
Ard Biesheuvel12c78bb2012-08-14 12:30:09 +0200514 * The areas typically covered are .got and .data.rel.ro, these are
515 * read-only from the program's POV, but contain absolute addresses
516 * that need to be relocated before use.
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200517 *
518 * Input:
519 * phdr_table -> program header table
Elliott Hughes105bc262012-08-15 16:56:00 -0700520 * phdr_count -> number of entries in tables
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200521 * load_bias -> load bias
522 * Return:
523 * 0 on error, -1 on failure (error code in errno).
524 */
Elliott Hughes0266ae52014-02-10 17:46:57 -0800525int phdr_table_protect_gnu_relro(const ElfW(Phdr)* phdr_table, size_t phdr_count, ElfW(Addr) load_bias) {
526 return _phdr_table_set_gnu_relro_prot(phdr_table, phdr_count, load_bias, PROT_READ);
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200527}
528
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +0000529/* Serialize the GNU relro segments to the given file descriptor. This can be
530 * performed after relocations to allow another process to later share the
531 * relocated segment, if it was loaded at the same address.
532 *
533 * Input:
534 * phdr_table -> program header table
535 * phdr_count -> number of entries in tables
536 * load_bias -> load bias
537 * fd -> writable file descriptor to use
538 * Return:
539 * 0 on error, -1 on failure (error code in errno).
540 */
541int phdr_table_serialize_gnu_relro(const ElfW(Phdr)* phdr_table, size_t phdr_count, ElfW(Addr) load_bias,
542 int fd) {
543 const ElfW(Phdr)* phdr = phdr_table;
544 const ElfW(Phdr)* phdr_limit = phdr + phdr_count;
545 ssize_t file_offset = 0;
546
547 for (phdr = phdr_table; phdr < phdr_limit; phdr++) {
548 if (phdr->p_type != PT_GNU_RELRO) {
549 continue;
550 }
551
552 ElfW(Addr) seg_page_start = PAGE_START(phdr->p_vaddr) + load_bias;
553 ElfW(Addr) seg_page_end = PAGE_END(phdr->p_vaddr + phdr->p_memsz) + load_bias;
554 ssize_t size = seg_page_end - seg_page_start;
555
556 ssize_t written = TEMP_FAILURE_RETRY(write(fd, reinterpret_cast<void*>(seg_page_start), size));
557 if (written != size) {
558 return -1;
559 }
560 void* map = mmap(reinterpret_cast<void*>(seg_page_start), size, PROT_READ,
561 MAP_PRIVATE|MAP_FIXED, fd, file_offset);
562 if (map == MAP_FAILED) {
563 return -1;
564 }
565 file_offset += size;
566 }
567 return 0;
568}
569
570/* Where possible, replace the GNU relro segments with mappings of the given
571 * file descriptor. This can be performed after relocations to allow a file
572 * previously created by phdr_table_serialize_gnu_relro in another process to
573 * replace the dirty relocated pages, saving memory, if it was loaded at the
574 * same address. We have to compare the data before we map over it, since some
575 * parts of the relro segment may not be identical due to other libraries in
576 * the process being loaded at different addresses.
577 *
578 * Input:
579 * phdr_table -> program header table
580 * phdr_count -> number of entries in tables
581 * load_bias -> load bias
582 * fd -> readable file descriptor to use
583 * Return:
584 * 0 on error, -1 on failure (error code in errno).
585 */
586int phdr_table_map_gnu_relro(const ElfW(Phdr)* phdr_table, size_t phdr_count, ElfW(Addr) load_bias,
587 int fd) {
588 // Map the file at a temporary location so we can compare its contents.
589 struct stat file_stat;
590 if (TEMP_FAILURE_RETRY(fstat(fd, &file_stat)) != 0) {
591 return -1;
592 }
593 off_t file_size = file_stat.st_size;
594 void* temp_mapping = mmap(NULL, file_size, PROT_READ, MAP_PRIVATE, fd, 0);
595 if (temp_mapping == MAP_FAILED) {
596 return -1;
597 }
598 size_t file_offset = 0;
599
600 // Iterate over the relro segments and compare/remap the pages.
601 const ElfW(Phdr)* phdr = phdr_table;
602 const ElfW(Phdr)* phdr_limit = phdr + phdr_count;
603
604 for (phdr = phdr_table; phdr < phdr_limit; phdr++) {
605 if (phdr->p_type != PT_GNU_RELRO) {
606 continue;
607 }
608
609 ElfW(Addr) seg_page_start = PAGE_START(phdr->p_vaddr) + load_bias;
610 ElfW(Addr) seg_page_end = PAGE_END(phdr->p_vaddr + phdr->p_memsz) + load_bias;
611
612 char* file_base = static_cast<char*>(temp_mapping) + file_offset;
613 char* mem_base = reinterpret_cast<char*>(seg_page_start);
614 size_t match_offset = 0;
615 size_t size = seg_page_end - seg_page_start;
616
617 while (match_offset < size) {
618 // Skip over dissimilar pages.
619 while (match_offset < size &&
620 memcmp(mem_base + match_offset, file_base + match_offset, PAGE_SIZE) != 0) {
621 match_offset += PAGE_SIZE;
622 }
623
624 // Count similar pages.
625 size_t mismatch_offset = match_offset;
626 while (mismatch_offset < size &&
627 memcmp(mem_base + mismatch_offset, file_base + mismatch_offset, PAGE_SIZE) == 0) {
628 mismatch_offset += PAGE_SIZE;
629 }
630
631 // Map over similar pages.
632 if (mismatch_offset > match_offset) {
633 void* map = mmap(mem_base + match_offset, mismatch_offset - match_offset,
634 PROT_READ, MAP_PRIVATE|MAP_FIXED, fd, match_offset);
635 if (map == MAP_FAILED) {
636 munmap(temp_mapping, file_size);
637 return -1;
638 }
639 }
640
641 match_offset = mismatch_offset;
642 }
643
644 // Add to the base file offset in case there are multiple relro segments.
645 file_offset += size;
646 }
647 munmap(temp_mapping, file_size);
648 return 0;
649}
650
651
Elliott Hughes4eeb1f12013-10-25 17:38:02 -0700652#if defined(__arm__)
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200653
654# ifndef PT_ARM_EXIDX
655# define PT_ARM_EXIDX 0x70000001 /* .ARM.exidx segment */
656# endif
657
658/* Return the address and size of the .ARM.exidx section in memory,
659 * if present.
660 *
661 * Input:
662 * phdr_table -> program header table
Elliott Hughes105bc262012-08-15 16:56:00 -0700663 * phdr_count -> number of entries in tables
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200664 * load_bias -> load bias
665 * Output:
666 * arm_exidx -> address of table in memory (NULL on failure).
667 * arm_exidx_count -> number of items in table (0 on failure).
668 * Return:
669 * 0 on error, -1 on failure (_no_ error code in errno)
670 */
Elliott Hughes0266ae52014-02-10 17:46:57 -0800671int phdr_table_get_arm_exidx(const ElfW(Phdr)* phdr_table, size_t phdr_count,
672 ElfW(Addr) load_bias,
673 ElfW(Addr)** arm_exidx, unsigned* arm_exidx_count) {
674 const ElfW(Phdr)* phdr = phdr_table;
675 const ElfW(Phdr)* phdr_limit = phdr + phdr_count;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200676
Elliott Hughes0266ae52014-02-10 17:46:57 -0800677 for (phdr = phdr_table; phdr < phdr_limit; phdr++) {
678 if (phdr->p_type != PT_ARM_EXIDX) {
679 continue;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200680 }
Elliott Hughes0266ae52014-02-10 17:46:57 -0800681
682 *arm_exidx = reinterpret_cast<ElfW(Addr)*>(load_bias + phdr->p_vaddr);
683 *arm_exidx_count = (unsigned)(phdr->p_memsz / 8);
684 return 0;
685 }
686 *arm_exidx = NULL;
687 *arm_exidx_count = 0;
688 return -1;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200689}
Elliott Hughes4eeb1f12013-10-25 17:38:02 -0700690#endif
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200691
Ard Biesheuvel12c78bb2012-08-14 12:30:09 +0200692/* Return the address and size of the ELF file's .dynamic section in memory,
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200693 * or NULL if missing.
694 *
695 * Input:
696 * phdr_table -> program header table
Elliott Hughes105bc262012-08-15 16:56:00 -0700697 * phdr_count -> number of entries in tables
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200698 * load_bias -> load bias
Ard Biesheuvel12c78bb2012-08-14 12:30:09 +0200699 * Output:
700 * dynamic -> address of table in memory (NULL on failure).
701 * dynamic_count -> number of items in table (0 on failure).
Chris Dearmancf239052013-01-11 15:32:20 -0800702 * dynamic_flags -> protection flags for section (unset on failure)
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200703 * Return:
Ard Biesheuvel12c78bb2012-08-14 12:30:09 +0200704 * void
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200705 */
Elliott Hughes0266ae52014-02-10 17:46:57 -0800706void phdr_table_get_dynamic_section(const ElfW(Phdr)* phdr_table, size_t phdr_count,
707 ElfW(Addr) load_bias,
708 ElfW(Dyn)** dynamic, size_t* dynamic_count, ElfW(Word)* dynamic_flags) {
709 const ElfW(Phdr)* phdr = phdr_table;
710 const ElfW(Phdr)* phdr_limit = phdr + phdr_count;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200711
Elliott Hughes0266ae52014-02-10 17:46:57 -0800712 for (phdr = phdr_table; phdr < phdr_limit; phdr++) {
713 if (phdr->p_type != PT_DYNAMIC) {
714 continue;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200715 }
Elliott Hughes0266ae52014-02-10 17:46:57 -0800716
717 *dynamic = reinterpret_cast<ElfW(Dyn)*>(load_bias + phdr->p_vaddr);
Ard Biesheuvel12c78bb2012-08-14 12:30:09 +0200718 if (dynamic_count) {
Elliott Hughes0266ae52014-02-10 17:46:57 -0800719 *dynamic_count = (unsigned)(phdr->p_memsz / 8);
Ard Biesheuvel12c78bb2012-08-14 12:30:09 +0200720 }
Elliott Hughes0266ae52014-02-10 17:46:57 -0800721 if (dynamic_flags) {
722 *dynamic_flags = phdr->p_flags;
723 }
724 return;
725 }
726 *dynamic = NULL;
727 if (dynamic_count) {
728 *dynamic_count = 0;
729 }
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200730}
731
Elliott Hughes650be4e2013-03-05 18:47:58 -0800732// Returns the address of the program header table as it appears in the loaded
733// segments in memory. This is in contrast with 'phdr_table_' which
734// is temporary and will be released before the library is relocated.
735bool ElfReader::FindPhdr() {
Elliott Hughes0266ae52014-02-10 17:46:57 -0800736 const ElfW(Phdr)* phdr_limit = phdr_table_ + phdr_num_;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200737
Elliott Hughes650be4e2013-03-05 18:47:58 -0800738 // If there is a PT_PHDR, use it directly.
Elliott Hughes0266ae52014-02-10 17:46:57 -0800739 for (const ElfW(Phdr)* phdr = phdr_table_; phdr < phdr_limit; ++phdr) {
Elliott Hughes650be4e2013-03-05 18:47:58 -0800740 if (phdr->p_type == PT_PHDR) {
741 return CheckPhdr(load_bias_ + phdr->p_vaddr);
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200742 }
Elliott Hughes650be4e2013-03-05 18:47:58 -0800743 }
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200744
Elliott Hughes650be4e2013-03-05 18:47:58 -0800745 // Otherwise, check the first loadable segment. If its file offset
746 // is 0, it starts with the ELF header, and we can trivially find the
747 // loaded program header from it.
Elliott Hughes0266ae52014-02-10 17:46:57 -0800748 for (const ElfW(Phdr)* phdr = phdr_table_; phdr < phdr_limit; ++phdr) {
Elliott Hughes650be4e2013-03-05 18:47:58 -0800749 if (phdr->p_type == PT_LOAD) {
750 if (phdr->p_offset == 0) {
Elliott Hughes0266ae52014-02-10 17:46:57 -0800751 ElfW(Addr) elf_addr = load_bias_ + phdr->p_vaddr;
Elliott Hughesfaf05ba2014-02-11 16:59:37 -0800752 const ElfW(Ehdr)* ehdr = reinterpret_cast<const ElfW(Ehdr)*>(elf_addr);
Elliott Hughes0266ae52014-02-10 17:46:57 -0800753 ElfW(Addr) offset = ehdr->e_phoff;
754 return CheckPhdr((ElfW(Addr))ehdr + offset);
Elliott Hughes650be4e2013-03-05 18:47:58 -0800755 }
756 break;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200757 }
Elliott Hughes650be4e2013-03-05 18:47:58 -0800758 }
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200759
Elliott Hughes650be4e2013-03-05 18:47:58 -0800760 DL_ERR("can't find loaded phdr for \"%s\"", name_);
761 return false;
762}
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200763
Elliott Hughes650be4e2013-03-05 18:47:58 -0800764// Ensures that our program header is actually within a loadable
765// segment. This should help catch badly-formed ELF files that
766// would cause the linker to crash later when trying to access it.
Elliott Hughes0266ae52014-02-10 17:46:57 -0800767bool ElfReader::CheckPhdr(ElfW(Addr) loaded) {
768 const ElfW(Phdr)* phdr_limit = phdr_table_ + phdr_num_;
769 ElfW(Addr) loaded_end = loaded + (phdr_num_ * sizeof(ElfW(Phdr)));
770 for (ElfW(Phdr)* phdr = phdr_table_; phdr < phdr_limit; ++phdr) {
Elliott Hughes650be4e2013-03-05 18:47:58 -0800771 if (phdr->p_type != PT_LOAD) {
772 continue;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200773 }
Elliott Hughes0266ae52014-02-10 17:46:57 -0800774 ElfW(Addr) seg_start = phdr->p_vaddr + load_bias_;
775 ElfW(Addr) seg_end = phdr->p_filesz + seg_start;
Elliott Hughes650be4e2013-03-05 18:47:58 -0800776 if (seg_start <= loaded && loaded_end <= seg_end) {
Elliott Hughes0266ae52014-02-10 17:46:57 -0800777 loaded_phdr_ = reinterpret_cast<const ElfW(Phdr)*>(loaded);
Elliott Hughes650be4e2013-03-05 18:47:58 -0800778 return true;
779 }
780 }
Elliott Hughesc00f2cb2013-10-04 17:01:33 -0700781 DL_ERR("\"%s\" loaded phdr %p not in loadable segment", name_, reinterpret_cast<void*>(loaded));
Elliott Hughes650be4e2013-03-05 18:47:58 -0800782 return false;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200783}