blob: e0d6d0e78f5fb1e0d65b7a8a1bfd6106070a28e4 [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
Dmitriy Ivanovde017802014-10-03 17:52:44 -0700122ElfReader::ElfReader(const char* name, int fd, off64_t file_offset)
123 : name_(name), fd_(fd), file_offset_(file_offset),
Dmitriy Ivanovcfad7ae2014-08-29 12:02:36 -0700124 phdr_num_(0), phdr_mmap_(nullptr), phdr_table_(nullptr), phdr_size_(0),
125 load_start_(nullptr), load_size_(0), load_bias_(0),
126 loaded_phdr_(nullptr) {
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200127}
128
Elliott Hughes650be4e2013-03-05 18:47:58 -0800129ElfReader::~ElfReader() {
Dmitriy Ivanovcfad7ae2014-08-29 12:02:36 -0700130 if (phdr_mmap_ != nullptr) {
Elliott Hughes650be4e2013-03-05 18:47:58 -0800131 munmap(phdr_mmap_, phdr_size_);
132 }
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200133}
134
Torne (Richard Coles)12bbb912014-02-06 14:34:21 +0000135bool ElfReader::Load(const android_dlextinfo* extinfo) {
Elliott Hughes650be4e2013-03-05 18:47:58 -0800136 return ReadElfHeader() &&
137 VerifyElfHeader() &&
138 ReadProgramHeader() &&
Torne (Richard Coles)12bbb912014-02-06 14:34:21 +0000139 ReserveAddressSpace(extinfo) &&
Elliott Hughes650be4e2013-03-05 18:47:58 -0800140 LoadSegments() &&
141 FindPhdr();
142}
143
144bool ElfReader::ReadElfHeader() {
Dmitriy Ivanovde017802014-10-03 17:52:44 -0700145 off64_t actual_offset = lseek64(fd_, file_offset_, SEEK_SET);
146
147 if (actual_offset != file_offset_) {
148 DL_ERR("seek to %" PRId64 " failed: %s", file_offset_, strerror(errno));
149 return false;
150 }
151
Elliott Hughes650be4e2013-03-05 18:47:58 -0800152 ssize_t rc = TEMP_FAILURE_RETRY(read(fd_, &header_, sizeof(header_)));
153 if (rc < 0) {
154 DL_ERR("can't read file \"%s\": %s", name_, strerror(errno));
155 return false;
156 }
157 if (rc != sizeof(header_)) {
Elliott Hughesc6200592013-09-30 18:43:46 -0700158 DL_ERR("\"%s\" is too small to be an ELF executable: only found %zd bytes", name_,
159 static_cast<size_t>(rc));
Elliott Hughes650be4e2013-03-05 18:47:58 -0800160 return false;
161 }
162 return true;
163}
164
165bool ElfReader::VerifyElfHeader() {
Elliott Hughes30021312014-07-15 16:53:13 -0700166 if (memcmp(header_.e_ident, ELFMAG, SELFMAG) != 0) {
Elliott Hughes650be4e2013-03-05 18:47:58 -0800167 DL_ERR("\"%s\" has bad ELF magic", name_);
168 return false;
169 }
170
Elliott Hughesc00f2cb2013-10-04 17:01:33 -0700171 // Try to give a clear diagnostic for ELF class mismatches, since they're
172 // an easy mistake to make during the 32-bit/64-bit transition period.
173 int elf_class = header_.e_ident[EI_CLASS];
174#if defined(__LP64__)
175 if (elf_class != ELFCLASS64) {
176 if (elf_class == ELFCLASS32) {
177 DL_ERR("\"%s\" is 32-bit instead of 64-bit", name_);
178 } else {
179 DL_ERR("\"%s\" has unknown ELF class: %d", name_, elf_class);
180 }
Elliott Hughes650be4e2013-03-05 18:47:58 -0800181 return false;
182 }
Elliott Hughesc00f2cb2013-10-04 17:01:33 -0700183#else
184 if (elf_class != ELFCLASS32) {
185 if (elf_class == ELFCLASS64) {
186 DL_ERR("\"%s\" is 64-bit instead of 32-bit", name_);
187 } else {
188 DL_ERR("\"%s\" has unknown ELF class: %d", name_, elf_class);
189 }
190 return false;
191 }
192#endif
193
Elliott Hughes650be4e2013-03-05 18:47:58 -0800194 if (header_.e_ident[EI_DATA] != ELFDATA2LSB) {
195 DL_ERR("\"%s\" not little-endian: %d", name_, header_.e_ident[EI_DATA]);
196 return false;
197 }
198
199 if (header_.e_type != ET_DYN) {
200 DL_ERR("\"%s\" has unexpected e_type: %d", name_, header_.e_type);
201 return false;
202 }
203
204 if (header_.e_version != EV_CURRENT) {
205 DL_ERR("\"%s\" has unexpected e_version: %d", name_, header_.e_version);
206 return false;
207 }
208
Marcus Oaklande365f9d2013-10-10 15:19:31 +0100209 if (header_.e_machine != ELF_TARG_MACH) {
Elliott Hughes650be4e2013-03-05 18:47:58 -0800210 DL_ERR("\"%s\" has unexpected e_machine: %d", name_, header_.e_machine);
211 return false;
212 }
213
214 return true;
215}
216
217// Loads the program header table from an ELF file into a read-only private
218// anonymous mmap-ed block.
219bool ElfReader::ReadProgramHeader() {
220 phdr_num_ = header_.e_phnum;
221
222 // Like the kernel, we only accept program header tables that
223 // are smaller than 64KiB.
Elliott Hughes0266ae52014-02-10 17:46:57 -0800224 if (phdr_num_ < 1 || phdr_num_ > 65536/sizeof(ElfW(Phdr))) {
Elliott Hughesc6200592013-09-30 18:43:46 -0700225 DL_ERR("\"%s\" has invalid e_phnum: %zd", name_, phdr_num_);
Elliott Hughes650be4e2013-03-05 18:47:58 -0800226 return false;
227 }
228
Elliott Hughes0266ae52014-02-10 17:46:57 -0800229 ElfW(Addr) page_min = PAGE_START(header_.e_phoff);
230 ElfW(Addr) page_max = PAGE_END(header_.e_phoff + (phdr_num_ * sizeof(ElfW(Phdr))));
231 ElfW(Addr) page_offset = PAGE_OFFSET(header_.e_phoff);
Elliott Hughes650be4e2013-03-05 18:47:58 -0800232
233 phdr_size_ = page_max - page_min;
234
Dmitriy Ivanovde017802014-10-03 17:52:44 -0700235 void* mmap_result = mmap64(nullptr, phdr_size_, PROT_READ, MAP_PRIVATE, fd_, file_offset_ + page_min);
Elliott Hughes650be4e2013-03-05 18:47:58 -0800236 if (mmap_result == MAP_FAILED) {
237 DL_ERR("\"%s\" phdr mmap failed: %s", name_, strerror(errno));
238 return false;
239 }
240
241 phdr_mmap_ = mmap_result;
Elliott Hughes0266ae52014-02-10 17:46:57 -0800242 phdr_table_ = reinterpret_cast<ElfW(Phdr)*>(reinterpret_cast<char*>(mmap_result) + page_offset);
Elliott Hughes650be4e2013-03-05 18:47:58 -0800243 return true;
244}
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200245
Brian Carlstrome7dffe12013-01-10 16:39:58 -0800246/* Returns the size of the extent of all the possibly non-contiguous
247 * loadable segments in an ELF program header table. This corresponds
248 * to the page-aligned size in bytes that needs to be reserved in the
249 * process' address space. If there are no loadable segments, 0 is
250 * returned.
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200251 *
Dmitriy Ivanovcfad7ae2014-08-29 12:02:36 -0700252 * If out_min_vaddr or out_max_vaddr are not null, they will be
Brian Carlstrome7dffe12013-01-10 16:39:58 -0800253 * set to the minimum and maximum addresses of pages to be reserved,
254 * or 0 if there is nothing to load.
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200255 */
Elliott Hughes0266ae52014-02-10 17:46:57 -0800256size_t phdr_table_get_load_size(const ElfW(Phdr)* phdr_table, size_t phdr_count,
257 ElfW(Addr)* out_min_vaddr,
258 ElfW(Addr)* out_max_vaddr) {
259 ElfW(Addr) min_vaddr = UINTPTR_MAX;
260 ElfW(Addr) max_vaddr = 0;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200261
Elliott Hughes0266ae52014-02-10 17:46:57 -0800262 bool found_pt_load = false;
263 for (size_t i = 0; i < phdr_count; ++i) {
264 const ElfW(Phdr)* phdr = &phdr_table[i];
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200265
Elliott Hughes0266ae52014-02-10 17:46:57 -0800266 if (phdr->p_type != PT_LOAD) {
267 continue;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200268 }
Elliott Hughes0266ae52014-02-10 17:46:57 -0800269 found_pt_load = true;
270
271 if (phdr->p_vaddr < min_vaddr) {
272 min_vaddr = phdr->p_vaddr;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200273 }
274
Elliott Hughes0266ae52014-02-10 17:46:57 -0800275 if (phdr->p_vaddr + phdr->p_memsz > max_vaddr) {
276 max_vaddr = phdr->p_vaddr + phdr->p_memsz;
277 }
278 }
279 if (!found_pt_load) {
280 min_vaddr = 0;
281 }
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200282
Elliott Hughes0266ae52014-02-10 17:46:57 -0800283 min_vaddr = PAGE_START(min_vaddr);
284 max_vaddr = PAGE_END(max_vaddr);
285
Dmitriy Ivanovcfad7ae2014-08-29 12:02:36 -0700286 if (out_min_vaddr != nullptr) {
Elliott Hughes0266ae52014-02-10 17:46:57 -0800287 *out_min_vaddr = min_vaddr;
288 }
Dmitriy Ivanovcfad7ae2014-08-29 12:02:36 -0700289 if (out_max_vaddr != nullptr) {
Elliott Hughes0266ae52014-02-10 17:46:57 -0800290 *out_max_vaddr = max_vaddr;
291 }
292 return max_vaddr - min_vaddr;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200293}
294
Elliott Hughes650be4e2013-03-05 18:47:58 -0800295// Reserve a virtual address range big enough to hold all loadable
296// segments of a program header table. This is done by creating a
297// private anonymous mmap() with PROT_NONE.
Torne (Richard Coles)12bbb912014-02-06 14:34:21 +0000298bool ElfReader::ReserveAddressSpace(const android_dlextinfo* extinfo) {
Elliott Hughes0266ae52014-02-10 17:46:57 -0800299 ElfW(Addr) min_vaddr;
Brian Carlstrome7dffe12013-01-10 16:39:58 -0800300 load_size_ = phdr_table_get_load_size(phdr_table_, phdr_num_, &min_vaddr);
Elliott Hughes650be4e2013-03-05 18:47:58 -0800301 if (load_size_ == 0) {
302 DL_ERR("\"%s\" has no loadable segments", name_);
303 return false;
304 }
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200305
Brian Carlstrome7dffe12013-01-10 16:39:58 -0800306 uint8_t* addr = reinterpret_cast<uint8_t*>(min_vaddr);
Torne (Richard Coles)12bbb912014-02-06 14:34:21 +0000307 void* start;
308 size_t reserved_size = 0;
309 bool reserved_hint = true;
310
Dmitriy Ivanovcfad7ae2014-08-29 12:02:36 -0700311 if (extinfo != nullptr) {
Torne (Richard Coles)12bbb912014-02-06 14:34:21 +0000312 if (extinfo->flags & ANDROID_DLEXT_RESERVED_ADDRESS) {
313 reserved_size = extinfo->reserved_size;
314 reserved_hint = false;
315 } else if (extinfo->flags & ANDROID_DLEXT_RESERVED_ADDRESS_HINT) {
316 reserved_size = extinfo->reserved_size;
317 }
318 }
319
320 if (load_size_ > reserved_size) {
321 if (!reserved_hint) {
322 DL_ERR("reserved address space %zd smaller than %zd bytes needed for \"%s\"",
323 reserved_size - load_size_, load_size_, name_);
324 return false;
325 }
326 int mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS;
327 start = mmap(addr, load_size_, PROT_NONE, mmap_flags, -1, 0);
328 if (start == MAP_FAILED) {
329 DL_ERR("couldn't reserve %zd bytes of address space for \"%s\"", load_size_, name_);
330 return false;
331 }
332 } else {
333 start = extinfo->reserved_addr;
Elliott Hughes650be4e2013-03-05 18:47:58 -0800334 }
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200335
Elliott Hughes650be4e2013-03-05 18:47:58 -0800336 load_start_ = start;
Brian Carlstrome7dffe12013-01-10 16:39:58 -0800337 load_bias_ = reinterpret_cast<uint8_t*>(start) - addr;
Elliott Hughes650be4e2013-03-05 18:47:58 -0800338 return true;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200339}
340
Elliott Hughes650be4e2013-03-05 18:47:58 -0800341bool ElfReader::LoadSegments() {
342 for (size_t i = 0; i < phdr_num_; ++i) {
Elliott Hughes0266ae52014-02-10 17:46:57 -0800343 const ElfW(Phdr)* phdr = &phdr_table_[i];
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200344
Elliott Hughes650be4e2013-03-05 18:47:58 -0800345 if (phdr->p_type != PT_LOAD) {
346 continue;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200347 }
Elliott Hughes650be4e2013-03-05 18:47:58 -0800348
349 // Segment addresses in memory.
Elliott Hughes0266ae52014-02-10 17:46:57 -0800350 ElfW(Addr) seg_start = phdr->p_vaddr + load_bias_;
351 ElfW(Addr) seg_end = seg_start + phdr->p_memsz;
Elliott Hughes650be4e2013-03-05 18:47:58 -0800352
Elliott Hughes0266ae52014-02-10 17:46:57 -0800353 ElfW(Addr) seg_page_start = PAGE_START(seg_start);
354 ElfW(Addr) seg_page_end = PAGE_END(seg_end);
Elliott Hughes650be4e2013-03-05 18:47:58 -0800355
Elliott Hughes0266ae52014-02-10 17:46:57 -0800356 ElfW(Addr) seg_file_end = seg_start + phdr->p_filesz;
Elliott Hughes650be4e2013-03-05 18:47:58 -0800357
358 // File offsets.
Elliott Hughes0266ae52014-02-10 17:46:57 -0800359 ElfW(Addr) file_start = phdr->p_offset;
360 ElfW(Addr) file_end = file_start + phdr->p_filesz;
Elliott Hughes650be4e2013-03-05 18:47:58 -0800361
Elliott Hughes0266ae52014-02-10 17:46:57 -0800362 ElfW(Addr) file_page_start = PAGE_START(file_start);
363 ElfW(Addr) file_length = file_end - file_page_start;
Elliott Hughes650be4e2013-03-05 18:47:58 -0800364
Brian Carlstrom82dcc792013-05-21 16:49:24 -0700365 if (file_length != 0) {
Dmitriy Ivanovde017802014-10-03 17:52:44 -0700366 void* seg_addr = mmap64(reinterpret_cast<void*>(seg_page_start),
Brian Carlstrom82dcc792013-05-21 16:49:24 -0700367 file_length,
368 PFLAGS_TO_PROT(phdr->p_flags),
369 MAP_FIXED|MAP_PRIVATE,
370 fd_,
Dmitriy Ivanovde017802014-10-03 17:52:44 -0700371 file_offset_ + file_page_start);
Brian Carlstrom82dcc792013-05-21 16:49:24 -0700372 if (seg_addr == MAP_FAILED) {
Elliott Hughesc6200592013-09-30 18:43:46 -0700373 DL_ERR("couldn't map \"%s\" segment %zd: %s", name_, i, strerror(errno));
Brian Carlstrom82dcc792013-05-21 16:49:24 -0700374 return false;
375 }
Elliott Hughes650be4e2013-03-05 18:47:58 -0800376 }
377
378 // if the segment is writable, and does not end on a page boundary,
379 // zero-fill it until the page limit.
380 if ((phdr->p_flags & PF_W) != 0 && PAGE_OFFSET(seg_file_end) > 0) {
Elliott Hughesfaf05ba2014-02-11 16:59:37 -0800381 memset(reinterpret_cast<void*>(seg_file_end), 0, PAGE_SIZE - PAGE_OFFSET(seg_file_end));
Elliott Hughes650be4e2013-03-05 18:47:58 -0800382 }
383
384 seg_file_end = PAGE_END(seg_file_end);
385
386 // seg_file_end is now the first page address after the file
387 // content. If seg_end is larger, we need to zero anything
388 // between them. This is done by using a private anonymous
389 // map for all extra pages.
390 if (seg_page_end > seg_file_end) {
Elliott Hughesfaf05ba2014-02-11 16:59:37 -0800391 void* zeromap = mmap(reinterpret_cast<void*>(seg_file_end),
Elliott Hughes650be4e2013-03-05 18:47:58 -0800392 seg_page_end - seg_file_end,
393 PFLAGS_TO_PROT(phdr->p_flags),
394 MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE,
395 -1,
396 0);
397 if (zeromap == MAP_FAILED) {
398 DL_ERR("couldn't zero fill \"%s\" gap: %s", name_, strerror(errno));
399 return false;
400 }
401 }
402 }
403 return true;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200404}
405
Elliott Hughes105bc262012-08-15 16:56:00 -0700406/* Used internally. Used to set the protection bits of all loaded segments
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200407 * with optional extra flags (i.e. really PROT_WRITE). Used by
408 * phdr_table_protect_segments and phdr_table_unprotect_segments.
409 */
Elliott Hughes0266ae52014-02-10 17:46:57 -0800410static int _phdr_table_set_load_prot(const ElfW(Phdr)* phdr_table, size_t phdr_count,
411 ElfW(Addr) load_bias, int extra_prot_flags) {
412 const ElfW(Phdr)* phdr = phdr_table;
413 const ElfW(Phdr)* phdr_limit = phdr + phdr_count;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200414
Elliott Hughes0266ae52014-02-10 17:46:57 -0800415 for (; phdr < phdr_limit; phdr++) {
416 if (phdr->p_type != PT_LOAD || (phdr->p_flags & PF_W) != 0) {
417 continue;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200418 }
Elliott Hughes0266ae52014-02-10 17:46:57 -0800419
420 ElfW(Addr) seg_page_start = PAGE_START(phdr->p_vaddr) + load_bias;
421 ElfW(Addr) seg_page_end = PAGE_END(phdr->p_vaddr + phdr->p_memsz) + load_bias;
422
Elliott Hughesfaf05ba2014-02-11 16:59:37 -0800423 int ret = mprotect(reinterpret_cast<void*>(seg_page_start),
Elliott Hughes0266ae52014-02-10 17:46:57 -0800424 seg_page_end - seg_page_start,
425 PFLAGS_TO_PROT(phdr->p_flags) | extra_prot_flags);
426 if (ret < 0) {
427 return -1;
428 }
429 }
430 return 0;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200431}
432
433/* Restore the original protection modes for all loadable segments.
434 * You should only call this after phdr_table_unprotect_segments and
435 * applying all relocations.
436 *
437 * Input:
438 * phdr_table -> program header table
Elliott Hughes105bc262012-08-15 16:56:00 -0700439 * phdr_count -> number of entries in tables
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200440 * load_bias -> load bias
441 * Return:
442 * 0 on error, -1 on failure (error code in errno).
443 */
Elliott Hughes0266ae52014-02-10 17:46:57 -0800444int phdr_table_protect_segments(const ElfW(Phdr)* phdr_table, size_t phdr_count, ElfW(Addr) load_bias) {
445 return _phdr_table_set_load_prot(phdr_table, phdr_count, load_bias, 0);
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200446}
447
448/* Change the protection of all loaded segments in memory to writable.
449 * This is useful before performing relocations. Once completed, you
450 * will have to call phdr_table_protect_segments to restore the original
451 * protection flags on all segments.
452 *
453 * Note that some writable segments can also have their content turned
454 * to read-only by calling phdr_table_protect_gnu_relro. This is no
455 * performed here.
456 *
457 * Input:
458 * phdr_table -> program header table
Elliott Hughes105bc262012-08-15 16:56:00 -0700459 * phdr_count -> number of entries in tables
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200460 * load_bias -> load bias
461 * Return:
462 * 0 on error, -1 on failure (error code in errno).
463 */
Elliott Hughes0266ae52014-02-10 17:46:57 -0800464int phdr_table_unprotect_segments(const ElfW(Phdr)* phdr_table, size_t phdr_count, ElfW(Addr) load_bias) {
465 return _phdr_table_set_load_prot(phdr_table, phdr_count, load_bias, PROT_WRITE);
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200466}
467
468/* Used internally by phdr_table_protect_gnu_relro and
469 * phdr_table_unprotect_gnu_relro.
470 */
Elliott Hughes0266ae52014-02-10 17:46:57 -0800471static int _phdr_table_set_gnu_relro_prot(const ElfW(Phdr)* phdr_table, size_t phdr_count,
472 ElfW(Addr) load_bias, int prot_flags) {
473 const ElfW(Phdr)* phdr = phdr_table;
474 const ElfW(Phdr)* phdr_limit = phdr + phdr_count;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200475
Elliott Hughes0266ae52014-02-10 17:46:57 -0800476 for (phdr = phdr_table; phdr < phdr_limit; phdr++) {
477 if (phdr->p_type != PT_GNU_RELRO) {
478 continue;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200479 }
Elliott Hughes0266ae52014-02-10 17:46:57 -0800480
481 // Tricky: what happens when the relro segment does not start
482 // or end at page boundaries? We're going to be over-protective
483 // here and put every page touched by the segment as read-only.
484
485 // This seems to match Ian Lance Taylor's description of the
486 // feature at http://www.airs.com/blog/archives/189.
487
488 // Extract:
489 // Note that the current dynamic linker code will only work
490 // correctly if the PT_GNU_RELRO segment starts on a page
491 // boundary. This is because the dynamic linker rounds the
492 // p_vaddr field down to the previous page boundary. If
493 // there is anything on the page which should not be read-only,
494 // the program is likely to fail at runtime. So in effect the
495 // linker must only emit a PT_GNU_RELRO segment if it ensures
496 // that it starts on a page boundary.
497 ElfW(Addr) seg_page_start = PAGE_START(phdr->p_vaddr) + load_bias;
498 ElfW(Addr) seg_page_end = PAGE_END(phdr->p_vaddr + phdr->p_memsz) + load_bias;
499
Elliott Hughesfaf05ba2014-02-11 16:59:37 -0800500 int ret = mprotect(reinterpret_cast<void*>(seg_page_start),
Elliott Hughes0266ae52014-02-10 17:46:57 -0800501 seg_page_end - seg_page_start,
502 prot_flags);
503 if (ret < 0) {
504 return -1;
505 }
506 }
507 return 0;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200508}
509
510/* Apply GNU relro protection if specified by the program header. This will
511 * turn some of the pages of a writable PT_LOAD segment to read-only, as
512 * specified by one or more PT_GNU_RELRO segments. This must be always
513 * performed after relocations.
514 *
Ard Biesheuvel12c78bb2012-08-14 12:30:09 +0200515 * The areas typically covered are .got and .data.rel.ro, these are
516 * read-only from the program's POV, but contain absolute addresses
517 * that need to be relocated before use.
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200518 *
519 * Input:
520 * phdr_table -> program header table
Elliott Hughes105bc262012-08-15 16:56:00 -0700521 * phdr_count -> number of entries in tables
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200522 * load_bias -> load bias
523 * Return:
524 * 0 on error, -1 on failure (error code in errno).
525 */
Elliott Hughes0266ae52014-02-10 17:46:57 -0800526int phdr_table_protect_gnu_relro(const ElfW(Phdr)* phdr_table, size_t phdr_count, ElfW(Addr) load_bias) {
527 return _phdr_table_set_gnu_relro_prot(phdr_table, phdr_count, load_bias, PROT_READ);
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200528}
529
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +0000530/* Serialize the GNU relro segments to the given file descriptor. This can be
531 * performed after relocations to allow another process to later share the
532 * relocated segment, if it was loaded at the same address.
533 *
534 * Input:
535 * phdr_table -> program header table
536 * phdr_count -> number of entries in tables
537 * load_bias -> load bias
538 * fd -> writable file descriptor to use
539 * Return:
540 * 0 on error, -1 on failure (error code in errno).
541 */
542int phdr_table_serialize_gnu_relro(const ElfW(Phdr)* phdr_table, size_t phdr_count, ElfW(Addr) load_bias,
543 int fd) {
544 const ElfW(Phdr)* phdr = phdr_table;
545 const ElfW(Phdr)* phdr_limit = phdr + phdr_count;
546 ssize_t file_offset = 0;
547
548 for (phdr = phdr_table; phdr < phdr_limit; phdr++) {
549 if (phdr->p_type != PT_GNU_RELRO) {
550 continue;
551 }
552
553 ElfW(Addr) seg_page_start = PAGE_START(phdr->p_vaddr) + load_bias;
554 ElfW(Addr) seg_page_end = PAGE_END(phdr->p_vaddr + phdr->p_memsz) + load_bias;
555 ssize_t size = seg_page_end - seg_page_start;
556
557 ssize_t written = TEMP_FAILURE_RETRY(write(fd, reinterpret_cast<void*>(seg_page_start), size));
558 if (written != size) {
559 return -1;
560 }
561 void* map = mmap(reinterpret_cast<void*>(seg_page_start), size, PROT_READ,
562 MAP_PRIVATE|MAP_FIXED, fd, file_offset);
563 if (map == MAP_FAILED) {
564 return -1;
565 }
566 file_offset += size;
567 }
568 return 0;
569}
570
571/* Where possible, replace the GNU relro segments with mappings of the given
572 * file descriptor. This can be performed after relocations to allow a file
573 * previously created by phdr_table_serialize_gnu_relro in another process to
574 * replace the dirty relocated pages, saving memory, if it was loaded at the
575 * same address. We have to compare the data before we map over it, since some
576 * parts of the relro segment may not be identical due to other libraries in
577 * the process being loaded at different addresses.
578 *
579 * Input:
580 * phdr_table -> program header table
581 * phdr_count -> number of entries in tables
582 * load_bias -> load bias
583 * fd -> readable file descriptor to use
584 * Return:
585 * 0 on error, -1 on failure (error code in errno).
586 */
587int phdr_table_map_gnu_relro(const ElfW(Phdr)* phdr_table, size_t phdr_count, ElfW(Addr) load_bias,
588 int fd) {
589 // Map the file at a temporary location so we can compare its contents.
590 struct stat file_stat;
591 if (TEMP_FAILURE_RETRY(fstat(fd, &file_stat)) != 0) {
592 return -1;
593 }
594 off_t file_size = file_stat.st_size;
Dmitriy Ivanovcfad7ae2014-08-29 12:02:36 -0700595 void* temp_mapping = nullptr;
Torne (Richard Coles)26ec9672014-04-30 15:48:40 +0100596 if (file_size > 0) {
Dmitriy Ivanovcfad7ae2014-08-29 12:02:36 -0700597 temp_mapping = mmap(nullptr, file_size, PROT_READ, MAP_PRIVATE, fd, 0);
Torne (Richard Coles)26ec9672014-04-30 15:48:40 +0100598 if (temp_mapping == MAP_FAILED) {
599 return -1;
600 }
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +0000601 }
602 size_t file_offset = 0;
603
604 // Iterate over the relro segments and compare/remap the pages.
605 const ElfW(Phdr)* phdr = phdr_table;
606 const ElfW(Phdr)* phdr_limit = phdr + phdr_count;
607
608 for (phdr = phdr_table; phdr < phdr_limit; phdr++) {
609 if (phdr->p_type != PT_GNU_RELRO) {
610 continue;
611 }
612
613 ElfW(Addr) seg_page_start = PAGE_START(phdr->p_vaddr) + load_bias;
614 ElfW(Addr) seg_page_end = PAGE_END(phdr->p_vaddr + phdr->p_memsz) + load_bias;
615
616 char* file_base = static_cast<char*>(temp_mapping) + file_offset;
617 char* mem_base = reinterpret_cast<char*>(seg_page_start);
618 size_t match_offset = 0;
619 size_t size = seg_page_end - seg_page_start;
620
Torne (Richard Coles)26ec9672014-04-30 15:48:40 +0100621 if (file_size - file_offset < size) {
622 // File is too short to compare to this segment. The contents are likely
623 // different as well (it's probably for a different library version) so
624 // just don't bother checking.
625 break;
626 }
627
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +0000628 while (match_offset < size) {
629 // Skip over dissimilar pages.
630 while (match_offset < size &&
631 memcmp(mem_base + match_offset, file_base + match_offset, PAGE_SIZE) != 0) {
632 match_offset += PAGE_SIZE;
633 }
634
635 // Count similar pages.
636 size_t mismatch_offset = match_offset;
637 while (mismatch_offset < size &&
638 memcmp(mem_base + mismatch_offset, file_base + mismatch_offset, PAGE_SIZE) == 0) {
639 mismatch_offset += PAGE_SIZE;
640 }
641
642 // Map over similar pages.
643 if (mismatch_offset > match_offset) {
644 void* map = mmap(mem_base + match_offset, mismatch_offset - match_offset,
645 PROT_READ, MAP_PRIVATE|MAP_FIXED, fd, match_offset);
646 if (map == MAP_FAILED) {
647 munmap(temp_mapping, file_size);
648 return -1;
649 }
650 }
651
652 match_offset = mismatch_offset;
653 }
654
655 // Add to the base file offset in case there are multiple relro segments.
656 file_offset += size;
657 }
658 munmap(temp_mapping, file_size);
659 return 0;
660}
661
662
Elliott Hughes4eeb1f12013-10-25 17:38:02 -0700663#if defined(__arm__)
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200664
665# ifndef PT_ARM_EXIDX
666# define PT_ARM_EXIDX 0x70000001 /* .ARM.exidx segment */
667# endif
668
669/* Return the address and size of the .ARM.exidx section in memory,
670 * if present.
671 *
672 * Input:
673 * phdr_table -> program header table
Elliott Hughes105bc262012-08-15 16:56:00 -0700674 * phdr_count -> number of entries in tables
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200675 * load_bias -> load bias
676 * Output:
Dmitriy Ivanovcfad7ae2014-08-29 12:02:36 -0700677 * arm_exidx -> address of table in memory (null on failure).
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200678 * arm_exidx_count -> number of items in table (0 on failure).
679 * Return:
680 * 0 on error, -1 on failure (_no_ error code in errno)
681 */
Elliott Hughes0266ae52014-02-10 17:46:57 -0800682int phdr_table_get_arm_exidx(const ElfW(Phdr)* phdr_table, size_t phdr_count,
683 ElfW(Addr) load_bias,
684 ElfW(Addr)** arm_exidx, unsigned* arm_exidx_count) {
685 const ElfW(Phdr)* phdr = phdr_table;
686 const ElfW(Phdr)* phdr_limit = phdr + phdr_count;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200687
Elliott Hughes0266ae52014-02-10 17:46:57 -0800688 for (phdr = phdr_table; phdr < phdr_limit; phdr++) {
689 if (phdr->p_type != PT_ARM_EXIDX) {
690 continue;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200691 }
Elliott Hughes0266ae52014-02-10 17:46:57 -0800692
693 *arm_exidx = reinterpret_cast<ElfW(Addr)*>(load_bias + phdr->p_vaddr);
694 *arm_exidx_count = (unsigned)(phdr->p_memsz / 8);
695 return 0;
696 }
Dmitriy Ivanovcfad7ae2014-08-29 12:02:36 -0700697 *arm_exidx = nullptr;
Elliott Hughes0266ae52014-02-10 17:46:57 -0800698 *arm_exidx_count = 0;
699 return -1;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200700}
Elliott Hughes4eeb1f12013-10-25 17:38:02 -0700701#endif
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200702
Ard Biesheuvel12c78bb2012-08-14 12:30:09 +0200703/* Return the address and size of the ELF file's .dynamic section in memory,
Dmitriy Ivanovcfad7ae2014-08-29 12:02:36 -0700704 * or null if missing.
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200705 *
706 * Input:
707 * phdr_table -> program header table
Elliott Hughes105bc262012-08-15 16:56:00 -0700708 * phdr_count -> number of entries in tables
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200709 * load_bias -> load bias
Ard Biesheuvel12c78bb2012-08-14 12:30:09 +0200710 * Output:
Dmitriy Ivanovcfad7ae2014-08-29 12:02:36 -0700711 * dynamic -> address of table in memory (null on failure).
Ningsheng Jian04f5f412014-09-16 15:22:10 +0800712 * dynamic_flags -> protection flags for section (unset on failure)
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200713 * Return:
Ard Biesheuvel12c78bb2012-08-14 12:30:09 +0200714 * void
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200715 */
Elliott Hughes0266ae52014-02-10 17:46:57 -0800716void phdr_table_get_dynamic_section(const ElfW(Phdr)* phdr_table, size_t phdr_count,
Ningsheng Jian04f5f412014-09-16 15:22:10 +0800717 ElfW(Addr) load_bias, ElfW(Dyn)** dynamic,
718 ElfW(Word)* dynamic_flags) {
Dmitriy Ivanovc0133a72014-09-05 14:57:59 -0700719 *dynamic = nullptr;
Dmitriy Ivanovae69a952014-09-05 16:42:53 -0700720 for (const ElfW(Phdr)* phdr = phdr_table, *phdr_limit = phdr + phdr_count; phdr < phdr_limit; phdr++) {
721 if (phdr->p_type == PT_DYNAMIC) {
722 *dynamic = reinterpret_cast<ElfW(Dyn)*>(load_bias + phdr->p_vaddr);
Ningsheng Jian04f5f412014-09-16 15:22:10 +0800723 if (dynamic_flags) {
724 *dynamic_flags = phdr->p_flags;
725 }
Dmitriy Ivanovae69a952014-09-05 16:42:53 -0700726 return;
727 }
Elliott Hughes0266ae52014-02-10 17:46:57 -0800728 }
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200729}
730
Elliott Hughes650be4e2013-03-05 18:47:58 -0800731// Returns the address of the program header table as it appears in the loaded
732// segments in memory. This is in contrast with 'phdr_table_' which
733// is temporary and will be released before the library is relocated.
734bool ElfReader::FindPhdr() {
Elliott Hughes0266ae52014-02-10 17:46:57 -0800735 const ElfW(Phdr)* phdr_limit = phdr_table_ + phdr_num_;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200736
Elliott Hughes650be4e2013-03-05 18:47:58 -0800737 // If there is a PT_PHDR, use it directly.
Elliott Hughes0266ae52014-02-10 17:46:57 -0800738 for (const ElfW(Phdr)* phdr = phdr_table_; phdr < phdr_limit; ++phdr) {
Elliott Hughes650be4e2013-03-05 18:47:58 -0800739 if (phdr->p_type == PT_PHDR) {
740 return CheckPhdr(load_bias_ + phdr->p_vaddr);
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200741 }
Elliott Hughes650be4e2013-03-05 18:47:58 -0800742 }
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200743
Elliott Hughes650be4e2013-03-05 18:47:58 -0800744 // Otherwise, check the first loadable segment. If its file offset
745 // is 0, it starts with the ELF header, and we can trivially find the
746 // loaded program header from it.
Elliott Hughes0266ae52014-02-10 17:46:57 -0800747 for (const ElfW(Phdr)* phdr = phdr_table_; phdr < phdr_limit; ++phdr) {
Elliott Hughes650be4e2013-03-05 18:47:58 -0800748 if (phdr->p_type == PT_LOAD) {
749 if (phdr->p_offset == 0) {
Elliott Hughes0266ae52014-02-10 17:46:57 -0800750 ElfW(Addr) elf_addr = load_bias_ + phdr->p_vaddr;
Elliott Hughesfaf05ba2014-02-11 16:59:37 -0800751 const ElfW(Ehdr)* ehdr = reinterpret_cast<const ElfW(Ehdr)*>(elf_addr);
Elliott Hughes0266ae52014-02-10 17:46:57 -0800752 ElfW(Addr) offset = ehdr->e_phoff;
753 return CheckPhdr((ElfW(Addr))ehdr + offset);
Elliott Hughes650be4e2013-03-05 18:47:58 -0800754 }
755 break;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200756 }
Elliott Hughes650be4e2013-03-05 18:47:58 -0800757 }
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200758
Elliott Hughes650be4e2013-03-05 18:47:58 -0800759 DL_ERR("can't find loaded phdr for \"%s\"", name_);
760 return false;
761}
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200762
Elliott Hughes650be4e2013-03-05 18:47:58 -0800763// Ensures that our program header is actually within a loadable
764// segment. This should help catch badly-formed ELF files that
765// would cause the linker to crash later when trying to access it.
Elliott Hughes0266ae52014-02-10 17:46:57 -0800766bool ElfReader::CheckPhdr(ElfW(Addr) loaded) {
767 const ElfW(Phdr)* phdr_limit = phdr_table_ + phdr_num_;
768 ElfW(Addr) loaded_end = loaded + (phdr_num_ * sizeof(ElfW(Phdr)));
769 for (ElfW(Phdr)* phdr = phdr_table_; phdr < phdr_limit; ++phdr) {
Elliott Hughes650be4e2013-03-05 18:47:58 -0800770 if (phdr->p_type != PT_LOAD) {
771 continue;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200772 }
Elliott Hughes0266ae52014-02-10 17:46:57 -0800773 ElfW(Addr) seg_start = phdr->p_vaddr + load_bias_;
774 ElfW(Addr) seg_end = phdr->p_filesz + seg_start;
Elliott Hughes650be4e2013-03-05 18:47:58 -0800775 if (seg_start <= loaded && loaded_end <= seg_end) {
Elliott Hughes0266ae52014-02-10 17:46:57 -0800776 loaded_phdr_ = reinterpret_cast<const ElfW(Phdr)*>(loaded);
Elliott Hughes650be4e2013-03-05 18:47:58 -0800777 return true;
778 }
779 }
Elliott Hughesc00f2cb2013-10-04 17:01:33 -0700780 DL_ERR("\"%s\" loaded phdr %p not in loadable segment", name_, reinterpret_cast<void*>(loaded));
Elliott Hughes650be4e2013-03-05 18:47:58 -0800781 return false;
David 'Digit' Turnerc1bd5592012-06-19 11:21:29 +0200782}