Bug-fix: fix target dll searching logic
[platform/core/dotnet/launcher.git] / NativeLauncher / tool / r2r_checker.cc
1 /*
2  * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
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 #include <fcntl.h>
18 #include <unistd.h>
19 #include <stdio.h>
20 #include <sys/mman.h>
21 #include <sys/stat.h>
22
23 #include <pal.h>
24 #include <pal_endian.h>
25 #include <ntimage.h>
26
27 #include <inc/corhdr.h>
28 #include <inc/readytorun.h>
29
30 #include <log.h>
31 #include <r2r_checker.h>
32
33 static inline UINT AlignUp(UINT value, UINT alignment)
34 {
35         return (value + alignment - 1) & ~(alignment - 1);
36 }
37
38 static inline UINT64 AlignUp(UINT64 value, UINT alignment)
39 {
40         return (value + alignment - 1)& ~(UINT64)(alignment - 1);
41 }
42
43 static IMAGE_NT_HEADERS* getNTHeaders(void* pAddr)
44 {
45         IMAGE_DOS_HEADER* pDOS = (IMAGE_DOS_HEADER*)pAddr;
46         if (pDOS->e_magic != VAL16(IMAGE_DOS_SIGNATURE)) return NULL;
47
48         return (IMAGE_NT_HEADERS*)((ULONG_PTR)pAddr + VAL32(pDOS->e_lfanew));
49 }
50
51 static IMAGE_DATA_DIRECTORY* getCorDirectoryEntry(IMAGE_NT_HEADERS* pNTHeaders)
52 {
53         IMAGE_DATA_DIRECTORY* pDir = NULL;
54         if (pNTHeaders->OptionalHeader.Magic == VAL16(IMAGE_NT_OPTIONAL_HDR32_MAGIC)) {
55                 pDir = (IMAGE_DATA_DIRECTORY*)((ULONG_PTR)(pNTHeaders)
56                                 + offsetof(IMAGE_NT_HEADERS32, OptionalHeader.DataDirectory)
57                                 + IMAGE_DIRECTORY_ENTRY_COMHEADER * sizeof(IMAGE_DATA_DIRECTORY));
58         } else if (pNTHeaders->OptionalHeader.Magic == VAL16(IMAGE_NT_OPTIONAL_HDR64_MAGIC)) {
59                 pDir = (IMAGE_DATA_DIRECTORY*)((ULONG_PTR)(pNTHeaders)
60                                 + offsetof(IMAGE_NT_HEADERS64, OptionalHeader.DataDirectory)
61                                 + IMAGE_DIRECTORY_ENTRY_COMHEADER * sizeof(IMAGE_DATA_DIRECTORY));
62         } else {
63                 _SERR("Invalid Optional Header Magic Number: 0x%x", VAL16(pNTHeaders->OptionalHeader.Magic));
64         }
65
66         return pDir;
67 }
68
69 static IMAGE_SECTION_HEADER* findFirstSection(IMAGE_NT_HEADERS* pNTHeaders)
70 {
71         return (IMAGE_SECTION_HEADER*)(
72                         (ULONG_PTR)(pNTHeaders) +
73                         offsetof(IMAGE_NT_HEADERS, OptionalHeader) +
74                         VAL16(pNTHeaders->FileHeader.SizeOfOptionalHeader));
75 }
76
77 static IMAGE_SECTION_HEADER* getSection(IMAGE_NT_HEADERS* pNTHeaders, UINT rva) {
78         IMAGE_SECTION_HEADER* section = (IMAGE_SECTION_HEADER*)(findFirstSection(pNTHeaders));
79         IMAGE_SECTION_HEADER* sectionEnd = section + VAL16(pNTHeaders->FileHeader.NumberOfSections);
80         while (section < sectionEnd) {
81                 if (rva < (VAL32(section->VirtualAddress)
82                                         + AlignUp((UINT)VAL32(section->Misc.VirtualSize), (UINT)VAL32(pNTHeaders->OptionalHeader.SectionAlignment)))) {
83                         if (rva < VAL32(section->VirtualAddress)) {
84                                 return NULL;
85                         } else {
86                                 return section;
87                         }
88                 }
89                 section++;
90         }
91
92         return NULL;
93 }
94
95 static ULONG_PTR getDirectoryData(void* pBaseAddr, IMAGE_NT_HEADERS* pNTHeaders, IMAGE_DATA_DIRECTORY* pDir) {
96         UINT rva = pDir->VirtualAddress;
97         if (rva == 0) {
98                 return 0;
99         }
100
101         IMAGE_SECTION_HEADER* section = getSection(pNTHeaders, rva);
102         if (!section) {
103                 return 0;
104         }
105
106         return (ULONG_PTR)pBaseAddr + rva - VAL32(section->VirtualAddress) + VAL32(section->PointerToRawData);
107 }
108
109 static bool hasValidR2RHeader(void* pAddr)
110 {
111         IMAGE_NT_HEADERS* pNTHeaders = getNTHeaders(pAddr);
112         if (!pNTHeaders) {
113                 return false;
114         }
115
116         IMAGE_DATA_DIRECTORY* pCorDir = getCorDirectoryEntry(pNTHeaders);
117         if (!pCorDir) {
118                 return false;
119         }
120
121         IMAGE_COR20_HEADER* pCor = (IMAGE_COR20_HEADER*)getDirectoryData(pAddr, pNTHeaders, pCorDir);
122         if (!pCor) {
123                 return false;
124         }
125
126         IMAGE_DATA_DIRECTORY* pR2RDir = &pCor->ManagedNativeHeader;
127         if (VAL32(pR2RDir->Size) >= sizeof(READYTORUN_HEADER)) {
128                 READYTORUN_HEADER* pR2RHeader = (READYTORUN_HEADER*)getDirectoryData(pAddr, pNTHeaders, pR2RDir);
129                 if (!pR2RHeader) {
130                         return false;
131                 }
132
133                 if (pR2RHeader->Signature != VAL16(READYTORUN_SIGNATURE)) {
134                         return false;
135                 }
136                 return true;
137         }
138         return false;
139 }
140
141 bool isR2RImage(const std::string& fileName)
142 {
143         int fd;
144         struct stat sb;
145         if ((fd = open(fileName.c_str(), O_RDONLY)) == -1) {
146                 return false;
147         }
148
149         if (fstat(fd, &sb) == -1) {
150                 close(fd);
151                 return false;
152         }
153
154         void* pAddr = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
155         if (pAddr == MAP_FAILED) {
156                 close(fd);
157                 return false;
158         }
159
160         bool ret = hasValidR2RHeader(pAddr);
161
162         munmap(pAddr, sb.st_size);
163         close(fd);
164         return ret;
165 }
166
167 unsigned int getSizeOfImage(const std::string& fileName)
168 {
169         int fd;
170         struct stat sb;
171         if ((fd = open(fileName.c_str(), O_RDONLY)) == -1) {
172                 return 0;
173         }
174
175         if (fstat(fd, &sb) == -1) {
176                 close(fd);
177                 return 0;
178         }
179
180         void* pAddr = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
181         if (pAddr == MAP_FAILED) {
182                 close(fd);
183                 return 0;
184         }
185
186         IMAGE_NT_HEADERS* pNTHeaders = getNTHeaders(pAddr);
187         if (!pNTHeaders) {
188                 munmap(pAddr, sb.st_size);
189                 close(fd);
190                 return 0;
191         }
192
193         // typedef unsigned int ULONG;
194         unsigned int ret = pNTHeaders->OptionalHeader.SizeOfImage;
195
196         munmap(pAddr, sb.st_size);
197         close(fd);
198         return ret;
199 }