1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #pragma once
18 
19 #include <sys/types.h>
20 #include <string>
21 #include <vector>
22 
23 #include <android-base/logging.h>
24 #include <elf.h>
25 
26 namespace android {
27 namespace elf64 {
28 
29 // Section content representation
30 typedef struct {
31     std::vector<char> data;   // Raw content of the data section.
32     uint64_t size;   // Size of the data section.
33     std::string name;      // The name of the section.
34     uint16_t index;  // Index of the section.
35 } Elf64_Sc;
36 
37 // Class to represent an ELF64 binary.
38 //
39 // An ELF binary is formed by 4 parts:
40 //
41 // - Executable header.
42 // - Program headers (present in executables or shared libraries).
43 // - Sections (.interp, .init, .plt, .text, .rodata, .data, .bss, .shstrtab, etc).
44 // - Section headers.
45 //
46 //                ______________________
47 //                |                    |
48 //                | Executable header  |
49 //                |____________________|
50 //                |                    |
51 //                |                    |
52 //                |  Program headers   |
53 //                |                    |
54 //                |____________________|
55 //                |                    |
56 //                |                    |
57 //                |      Sections      |
58 //                |                    |
59 //                |____________________|
60 //                |                    |
61 //                |                    |
62 //                |  Section headers   |
63 //                |                    |
64 //                |____________________|
65 //
66 //
67 // The structs defined in linux for ELF parts can be found in:
68 //
69 //   - /usr/include/elf.h.
70 //   - https://elixir.bootlin.com/linux/v5.14.21/source/include/uapi/linux/elf.h#L222
71 class Elf64Binary {
72   public:
73     Elf64_Ehdr ehdr;
74     std::vector<Elf64_Phdr> phdrs;
75     std::vector<Elf64_Shdr> shdrs;
76     std::vector<Elf64_Sc> sections;
77     std::string path;
78 
IsElf64()79     bool IsElf64() { return ehdr.e_ident[EI_CLASS] == ELFCLASS64; }
80 
81     // Returns the index of the dynamic section header if found,
82     // otherwise it returns -1.
83     //
84     // Note: The dynamic section can be identified by:
85     //
86     //   - the section header with name .dynamic
87     //   - the section header type SHT_DYNAMIC
GetDynamicSectionIndex()88     int GetDynamicSectionIndex() {
89         for (int i = 0; i < shdrs.size(); i++) {
90             if (shdrs.at(i).sh_type == SHT_DYNAMIC) {
91                 return i;
92             }
93         }
94 
95         return -1;
96     }
97 
98     // Populate dynEntries with the entries in the .dynamic section.
AppendDynamicEntries(std::vector<Elf64_Dyn> * dynEntries)99     void AppendDynamicEntries(std::vector<Elf64_Dyn>* dynEntries) {
100         int idx = GetDynamicSectionIndex();
101 
102         if (idx == -1) {
103             return;
104         }
105 
106         Elf64_Dyn* dynPtr = (Elf64_Dyn*)sections.at(idx).data.data();
107         int numEntries = sections.at(idx).data.size() / sizeof(*dynPtr);
108 
109         for (int j = 0; j < numEntries; j++) {
110             Elf64_Dyn dynEntry;
111             memcpy(&dynEntry, dynPtr, sizeof(*dynPtr));
112             dynPtr++;
113 
114             dynEntries->push_back(dynEntry);
115         }
116     }
117 
118     // Set the dynEntries in the .dynamic section.
SetDynamicEntries(const std::vector<Elf64_Dyn> * dynEntries)119     void SetDynamicEntries(const std::vector<Elf64_Dyn>* dynEntries) {
120         int idx = GetDynamicSectionIndex();
121 
122         if (idx == -1) {
123             return;
124         }
125 
126         Elf64_Dyn* dynPtr = (Elf64_Dyn*)sections.at(idx).data.data();
127         int numEntries = sections.at(idx).data.size() / sizeof(*dynPtr);
128 
129         for (int j = 0; j < dynEntries->size() && j < numEntries; j++) {
130             memcpy(dynPtr, &dynEntries->at(j), sizeof(*dynPtr));
131             dynPtr++;
132         }
133     }
134 
135     // Returns the string at the given offset in the dynamic string table.
136     // If .dynamic or .dynstr sections are not found, it returns an empty string.
137     // If the offset is invalid, it returns an empty  string.
GetStrFromDynStrTable(Elf64_Xword offset)138     std::string GetStrFromDynStrTable(Elf64_Xword offset) {
139         int idx = GetDynamicSectionIndex();
140 
141         if (idx == -1) {
142             return "";
143         }
144 
145         // Get the index of the string table .dynstr.
146         Elf64_Word dynStrIdx = shdrs.at(idx).sh_link;
147         if (offset >= sections.at(dynStrIdx).data.size()) {
148             return "";
149         }
150 
151         char* st = sections.at(dynStrIdx).data.data();
152 
153         CHECK_NE(nullptr, memchr(&st[offset], 0, sections.at(dynStrIdx).data.size() - offset));
154         return &st[offset];
155     }
156 };
157 
158 }  // namespace elf64
159 }  // namespace android
160