1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef ECMASCRIPT_COMPILER_AOT_FILE_ELF_CHECKER_H
17 #define ECMASCRIPT_COMPILER_AOT_FILE_ELF_CHECKER_H
18 
19 #include "ecmascript/compiler/aot_file/aot_file_manager.h"
20 #include "ecmascript/compiler/binary_section.h"
21 #include <fcntl.h>
22 #include <stddef.h>
23 #include <stdint.h>
24 #include <string>
25 #include <unistd.h>
26 
27 #if BYTE_ORDER == LITTLE_ENDIAN
28 #define ELF_BYTEORDER llvm::ELF::ELFDATA2LSB
29 #else
30 #define ELF_BYTEORDER llvm::ELF::ELFDATA2MSB
31 #endif
32 #if (defined __i386__ || defined __x86_64__) && !CHECK_UNDEFINED
33 #define ALLOW_UNALIGNED 1
34 #else
35 #define ALLOW_UNALIGNED 0
36 #endif
37 
38 namespace panda::ecmascript {
39 class ElfChecker {
40 public:
41     enum { ELF_F_MMAPPED = 0x40, ELF_F_MALLOCED = 0x80, ELF_F_FILEDATA = 0x100 };
42 
43     /* Identification values for recognized object files.  */
44     enum ElfKind {
45         ELF_KIND_NONE, /* Unknown.  */
46         ELF_KIND_COFF, /* Stupid old COFF.  */
47         ELF_KIND_ELF, /* ELF file.  */
48         /* Keep this the last entry.  */
49         ELF_KIND_NUM
50     };
51 
52     /* Commands for `...'.  */
53     enum ElfCommand {
54         ELF_CMD_NULL, /* Nothing, terminate, or compute only.  */
55         ELF_CMD_READ, /* Read .. */
56         ELF_CMD_RDWR, /* Read and write .. */
57         ELF_CMD_WRITE, /* Write .. */
58         ELF_CMD_CLR, /* Clear flag.  */
59         ELF_CMD_SET, /* Set flag.  */
60         ELF_CMD_FDDONE, /* Signal that file descriptor will not be
61                  used anymore.  */
62         ELF_CMD_FDREAD, /* Read rest of data so that file descriptor
63                  is not used anymore.  */
64         /* The following are extensions.  */
65         ELF_CMD_READ_MMAP, /* Read, but mmap the file if possible.  */
66         ELF_CMD_RDWR_MMAP, /* Read and write, with mmap.  */
67         ELF_CMD_WRITE_MMAP, /* Write, with mmap.  */
68         ELF_CMD_READ_MMAP_PRIVATE, /* Read, but memory is writable, results are
69                         not written to the file.  */
70         ELF_CMD_EMPTY, /* Copy basic file data but not the content. */
71         /* Keep this the last entry.  */
72         ELF_CMD_NUM
73     };
74 
75     /* Known translation types.  */
76     enum ElfType {
77         ELF_TYPE_BYTE, /* unsigned char */
78         ELF_TYPE_ADDR, /* Elf32_Addr, Elf64_Addr, ... */
79         ELF_TYPE_DYN, /* Dynamic section record.  */
80         ELF_TYPE_EHDR, /* ELF header.  */
81         ELF_TYPE_HALF, /* Elf32_Half, Elf64_Half, ... */
82         ELF_TYPE_OFF, /* Elf32_Off, Elf64_Off, ... */
83         ELF_TYPE_PHDR, /* Program header.  */
84         ELF_TYPE_RELA, /* Relocation entry with addend.  */
85         ELF_TYPE_REL, /* Relocation entry.  */
86         ELF_TYPE_SHDR, /* Section header.  */
87         ELF_TYPE_SWORD, /* Elf32_Sword, Elf64_Sword, ... */
88         ELF_TYPE_SYM, /* Symbol record.  */
89         ELF_TYPE_WORD, /* Elf32_Word, Elf64_Word, ... */
90         ELF_TYPE_XWORD, /* Elf32_Xword, Elf64_Xword, ... */
91         ELF_TYPE_SXWORD, /* Elf32_Sxword, Elf64_Sxword, ... */
92         ELF_TYPE_VDEF, /* Elf32_Verdef, Elf64_Verdef, ... */
93         ELF_TYPE_VDAUX, /* Elf32_Verdaux, Elf64_Verdaux, ... */
94         ELF_TYPE_VNEED, /* Elf32_Verneed, Elf64_Verneed, ... */
95         ELF_TYPE_VNAUX, /* Elf32_Vernaux, Elf64_Vernaux, ... */
96         ELF_TYPE_NHDR, /* Elf32_Nhdr, Elf64_Nhdr, ... */
97         ELF_TYPE_SYMINFO, /* Elf32_Syminfo, Elf64_Syminfo, ... */
98         ELF_TYPE_MOVE, /* Elf32_Move, Elf64_Move, ... */
99         ELF_TYPE_LIB, /* Elf32_Lib, Elf64_Lib, ... */
100         ELF_TYPE_GNUHASH, /* GNU-style hash section.  */
101         ELF_TYPE_AUXV, /* Elf32_auxv_t, Elf64_auxv_t, ... */
102         ELF_TYPE_CHDR, /* Compressed, Elf32_Chdr, Elf64_Chdr, ... */
103         ELF_TYPE_NHDR8, /* Special GNU Properties note.  Same as Nhdr,
104                 except padding.  */
105         /* Keep this the last entry.  */
106         ELF_TYPE_NUM
107     };
108 
109     /* Error values.  */
110     enum {
111         ELF_ERR_NOERROR = 0,
112         ELF_ERR_UNKNOWN_ERROR,
113         ELF_ERR_UNKNOWN_VERSION,
114         ELF_ERR_UNKNOWN_TYPE,
115         ELF_ERR_INVALID_HANDLE,
116         ELF_ERR_SOURCE_SIZE,
117         ELF_ERR_DEST_SIZE,
118         ELF_ERR_INVALID_ENCODING,
119         ELF_ERR_NOMEM,
120         ELF_ERR_INVALID_FILE,
121         ELF_ERR_INVALID_ELF,
122         ELF_ERR_INVALID_OP,
123         ELF_ERR_NO_VERSION,
124         ELF_ERR_INVALID_CMD,
125         ELF_ERR_RANGE,
126         ELF_ERR_ARCHIVE_FMAG,
127         ELF_ERR_INVALID_ARCHIVE,
128         ELF_ERR_NO_ARCHIVE,
129         ELF_ERR_NO_INDEX,
130         ELF_ERR_READ_ERROR,
131         ELF_ERR_WRITE_ERROR,
132         ELF_ERR_INVALID_CLASS,
133         ELF_ERR_INVALID_INDEX,
134         ELF_ERR_INVALID_OPERAND,
135         ELF_ERR_INVALID_SECTION,
136         ELF_ERR_INVALID_COMMAND,
137         ELF_ERR_WRONG_ORDER_EHDR,
138         ELF_ERR_FD_DISABLED,
139         ELF_ERR_FD_MISMATCH,
140         ELF_ERR_OFFSET_RANGE,
141         ELF_ERR_NOT_NUL_SECTION,
142         ELF_ERR_DATA_MISMATCH,
143         ELF_ERR_INVALID_SECTION_HEADER,
144         ELF_ERR_INVALID_DATA,
145         ELF_ERR_DATA_ENCODING,
146         ELF_ERR_SECTION_TOO_SMALL,
147         ELF_ERR_INVALID_ALIGN,
148         ELF_ERR_INVALID_SHENTSIZE,
149         ELF_ERR_UPDATE_RO,
150         ELF_ERR_NOFILE,
151         ELF_ERR_GROUP_NOT_REL,
152         ELF_ERR_INVALID_PHDR,
153         ELF_ERR_NO_PHDR,
154         ELF_ERR_INVALID_OFFSET,
155         ELF_ERR_INVALID_SECTION_TYPE,
156         ELF_ERR_INVALID_SECTION_FLAGS,
157         ELF_ERR_NOT_COMPRESSED,
158         ELF_ERR_ALREADY_COMPRESSED,
159         ELF_ERR_UNKNOWN_COMPRESSION_TYPE,
160         ELF_ERR_COMPRESS_ERROR,
161         ELF_ERR_DECOMPRESS_ERROR,
162         /* Keep this as the last entry.  */
163         ELF_ERR_NUM
164     };
165 
166     /* Descriptor for data to be converted to or from memory format.  */
167     struct ElfData {
168         void* dataBuffer; /* Pointer to the actual data.  */
169         ElfType dataType; /* Type of this piece of data.  */
170         unsigned int dataVersion; /* ELF version.  */
171         size_t dataSize; /* Size in bytes.  */
172         int64_t sectionOffset; /* Offset into section.  */
173         size_t sectionAlignment; /* Alignment in section.  */
174     };
175 
176     struct ElfSectionBase;
177     struct ElfSectionList;
178     struct Elf;
179 
180     /* The visible `ElfData' type is not sufficient for some operations due
181        to a misdesigned interface.  Extend it for internal purposes.  */
182     struct ElfSectionData {
183         ElfData data;
184         ElfSectionBase* sectionPtr;
185     };
186 
187     /* List of `ElfData' descriptors.  This is what makes up the section
188        contents.  */
189     struct ElfDataList {
190         /* `data' *must* be the first element in the struct.  */
191         ElfSectionData data;
192         struct ElfDataList* next;
193         int flags;
194     };
195 
196     /* Descriptor for ELF section.  */
197     struct ElfSectionBase {
198         /* Describe for elf sections */
199         ElfDataList dataList; /* List of data buffers.  */
200         ElfDataList* dataListRear; /* Pointer to the rear of the data list. */
201 
202         ElfSectionData rawData; /* Uninterpreted data of the section.  */
203 
204         int dataRead; /* Nonzero if the section was created by the
205                       user or if the data from the file/memory
206                       is read.  */
207         int extendSectionHeaderIndex; /* Index of the extended section index
208                   table for this symbol table (if this
209                   section is a symbol table).  */
210 
211         size_t index; /* Index of this section.  */
212         struct Elf* elf; /* The underlying ELF file.  */
213 
214         union {
215             llvm::ELF::Elf32_Shdr* e32; /* Pointer to 32bit section header.  */
216             llvm::ELF::Elf64_Shdr* e64; /* Pointer to 64bit section header.  */
217         } shdr;
218 
219         unsigned int sectionHeaderFlags; /* Section header modified?  */
220         unsigned int flags; /* Section changed in size? */
221 
222         char* rawDataBase; /* The unmodified data of the section.  */
223         char* dataBase; /* The converted data of the section.  */
224 
225         char* zipDataBase; /* The uncompressed data of the section.  */
226         size_t zipDataSize; /* If zipDataBase != NULL, the size of data.  */
227         size_t zipDataAlign; /* If zipDataBase != NULL, the addralign.  */
228 
229         ElfSectionList* list; /* Pointer to the section list element the
230                          data is in.  */
231     };
232 
233     /* List of section.  */
234     struct ElfSectionList {
235         unsigned int cnt; /* Number of elements of 'data' used.  */
236         unsigned int max; /* Number of elements of 'data' allocated.  */
237         struct ElfSectionList* next; /* Next block of sections.  */
datapanda::ecmascript::ElfChecker::ElfSectionList238         ElfSectionBase* data()
239         {
240             return reinterpret_cast<ElfSectionBase*>(reinterpret_cast<char*>(this) + sizeof(ElfSectionList));
241         }
242     };
243 
244     /* elf_getdata_rawchunk result.  */
245     struct ElfDataChunk {
246         ElfSectionData data;
247         union {
248             ElfSectionBase dummySection;
249             struct ElfDataChunk* next;
250         };
251         int64_t offset; /* The original raw offset in the Elf image.  */
252     };
253 
254     struct Elf {
255         /* Address to which the file was mapped.  NULL if not mapped.  */
256         void* mapAddress;
257 
258         /* When created for an archive member this points to the descriptor
259            for the archive. */
260         Elf* parent;
261         Elf* next; /* Used in list of archive descriptors.  */
262 
263         /* What kind of file is underneath (ELF file, archive...).  */
264         ElfKind kind;
265 
266         /* Command used to create this descriptor.  */
267         ElfCommand cmd;
268 
269         /* The binary class.  */
270         unsigned int binaryClass;
271 
272         /* The used file descriptor.  -1 if not available anymore.  */
273         int fildes;
274 
275         /* Offset in the archive this file starts or zero.  */
276         int64_t startOffset;
277 
278         /* Size of the file in the archive or the entire file size, or ~0
279            for an (yet) unknown size.  */
280         size_t maxSize;
281 
282         /* Describes the way the memory was allocated and if the dirty bit is
283            signalled it means that the whole file has to be rewritten since
284            the layout changed.  */
285         int flags;
286 
287         /* Reference counting for the descriptor.  */
288         int refCount;
289 
290         union {
291             struct {
292                 void* elfHeaderPtr;
293                 void* secHeaderPtr;
294                 void* proHeaderPtr;
295 
296                 ElfSectionList* sectionLast; /* Last element in the section list.
297                              If NULL the data has not yet been
298                              read from the file.  */
299                 ElfDataChunk* rawChunks; /* List of elf_getdata_rawchunk results.  */
300                 unsigned int scnincr; /* Number of sections allocate the last
301                              time.  */
302                 int elfHeaderFlags; /* Flags (dirty) for ELF header.  */
303                 int progHeaderFlags; /* Flags (dirty|malloc) for program header.  */
304                 int secHeaderMalloced; /* Nonzero if shdr array was allocated.  */
305                 off_t sizeStrOffset; /* Offset of the size string in the parent
306                              if this is an archive member.  */
307             } elf;
308 
309             struct {
310                 llvm::ELF::Elf32_Ehdr* ehdr; /* Pointer to the ELF header.  This is
311                        never malloced.  */
312                 llvm::ELF::Elf32_Shdr* shdr; /* Used when reading from a file.  */
313                 llvm::ELF::Elf32_Phdr* phdr; /* Pointer to the program header array.  */
314                 ElfSectionList* sectionLast; /* Last element in the section list.
315                              If NULL the data has not yet been
316                              read from the file.  */
317                 ElfDataChunk* rawChunks; /* List of elf_getdata_rawchunk results.  */
318                 unsigned int scnincr; /* Number of sections allocate the last
319                              time.  */
320                 int elfHeaderFlags; /* Flags (dirty) for ELF header.  */
321                 int progHeaderFlags; /* Flags (dirty|malloc) for program header.  */
322                 int secHeaderMalloced; /* Nonzero if shdr array was allocated.  */
323                 int64_t sizeStrOffset; /* Offset of the size string in the parent
324                              if this is an archive member.  */
325                 llvm::ELF::Elf32_Ehdr elfHeaderMem; /* Memory used for ELF header when
326                             not mmaped.  */
327                 char fillToAlign[sizeof(llvm::ELF::Elf64_Ehdr) - sizeof(llvm::ELF::Elf32_Ehdr)];
328 
329                 /* The section array.  */
330                 ElfSectionList sections;
331             } elf32;
332 
333             struct {
334                 llvm::ELF::Elf64_Ehdr* ehdr; /* Pointer to the ELF header.  This is
335                        never malloced.  */
336                 llvm::ELF::Elf64_Shdr* shdr; /* Used when reading from a file.  */
337                 llvm::ELF::Elf64_Phdr* phdr; /* Pointer to the program header array.  */
338                 ElfSectionList* sectionLast; /* Last element in the section list.
339                              If NULL the data has not yet been
340                              read from the file.  */
341                 ElfDataChunk* rawChunks; /* List of elf_getdata_rawchunk results.  */
342                 unsigned int scnincr; /* Number of sections allocate the last
343                              time.  */
344                 int elfHeaderFlags; /* Flags (dirty) for ELF header.  */
345                 int progHeaderFlags; /* Flags (dirty|malloc) for program header.  */
346                 int secHeaderMalloced; /* Nonzero if shdr array was allocated.  */
347                 int64_t sizeStrOffset; /* Offset of the size string in the parent
348                              if this is an archive member.  */
349                 llvm::ELF::Elf64_Ehdr elfHeaderMem; /* Memory used for ELF header when
350                             not mmaped.  */
351 
352                 /* The section array.  */
353                 ElfSectionList sections;
354             } elf64;
355         } state;
356 
357         /* There absolutely never must be anything following the union.  */
358     };
359 
360     ElfChecker() = delete;
361     ElfChecker(const ElfChecker&) = delete;
362     explicit ElfChecker(const void* data, int len);
363     explicit ElfChecker(const std::string&);
364     explicit ElfChecker(const MemMap&);
365     ~ElfChecker();
366     bool CheckValidElf();
367 
368 private:
369     int CheckIfError(void) const;
370     void SetErrorCode(int value);
371 
372     Elf* ElfAllocate(
373         void* map_address, int64_t offset, size_t maxsize, ElfCommand cmd, Elf* parent, ElfKind kind, size_t extra);
374 
375     ElfKind GetElfKind(void* buf) const;
376 
377     template <typename FromElfHeader, typename FromElfSectionHeader, typename SizeType>
378     size_t GetSectionHeaderNum(
379         FromElfHeader* ehdr, size_t maxsize, unsigned char* eIdent, void* mapAddress, int64_t offset);
380     size_t GetShnum(void* map_address, unsigned char* e_ident, int64_t offset, size_t maxsize);
381     /* Create descriptor for ELF file in memory.  */
382     template <typename ElfEhdr, typename ElfShdr, typename ElfItemField>
383     Elf* GetElfItem(ElfItemField& elfItemField, void* mapAddress, unsigned char* eIdent, int64_t offset, size_t maxSize,
384         ElfCommand cmd, size_t scnCnt, Elf* elf);
385     Elf* FileReadElf(
386         void* map_address, unsigned char* e_ident, int64_t offset, size_t maxsize, ElfCommand cmd, Elf* parent);
387     Elf* ReadMmapedFile(void* map_address, int64_t offset, size_t maxsize, ElfCommand cmd, Elf* parent);
388     Elf* ElfMemory(char* image, size_t size);
389     int ElfRelease(Elf* elf) const;
390     char* elfData_;
391     size_t elfLen_;
392     int elfErrorCode_ { 0 };
393     const bool fromMmap_ { false };
394 };
395 } // namespace panda::ecmascript
396 #endif // ECMASCRIPT_COMPILER_AOT_FILE_ELF_CHECKER_H
397