blob: 91a2fb80d5bd256f647d61af19831924ccfc3e8f [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>
Elliott Hughes05fc1d72015-01-28 18:02:33 -080032#include <string.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
Elliott Hughesb5140262014-12-02 16:16:29 -080041static int GetTargetElfMachine() {
42#if defined(__arm__)
43 return EM_ARM;
44#elif defined(__aarch64__)
45 return EM_AARCH64;
46#elif defined(__i386__)
47 return EM_386;
48#elif defined(__mips__)
49 return EM_MIPS;
50#elif defined(__x86_64__)
51 return EM_X86_64;
52#endif
53}
54
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +020055/**
56 TECHNICAL NOTE ON ELF LOADING.
57
58 An ELF file's program header table contains one or more PT_LOAD
59 segments, which corresponds to portions of the file that need to
60 be mapped into the process' address space.
61
62 Each loadable segment has the following important properties:
63
64 p_offset -> segment file offset
65 p_filesz -> segment file size
66 p_memsz -> segment memory size (always >= p_filesz)
67 p_vaddr -> segment's virtual address
68 p_flags -> segment flags (e.g. readable, writable, executable)
69
Elliott Hughes0266ae52014-02-10 17:46:57 -080070 We will ignore the p_paddr and p_align fields of ElfW(Phdr) for now.
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +020071
72 The loadable segments can be seen as a list of [p_vaddr ... p_vaddr+p_memsz)
73 ranges of virtual addresses. A few rules apply:
74
75 - the virtual address ranges should not overlap.
76
77 - if a segment's p_filesz is smaller than its p_memsz, the extra bytes
78 between them should always be initialized to 0.
79
80 - ranges do not necessarily start or end at page boundaries. Two distinct
81 segments can have their start and end on the same page. In this case, the
82 page inherits the mapping flags of the latter segment.
83
84 Finally, the real load addrs of each segment is not p_vaddr. Instead the
85 loader decides where to load the first segment, then will load all others
86 relative to the first one to respect the initial range layout.
87
88 For example, consider the following list:
89
90 [ offset:0, filesz:0x4000, memsz:0x4000, vaddr:0x30000 ],
91 [ offset:0x4000, filesz:0x2000, memsz:0x8000, vaddr:0x40000 ],
92
93 This corresponds to two segments that cover these virtual address ranges:
94
95 0x30000...0x34000
96 0x40000...0x48000
97
98 If the loader decides to load the first segment at address 0xa0000000
99 then the segments' load address ranges will be:
100
101 0xa0030000...0xa0034000
102 0xa0040000...0xa0048000
103
104 In other words, all segments must be loaded at an address that has the same
105 constant offset from their p_vaddr value. This offset is computed as the
106 difference between the first segment's load address, and its p_vaddr value.
107
108 However, in practice, segments do _not_ start at page boundaries. Since we
109 can only memory-map at page boundaries, this means that the bias is
110 computed as:
111
112 load_bias = phdr0_load_address - PAGE_START(phdr0->p_vaddr)
113
114 (NOTE: The value must be used as a 32-bit unsigned integer, to deal with
115 possible wrap around UINT32_MAX for possible large p_vaddr values).
116
117 And that the phdr0_load_address must start at a page boundary, with
118 the segment's real content starting at:
119
120 phdr0_load_address + PAGE_OFFSET(phdr0->p_vaddr)
121
122 Note that ELF requires the following condition to make the mmap()-ing work:
123
124 PAGE_OFFSET(phdr0->p_vaddr) == PAGE_OFFSET(phdr0->p_offset)
125
126 The load_bias must be added to any p_vaddr value read from the ELF file to
127 determine the corresponding memory address.
128
129 **/
130
Elliott Hughesfaf05ba2014-02-11 16:59:37 -0800131#define MAYBE_MAP_FLAG(x, from, to) (((x) & (from)) ? (to) : 0)
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200132#define PFLAGS_TO_PROT(x) (MAYBE_MAP_FLAG((x), PF_X, PROT_EXEC) | \
133 MAYBE_MAP_FLAG((x), PF_R, PROT_READ) | \
134 MAYBE_MAP_FLAG((x), PF_W, PROT_WRITE))
135
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -0700136ElfReader::ElfReader(const char* name, int fd, off64_t file_offset)
137 : name_(name), fd_(fd), file_offset_(file_offset),
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700138 phdr_num_(0), phdr_mmap_(nullptr), phdr_table_(nullptr), phdr_size_(0),
139 load_start_(nullptr), load_size_(0), load_bias_(0),
140 loaded_phdr_(nullptr) {
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200141}
142
Elliott Hughes650be4e2013-03-05 18:47:58 -0800143ElfReader::~ElfReader() {
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700144 if (phdr_mmap_ != nullptr) {
Elliott Hughes650be4e2013-03-05 18:47:58 -0800145 munmap(phdr_mmap_, phdr_size_);
146 }
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200147}
148
Torne (Richard Coles)12bbb912014-02-06 14:34:21 +0000149bool ElfReader::Load(const android_dlextinfo* extinfo) {
Elliott Hughes650be4e2013-03-05 18:47:58 -0800150 return ReadElfHeader() &&
151 VerifyElfHeader() &&
152 ReadProgramHeader() &&
Torne (Richard Coles)12bbb912014-02-06 14:34:21 +0000153 ReserveAddressSpace(extinfo) &&
Elliott Hughes650be4e2013-03-05 18:47:58 -0800154 LoadSegments() &&
155 FindPhdr();
156}
157
158bool ElfReader::ReadElfHeader() {
Dmitriy Ivanova6c12792014-10-21 12:09:18 -0700159 ssize_t rc = TEMP_FAILURE_RETRY(pread64(fd_, &header_, sizeof(header_), file_offset_));
Elliott Hughes650be4e2013-03-05 18:47:58 -0800160 if (rc < 0) {
161 DL_ERR("can't read file \"%s\": %s", name_, strerror(errno));
162 return false;
163 }
Dmitriy Ivanova6c12792014-10-21 12:09:18 -0700164
Elliott Hughes650be4e2013-03-05 18:47:58 -0800165 if (rc != sizeof(header_)) {
Elliott Hughesc6200592013-09-30 18:43:46 -0700166 DL_ERR("\"%s\" is too small to be an ELF executable: only found %zd bytes", name_,
167 static_cast<size_t>(rc));
Elliott Hughes650be4e2013-03-05 18:47:58 -0800168 return false;
169 }
170 return true;
171}
172
173bool ElfReader::VerifyElfHeader() {
Elliott Hughes625993d2014-07-15 16:53:13 -0700174 if (memcmp(header_.e_ident, ELFMAG, SELFMAG) != 0) {
Elliott Hughes650be4e2013-03-05 18:47:58 -0800175 DL_ERR("\"%s\" has bad ELF magic", name_);
176 return false;
177 }
178
Elliott Hughesc00f2cb2013-10-04 17:01:33 -0700179 // Try to give a clear diagnostic for ELF class mismatches, since they're
180 // an easy mistake to make during the 32-bit/64-bit transition period.
181 int elf_class = header_.e_ident[EI_CLASS];
182#if defined(__LP64__)
183 if (elf_class != ELFCLASS64) {
184 if (elf_class == ELFCLASS32) {
185 DL_ERR("\"%s\" is 32-bit instead of 64-bit", name_);
186 } else {
187 DL_ERR("\"%s\" has unknown ELF class: %d", name_, elf_class);
188 }
Elliott Hughes650be4e2013-03-05 18:47:58 -0800189 return false;
190 }
Elliott Hughesc00f2cb2013-10-04 17:01:33 -0700191#else
192 if (elf_class != ELFCLASS32) {
193 if (elf_class == ELFCLASS64) {
194 DL_ERR("\"%s\" is 64-bit instead of 32-bit", name_);
195 } else {
196 DL_ERR("\"%s\" has unknown ELF class: %d", name_, elf_class);
197 }
198 return false;
199 }
200#endif
201
Elliott Hughes650be4e2013-03-05 18:47:58 -0800202 if (header_.e_ident[EI_DATA] != ELFDATA2LSB) {
203 DL_ERR("\"%s\" not little-endian: %d", name_, header_.e_ident[EI_DATA]);
204 return false;
205 }
206
207 if (header_.e_type != ET_DYN) {
208 DL_ERR("\"%s\" has unexpected e_type: %d", name_, header_.e_type);
209 return false;
210 }
211
212 if (header_.e_version != EV_CURRENT) {
213 DL_ERR("\"%s\" has unexpected e_version: %d", name_, header_.e_version);
214 return false;
215 }
216
Elliott Hughesb5140262014-12-02 16:16:29 -0800217 if (header_.e_machine != GetTargetElfMachine()) {
Elliott Hughes650be4e2013-03-05 18:47:58 -0800218 DL_ERR("\"%s\" has unexpected e_machine: %d", name_, header_.e_machine);
219 return false;
220 }
221
222 return true;
223}
224
225// Loads the program header table from an ELF file into a read-only private
226// anonymous mmap-ed block.
227bool ElfReader::ReadProgramHeader() {
228 phdr_num_ = header_.e_phnum;
229
230 // Like the kernel, we only accept program header tables that
231 // are smaller than 64KiB.
Elliott Hughes0266ae52014-02-10 17:46:57 -0800232 if (phdr_num_ < 1 || phdr_num_ > 65536/sizeof(ElfW(Phdr))) {
Elliott Hughesc6200592013-09-30 18:43:46 -0700233 DL_ERR("\"%s\" has invalid e_phnum: %zd", name_, phdr_num_);
Elliott Hughes650be4e2013-03-05 18:47:58 -0800234 return false;
235 }
236
Elliott Hughes0266ae52014-02-10 17:46:57 -0800237 ElfW(Addr) page_min = PAGE_START(header_.e_phoff);
238 ElfW(Addr) page_max = PAGE_END(header_.e_phoff + (phdr_num_ * sizeof(ElfW(Phdr))));
239 ElfW(Addr) page_offset = PAGE_OFFSET(header_.e_phoff);
Elliott Hughes650be4e2013-03-05 18:47:58 -0800240
241 phdr_size_ = page_max - page_min;
242
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -0700243 void* mmap_result = mmap64(nullptr, phdr_size_, PROT_READ, MAP_PRIVATE, fd_, file_offset_ + page_min);
Elliott Hughes650be4e2013-03-05 18:47:58 -0800244 if (mmap_result == MAP_FAILED) {
245 DL_ERR("\"%s\" phdr mmap failed: %s", name_, strerror(errno));
246 return false;
247 }
248
249 phdr_mmap_ = mmap_result;
Elliott Hughes0266ae52014-02-10 17:46:57 -0800250 phdr_table_ = reinterpret_cast<ElfW(Phdr)*>(reinterpret_cast<char*>(mmap_result) + page_offset);
Elliott Hughes650be4e2013-03-05 18:47:58 -0800251 return true;
252}
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200253
Brian Carlstrome7dffe12013-01-10 16:39:58 -0800254/* Returns the size of the extent of all the possibly non-contiguous
255 * loadable segments in an ELF program header table. This corresponds
256 * to the page-aligned size in bytes that needs to be reserved in the
257 * process' address space. If there are no loadable segments, 0 is
258 * returned.
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200259 *
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700260 * If out_min_vaddr or out_max_vaddr are not null, they will be
Brian Carlstrome7dffe12013-01-10 16:39:58 -0800261 * set to the minimum and maximum addresses of pages to be reserved,
262 * or 0 if there is nothing to load.
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200263 */
Elliott Hughes0266ae52014-02-10 17:46:57 -0800264size_t phdr_table_get_load_size(const ElfW(Phdr)* phdr_table, size_t phdr_count,
265 ElfW(Addr)* out_min_vaddr,
266 ElfW(Addr)* out_max_vaddr) {
267 ElfW(Addr) min_vaddr = UINTPTR_MAX;
268 ElfW(Addr) max_vaddr = 0;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200269
Elliott Hughes0266ae52014-02-10 17:46:57 -0800270 bool found_pt_load = false;
271 for (size_t i = 0; i < phdr_count; ++i) {
272 const ElfW(Phdr)* phdr = &phdr_table[i];
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200273
Elliott Hughes0266ae52014-02-10 17:46:57 -0800274 if (phdr->p_type != PT_LOAD) {
275 continue;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200276 }
Elliott Hughes0266ae52014-02-10 17:46:57 -0800277 found_pt_load = true;
278
279 if (phdr->p_vaddr < min_vaddr) {
280 min_vaddr = phdr->p_vaddr;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200281 }
282
Elliott Hughes0266ae52014-02-10 17:46:57 -0800283 if (phdr->p_vaddr + phdr->p_memsz > max_vaddr) {
284 max_vaddr = phdr->p_vaddr + phdr->p_memsz;
285 }
286 }
287 if (!found_pt_load) {
288 min_vaddr = 0;
289 }
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200290
Elliott Hughes0266ae52014-02-10 17:46:57 -0800291 min_vaddr = PAGE_START(min_vaddr);
292 max_vaddr = PAGE_END(max_vaddr);
293
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700294 if (out_min_vaddr != nullptr) {
Elliott Hughes0266ae52014-02-10 17:46:57 -0800295 *out_min_vaddr = min_vaddr;
296 }
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700297 if (out_max_vaddr != nullptr) {
Elliott Hughes0266ae52014-02-10 17:46:57 -0800298 *out_max_vaddr = max_vaddr;
299 }
300 return max_vaddr - min_vaddr;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200301}
302
Elliott Hughes650be4e2013-03-05 18:47:58 -0800303// Reserve a virtual address range big enough to hold all loadable
304// segments of a program header table. This is done by creating a
305// private anonymous mmap() with PROT_NONE.
Torne (Richard Coles)12bbb912014-02-06 14:34:21 +0000306bool ElfReader::ReserveAddressSpace(const android_dlextinfo* extinfo) {
Elliott Hughes0266ae52014-02-10 17:46:57 -0800307 ElfW(Addr) min_vaddr;
Brian Carlstrome7dffe12013-01-10 16:39:58 -0800308 load_size_ = phdr_table_get_load_size(phdr_table_, phdr_num_, &min_vaddr);
Elliott Hughes650be4e2013-03-05 18:47:58 -0800309 if (load_size_ == 0) {
310 DL_ERR("\"%s\" has no loadable segments", name_);
311 return false;
312 }
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200313
Brian Carlstrome7dffe12013-01-10 16:39:58 -0800314 uint8_t* addr = reinterpret_cast<uint8_t*>(min_vaddr);
Torne (Richard Coles)12bbb912014-02-06 14:34:21 +0000315 void* start;
316 size_t reserved_size = 0;
317 bool reserved_hint = true;
318
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700319 if (extinfo != nullptr) {
Torne (Richard Coles)12bbb912014-02-06 14:34:21 +0000320 if (extinfo->flags & ANDROID_DLEXT_RESERVED_ADDRESS) {
321 reserved_size = extinfo->reserved_size;
322 reserved_hint = false;
323 } else if (extinfo->flags & ANDROID_DLEXT_RESERVED_ADDRESS_HINT) {
324 reserved_size = extinfo->reserved_size;
325 }
326 }
327
328 if (load_size_ > reserved_size) {
329 if (!reserved_hint) {
330 DL_ERR("reserved address space %zd smaller than %zd bytes needed for \"%s\"",
331 reserved_size - load_size_, load_size_, name_);
332 return false;
333 }
334 int mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS;
335 start = mmap(addr, load_size_, PROT_NONE, mmap_flags, -1, 0);
336 if (start == MAP_FAILED) {
337 DL_ERR("couldn't reserve %zd bytes of address space for \"%s\"", load_size_, name_);
338 return false;
339 }
340 } else {
341 start = extinfo->reserved_addr;
Elliott Hughes650be4e2013-03-05 18:47:58 -0800342 }
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200343
Elliott Hughes650be4e2013-03-05 18:47:58 -0800344 load_start_ = start;
Brian Carlstrome7dffe12013-01-10 16:39:58 -0800345 load_bias_ = reinterpret_cast<uint8_t*>(start) - addr;
Elliott Hughes650be4e2013-03-05 18:47:58 -0800346 return true;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200347}
348
Elliott Hughes650be4e2013-03-05 18:47:58 -0800349bool ElfReader::LoadSegments() {
350 for (size_t i = 0; i < phdr_num_; ++i) {
Elliott Hughes0266ae52014-02-10 17:46:57 -0800351 const ElfW(Phdr)* phdr = &phdr_table_[i];
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200352
Elliott Hughes650be4e2013-03-05 18:47:58 -0800353 if (phdr->p_type != PT_LOAD) {
354 continue;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200355 }
Elliott Hughes650be4e2013-03-05 18:47:58 -0800356
357 // Segment addresses in memory.
Elliott Hughes0266ae52014-02-10 17:46:57 -0800358 ElfW(Addr) seg_start = phdr->p_vaddr + load_bias_;
359 ElfW(Addr) seg_end = seg_start + phdr->p_memsz;
Elliott Hughes650be4e2013-03-05 18:47:58 -0800360
Elliott Hughes0266ae52014-02-10 17:46:57 -0800361 ElfW(Addr) seg_page_start = PAGE_START(seg_start);
362 ElfW(Addr) seg_page_end = PAGE_END(seg_end);
Elliott Hughes650be4e2013-03-05 18:47:58 -0800363
Elliott Hughes0266ae52014-02-10 17:46:57 -0800364 ElfW(Addr) seg_file_end = seg_start + phdr->p_filesz;
Elliott Hughes650be4e2013-03-05 18:47:58 -0800365
366 // File offsets.
Elliott Hughes0266ae52014-02-10 17:46:57 -0800367 ElfW(Addr) file_start = phdr->p_offset;
368 ElfW(Addr) file_end = file_start + phdr->p_filesz;
Elliott Hughes650be4e2013-03-05 18:47:58 -0800369
Elliott Hughes0266ae52014-02-10 17:46:57 -0800370 ElfW(Addr) file_page_start = PAGE_START(file_start);
371 ElfW(Addr) file_length = file_end - file_page_start;
Elliott Hughes650be4e2013-03-05 18:47:58 -0800372
Brian Carlstrom82dcc792013-05-21 16:49:24 -0700373 if (file_length != 0) {
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -0700374 void* seg_addr = mmap64(reinterpret_cast<void*>(seg_page_start),
Brian Carlstrom82dcc792013-05-21 16:49:24 -0700375 file_length,
376 PFLAGS_TO_PROT(phdr->p_flags),
377 MAP_FIXED|MAP_PRIVATE,
378 fd_,
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -0700379 file_offset_ + file_page_start);
Brian Carlstrom82dcc792013-05-21 16:49:24 -0700380 if (seg_addr == MAP_FAILED) {
Elliott Hughesc6200592013-09-30 18:43:46 -0700381 DL_ERR("couldn't map \"%s\" segment %zd: %s", name_, i, strerror(errno));
Brian Carlstrom82dcc792013-05-21 16:49:24 -0700382 return false;
383 }
Elliott Hughes650be4e2013-03-05 18:47:58 -0800384 }
385
386 // if the segment is writable, and does not end on a page boundary,
387 // zero-fill it until the page limit.
388 if ((phdr->p_flags & PF_W) != 0 && PAGE_OFFSET(seg_file_end) > 0) {
Elliott Hughesfaf05ba2014-02-11 16:59:37 -0800389 memset(reinterpret_cast<void*>(seg_file_end), 0, PAGE_SIZE - PAGE_OFFSET(seg_file_end));
Elliott Hughes650be4e2013-03-05 18:47:58 -0800390 }
391
392 seg_file_end = PAGE_END(seg_file_end);
393
394 // seg_file_end is now the first page address after the file
395 // content. If seg_end is larger, we need to zero anything
396 // between them. This is done by using a private anonymous
397 // map for all extra pages.
398 if (seg_page_end > seg_file_end) {
Elliott Hughesfaf05ba2014-02-11 16:59:37 -0800399 void* zeromap = mmap(reinterpret_cast<void*>(seg_file_end),
Elliott Hughes650be4e2013-03-05 18:47:58 -0800400 seg_page_end - seg_file_end,
401 PFLAGS_TO_PROT(phdr->p_flags),
402 MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE,
403 -1,
404 0);
405 if (zeromap == MAP_FAILED) {
406 DL_ERR("couldn't zero fill \"%s\" gap: %s", name_, strerror(errno));
407 return false;
408 }
409 }
410 }
411 return true;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200412}
413
Elliott Hughes105bc262012-08-15 16:56:00 -0700414/* Used internally. Used to set the protection bits of all loaded segments
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200415 * with optional extra flags (i.e. really PROT_WRITE). Used by
416 * phdr_table_protect_segments and phdr_table_unprotect_segments.
417 */
Elliott Hughes0266ae52014-02-10 17:46:57 -0800418static int _phdr_table_set_load_prot(const ElfW(Phdr)* phdr_table, size_t phdr_count,
419 ElfW(Addr) load_bias, int extra_prot_flags) {
420 const ElfW(Phdr)* phdr = phdr_table;
421 const ElfW(Phdr)* phdr_limit = phdr + phdr_count;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200422
Elliott Hughes0266ae52014-02-10 17:46:57 -0800423 for (; phdr < phdr_limit; phdr++) {
424 if (phdr->p_type != PT_LOAD || (phdr->p_flags & PF_W) != 0) {
425 continue;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200426 }
Elliott Hughes0266ae52014-02-10 17:46:57 -0800427
428 ElfW(Addr) seg_page_start = PAGE_START(phdr->p_vaddr) + load_bias;
429 ElfW(Addr) seg_page_end = PAGE_END(phdr->p_vaddr + phdr->p_memsz) + load_bias;
430
Elliott Hughesfaf05ba2014-02-11 16:59:37 -0800431 int ret = mprotect(reinterpret_cast<void*>(seg_page_start),
Elliott Hughes0266ae52014-02-10 17:46:57 -0800432 seg_page_end - seg_page_start,
433 PFLAGS_TO_PROT(phdr->p_flags) | extra_prot_flags);
434 if (ret < 0) {
435 return -1;
436 }
437 }
438 return 0;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200439}
440
441/* Restore the original protection modes for all loadable segments.
442 * You should only call this after phdr_table_unprotect_segments and
443 * applying all relocations.
444 *
445 * Input:
446 * phdr_table -> program header table
Elliott Hughes105bc262012-08-15 16:56:00 -0700447 * phdr_count -> number of entries in tables
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200448 * load_bias -> load bias
449 * Return:
450 * 0 on error, -1 on failure (error code in errno).
451 */
Elliott Hughes0266ae52014-02-10 17:46:57 -0800452int phdr_table_protect_segments(const ElfW(Phdr)* phdr_table, size_t phdr_count, ElfW(Addr) load_bias) {
453 return _phdr_table_set_load_prot(phdr_table, phdr_count, load_bias, 0);
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200454}
455
456/* Change the protection of all loaded segments in memory to writable.
457 * This is useful before performing relocations. Once completed, you
458 * will have to call phdr_table_protect_segments to restore the original
459 * protection flags on all segments.
460 *
461 * Note that some writable segments can also have their content turned
462 * to read-only by calling phdr_table_protect_gnu_relro. This is no
463 * performed here.
464 *
465 * Input:
466 * phdr_table -> program header table
Elliott Hughes105bc262012-08-15 16:56:00 -0700467 * phdr_count -> number of entries in tables
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200468 * load_bias -> load bias
469 * Return:
470 * 0 on error, -1 on failure (error code in errno).
471 */
Elliott Hughes0266ae52014-02-10 17:46:57 -0800472int phdr_table_unprotect_segments(const ElfW(Phdr)* phdr_table, size_t phdr_count, ElfW(Addr) load_bias) {
473 return _phdr_table_set_load_prot(phdr_table, phdr_count, load_bias, PROT_WRITE);
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200474}
475
476/* Used internally by phdr_table_protect_gnu_relro and
477 * phdr_table_unprotect_gnu_relro.
478 */
Elliott Hughes0266ae52014-02-10 17:46:57 -0800479static int _phdr_table_set_gnu_relro_prot(const ElfW(Phdr)* phdr_table, size_t phdr_count,
480 ElfW(Addr) load_bias, int prot_flags) {
481 const ElfW(Phdr)* phdr = phdr_table;
482 const ElfW(Phdr)* phdr_limit = phdr + phdr_count;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200483
Elliott Hughes0266ae52014-02-10 17:46:57 -0800484 for (phdr = phdr_table; phdr < phdr_limit; phdr++) {
485 if (phdr->p_type != PT_GNU_RELRO) {
486 continue;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200487 }
Elliott Hughes0266ae52014-02-10 17:46:57 -0800488
489 // Tricky: what happens when the relro segment does not start
490 // or end at page boundaries? We're going to be over-protective
491 // here and put every page touched by the segment as read-only.
492
493 // This seems to match Ian Lance Taylor's description of the
494 // feature at http://www.airs.com/blog/archives/189.
495
496 // Extract:
497 // Note that the current dynamic linker code will only work
498 // correctly if the PT_GNU_RELRO segment starts on a page
499 // boundary. This is because the dynamic linker rounds the
500 // p_vaddr field down to the previous page boundary. If
501 // there is anything on the page which should not be read-only,
502 // the program is likely to fail at runtime. So in effect the
503 // linker must only emit a PT_GNU_RELRO segment if it ensures
504 // that it starts on a page boundary.
505 ElfW(Addr) seg_page_start = PAGE_START(phdr->p_vaddr) + load_bias;
506 ElfW(Addr) seg_page_end = PAGE_END(phdr->p_vaddr + phdr->p_memsz) + load_bias;
507
Elliott Hughesfaf05ba2014-02-11 16:59:37 -0800508 int ret = mprotect(reinterpret_cast<void*>(seg_page_start),
Elliott Hughes0266ae52014-02-10 17:46:57 -0800509 seg_page_end - seg_page_start,
510 prot_flags);
511 if (ret < 0) {
512 return -1;
513 }
514 }
515 return 0;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200516}
517
518/* Apply GNU relro protection if specified by the program header. This will
519 * turn some of the pages of a writable PT_LOAD segment to read-only, as
520 * specified by one or more PT_GNU_RELRO segments. This must be always
521 * performed after relocations.
522 *
Ard Biesheuvel12c78bb2012-08-14 12:30:09 +0200523 * The areas typically covered are .got and .data.rel.ro, these are
524 * read-only from the program's POV, but contain absolute addresses
525 * that need to be relocated before use.
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200526 *
527 * Input:
528 * phdr_table -> program header table
Elliott Hughes105bc262012-08-15 16:56:00 -0700529 * phdr_count -> number of entries in tables
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200530 * load_bias -> load bias
531 * Return:
532 * 0 on error, -1 on failure (error code in errno).
533 */
Elliott Hughes0266ae52014-02-10 17:46:57 -0800534int phdr_table_protect_gnu_relro(const ElfW(Phdr)* phdr_table, size_t phdr_count, ElfW(Addr) load_bias) {
535 return _phdr_table_set_gnu_relro_prot(phdr_table, phdr_count, load_bias, PROT_READ);
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200536}
537
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +0000538/* Serialize the GNU relro segments to the given file descriptor. This can be
539 * performed after relocations to allow another process to later share the
540 * relocated segment, if it was loaded at the same address.
541 *
542 * Input:
543 * phdr_table -> program header table
544 * phdr_count -> number of entries in tables
545 * load_bias -> load bias
546 * fd -> writable file descriptor to use
547 * Return:
548 * 0 on error, -1 on failure (error code in errno).
549 */
550int phdr_table_serialize_gnu_relro(const ElfW(Phdr)* phdr_table, size_t phdr_count, ElfW(Addr) load_bias,
551 int fd) {
552 const ElfW(Phdr)* phdr = phdr_table;
553 const ElfW(Phdr)* phdr_limit = phdr + phdr_count;
554 ssize_t file_offset = 0;
555
556 for (phdr = phdr_table; phdr < phdr_limit; phdr++) {
557 if (phdr->p_type != PT_GNU_RELRO) {
558 continue;
559 }
560
561 ElfW(Addr) seg_page_start = PAGE_START(phdr->p_vaddr) + load_bias;
562 ElfW(Addr) seg_page_end = PAGE_END(phdr->p_vaddr + phdr->p_memsz) + load_bias;
563 ssize_t size = seg_page_end - seg_page_start;
564
565 ssize_t written = TEMP_FAILURE_RETRY(write(fd, reinterpret_cast<void*>(seg_page_start), size));
566 if (written != size) {
567 return -1;
568 }
569 void* map = mmap(reinterpret_cast<void*>(seg_page_start), size, PROT_READ,
570 MAP_PRIVATE|MAP_FIXED, fd, file_offset);
571 if (map == MAP_FAILED) {
572 return -1;
573 }
574 file_offset += size;
575 }
576 return 0;
577}
578
579/* Where possible, replace the GNU relro segments with mappings of the given
580 * file descriptor. This can be performed after relocations to allow a file
581 * previously created by phdr_table_serialize_gnu_relro in another process to
582 * replace the dirty relocated pages, saving memory, if it was loaded at the
583 * same address. We have to compare the data before we map over it, since some
584 * parts of the relro segment may not be identical due to other libraries in
585 * the process being loaded at different addresses.
586 *
587 * Input:
588 * phdr_table -> program header table
589 * phdr_count -> number of entries in tables
590 * load_bias -> load bias
591 * fd -> readable file descriptor to use
592 * Return:
593 * 0 on error, -1 on failure (error code in errno).
594 */
595int phdr_table_map_gnu_relro(const ElfW(Phdr)* phdr_table, size_t phdr_count, ElfW(Addr) load_bias,
596 int fd) {
597 // Map the file at a temporary location so we can compare its contents.
598 struct stat file_stat;
599 if (TEMP_FAILURE_RETRY(fstat(fd, &file_stat)) != 0) {
600 return -1;
601 }
602 off_t file_size = file_stat.st_size;
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700603 void* temp_mapping = nullptr;
Torne (Richard Coles)26ec9672014-04-30 15:48:40 +0100604 if (file_size > 0) {
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700605 temp_mapping = mmap(nullptr, file_size, PROT_READ, MAP_PRIVATE, fd, 0);
Torne (Richard Coles)26ec9672014-04-30 15:48:40 +0100606 if (temp_mapping == MAP_FAILED) {
607 return -1;
608 }
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +0000609 }
610 size_t file_offset = 0;
611
612 // Iterate over the relro segments and compare/remap the pages.
613 const ElfW(Phdr)* phdr = phdr_table;
614 const ElfW(Phdr)* phdr_limit = phdr + phdr_count;
615
616 for (phdr = phdr_table; phdr < phdr_limit; phdr++) {
617 if (phdr->p_type != PT_GNU_RELRO) {
618 continue;
619 }
620
621 ElfW(Addr) seg_page_start = PAGE_START(phdr->p_vaddr) + load_bias;
622 ElfW(Addr) seg_page_end = PAGE_END(phdr->p_vaddr + phdr->p_memsz) + load_bias;
623
624 char* file_base = static_cast<char*>(temp_mapping) + file_offset;
625 char* mem_base = reinterpret_cast<char*>(seg_page_start);
626 size_t match_offset = 0;
627 size_t size = seg_page_end - seg_page_start;
628
Torne (Richard Coles)26ec9672014-04-30 15:48:40 +0100629 if (file_size - file_offset < size) {
630 // File is too short to compare to this segment. The contents are likely
631 // different as well (it's probably for a different library version) so
632 // just don't bother checking.
633 break;
634 }
635
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +0000636 while (match_offset < size) {
637 // Skip over dissimilar pages.
638 while (match_offset < size &&
639 memcmp(mem_base + match_offset, file_base + match_offset, PAGE_SIZE) != 0) {
640 match_offset += PAGE_SIZE;
641 }
642
643 // Count similar pages.
644 size_t mismatch_offset = match_offset;
645 while (mismatch_offset < size &&
646 memcmp(mem_base + mismatch_offset, file_base + mismatch_offset, PAGE_SIZE) == 0) {
647 mismatch_offset += PAGE_SIZE;
648 }
649
650 // Map over similar pages.
651 if (mismatch_offset > match_offset) {
652 void* map = mmap(mem_base + match_offset, mismatch_offset - match_offset,
653 PROT_READ, MAP_PRIVATE|MAP_FIXED, fd, match_offset);
654 if (map == MAP_FAILED) {
655 munmap(temp_mapping, file_size);
656 return -1;
657 }
658 }
659
660 match_offset = mismatch_offset;
661 }
662
663 // Add to the base file offset in case there are multiple relro segments.
664 file_offset += size;
665 }
666 munmap(temp_mapping, file_size);
667 return 0;
668}
669
670
Elliott Hughes4eeb1f12013-10-25 17:38:02 -0700671#if defined(__arm__)
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200672
673# ifndef PT_ARM_EXIDX
674# define PT_ARM_EXIDX 0x70000001 /* .ARM.exidx segment */
675# endif
676
677/* Return the address and size of the .ARM.exidx section in memory,
678 * if present.
679 *
680 * Input:
681 * phdr_table -> program header table
Elliott Hughes105bc262012-08-15 16:56:00 -0700682 * phdr_count -> number of entries in tables
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200683 * load_bias -> load bias
684 * Output:
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700685 * arm_exidx -> address of table in memory (null on failure).
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200686 * arm_exidx_count -> number of items in table (0 on failure).
687 * Return:
688 * 0 on error, -1 on failure (_no_ error code in errno)
689 */
Elliott Hughes0266ae52014-02-10 17:46:57 -0800690int phdr_table_get_arm_exidx(const ElfW(Phdr)* phdr_table, size_t phdr_count,
691 ElfW(Addr) load_bias,
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -0800692 ElfW(Addr)** arm_exidx, size_t* arm_exidx_count) {
Elliott Hughes0266ae52014-02-10 17:46:57 -0800693 const ElfW(Phdr)* phdr = phdr_table;
694 const ElfW(Phdr)* phdr_limit = phdr + phdr_count;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200695
Elliott Hughes0266ae52014-02-10 17:46:57 -0800696 for (phdr = phdr_table; phdr < phdr_limit; phdr++) {
697 if (phdr->p_type != PT_ARM_EXIDX) {
698 continue;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200699 }
Elliott Hughes0266ae52014-02-10 17:46:57 -0800700
701 *arm_exidx = reinterpret_cast<ElfW(Addr)*>(load_bias + phdr->p_vaddr);
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -0800702 *arm_exidx_count = phdr->p_memsz / 8;
Elliott Hughes0266ae52014-02-10 17:46:57 -0800703 return 0;
704 }
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700705 *arm_exidx = nullptr;
Elliott Hughes0266ae52014-02-10 17:46:57 -0800706 *arm_exidx_count = 0;
707 return -1;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200708}
Elliott Hughes4eeb1f12013-10-25 17:38:02 -0700709#endif
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200710
Ard Biesheuvel12c78bb2012-08-14 12:30:09 +0200711/* Return the address and size of the ELF file's .dynamic section in memory,
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700712 * or null if missing.
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200713 *
714 * Input:
715 * phdr_table -> program header table
Elliott Hughes105bc262012-08-15 16:56:00 -0700716 * phdr_count -> number of entries in tables
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200717 * load_bias -> load bias
Ard Biesheuvel12c78bb2012-08-14 12:30:09 +0200718 * Output:
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700719 * dynamic -> address of table in memory (null on failure).
Ningsheng Jiane93be992014-09-16 15:22:10 +0800720 * dynamic_flags -> protection flags for section (unset on failure)
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200721 * Return:
Ard Biesheuvel12c78bb2012-08-14 12:30:09 +0200722 * void
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200723 */
Elliott Hughes0266ae52014-02-10 17:46:57 -0800724void phdr_table_get_dynamic_section(const ElfW(Phdr)* phdr_table, size_t phdr_count,
Ningsheng Jiane93be992014-09-16 15:22:10 +0800725 ElfW(Addr) load_bias, ElfW(Dyn)** dynamic,
726 ElfW(Word)* dynamic_flags) {
Dmitriy Ivanov498eb182014-09-05 14:57:59 -0700727 *dynamic = nullptr;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700728 for (const ElfW(Phdr)* phdr = phdr_table, *phdr_limit = phdr + phdr_count; phdr < phdr_limit; phdr++) {
729 if (phdr->p_type == PT_DYNAMIC) {
730 *dynamic = reinterpret_cast<ElfW(Dyn)*>(load_bias + phdr->p_vaddr);
Ningsheng Jiane93be992014-09-16 15:22:10 +0800731 if (dynamic_flags) {
732 *dynamic_flags = phdr->p_flags;
733 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700734 return;
735 }
Elliott Hughes0266ae52014-02-10 17:46:57 -0800736 }
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200737}
738
Robert Grosse4544d9f2014-10-15 14:32:19 -0700739// Sets loaded_phdr_ to the address of the program header table as it appears
740// in the loaded segments in memory. This is in contrast with phdr_table_,
741// which is temporary and will be released before the library is relocated.
Elliott Hughes650be4e2013-03-05 18:47:58 -0800742bool ElfReader::FindPhdr() {
Elliott Hughes0266ae52014-02-10 17:46:57 -0800743 const ElfW(Phdr)* phdr_limit = phdr_table_ + phdr_num_;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200744
Elliott Hughes650be4e2013-03-05 18:47:58 -0800745 // If there is a PT_PHDR, use it directly.
Elliott Hughes0266ae52014-02-10 17:46:57 -0800746 for (const ElfW(Phdr)* phdr = phdr_table_; phdr < phdr_limit; ++phdr) {
Elliott Hughes650be4e2013-03-05 18:47:58 -0800747 if (phdr->p_type == PT_PHDR) {
748 return CheckPhdr(load_bias_ + phdr->p_vaddr);
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200749 }
Elliott Hughes650be4e2013-03-05 18:47:58 -0800750 }
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200751
Elliott Hughes650be4e2013-03-05 18:47:58 -0800752 // Otherwise, check the first loadable segment. If its file offset
753 // is 0, it starts with the ELF header, and we can trivially find the
754 // loaded program header from it.
Elliott Hughes0266ae52014-02-10 17:46:57 -0800755 for (const ElfW(Phdr)* phdr = phdr_table_; phdr < phdr_limit; ++phdr) {
Elliott Hughes650be4e2013-03-05 18:47:58 -0800756 if (phdr->p_type == PT_LOAD) {
757 if (phdr->p_offset == 0) {
Elliott Hughes0266ae52014-02-10 17:46:57 -0800758 ElfW(Addr) elf_addr = load_bias_ + phdr->p_vaddr;
Elliott Hughesfaf05ba2014-02-11 16:59:37 -0800759 const ElfW(Ehdr)* ehdr = reinterpret_cast<const ElfW(Ehdr)*>(elf_addr);
Elliott Hughes0266ae52014-02-10 17:46:57 -0800760 ElfW(Addr) offset = ehdr->e_phoff;
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -0800761 return CheckPhdr(reinterpret_cast<ElfW(Addr)>(ehdr) + offset);
Elliott Hughes650be4e2013-03-05 18:47:58 -0800762 }
763 break;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200764 }
Elliott Hughes650be4e2013-03-05 18:47:58 -0800765 }
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200766
Elliott Hughes650be4e2013-03-05 18:47:58 -0800767 DL_ERR("can't find loaded phdr for \"%s\"", name_);
768 return false;
769}
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200770
Elliott Hughes650be4e2013-03-05 18:47:58 -0800771// Ensures that our program header is actually within a loadable
772// segment. This should help catch badly-formed ELF files that
773// would cause the linker to crash later when trying to access it.
Elliott Hughes0266ae52014-02-10 17:46:57 -0800774bool ElfReader::CheckPhdr(ElfW(Addr) loaded) {
775 const ElfW(Phdr)* phdr_limit = phdr_table_ + phdr_num_;
776 ElfW(Addr) loaded_end = loaded + (phdr_num_ * sizeof(ElfW(Phdr)));
777 for (ElfW(Phdr)* phdr = phdr_table_; phdr < phdr_limit; ++phdr) {
Elliott Hughes650be4e2013-03-05 18:47:58 -0800778 if (phdr->p_type != PT_LOAD) {
779 continue;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200780 }
Elliott Hughes0266ae52014-02-10 17:46:57 -0800781 ElfW(Addr) seg_start = phdr->p_vaddr + load_bias_;
782 ElfW(Addr) seg_end = phdr->p_filesz + seg_start;
Elliott Hughes650be4e2013-03-05 18:47:58 -0800783 if (seg_start <= loaded && loaded_end <= seg_end) {
Elliott Hughes0266ae52014-02-10 17:46:57 -0800784 loaded_phdr_ = reinterpret_cast<const ElfW(Phdr)*>(loaded);
Elliott Hughes650be4e2013-03-05 18:47:58 -0800785 return true;
786 }
787 }
Elliott Hughesc00f2cb2013-10-04 17:01:33 -0700788 DL_ERR("\"%s\" loaded phdr %p not in loadable segment", name_, reinterpret_cast<void*>(loaded));
Elliott Hughes650be4e2013-03-05 18:47:58 -0800789 return false;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200790}