Add r2r checker (#355)
author정동헌/Common Platform Lab(SR)/Principal Engineer/삼성전자 <dheon.jung@samsung.com>
Thu, 16 Dec 2021 01:03:42 +0000 (10:03 +0900)
committerGitHub Enterprise <noreply-CODE@samsung.com>
Thu, 16 Dec 2021 01:03:42 +0000 (10:03 +0900)
* Add r2r checker

Implement a function to Identify a file is R2R image or not.
```isR2RImage(std::stringfileName)```

* Add missed endian conversion

* Add some error print codes

* Update error logs and a function name

* Update checked based on CLR headers

Co-authored-by: Dong-Heon Jung <clamp03@gmail.com>
NativeLauncher/CMakeLists.txt
NativeLauncher/inc/r2r_checker.h [new file with mode: 0644]
NativeLauncher/tool/ni_common.cc
NativeLauncher/tool/r2r_checker.cc [new file with mode: 0644]
packaging/dotnet-launcher.spec

index 58705d0..cba9252 100644 (file)
@@ -73,6 +73,8 @@ ENDIF(DEFINED DEFAULT_BASE_ADDR_START)
 
 ADD_DEFINITIONS(-DLOADERDIR="${LOADERDIR}")
 
+ADD_DEFINITIONS(-DPAL_STDCPP_COMPAT)
+
 OPTION(NOT_USE_FUNCTION "Remove build warning" OFF)
 IF(NOT_USE_FUNCTION)
     ADD_DEFINITIONS("-DNOT_USE_FUNCTION")
@@ -189,9 +191,11 @@ TARGET_LINK_LIBRARIES(${TAC_COMMON} ${${PROJECT_NAME}_LDFLAGS} ${DOTNET_LAUNCHER
 SET(NI_COMMON "ni_common")
 SET(${NI_COMMON}_SOURCE_FILES
     tool/ni_common.cc
+    tool/r2r_checker.cc
 )
 ADD_LIBRARY(${NI_COMMON} SHARED ${${NI_COMMON}_SOURCE_FILES})
 SET_TARGET_PROPERTIES(${NI_COMMON} PROPERTIES COMPILE_FLAGS ${EXTRA_CFLAGS_LIB})
+TARGET_INCLUDE_DIRECTORIES(${NI_COMMON} PRIVATE ${RUNTIME_DIR}/src/ ${RUNTIME_DIR}/src/pal ${RUNTIME_DIR}/src/pal/inc ${RUNTIME_DIR}/src/pal/inc/rt)
 TARGET_LINK_LIBRARIES(${NI_COMMON} ${${PROJECT_NAME}_LDFLAGS} ${DOTNET_LAUNCHER_UTIL} ${TAC_COMMON})
 
 SET(MULTI_TARGET_RESOLVER "multi_target_resolver")
diff --git a/NativeLauncher/inc/r2r_checker.h b/NativeLauncher/inc/r2r_checker.h
new file mode 100644 (file)
index 0000000..7c74548
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __R2R_CHECKER_H__
+#define __R2R_CHECKER_H__
+
+#include <string>
+
+bool isR2RImage(std::string fileName);
+
+#endif /* __R2R_CHECKER_H__ */
index 5ed08c8..5f1487e 100644 (file)
@@ -45,6 +45,7 @@
 #include "tac_common.h"
 #include "path_manager.h"
 #include "plugin_manager.h"
+#include "r2r_checker.h"
 
 #ifdef  LOG_TAG
 #undef  LOG_TAG
diff --git a/NativeLauncher/tool/r2r_checker.cc b/NativeLauncher/tool/r2r_checker.cc
new file mode 100644 (file)
index 0000000..c5b5b63
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+
+#include <pal.h>
+#include <pal_endian.h>
+#include <ntimage.h>
+
+#include <inc/corhdr.h>
+#include <inc/readytorun.h>
+
+#include <log.h>
+#include <r2r_checker.h>
+
+static inline UINT AlignUp(UINT value, UINT alignment)
+{
+       return (value + alignment - 1) & ~(alignment - 1);
+}
+
+static inline UINT64 AlignUp(UINT64 value, UINT alignment)
+{
+       return (value + alignment - 1)& ~(UINT64)(alignment - 1);
+}
+
+static IMAGE_NT_HEADERS* getNTHeaders(void* pAddr)
+{
+       IMAGE_DOS_HEADER* pDOS = (IMAGE_DOS_HEADER*)pAddr;
+       if (pDOS->e_magic != VAL16(IMAGE_DOS_SIGNATURE)) return NULL;
+
+       return (IMAGE_NT_HEADERS*)((ULONG_PTR)pAddr + VAL32(pDOS->e_lfanew));
+}
+
+static IMAGE_DATA_DIRECTORY* getCorDirectoryEntry(IMAGE_NT_HEADERS* pNTHeaders)
+{
+       IMAGE_DATA_DIRECTORY* pDir = NULL;
+       if (pNTHeaders->OptionalHeader.Magic == VAL16(IMAGE_NT_OPTIONAL_HDR32_MAGIC)) {
+               pDir = (IMAGE_DATA_DIRECTORY*)((ULONG_PTR)(pNTHeaders)
+                               + offsetof(IMAGE_NT_HEADERS32, OptionalHeader.DataDirectory)
+                               + IMAGE_DIRECTORY_ENTRY_COMHEADER * sizeof(IMAGE_DATA_DIRECTORY));
+       } else if (pNTHeaders->OptionalHeader.Magic == VAL16(IMAGE_NT_OPTIONAL_HDR64_MAGIC)) {
+               pDir = (IMAGE_DATA_DIRECTORY*)((ULONG_PTR)(pNTHeaders)
+                               + offsetof(IMAGE_NT_HEADERS64, OptionalHeader.DataDirectory)
+                               + IMAGE_DIRECTORY_ENTRY_COMHEADER * sizeof(IMAGE_DATA_DIRECTORY));
+       } else {
+               _SERR("Invalid Optional Header Magic Number: 0x%x", VAL16(pNTHeaders->OptionalHeader.Magic));
+       }
+
+       return pDir;
+}
+
+static IMAGE_SECTION_HEADER* findFirstSection(IMAGE_NT_HEADERS* pNTHeaders)
+{
+       return (IMAGE_SECTION_HEADER*)(
+                       (ULONG_PTR)(pNTHeaders) +
+                       offsetof(IMAGE_NT_HEADERS, OptionalHeader) +
+                       VAL16(pNTHeaders->FileHeader.SizeOfOptionalHeader));
+}
+
+static IMAGE_SECTION_HEADER* getSection(IMAGE_NT_HEADERS* pNTHeaders, UINT rva) {
+       IMAGE_SECTION_HEADER* section = (IMAGE_SECTION_HEADER*)(findFirstSection(pNTHeaders));
+       IMAGE_SECTION_HEADER* sectionEnd = section + VAL16(pNTHeaders->FileHeader.NumberOfSections);
+       while (section < sectionEnd) {
+               if (rva < (VAL32(section->VirtualAddress)
+                                       + AlignUp((UINT)VAL32(section->Misc.VirtualSize), (UINT)VAL32(pNTHeaders->OptionalHeader.SectionAlignment)))) {
+                       if (rva < VAL32(section->VirtualAddress)) {
+                               return NULL;
+                       } else {
+                               return section;
+                       }
+               }
+               section++;
+       }
+
+       return NULL;
+}
+
+static ULONG_PTR getDirectoryData(void* pBaseAddr, IMAGE_NT_HEADERS* pNTHeaders, IMAGE_DATA_DIRECTORY* pDir) {
+       UINT rva = pDir->VirtualAddress;
+       if (rva == 0) {
+               return 0;
+       }
+
+       IMAGE_SECTION_HEADER* section = getSection(pNTHeaders, rva);
+       if (!section) {
+               return 0;
+       }
+
+       return (ULONG_PTR)pBaseAddr + rva - VAL32(section->VirtualAddress) + VAL32(section->PointerToRawData);
+}
+
+static bool hasValidR2RHeader(void* pAddr)
+{
+       IMAGE_NT_HEADERS* pNTHeaders = getNTHeaders(pAddr);
+       if (!pNTHeaders) {
+               _SERR("Invalid NT Header");
+               return false;
+       }
+
+       IMAGE_DATA_DIRECTORY* pCorDir = getCorDirectoryEntry(pNTHeaders);
+       if (!pCorDir) {
+               _SERR("Invalid Cor Data Directory");
+               return false;
+       }
+
+       IMAGE_COR20_HEADER* pCor = (IMAGE_COR20_HEADER*)getDirectoryData(pAddr, pNTHeaders, pCorDir);
+       if (!pCor) {
+               _SERR("Invalid Cor Header");
+               return false;
+       }
+
+       IMAGE_DATA_DIRECTORY* pR2RDir = &pCor->ManagedNativeHeader;
+       if (VAL32(pR2RDir->Size) >= sizeof(READYTORUN_HEADER)) {
+               READYTORUN_HEADER* pR2RHeader = (READYTORUN_HEADER*)getDirectoryData(pAddr, pNTHeaders, pR2RDir);
+               if (!pR2RHeader) {
+                       return false;
+               }
+
+               if (pR2RHeader->Signature != VAL16(READYTORUN_SIGNATURE)) {
+                       return false;
+               }
+               return true;
+       }
+       return false;
+}
+
+bool isR2RImage(std::string fileName)
+{
+       int fd;
+       struct stat sb;
+       if ((fd = open(fileName.c_str(), O_RDONLY)) == -1) {
+               _SERR("File Not Found: %s", fileName.c_str());
+               return false;
+       }
+
+       if (fstat(fd, &sb) == -1) {
+               return false;
+       }
+
+       void* pAddr = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+       if (pAddr == MAP_FAILED) {
+               _SERR("Fail to Map File: %s", fileName.c_str());
+               close(fd);
+               return false;
+       }
+
+       bool ret = hasValidR2RHeader(pAddr);
+
+       munmap(pAddr, sb.st_size);
+       close(fd);
+       return ret;
+}
index cc6d8f5..b4067b6 100644 (file)
@@ -30,6 +30,7 @@ BuildRequires: boost-devel
 BuildRequires: aul-devel
 BuildRequires: dotnet-build-tools
 BuildRequires: unzip
+BuildRequires: coreclr-devel
 
 %if 0%{?asan_enabled}
 BuildRequires: clang >= 3.8