From 47be84081deb436f3a9515424d7921db58445a4d Mon Sep 17 00:00:00 2001 From: =?utf8?q?=EC=A0=95=EB=8F=99=ED=97=8C/Common=20Platform=20Lab=28SR=29?= =?utf8?q?/Principal=20Engineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Thu, 16 Dec 2021 10:03:42 +0900 Subject: [PATCH] Add r2r checker (#355) * 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 --- NativeLauncher/CMakeLists.txt | 4 + NativeLauncher/inc/r2r_checker.h | 24 ++++++ NativeLauncher/tool/ni_common.cc | 1 + NativeLauncher/tool/r2r_checker.cc | 168 +++++++++++++++++++++++++++++++++++++ packaging/dotnet-launcher.spec | 1 + 5 files changed, 198 insertions(+) create mode 100644 NativeLauncher/inc/r2r_checker.h create mode 100644 NativeLauncher/tool/r2r_checker.cc diff --git a/NativeLauncher/CMakeLists.txt b/NativeLauncher/CMakeLists.txt index 58705d0..cba9252 100644 --- a/NativeLauncher/CMakeLists.txt +++ b/NativeLauncher/CMakeLists.txt @@ -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 index 0000000..7c74548 --- /dev/null +++ b/NativeLauncher/inc/r2r_checker.h @@ -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 + +bool isR2RImage(std::string fileName); + +#endif /* __R2R_CHECKER_H__ */ diff --git a/NativeLauncher/tool/ni_common.cc b/NativeLauncher/tool/ni_common.cc index 5ed08c8..5f1487e 100644 --- a/NativeLauncher/tool/ni_common.cc +++ b/NativeLauncher/tool/ni_common.cc @@ -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 index 0000000..c5b5b63 --- /dev/null +++ b/NativeLauncher/tool/r2r_checker.cc @@ -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 +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +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; +} diff --git a/packaging/dotnet-launcher.spec b/packaging/dotnet-launcher.spec index cc6d8f5..b4067b6 100644 --- a/packaging/dotnet-launcher.spec +++ b/packaging/dotnet-launcher.spec @@ -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 -- 2.7.4