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
38namespace panda::ecmascript {
39class ElfChecker {
40public:
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.  */
238        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
368private:
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