Thu, 15 Jan 2015 15:59:08 +0100
Implement a real Private Browsing Mode condition by changing the API/ABI;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #undef NDEBUG
6 #include <cstring>
7 #include <assert.h>
8 #include "elfxx.h"
10 template <class endian, typename R, typename T>
11 void Elf_Ehdr_Traits::swap(T &t, R &r)
12 {
13 memcpy(r.e_ident, t.e_ident, sizeof(r.e_ident));
14 r.e_type = endian::swap(t.e_type);
15 r.e_machine = endian::swap(t.e_machine);
16 r.e_version = endian::swap(t.e_version);
17 r.e_entry = endian::swap(t.e_entry);
18 r.e_phoff = endian::swap(t.e_phoff);
19 r.e_shoff = endian::swap(t.e_shoff);
20 r.e_flags = endian::swap(t.e_flags);
21 r.e_ehsize = endian::swap(t.e_ehsize);
22 r.e_phentsize = endian::swap(t.e_phentsize);
23 r.e_phnum = endian::swap(t.e_phnum);
24 r.e_shentsize = endian::swap(t.e_shentsize);
25 r.e_shnum = endian::swap(t.e_shnum);
26 r.e_shstrndx = endian::swap(t.e_shstrndx);
27 }
29 template <class endian, typename R, typename T>
30 void Elf_Phdr_Traits::swap(T &t, R &r)
31 {
32 r.p_type = endian::swap(t.p_type);
33 r.p_offset = endian::swap(t.p_offset);
34 r.p_vaddr = endian::swap(t.p_vaddr);
35 r.p_paddr = endian::swap(t.p_paddr);
36 r.p_filesz = endian::swap(t.p_filesz);
37 r.p_memsz = endian::swap(t.p_memsz);
38 r.p_flags = endian::swap(t.p_flags);
39 r.p_align = endian::swap(t.p_align);
40 }
42 template <class endian, typename R, typename T>
43 void Elf_Shdr_Traits::swap(T &t, R &r)
44 {
45 r.sh_name = endian::swap(t.sh_name);
46 r.sh_type = endian::swap(t.sh_type);
47 r.sh_flags = endian::swap(t.sh_flags);
48 r.sh_addr = endian::swap(t.sh_addr);
49 r.sh_offset = endian::swap(t.sh_offset);
50 r.sh_size = endian::swap(t.sh_size);
51 r.sh_link = endian::swap(t.sh_link);
52 r.sh_info = endian::swap(t.sh_info);
53 r.sh_addralign = endian::swap(t.sh_addralign);
54 r.sh_entsize = endian::swap(t.sh_entsize);
55 }
57 template <class endian, typename R, typename T>
58 void Elf_Dyn_Traits::swap(T &t, R &r)
59 {
60 r.d_tag = endian::swap(t.d_tag);
61 r.d_un.d_val = endian::swap(t.d_un.d_val);
62 }
64 template <class endian, typename R, typename T>
65 void Elf_Sym_Traits::swap(T &t, R &r)
66 {
67 r.st_name = endian::swap(t.st_name);
68 r.st_value = endian::swap(t.st_value);
69 r.st_size = endian::swap(t.st_size);
70 r.st_info = t.st_info;
71 r.st_other = t.st_other;
72 r.st_shndx = endian::swap(t.st_shndx);
73 }
75 template <class endian>
76 struct _Rel_info {
77 static inline void swap(Elf32_Word &t, Elf32_Word &r) { r = endian::swap(t); }
78 static inline void swap(Elf64_Xword &t, Elf64_Xword &r) { r = endian::swap(t); }
79 static inline void swap(Elf64_Xword &t, Elf32_Word &r) {
80 r = endian::swap(ELF32_R_INFO(ELF64_R_SYM(t), ELF64_R_TYPE(t)));
81 }
82 static inline void swap(Elf32_Word &t, Elf64_Xword &r) {
83 r = endian::swap(ELF64_R_INFO(ELF32_R_SYM(t), ELF32_R_TYPE(t)));
84 }
85 };
87 template <class endian, typename R, typename T>
88 void Elf_Rel_Traits::swap(T &t, R &r)
89 {
90 r.r_offset = endian::swap(t.r_offset);
91 _Rel_info<endian>::swap(t.r_info, r.r_info);
92 }
94 template <class endian, typename R, typename T>
95 void Elf_Rela_Traits::swap(T &t, R &r)
96 {
97 r.r_offset = endian::swap(t.r_offset);
98 _Rel_info<endian>::swap(t.r_info, r.r_info);
99 r.r_addend = endian::swap(t.r_addend);
100 }
102 static const Elf32_Shdr null32_section =
103 { 0, SHT_NULL, 0, 0, 0, 0, SHN_UNDEF, 0, 0, 0 };
105 Elf_Shdr null_section(null32_section);
107 Elf_Ehdr::Elf_Ehdr(std::ifstream &file, char ei_class, char ei_data)
108 : serializable<Elf_Ehdr_Traits>(file, ei_class, ei_data),
109 ElfSection(null_section, nullptr, nullptr)
110 {
111 shdr.sh_size = Elf_Ehdr::size(ei_class);
112 }
114 Elf::Elf(std::ifstream &file)
115 {
116 if (!file.is_open())
117 throw std::runtime_error("Error opening file");
119 file.exceptions(std::ifstream::eofbit | std::ifstream::failbit | std::ifstream::badbit);
120 // Read ELF magic number and identification information
121 char e_ident[EI_VERSION];
122 file.seekg(0);
123 file.read(e_ident, sizeof(e_ident));
124 file.seekg(0);
125 ehdr = new Elf_Ehdr(file, e_ident[EI_CLASS], e_ident[EI_DATA]);
127 // ELFOSABI_LINUX is kept unsupported because I haven't looked whether
128 // STB_GNU_UNIQUE or STT_GNU_IFUNC would need special casing.
129 if ((ehdr->e_ident[EI_OSABI] != ELFOSABI_NONE) && (ehdr->e_ident[EI_ABIVERSION] != 0))
130 throw std::runtime_error("unsupported ELF ABI");
132 if (ehdr->e_version != 1)
133 throw std::runtime_error("unsupported ELF version");
135 // Sanity checks
136 if (ehdr->e_shnum == 0)
137 throw std::runtime_error("sstripped ELF files aren't supported");
139 if (ehdr->e_ehsize != Elf_Ehdr::size(e_ident[EI_CLASS]))
140 throw std::runtime_error("unsupported ELF inconsistency: ehdr.e_ehsize != sizeof(ehdr)");
142 if (ehdr->e_shentsize != Elf_Shdr::size(e_ident[EI_CLASS]))
143 throw std::runtime_error("unsupported ELF inconsistency: ehdr.e_shentsize != sizeof(shdr)");
145 if (ehdr->e_phnum == 0) {
146 if (ehdr->e_phoff != 0)
147 throw std::runtime_error("unsupported ELF inconsistency: e_phnum == 0 && e_phoff != 0");
148 if (ehdr->e_phentsize != 0)
149 throw std::runtime_error("unsupported ELF inconsistency: e_phnum == 0 && e_phentsize != 0");
150 } else if (ehdr->e_phoff != ehdr->e_ehsize)
151 throw std::runtime_error("unsupported ELF inconsistency: ehdr->e_phoff != ehdr->e_ehsize");
152 else if (ehdr->e_phentsize != Elf_Phdr::size(e_ident[EI_CLASS]))
153 throw std::runtime_error("unsupported ELF inconsistency: ehdr->e_phentsize != sizeof(phdr)");
155 // Read section headers
156 Elf_Shdr **shdr = new Elf_Shdr *[ehdr->e_shnum];
157 file.seekg(ehdr->e_shoff);
158 for (int i = 0; i < ehdr->e_shnum; i++)
159 shdr[i] = new Elf_Shdr(file, e_ident[EI_CLASS], e_ident[EI_DATA]);
161 // Sanity check in section header for index 0
162 if ((shdr[0]->sh_name != 0) || (shdr[0]->sh_type != SHT_NULL) ||
163 (shdr[0]->sh_flags != 0) || (shdr[0]->sh_addr != 0) ||
164 (shdr[0]->sh_offset != 0) || (shdr[0]->sh_size != 0) ||
165 (shdr[0]->sh_link != SHN_UNDEF) || (shdr[0]->sh_info != 0) ||
166 (shdr[0]->sh_addralign != 0) || (shdr[0]->sh_entsize != 0))
167 throw std::runtime_error("Section header for index 0 contains unsupported values");
169 if ((shdr[ehdr->e_shstrndx]->sh_link != 0) || (shdr[ehdr->e_shstrndx]->sh_info != 0))
170 throw std::runtime_error("unsupported ELF content: string table with sh_link != 0 || sh_info != 0");
172 // Store these temporarily
173 tmp_shdr = shdr;
174 tmp_file = &file;
176 // Fill sections list
177 sections = new ElfSection *[ehdr->e_shnum];
178 for (int i = 0; i < ehdr->e_shnum; i++)
179 sections[i] = nullptr;
180 for (int i = 1; i < ehdr->e_shnum; i++) {
181 if (sections[i] != nullptr)
182 continue;
183 getSection(i);
184 }
185 Elf_Shdr s;
186 s.sh_name = 0;
187 s.sh_type = SHT_NULL;
188 s.sh_flags = 0;
189 s.sh_addr = 0;
190 s.sh_offset = ehdr->e_shoff;
191 s.sh_entsize = Elf_Shdr::size(e_ident[EI_CLASS]);
192 s.sh_size = s.sh_entsize * ehdr->e_shnum;
193 s.sh_link = 0;
194 s.sh_info = 0;
195 s.sh_addralign = (e_ident[EI_CLASS] == ELFCLASS32) ? 4 : 8;
196 shdr_section = new ElfSection(s, nullptr, nullptr);
198 // Fake section for program headers
199 s.sh_offset = ehdr->e_phoff;
200 s.sh_addr = ehdr->e_phoff;
201 s.sh_entsize = Elf_Phdr::size(e_ident[EI_CLASS]);
202 s.sh_size = s.sh_entsize * ehdr->e_phnum;
203 phdr_section = new ElfSection(s, nullptr, nullptr);
205 phdr_section->insertAfter(ehdr, false);
207 sections[1]->insertAfter(phdr_section, false);
208 for (int i = 2; i < ehdr->e_shnum; i++) {
209 // TODO: this should be done in a better way
210 if ((shdr_section->getPrevious() == nullptr) && (shdr[i]->sh_offset > ehdr->e_shoff)) {
211 shdr_section->insertAfter(sections[i - 1], false);
212 sections[i]->insertAfter(shdr_section, false);
213 } else
214 sections[i]->insertAfter(sections[i - 1], false);
215 }
216 if (shdr_section->getPrevious() == nullptr)
217 shdr_section->insertAfter(sections[ehdr->e_shnum - 1], false);
219 tmp_file = nullptr;
220 tmp_shdr = nullptr;
221 for (int i = 0; i < ehdr->e_shnum; i++)
222 delete shdr[i];
223 delete[] shdr;
225 eh_shstrndx = (ElfStrtab_Section *)sections[ehdr->e_shstrndx];
227 // Skip reading program headers if there aren't any
228 if (ehdr->e_phnum == 0)
229 return;
231 // Read program headers
232 file.seekg(ehdr->e_phoff);
233 for (int i = 0; i < ehdr->e_phnum; i++) {
234 Elf_Phdr phdr(file, e_ident[EI_CLASS], e_ident[EI_DATA]);
235 if (phdr.p_type == PT_LOAD) {
236 // Default alignment for PT_LOAD on x86-64 prevents elfhack from
237 // doing anything useful. However, the system doesn't actually
238 // require such a big alignment, so in order for elfhack to work
239 // efficiently, reduce alignment when it's originally the default
240 // one.
241 if ((ehdr->e_machine == EM_X86_64) && (phdr.p_align == 0x200000))
242 phdr.p_align = 0x1000;
243 }
244 ElfSegment *segment = new ElfSegment(&phdr);
245 // Some segments aren't entirely filled (if at all) by sections
246 // For those, we use fake sections
247 if ((phdr.p_type == PT_LOAD) && (phdr.p_offset == 0)) {
248 // Use a fake section for ehdr and phdr
249 ehdr->getShdr().sh_addr = phdr.p_vaddr;
250 phdr_section->getShdr().sh_addr += phdr.p_vaddr;
251 segment->addSection(ehdr);
252 segment->addSection(phdr_section);
253 }
254 if (phdr.p_type == PT_PHDR)
255 segment->addSection(phdr_section);
256 for (int j = 1; j < ehdr->e_shnum; j++)
257 if (phdr.contains(sections[j]))
258 segment->addSection(sections[j]);
259 // Make sure that our view of segments corresponds to the original
260 // ELF file.
261 assert(segment->getFileSize() == phdr.p_filesz);
262 // gold makes TLS segments end on an aligned virtual address, even
263 // when the underlying section ends before that, while bfd ld
264 // doesn't. It's fine if we don't keep that alignment.
265 unsigned int memsize = segment->getMemSize();
266 if (phdr.p_type == PT_TLS && memsize != phdr.p_memsz) {
267 unsigned int align = segment->getAlign();
268 memsize = (memsize + align - 1) & ~(align - 1);
269 }
270 assert(memsize == phdr.p_memsz);
271 segments.push_back(segment);
272 }
274 new (&eh_entry) ElfLocation(ehdr->e_entry, this);
275 }
277 Elf::~Elf()
278 {
279 for (std::vector<ElfSegment *>::iterator seg = segments.begin(); seg != segments.end(); seg++)
280 delete *seg;
281 delete[] sections;
282 ElfSection *section = ehdr;
283 while (section != nullptr) {
284 ElfSection *next = section->getNext();
285 delete section;
286 section = next;
287 }
288 }
290 // TODO: This shouldn't fail after inserting sections
291 ElfSection *Elf::getSection(int index)
292 {
293 if ((index < -1) || (index >= ehdr->e_shnum))
294 throw std::runtime_error("Section index out of bounds");
295 if (index == -1)
296 index = ehdr->e_shstrndx; // TODO: should be fixed to use the actual current number
297 // Special case: the section at index 0 is void
298 if (index == 0)
299 return nullptr;
300 // Infinite recursion guard
301 if (sections[index] == (ElfSection *)this)
302 return nullptr;
303 if (sections[index] == nullptr) {
304 sections[index] = (ElfSection *)this;
305 switch (tmp_shdr[index]->sh_type) {
306 case SHT_DYNAMIC:
307 sections[index] = new ElfDynamic_Section(*tmp_shdr[index], tmp_file, this);
308 break;
309 case SHT_REL:
310 sections[index] = new ElfRel_Section<Elf_Rel>(*tmp_shdr[index], tmp_file, this);
311 break;
312 case SHT_RELA:
313 sections[index] = new ElfRel_Section<Elf_Rela>(*tmp_shdr[index], tmp_file, this);
314 break;
315 case SHT_DYNSYM:
316 case SHT_SYMTAB:
317 sections[index] = new ElfSymtab_Section(*tmp_shdr[index], tmp_file, this);
318 break;
319 case SHT_STRTAB:
320 sections[index] = new ElfStrtab_Section(*tmp_shdr[index], tmp_file, this);
321 break;
322 default:
323 sections[index] = new ElfSection(*tmp_shdr[index], tmp_file, this);
324 }
325 }
326 return sections[index];
327 }
329 ElfSection *Elf::getSectionAt(unsigned int offset)
330 {
331 for (int i = 1; i < ehdr->e_shnum; i++) {
332 ElfSection *section = getSection(i);
333 if ((section != nullptr) && (section->getFlags() & SHF_ALLOC) && !(section->getFlags() & SHF_TLS) &&
334 (offset >= section->getAddr()) && (offset < section->getAddr() + section->getSize()))
335 return section;
336 }
337 return nullptr;
338 }
340 ElfSegment *Elf::getSegmentByType(unsigned int type, ElfSegment *last)
341 {
342 std::vector<ElfSegment *>::iterator seg;
343 if (last) {
344 seg = std::find(segments.begin(), segments.end(), last);
345 ++seg;
346 } else
347 seg = segments.begin();
348 for (; seg != segments.end(); seg++)
349 if ((*seg)->getType() == type)
350 return *seg;
351 return nullptr;
352 }
354 void Elf::removeSegment(ElfSegment *segment)
355 {
356 if (!segment)
357 return;
358 std::vector<ElfSegment *>::iterator seg;
359 seg = std::find(segments.begin(), segments.end(), segment);
360 if (seg == segments.end())
361 return;
362 segment->clear();
363 segments.erase(seg);
364 }
366 ElfDynamic_Section *Elf::getDynSection()
367 {
368 for (std::vector<ElfSegment *>::iterator seg = segments.begin(); seg != segments.end(); seg++)
369 if (((*seg)->getType() == PT_DYNAMIC) && ((*seg)->getFirstSection() != nullptr) &&
370 (*seg)->getFirstSection()->getType() == SHT_DYNAMIC)
371 return (ElfDynamic_Section *)(*seg)->getFirstSection();
373 return nullptr;
374 }
376 void Elf::normalize()
377 {
378 // fixup section headers sh_name; TODO: that should be done by sections
379 // themselves
380 for (ElfSection *section = ehdr; section != nullptr; section = section->getNext()) {
381 if (section->getIndex() == 0)
382 continue;
383 else
384 ehdr->e_shnum = section->getIndex() + 1;
385 section->getShdr().sh_name = eh_shstrndx->getStrIndex(section->getName());
386 }
387 ehdr->markDirty();
388 // Check segments consistency
389 int i = 0;
390 for (std::vector<ElfSegment *>::iterator seg = segments.begin(); seg != segments.end(); seg++, i++) {
391 std::list<ElfSection *>::iterator it = (*seg)->begin();
392 for (ElfSection *last = *(it++); it != (*seg)->end(); last = *(it++)) {
393 if (((*it)->getType() != SHT_NOBITS) &&
394 ((*it)->getAddr() - last->getAddr()) != ((*it)->getOffset() - last->getOffset())) {
395 throw std::runtime_error("Segments inconsistency");
396 }
397 }
398 }
399 // fixup ehdr before writing
400 if (ehdr->e_phnum != segments.size()) {
401 ehdr->e_phnum = segments.size();
402 phdr_section->getShdr().sh_size = segments.size() * Elf_Phdr::size(ehdr->e_ident[EI_CLASS]);
403 phdr_section->getNext()->markDirty();
404 }
405 // fixup shdr before writing
406 if (ehdr->e_shnum != shdr_section->getSize() / shdr_section->getEntSize())
407 shdr_section->getShdr().sh_size = ehdr->e_shnum * Elf_Shdr::size(ehdr->e_ident[EI_CLASS]);
408 ehdr->e_shoff = shdr_section->getOffset();
409 ehdr->e_entry = eh_entry.getValue();
410 ehdr->e_shstrndx = eh_shstrndx->getIndex();
411 }
413 void Elf::write(std::ofstream &file)
414 {
415 normalize();
416 for (ElfSection *section = ehdr;
417 section != nullptr; section = section->getNext()) {
418 file.seekp(section->getOffset());
419 if (section == phdr_section) {
420 for (std::vector<ElfSegment *>::iterator seg = segments.begin(); seg != segments.end(); seg++) {
421 Elf_Phdr phdr;
422 phdr.p_type = (*seg)->getType();
423 phdr.p_flags = (*seg)->getFlags();
424 phdr.p_offset = (*seg)->getOffset();
425 phdr.p_vaddr = (*seg)->getAddr();
426 phdr.p_paddr = phdr.p_vaddr + (*seg)->getVPDiff();
427 phdr.p_filesz = (*seg)->getFileSize();
428 phdr.p_memsz = (*seg)->getMemSize();
429 phdr.p_align = (*seg)->getAlign();
430 phdr.serialize(file, ehdr->e_ident[EI_CLASS], ehdr->e_ident[EI_DATA]);
431 }
432 } else if (section == shdr_section) {
433 null_section.serialize(file, ehdr->e_ident[EI_CLASS], ehdr->e_ident[EI_DATA]);
434 for (ElfSection *sec = ehdr; sec!= nullptr; sec = sec->getNext()) {
435 if (sec->getType() != SHT_NULL)
436 sec->getShdr().serialize(file, ehdr->e_ident[EI_CLASS], ehdr->e_ident[EI_DATA]);
437 }
438 } else
439 section->serialize(file, ehdr->e_ident[EI_CLASS], ehdr->e_ident[EI_DATA]);
440 }
441 }
443 ElfSection::ElfSection(Elf_Shdr &s, std::ifstream *file, Elf *parent)
444 : shdr(s),
445 link(shdr.sh_link == SHN_UNDEF ? nullptr : parent->getSection(shdr.sh_link)),
446 next(nullptr), previous(nullptr), index(-1)
447 {
448 if ((file == nullptr) || (shdr.sh_type == SHT_NULL) || (shdr.sh_type == SHT_NOBITS))
449 data = nullptr;
450 else {
451 data = new char[shdr.sh_size];
452 int pos = file->tellg();
453 file->seekg(shdr.sh_offset);
454 file->read(data, shdr.sh_size);
455 file->seekg(pos);
456 }
457 if (shdr.sh_name == 0)
458 name = nullptr;
459 else {
460 ElfStrtab_Section *strtab = (ElfStrtab_Section *) parent->getSection(-1);
461 // Special case (see elfgeneric.cpp): if strtab is nullptr, the
462 // section being created is the strtab.
463 if (strtab == nullptr)
464 name = &data[shdr.sh_name];
465 else
466 name = strtab->getStr(shdr.sh_name);
467 }
468 // Only SHT_REL/SHT_RELA sections use sh_info to store a section
469 // number.
470 if ((shdr.sh_type == SHT_REL) || (shdr.sh_type == SHT_RELA))
471 info.section = shdr.sh_info ? parent->getSection(shdr.sh_info) : nullptr;
472 else
473 info.index = shdr.sh_info;
474 }
476 unsigned int ElfSection::getAddr()
477 {
478 if (shdr.sh_addr != (Elf32_Word)-1)
479 return shdr.sh_addr;
481 // It should be safe to adjust sh_addr for all allocated sections that
482 // are neither SHT_NOBITS nor SHT_PROGBITS
483 if ((previous != nullptr) && isRelocatable()) {
484 unsigned int addr = previous->getAddr();
485 if (previous->getType() != SHT_NOBITS)
486 addr += previous->getSize();
488 if (addr & (getAddrAlign() - 1))
489 addr = (addr | (getAddrAlign() - 1)) + 1;
491 return (shdr.sh_addr = addr);
492 }
493 return shdr.sh_addr;
494 }
496 unsigned int ElfSection::getOffset()
497 {
498 if (shdr.sh_offset != (Elf32_Word)-1)
499 return shdr.sh_offset;
501 if (previous == nullptr)
502 return (shdr.sh_offset = 0);
504 unsigned int offset = previous->getOffset();
506 ElfSegment *ptload = getSegmentByType(PT_LOAD);
507 ElfSegment *prev_ptload = previous->getSegmentByType(PT_LOAD);
509 if (ptload && (ptload == prev_ptload)) {
510 offset += getAddr() - previous->getAddr();
511 return (shdr.sh_offset = offset);
512 }
514 if (previous->getType() != SHT_NOBITS)
515 offset += previous->getSize();
517 Elf32_Word align = 0x1000;
518 for (std::vector<ElfSegment *>::iterator seg = segments.begin(); seg != segments.end(); seg++)
519 align = std::max(align, (*seg)->getAlign());
521 Elf32_Word mask = align - 1;
522 // SHF_TLS is used for .tbss which is some kind of special case.
523 if (((getType() != SHT_NOBITS) || (getFlags() & SHF_TLS)) && (getFlags() & SHF_ALLOC)) {
524 if ((getAddr() & mask) < (offset & mask))
525 offset = (offset | mask) + (getAddr() & mask) + 1;
526 else
527 offset = (offset & ~mask) + (getAddr() & mask);
528 }
529 if ((getType() != SHT_NOBITS) && (offset & (getAddrAlign() - 1)))
530 offset = (offset | (getAddrAlign() - 1)) + 1;
532 // Two subsequent sections can't be mapped in the same page in memory
533 // if they aren't in the same 4K block on disk.
534 if ((getType() != SHT_NOBITS) && getAddr()) {
535 if (((offset >> 12) != (previous->getOffset() >> 12)) &&
536 ((getAddr() >> 12) == (previous->getAddr() >> 12)))
537 throw std::runtime_error("Moving section would require overlapping segments");
538 }
540 return (shdr.sh_offset = offset);
541 }
543 int ElfSection::getIndex()
544 {
545 if (index != -1)
546 return index;
547 if (getType() == SHT_NULL)
548 return (index = 0);
549 ElfSection *reference;
550 for (reference = previous; (reference != nullptr) && (reference->getType() == SHT_NULL); reference = reference->getPrevious());
551 if (reference == nullptr)
552 return (index = 1);
553 return (index = reference->getIndex() + 1);
554 }
556 Elf_Shdr &ElfSection::getShdr()
557 {
558 getOffset();
559 if (shdr.sh_link == (Elf32_Word)-1)
560 shdr.sh_link = getLink() ? getLink()->getIndex() : 0;
561 if (shdr.sh_info == (Elf32_Word)-1)
562 shdr.sh_info = ((getType() == SHT_REL) || (getType() == SHT_RELA)) ?
563 (getInfo().section ? getInfo().section->getIndex() : 0) :
564 getInfo().index;
566 return shdr;
567 }
569 ElfSegment::ElfSegment(Elf_Phdr *phdr)
570 : type(phdr->p_type), v_p_diff(phdr->p_paddr - phdr->p_vaddr),
571 flags(phdr->p_flags), align(phdr->p_align), vaddr(phdr->p_vaddr),
572 filesz(phdr->p_filesz), memsz(phdr->p_memsz) {}
574 void ElfSegment::addSection(ElfSection *section)
575 {
576 // Make sure all sections in PT_GNU_RELRO won't be moved by elfhack
577 assert(!((type == PT_GNU_RELRO) && (section->isRelocatable())));
579 //TODO: Check overlapping sections
580 std::list<ElfSection *>::iterator i;
581 for (i = sections.begin(); i != sections.end(); ++i)
582 if ((*i)->getAddr() > section->getAddr())
583 break;
584 sections.insert(i, section);
585 section->addToSegment(this);
586 }
588 void ElfSegment::removeSection(ElfSection *section)
589 {
590 sections.remove(section);
591 section->removeFromSegment(this);
592 }
594 unsigned int ElfSegment::getFileSize()
595 {
596 if (type == PT_GNU_RELRO || isElfHackFillerSegment())
597 return filesz;
599 if (sections.empty())
600 return 0;
601 // Search the last section that is not SHT_NOBITS
602 std::list<ElfSection *>::reverse_iterator i;
603 for (i = sections.rbegin(); (i != sections.rend()) && ((*i)->getType() == SHT_NOBITS); ++i);
604 // All sections are SHT_NOBITS
605 if (i == sections.rend())
606 return 0;
608 unsigned int end = (*i)->getAddr() + (*i)->getSize();
610 return end - sections.front()->getAddr();
611 }
613 unsigned int ElfSegment::getMemSize()
614 {
615 if (type == PT_GNU_RELRO || isElfHackFillerSegment())
616 return memsz;
618 if (sections.empty())
619 return 0;
621 unsigned int end = sections.back()->getAddr() + sections.back()->getSize();
623 return end - sections.front()->getAddr();
624 }
626 unsigned int ElfSegment::getOffset()
627 {
628 if ((type == PT_GNU_RELRO) && !sections.empty() &&
629 (sections.front()->getAddr() != vaddr))
630 throw std::runtime_error("PT_GNU_RELRO segment doesn't start on a section start");
632 // Neither bionic nor glibc linkers seem to like when the offset of that segment is 0
633 if (isElfHackFillerSegment())
634 return vaddr;
636 return sections.empty() ? 0 : sections.front()->getOffset();
637 }
639 unsigned int ElfSegment::getAddr()
640 {
641 if ((type == PT_GNU_RELRO) && !sections.empty() &&
642 (sections.front()->getAddr() != vaddr))
643 throw std::runtime_error("PT_GNU_RELRO segment doesn't start on a section start");
645 if (isElfHackFillerSegment())
646 return vaddr;
648 return sections.empty() ? 0 : sections.front()->getAddr();
649 }
651 void ElfSegment::clear()
652 {
653 for (std::list<ElfSection *>::iterator i = sections.begin(); i != sections.end(); ++i)
654 (*i)->removeFromSegment(this);
655 sections.clear();
656 }
658 ElfValue *ElfDynamic_Section::getValueForType(unsigned int tag)
659 {
660 for (unsigned int i = 0; i < shdr.sh_size / shdr.sh_entsize; i++)
661 if (dyns[i].tag == tag)
662 return dyns[i].value;
664 return nullptr;
665 }
667 ElfSection *ElfDynamic_Section::getSectionForType(unsigned int tag)
668 {
669 ElfValue *value = getValueForType(tag);
670 return value ? value->getSection() : nullptr;
671 }
673 bool ElfDynamic_Section::setValueForType(unsigned int tag, ElfValue *val)
674 {
675 unsigned int i;
676 unsigned int shnum = shdr.sh_size / shdr.sh_entsize;
677 for (i = 0; (i < shnum) && (dyns[i].tag != DT_NULL); i++)
678 if (dyns[i].tag == tag) {
679 delete dyns[i].value;
680 dyns[i].value = val;
681 return true;
682 }
683 // If we get here, this means we didn't match for the given tag
684 // Most of the time, there are a few DT_NULL entries, that we can
685 // use to add our value, but if we are on the last entry, we can't.
686 if (i >= shnum - 1)
687 return false;
689 dyns[i].tag = tag;
690 dyns[i].value = val;
691 return true;
692 }
694 ElfDynamic_Section::ElfDynamic_Section(Elf_Shdr &s, std::ifstream *file, Elf *parent)
695 : ElfSection(s, file, parent)
696 {
697 int pos = file->tellg();
698 dyns.resize(s.sh_size / s.sh_entsize);
699 file->seekg(shdr.sh_offset);
700 // Here we assume tags refer to only one section (e.g. DT_RELSZ accounts
701 // for .rel.dyn size)
702 for (unsigned int i = 0; i < s.sh_size / s.sh_entsize; i++) {
703 Elf_Dyn dyn(*file, parent->getClass(), parent->getData());
704 dyns[i].tag = dyn.d_tag;
705 switch (dyn.d_tag) {
706 case DT_NULL:
707 case DT_SYMBOLIC:
708 case DT_TEXTREL:
709 case DT_BIND_NOW:
710 dyns[i].value = new ElfValue();
711 break;
712 case DT_NEEDED:
713 case DT_SONAME:
714 case DT_RPATH:
715 case DT_PLTREL:
716 case DT_RUNPATH:
717 case DT_FLAGS:
718 case DT_RELACOUNT:
719 case DT_RELCOUNT:
720 case DT_VERDEFNUM:
721 case DT_VERNEEDNUM:
722 dyns[i].value = new ElfPlainValue(dyn.d_un.d_val);
723 break;
724 case DT_PLTGOT:
725 case DT_HASH:
726 case DT_STRTAB:
727 case DT_SYMTAB:
728 case DT_RELA:
729 case DT_INIT:
730 case DT_FINI:
731 case DT_REL:
732 case DT_JMPREL:
733 case DT_INIT_ARRAY:
734 case DT_FINI_ARRAY:
735 case DT_GNU_HASH:
736 case DT_VERSYM:
737 case DT_VERNEED:
738 case DT_VERDEF:
739 dyns[i].value = new ElfLocation(dyn.d_un.d_ptr, parent);
740 break;
741 default:
742 dyns[i].value = nullptr;
743 }
744 }
745 // Another loop to get the section sizes
746 for (unsigned int i = 0; i < s.sh_size / s.sh_entsize; i++)
747 switch (dyns[i].tag) {
748 case DT_PLTRELSZ:
749 dyns[i].value = new ElfSize(getSectionForType(DT_JMPREL));
750 break;
751 case DT_RELASZ:
752 dyns[i].value = new ElfSize(getSectionForType(DT_RELA));
753 break;
754 case DT_STRSZ:
755 dyns[i].value = new ElfSize(getSectionForType(DT_STRTAB));
756 break;
757 case DT_RELSZ:
758 dyns[i].value = new ElfSize(getSectionForType(DT_REL));
759 break;
760 case DT_INIT_ARRAYSZ:
761 dyns[i].value = new ElfSize(getSectionForType(DT_INIT_ARRAY));
762 break;
763 case DT_FINI_ARRAYSZ:
764 dyns[i].value = new ElfSize(getSectionForType(DT_FINI_ARRAY));
765 break;
766 case DT_RELAENT:
767 dyns[i].value = new ElfEntSize(getSectionForType(DT_RELA));
768 break;
769 case DT_SYMENT:
770 dyns[i].value = new ElfEntSize(getSectionForType(DT_SYMTAB));
771 break;
772 case DT_RELENT:
773 dyns[i].value = new ElfEntSize(getSectionForType(DT_REL));
774 break;
775 }
777 file->seekg(pos);
778 }
780 ElfDynamic_Section::~ElfDynamic_Section()
781 {
782 for (unsigned int i = 0; i < shdr.sh_size / shdr.sh_entsize; i++)
783 delete dyns[i].value;
784 }
786 void ElfDynamic_Section::serialize(std::ofstream &file, char ei_class, char ei_data)
787 {
788 for (unsigned int i = 0; i < shdr.sh_size / shdr.sh_entsize; i++) {
789 Elf_Dyn dyn;
790 dyn.d_tag = dyns[i].tag;
791 dyn.d_un.d_val = (dyns[i].value != nullptr) ? dyns[i].value->getValue() : 0;
792 dyn.serialize(file, ei_class, ei_data);
793 }
794 }
796 ElfSymtab_Section::ElfSymtab_Section(Elf_Shdr &s, std::ifstream *file, Elf *parent)
797 : ElfSection(s, file, parent)
798 {
799 int pos = file->tellg();
800 syms.resize(s.sh_size / s.sh_entsize);
801 ElfStrtab_Section *strtab = (ElfStrtab_Section *)getLink();
802 file->seekg(shdr.sh_offset);
803 for (unsigned int i = 0; i < shdr.sh_size / shdr.sh_entsize; i++) {
804 Elf_Sym sym(*file, parent->getClass(), parent->getData());
805 syms[i].name = strtab->getStr(sym.st_name);
806 syms[i].info = sym.st_info;
807 syms[i].other = sym.st_other;
808 ElfSection *section = (sym.st_shndx == SHN_ABS) ? nullptr : parent->getSection(sym.st_shndx);
809 new (&syms[i].value) ElfLocation(section, sym.st_value, ElfLocation::ABSOLUTE);
810 syms[i].size = sym.st_size;
811 syms[i].defined = (sym.st_shndx != SHN_UNDEF);
812 }
813 file->seekg(pos);
814 }
816 void
817 ElfSymtab_Section::serialize(std::ofstream &file, char ei_class, char ei_data)
818 {
819 ElfStrtab_Section *strtab = (ElfStrtab_Section *)getLink();
820 for (unsigned int i = 0; i < shdr.sh_size / shdr.sh_entsize; i++) {
821 Elf_Sym sym;
822 sym.st_name = strtab->getStrIndex(syms[i].name);
823 sym.st_info = syms[i].info;
824 sym.st_other = syms[i].other;
825 sym.st_value = syms[i].value.getValue();
826 ElfSection *section = syms[i].value.getSection();
827 if (syms[i].defined)
828 sym.st_shndx = section ? section->getIndex() : SHN_ABS;
829 else
830 sym.st_shndx = SHN_UNDEF;
831 sym.st_size = syms[i].size;
832 sym.serialize(file, ei_class, ei_data);
833 }
834 }
836 Elf_SymValue *
837 ElfSymtab_Section::lookup(const char *name, unsigned int type_filter)
838 {
839 for (std::vector<Elf_SymValue>::iterator sym = syms.begin();
840 sym != syms.end(); sym++) {
841 if ((type_filter & (1 << ELF32_ST_TYPE(sym->info))) &&
842 (strcmp(sym->name, name) == 0)) {
843 return &*sym;
844 }
845 }
846 return nullptr;
847 }
849 const char *
850 ElfStrtab_Section::getStr(unsigned int index)
851 {
852 for (std::vector<table_storage>::iterator t = table.begin();
853 t != table.end(); t++) {
854 if (index < t->used)
855 return t->buf + index;
856 index -= t->used;
857 }
858 assert(1 == 0);
859 return nullptr;
860 }
862 const char *
863 ElfStrtab_Section::getStr(const char *string)
864 {
865 if (string == nullptr)
866 return nullptr;
868 // If the given string is within the section, return it
869 for (std::vector<table_storage>::iterator t = table.begin();
870 t != table.end(); t++)
871 if ((string >= t->buf) && (string < t->buf + t->used))
872 return string;
874 // TODO: should scan in the section to find an existing string
876 // If not, we need to allocate the string in the section
877 size_t len = strlen(string) + 1;
879 if (table.back().size - table.back().used < len)
880 table.resize(table.size() + 1);
882 char *alloc_str = table.back().buf + table.back().used;
883 memcpy(alloc_str, string, len);
884 table.back().used += len;
886 shdr.sh_size += len;
887 markDirty();
889 return alloc_str;
890 }
892 unsigned int
893 ElfStrtab_Section::getStrIndex(const char *string)
894 {
895 if (string == nullptr)
896 return 0;
898 unsigned int index = 0;
899 string = getStr(string);
900 for (std::vector<table_storage>::iterator t = table.begin();
901 t != table.end(); t++) {
902 if ((string >= t->buf) && (string < t->buf + t->used))
903 return index + (string - t->buf);
904 index += t->used;
905 }
907 assert(1 == 0);
908 return 0;
909 }
911 void
912 ElfStrtab_Section::serialize(std::ofstream &file, char ei_class, char ei_data)
913 {
914 file.seekp(getOffset());
915 for (std::vector<table_storage>::iterator t = table.begin();
916 t != table.end(); t++)
917 file.write(t->buf, t->used);
918 }