diff --git a/bundle.json b/bundle.json index aa041e33087be685205d1bb04fa64672fb9bf74d..5a6d5004bf4d99e9d47d6c1aad3ac33dbcba831f 100644 --- a/bundle.json +++ b/bundle.json @@ -70,7 +70,8 @@ ], "test": [ "//base/security/device_security_level/test/dslm_unit_test:dslm_test", - "//base/security/device_security_level/test/dslm_fuzz_test:dslm_fuzz" + "//base/security/device_security_level/test/dslm_fuzz_test:dslm_fuzz", + "//base/security/device_security_level/xpm_test:xpm_test" ] } } diff --git a/xpm_test/BUILD.gn b/xpm_test/BUILD.gn new file mode 100755 index 0000000000000000000000000000000000000000..0f03c3850e1c3240947c8d75b5bf447a0d4e432b --- /dev/null +++ b/xpm_test/BUILD.gn @@ -0,0 +1,119 @@ +# import("//build/ohos.gni") + +# ohos_executable("xpm_test") { +# sources = [ "xpm_test.c" ] + +# install_enable = true +# part_name = "device_security_level" +# subsystem_name = "security" +# } + +# ohos_shared_library("xpm") { +# sources = [ "xpm_lib.c" ] + +# install_enable = true +# part_name = "device_security_level" +# subsystem_name = "security" +# } + +import("//build/ohos.gni") +import("//build/test.gni") + +# test unittest +ohos_unittest("xpm_test") { + install_enable = true + testonly = true + part_name = "device_security_level" + subsystem_name = "security" + module_out_path = "${part_name}/${target_name}" + + sources = [ + "xpm_common.cpp", + "xpm_elf.cpp", + #"xpm_permissive_test.cpp", + "xpm_enforce_bin_normal_test.cpp", + "xpm_enforce_bin_webview_test.cpp", + "xpm_enforce_abc_normal_test.cpp", + "xpm_enforce_abc_debug_test.cpp", + "xpm_integrity_test.cpp" + ] + + include_dirs = [ + "//third_party/selinux/libselinux/include", + ] + + cflags = [ + "-O0", + "-Wno-unused-variable", + "-fno-omit-frame-pointer", + "-DSUPPORT_KNOWN_EXCEPTION", + ] + cflags_cc = cflags + + configs = [ ] + + deps = [ + "//base/security/device_security_level/xpm_test:xpm", + "//base/security/device_security_level/xpm_test:xpmWT", + "//base/security/device_security_level/xpm_test:xpmRO", + "//base/security/device_security_level/xpm_test:xpm17", + "//third_party/selinux:libselinux", + ] + + external_deps = [ + "c_utils:utils", + "hilog_native:libhilog", + ] +} + +ohos_shared_library("xpm") { + sources = [ "xpm_lib.c" ] + + ldflags = [ + "-Wl,-z,max-page-size=4096", + "-Wl,-z,separate-code", +] + + install_enable = true + part_name = "device_security_level" + subsystem_name = "security" +} + +ohos_shared_library("xpmRO") { + sources = [ "xpm_lib.c" ] + + ldflags = [ + "-Wl,-z,max-page-size=4096", + "-Wl,-z,separate-code", +] + + install_enable = true + part_name = "device_security_level" + subsystem_name = "security" +} + +ohos_shared_library("xpmWT") { + sources = [ "xpm_lib.c" ] + + ldflags = [ + "-Wl,-z,max-page-size=4096", + "-Wl,-z,separate-code", +] + + install_enable = true + part_name = "device_security_level" + subsystem_name = "security" +} + +ohos_shared_library("xpm17") { + sources = [ "xpm_lib.c" ] + + ldflags = [ + "-Wl,-z,max-page-size=4096", + "-Wl,-z,separate-code", +] + + install_enable = true + part_name = "device_security_level" + subsystem_name = "security" +} \ No newline at end of file diff --git a/xpm_test/libxpm_lib.lds b/xpm_test/libxpm_lib.lds new file mode 100755 index 0000000000000000000000000000000000000000..b6a6164649c485db2f0b5f3f9b3a29a71fcabd99 --- /dev/null +++ b/xpm_test/libxpm_lib.lds @@ -0,0 +1,55 @@ +PHDRS { + phdrs PT_PHDR PHDRS FLAGS(4) ; + open_ro PT_LOAD FILEHDR PHDRS ; + open_rx PT_LOAD FLAGS(5) ; + shut_rw PT_LOAD FLAGS(6) ; + open_rw PT_LOAD ; + dynamic PT_DYNAMIC ; + relro PT_GNU_RELRO FLAGS(4) ; + eh_hdr PT_GNU_EH_FRAME FLAGS(4) ; + stack PT_GNU_STACK FLAGS(6) ; + note PT_NOTE FLAGS(4) ; +} + + + +SECTIONS { + . = SIZEOF_HEADERS; + + .note.ohos.ident : { *(.note.ohos.ident) } :open_ro :note + .note.gnu.build-id : { *(.note.gnu.build-id) } + + .dynsym : { *(.dynsym) } :open_ro + .dynstr : { *(.dynstr) } + .gnu.hash : { *(.gnu.hash) } + .hash : { *(.hash) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.dyn : { *(rel.dyn)} + .rela.dyn : { *(rela.dyn)} + .relr.dyn : { *(relr.dyn)} + .rel.plt : { *(relr.plt)} + .rela.plt : { *(rela.plt)} + .rodata : { *(.rodata .rodata.*) } + .eh_frame : { *(.eh_frame) } + .eh_frame_hdr : { *(.eh_frame_hdr) } :open_ro :eh_hdr + + . = ALIGN(CONSTANT(COMMONPAGESIZE)); + .text : { *(.text .text.*) } :open_rx + .plt : { *(.plt) } + + . = ALIGN(CONSTANT(COMMONPAGESIZE)); + .dynamic : { *(.dynamic) } :shut_rw :relro :dynamic + .init_array : { *(.init_array) } :shut_rw :relro + + .fini_array : { *(.fini_array) } + .data.rel.ro : { *(.data.rel.ro .data.rel.ro.*) } + + .got : { *(.got) } + .got.plt : { *(.got.plt) } + + . = ALIGN(CONSTANT(COMMONPAGESIZE)); + .data : { *(.data .data.*) } :open_rw + .bss : { *(.bss .bss.*)} +} \ No newline at end of file diff --git a/xpm_test/xpm_common.cpp b/xpm_test/xpm_common.cpp new file mode 100644 index 0000000000000000000000000000000000000000..03926efa06357bc24f5dc8607644007a57257cb2 --- /dev/null +++ b/xpm_test/xpm_common.cpp @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * 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 "xpm_common.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "selinux/selinux.h" +#include "file_ex.h" +#include "xpm_log.h" + +namespace OHOS { +namespace Security { +namespace XpmUnitTest { +int g_fd; +struct XpmRegionArea g_area; +unsigned long g_dataOffset, g_dataSize; +unsigned long g_codeOffset, g_codeSize; + +int SetXpmRegion(void) +{ + struct XpmRegionInfo info = { 0, XPM_REGION_LEN }; + + int fd = open(XPM_DEV_PATH.c_str(), O_RDWR); + if (fd < 0) { + XPM_LOG_ERROR("open xpm dev file failed(%{public}s)", strerror(errno)); + return -1; + } + + int ret = ioctl(fd, SET_XPM_REGION, &info); + if (ret < 0) { + XPM_LOG_ERROR("xpm set region failed(%{public}s)", strerror(errno)); + return -1; + } + + close(fd); + return 0; +} + +int GetXpmRegion(struct XpmRegionArea *area) +{ + if (area == nullptr) { + XPM_LOG_ERROR("input area is NULL"); + return -1; + } + + pid_t pid = getpid(); + std::string path = XPM_PROC_PREFIX_PATH + std::to_string(pid) + XPM_PROC_SUFFIX_PATH; + int fd = open(path.c_str(), O_RDWR); + if (fd < 0) { + XPM_LOG_ERROR("open xpm proc file failed(%{public}s)", strerror(errno)); + return -1; + } + + char xpm_region[XPM_PROC_LENGTH] = {0}; + int ret = read(fd, xpm_region, sizeof(xpm_region)); + if (ret < 0) { + XPM_LOG_ERROR("read xpm proc file failed(%{public}s)", strerror(errno)); + return -1; + } + + ret = sscanf(xpm_region, "%lx-%lx", &area->start, &area->end); + if (ret < 0) { + XPM_LOG_ERROR("sscanf xpm region string failed(%{public}s)", strerror(errno)); + return -1; + } + + close(fd); + return 0; +} + +int InitXpmRegion(struct XpmRegionArea *area) +{ + if (area == nullptr) { + XPM_LOG_ERROR("input area is NULL"); + return -1; + } + + int ret = SetXpmRegion(); + if (ret != 0) { + XPM_LOG_ERROR("set xpm region failed"); + return ret; + } + + ret = GetXpmRegion(area); + if (ret != 0) { + XPM_LOG_ERROR("get xpm region failed"); + return ret; + } + + return 0; +} + +bool IsXpmRegionInner(unsigned long start, unsigned long end) +{ + struct XpmRegionArea area = {0}; + + int ret = GetXpmRegion(&area); + if (ret < 0) { + XPM_LOG_ERROR("get xpm region failed"); + return false; + } + + if (start >= area.start && end <= area.end) { + return true; + } + + return false; +} + +bool IsXpmRegionOuter(unsigned long start, unsigned long end) +{ + struct XpmRegionArea area = {0}; + + int ret = GetXpmRegion(&area); + if (ret < 0) { + XPM_LOG_ERROR("get xpm region failed"); + return false; + } + + if (start >= area.end || end <= area.start) { + return true; + } + + return false; +} + +int SetCon(const char *type) +{ + return setcon(type); +} + +static jmp_buf setjmp_env; + +void SegFaultSigaction(int signal) +{ + siglongjmp(setjmp_env, signal); +} + +int RegisterSignal() +{ + struct sigaction act; + act.sa_handler = SegFaultSigaction; + sigemptyset(&act.sa_mask); + sigaddset(&act.sa_mask, SIGQUIT); + act.sa_flags = SA_RESETHAND; + return sigaction(SIGSEGV, &act, NULL); +} + +int ExecSumFunPtr(void *funcPtr) +{ +// SumFuncPtr sum_func; +// int ret; + +// RegisterSignal(); + +// ret = sigsetjmp(setjmp_env, 1); +// if(ret == SIGSEGV) { +// return 0; +// } + + int ret = ((SumFuncPtr)funcPtr)(1, 2); + +// return 1; + return ret == 4 ? 0 : -1; +} + +int AccessData(void *addr, int op) +{ +// int ret; +// RegisterSignal(); + + // ret = sigsetjmp(setjmp_env, 1); + // if (ret == SIGSEGV) { + // return 0; + // } + uint8_t val; + switch (op) { + case OP_READ: //只读 + val = ((uint8_t *)addr)[0]; + break; + case OP_WRITE:{ //写前读 + val = ((uint8_t *)addr)[0]; + ((uint8_t *)addr)[100] = val; + } + break; + case OP_WRITE_ONLY: //只写 + ((uint8_t *)addr)[100] = 3; + break; + default: + break; + } + + // return 1; + return 0; +} + +} // namespace XpmUnitTest +} // namespace Security +} // namespace OHOS \ No newline at end of file diff --git a/xpm_test/xpm_common.h b/xpm_test/xpm_common.h new file mode 100644 index 0000000000000000000000000000000000000000..065dcb32ce373d3c341d515dd331bd3607d8b5da --- /dev/null +++ b/xpm_test/xpm_common.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 XPM_COMMON_TEST_H +#define XPM_COMMON_TEST_H + +#include +#include +#include + +namespace OHOS { +namespace Security { +namespace XpmUnitTest { +struct XpmRegionInfo { + unsigned long base; + unsigned long length; +}; + +struct XpmRegionArea { + unsigned long start; + unsigned long end; +}; + +const std::string XPM_DEV_PATH = "/dev/xpm"; +const std::string XPM_LIB_PATH = "/system/lib64/libxpm.z.so"; +const std::string XPM_PROC_PREFIX_PATH = "/proc/"; +const std::string XPM_PROC_SUFFIX_PATH = "/xpm_region"; +const std::string XPM_DEBUG_FS_MODE_PATH = "/sys/kernel/debug/xpm/xpm_mode"; +const std::string SELINUX_MODE_PATH = "/sys/fs/selinux/enforce"; + +const std::string SELINUX_TYPE_NWEBSPAWN = "u:r:nwebspawn:s0"; +const std::string SELINUX_TYPE_DEBUG_HAP = "u:r:debug_hap:s0"; +const std::string SELINUX_TYPE_SH = "u:r:sh:s0"; +const std::string PERMISSIVE_MODE = "0"; +const std::string ENFORCE_MODE = "1"; + +constexpr unsigned long XPM_REGION_LEN = 0x8000000; +constexpr unsigned long SET_XPM_REGION = _IOW('x', 0x01, struct XpmRegionInfo); +constexpr unsigned long XPM_PROC_LENGTH = 50; +constexpr unsigned long MAP_XPM = 0x40; + +constexpr unsigned long SUM_FUN_OFFSET = 0x0; +constexpr unsigned long ANON_SIZE = 0x1000; +constexpr unsigned long NEW_ANON_SIZE = ANON_SIZE; + +const unsigned long PAGE_SIZE = (sysconf(_SC_PAGESIZE)); +const unsigned long PAGE_MASK = ~(PAGE_SIZE - 1); + +constexpr unsigned int OP_READ = 0; +constexpr unsigned int OP_WRITE = 1; +constexpr unsigned int OP_WRITE_ONLY = 2; + +typedef int (*SumFuncPtr)(int, int); + +int SetCon(const char *type); +int SetXpmRegion(void); +int GetXpmRegion(struct XpmRegionArea *area); +int InitXpmRegion(struct XpmRegionArea *area); +bool IsXpmRegionInner(unsigned long start, unsigned long end); +bool IsXpmRegionOuter(unsigned long start, unsigned long end); + +void SegFaultSigaction(int signal); +int RegisterSignal(); +int ExecSumFunPtr(void *funcPtr); +int AccessData(void *addr, int op); +} // namespace XpmUnitTest +} // namespace Security +} // namespace OHOS + +#endif \ No newline at end of file diff --git a/xpm_test/xpm_elf.cpp b/xpm_test/xpm_elf.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a734626da279da3b680c6f9f51c6437f1e997f94 --- /dev/null +++ b/xpm_test/xpm_elf.cpp @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * 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 "xpm_elf.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "xpm_log.h" + +namespace OHOS { +namespace Security { +namespace XpmUnitTest { +static int GetElfClass(FILE *fp, uint8_t *buf, uint32_t bufLen, uint8_t *elfClass) +{ + if (memcmp(buf, ELFMAG, SELFMAG) != 0) { + XPM_LOG_ERROR("file is not elf"); + return -1; + } + + *elfClass = buf[EI_CLASS]; + return 0; +} + +static uint8_t *ParseElfInfo(const char *path, uint8_t *elfClass) +{ + if (path == NULL || elfClass == NULL) { + XPM_LOG_ERROR("input elf path or elfClass is NULL"); + return NULL; + } + + FILE *fp = fopen(path, "r"); + if (fp == NULL) { + XPM_LOG_ERROR("open path(%{public}s) failed(%{public}s)", path, strerror(errno)); + return NULL; + } + + fseek(fp, 0, SEEK_END); + uint32_t fileSize = ftell(fp); + rewind(fp); + + uint8_t *buf = new uint8_t[fileSize]; + if (buf == NULL) { + XPM_LOG_ERROR("malloc %{public}u bytes failed", fileSize); + fclose(fp); + return NULL; + } + + int ret = fread(buf, 1, fileSize, fp); + if (ret < 0) { + XPM_LOG_ERROR("fread failed(%s)", strerror(errno)); + fclose(fp); + delete [] buf; + return NULL; + } + + ret = GetElfClass(fp, buf, fileSize, elfClass); + if (ret != 0) { + XPM_LOG_ERROR("get elf class failed"); + fclose(fp); + delete [] buf; + return NULL; + } + + fclose(fp); + return buf; +} + +static void DestroyElfInfo(uint8_t *buf) +{ + if (buf != NULL) { + delete [] buf; + } +} + +static int GetElf64Segment(uint8_t *buf, unsigned long *offset, unsigned long *size, uint32_t flag) +{ + Elf64_Ehdr *ehdr = (Elf64_Ehdr *)buf; + uint32_t phNum = ehdr->e_phnum; + Elf64_Phdr *phdr = (Elf64_Phdr *)&buf[ehdr->e_phoff]; + + for (int i = phNum - 1; i >= 0; i--) { + if ((phdr[i].p_type == PT_LOAD) && ((phdr[i].p_flags & flag) == flag)) { + *offset = phdr[i].p_offset; + *size = phdr[i].p_filesz; + return 0; + } + } + + return -1; +} + +static int GetElf32Segment(uint8_t *buf, unsigned long *offset, unsigned long *size, uint32_t flag) +{ + Elf32_Ehdr *ehdr = (Elf32_Ehdr *)buf; + uint32_t phNum = ehdr->e_phnum; + Elf32_Phdr *phdr = (Elf32_Phdr *)&buf[ehdr->e_phoff]; + + for (int i = phNum - 1; i >= 0; i--) { + if ((phdr[i].p_type == PT_LOAD) && ((phdr[i].p_flags & flag) == flag)) { + *offset = phdr[i].p_offset; + *size = phdr[i].p_filesz; + return 0; + } + } + + return -1; +} + +int GetDataSegment(const char *path, unsigned long *offset, unsigned long *size) +{ + if (offset == NULL || size == NULL) { + XPM_LOG_ERROR("input param is NULL"); + return -1; + } + + int ret = -1; + uint8_t elfClass; + uint8_t *buf = ParseElfInfo(path, &elfClass); + switch (elfClass) + { + case ELFCLASS64: + ret = GetElf64Segment(buf, offset, size, PF_R | PF_W); + break; + case ELFCLASS32: + ret = GetElf32Segment(buf, offset, size, PF_R | PF_W); + break; + default: + break; + } + + DestroyElfInfo(buf); + XPM_LOG_INFO("result: %d, [offset: 0x%lx, size: 0x%lx]", ret, *offset, *size); + return ret; +} + +int GetCodeSegment(const char *path, unsigned long *offset, unsigned long *size) +{ + if (offset == NULL || size == NULL) { + XPM_LOG_ERROR("input param is NULL"); + return -1; + } + + int ret = -1; + uint8_t elfClass; + uint8_t *buf = ParseElfInfo(path, &elfClass); + switch (elfClass) + { + case ELFCLASS64: + ret = GetElf64Segment(buf, offset, size, PF_X); + break; + case ELFCLASS32: + ret = GetElf32Segment(buf, offset, size, PF_X); + break; + default: + break; + } + + DestroyElfInfo(buf); + XPM_LOG_INFO("result: %d, [offset: 0x%lx, size: 0x%lx]", ret, *offset, *size); + return ret; +} +} // namespace XpmUnitTest +} // namespace Security +} // namespace OHOS diff --git a/xpm_test/xpm_elf.h b/xpm_test/xpm_elf.h new file mode 100644 index 0000000000000000000000000000000000000000..560537d01f677f6ca68dbc394a5b35ce8459a14d --- /dev/null +++ b/xpm_test/xpm_elf.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 XPM_ELF_H +#define XPM_ELF_H + +namespace OHOS { +namespace Security { +namespace XpmUnitTest { +int GetDataSegment(const char *path, unsigned long *start, unsigned long *end); +int GetCodeSegment(const char *path, unsigned long *start, unsigned long *end); +} // namespace XpmUnitTest +} // namespace Security +} // namespace OHOS + +#endif \ No newline at end of file diff --git a/xpm_test/xpm_enforce_abc_debug_test.cpp b/xpm_test/xpm_enforce_abc_debug_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e5921aebd0eb88fdb431b8ea39f76f76ec79517e --- /dev/null +++ b/xpm_test/xpm_enforce_abc_debug_test.cpp @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * 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 "xpm_enforce_abc_debug_test.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "file_ex.h" +#include "xpm_common.h" +#include "xpm_elf.h" +#include "xpm_log.h" + +using namespace std; +using namespace std::chrono; +using namespace testing; +using namespace testing::ext; + +namespace OHOS { +namespace Security { +namespace XpmUnitTest { +static int g_fd; +static struct XpmRegionArea g_area; +static unsigned long g_dataOffset, g_dataSize; +static unsigned long g_codeOffset, g_codeSize; +void XpmEnforceAbcDebugTest::SetUpTestCase() +{ + SaveStringToFile(SELINUX_MODE_PATH, PERMISSIVE_MODE); + g_fd = open(XPM_LIB_PATH.c_str(), O_RDWR); + + int ret = GetDataSegment(XPM_LIB_PATH.c_str(), &g_dataOffset, &g_dataSize); + ASSERT_EQ(0, ret) << "GetDataSegment failed: " << ret; + + ret = GetCodeSegment(XPM_LIB_PATH.c_str(), &g_codeOffset, &g_codeSize); + ASSERT_EQ(0, ret) << "GetCodeSegment failed: " << ret; + + ret = InitXpmRegion(&g_area); + ASSERT_EQ(0, ret) << "InitXpmRegion failed: " << ret; + + ret = SetCon(SELINUX_TYPE_DEBUG_HAP.c_str()); + ASSERT_EQ(0, ret); + + SaveStringToFile(XPM_DEBUG_FS_MODE_PATH, ENFORCE_MODE); +} + +void XpmEnforceAbcDebugTest::TearDownTestCase() +{ + close(g_fd); + SetCon(SELINUX_TYPE_SH.c_str()); + SaveStringToFile(XPM_DEBUG_FS_MODE_PATH, PERMISSIVE_MODE); + SaveStringToFile(SELINUX_MODE_PATH, ENFORCE_MODE); +} + +void XpmEnforceAbcDebugTest::SetUp() +{ +} + +void XpmEnforceAbcDebugTest::TearDown() +{ +} + +/** + * @tc.number 2 + * @tc.name: FileMmapDataToRxTest + * @tc.desc: 调试应用中数据段文件映射到r-x权限内存 + * @tc.result: 映射成功,调试应用不管控签名和代码段 + */ +HWTEST_F(XpmEnforceAbcDebugTest, FileMmapDataToRxTest, TestSize.Level0) +{ + // mmap failed, has [signature] error + void *addr = mmap(NULL, g_dataSize, PROT_READ | PROT_EXEC, MAP_PRIVATE, g_fd, g_dataOffset & PAGE_MASK); + EXPECT_NE(MAP_FAILED, addr); + + // release resource + munmap(addr, g_dataSize); +} + +/** + * @tc.number 6 + * @tc.name: FileMprotectDataRoToRxTest + * @tc.desc: 调试应用中数据段文件映射的r--权限内存通过mprotect修改为r-x权限 + * @tc.result: 修改操作成功,调试应用不管控签名和代码段 + */ +HWTEST_F(XpmEnforceAbcDebugTest, FileMprotectDataRoToRxTest, TestSize.Level0) +{ + void *addr = mmap(NULL, g_dataSize, PROT_READ, MAP_PRIVATE, g_fd, g_dataOffset & PAGE_MASK); + EXPECT_NE(MAP_FAILED, addr); + + // mprotect failed at enforce mode, has [signature] error + int ret = mprotect(addr, g_dataSize, PROT_READ | PROT_EXEC); + EXPECT_EQ(0, ret); + + // release resource + munmap(addr, g_dataSize); +} + +/** + * @tc.number 12 + * @tc.name: FileRemapDataRoToRxTest + * @tc.desc: 调试应用中数据段文件映射的r--权限内存通过mremap修改为r-x权限 + * @tc.result: 修改操作成功,调试应用不管控签名和代码段 + */ +HWTEST_F(XpmEnforceAbcDebugTest, FileRemapDataRoToRxTest, TestSize.Level0) +{ + void *addr1 = mmap(NULL, g_dataSize, PROT_READ | PROT_WRITE, MAP_PRIVATE, g_fd, g_dataOffset & PAGE_MASK); + EXPECT_NE(MAP_FAILED, addr1); + + void *addr2 = mremap(addr1, g_dataSize, g_dataSize, MREMAP_MAYMOVE); + EXPECT_NE(MAP_FAILED, addr2); + + // mprotect failed at enforce mode, has [signature] error + int ret = mprotect(addr2, g_dataSize, PROT_READ | PROT_EXEC); + EXPECT_EQ(0, ret); + + // release resource + munmap(addr2, g_dataSize); +} + +/** + * @tc.number 13 + * @tc.name: FileRemapDataRwToRxTest + * @tc.desc: 调试应用中数据段文件映射的rw-权限内存通过mremap修改为r-x权限 + * @tc.result: 修改操作成功,调试应用不管控签名和代码段 + */ +HWTEST_F(XpmEnforceAbcDebugTest, FileRemapDataRwToRxTest, TestSize.Level0) +{ + void *addr1 = mmap(NULL, g_dataSize, PROT_READ | PROT_WRITE, MAP_PRIVATE, g_fd, g_dataOffset & PAGE_MASK); + EXPECT_NE(MAP_FAILED, addr1); + + void *addr2 = mremap(addr1, g_dataSize, g_dataSize, MREMAP_MAYMOVE); + EXPECT_NE(MAP_FAILED, addr2); + + // mprotect failed at enforce mode, has [signature] error + int ret = mprotect(addr2, g_dataSize, PROT_READ | PROT_EXEC); + EXPECT_EQ(0, ret); + + // release resource + munmap(addr2, g_dataSize); +} + +/** + * @tc.number 18 + * @tc.name: AnonMmapRwTest + * @tc.desc: 调试应用匿名映射rw-权限内存 + * @tc.result: 匿名映射成功,rw-匿名内存不做管控 + */ +HWTEST_F(XpmEnforceAbcDebugTest, AnonMmapRwTest, TestSize.Level0) +{ + void *addr = mmap(NULL, ANON_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + EXPECT_NE(MAP_FAILED, addr); + + // release resource + munmap(addr, ANON_SIZE); +} + +/** + * @tc.number 19 + * @tc.name: AnonMmapRwxTest + * @tc.desc: 调试应用匿名映射rwx权限内存 + * @tc.result: 匿名映射成功,调试应用允许匿名映射x权限 + */ +HWTEST_F(XpmEnforceAbcDebugTest, AnonMmapRwxTest, TestSize.Level0) +{ + void *addr = mmap(NULL, ANON_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + EXPECT_NE(MAP_FAILED, addr); +} + +/** + * @tc.number 20 + * @tc.name: AnonMprotectRwToRwxTest + * @tc.desc: 调试应用匿名映射的rw权限内存通过mprotect修改为rwx匿名内存 + * @tc.result: 修改匿名内存为rwx成功,调试应用允许匿名映射x权限 + */ +HWTEST_F(XpmEnforceAbcDebugTest, AnonMprotectRwToRwxTest, TestSize.Level0) +{ + // 1. 匿名映射映射rw-内存 + void *addr = mmap(NULL, ANON_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + EXPECT_NE(MAP_FAILED, addr); + + // 2. 修改匿名内存为rwx + int ret = mprotect(addr, ANON_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC); + EXPECT_EQ(0, ret); + + // release resource + munmap(addr, ANON_SIZE); +} + +/** + * @tc.number 21 + * @tc.name: AnonMprotectRwToRwxTest + * @tc.desc: 调试应用匿名映射的rw-权限内存通过mprotect修改为r--匿名内存,之后再修改为r-x匿名内存 + * @tc.result: 修改匿名内存为rx成功,调试应用允许匿名映射x权限 + */ +HWTEST_F(XpmEnforceAbcDebugTest, AnonMprotectRwToRoToRxTest, TestSize.Level0) +{ + // 1. 匿名映射映射rw-内存 + void *addr = mmap(NULL, ANON_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + EXPECT_NE(MAP_FAILED, addr); + + // 2. 修改匿名内存为r-- + int ret = mprotect(addr, ANON_SIZE, PROT_READ); + EXPECT_EQ(0, ret); + + // 3. 修改匿名内存为r-x + ret = mprotect(addr, ANON_SIZE, PROT_READ | PROT_EXEC); + EXPECT_EQ(0, ret); + + // release resource + munmap(addr, ANON_SIZE); +} + +/** + * @tc.number 22 + * @tc.name: AnonRmapRwToRxTest + * @tc.desc: 调试应用匿名映射的rw-权限内存重映射到r-x匿名内存 + * @tc.result: 重映射到r-x成功,调试应用允许匿名映射x权限 + */ +HWTEST_F(XpmEnforceAbcDebugTest, AnonRmapRwToRxTest, TestSize.Level0) +{ + // 1. 匿名映射映射rw-内存 + void *addr1 = mmap(NULL, ANON_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + EXPECT_NE(MAP_FAILED, addr1); + + // 2. 重映射匿名内存 + void *addr2 = mremap(addr1, ANON_SIZE, NEW_ANON_SIZE, MREMAP_MAYMOVE); + EXPECT_NE(MAP_FAILED, addr2); + + // 3. 修改匿名内存为r-x + int ret = mprotect(addr2, NEW_ANON_SIZE, PROT_READ | PROT_EXEC); + EXPECT_EQ(0, ret); + + // release resource + munmap(addr2, ANON_SIZE); +} + +} // namespace XpmUnitTest +} // namespace Security +} // namespace OHOS \ No newline at end of file diff --git a/xpm_test/xpm_enforce_abc_debug_test.h b/xpm_test/xpm_enforce_abc_debug_test.h new file mode 100644 index 0000000000000000000000000000000000000000..ff3daa7642b87382f054ccf175b17e848441572f --- /dev/null +++ b/xpm_test/xpm_enforce_abc_debug_test.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 XPM_ENFORCE_ABC_DEBUG_TEST +#define XPM_ENFORCE_ABC_DEBUG_TEST + +#include + +namespace OHOS { +namespace Security { +namespace XpmUnitTest { +using namespace testing::ext; +class XpmEnforceAbcDebugTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp() override; + void TearDown() override; +}; +} // namespace XpmUnitTest +} // namespace Security +} // namespace OHOS + +#endif // XPM_ENFORCE_ABC_DEBUG_TEST \ No newline at end of file diff --git a/xpm_test/xpm_enforce_abc_normal_test.cpp b/xpm_test/xpm_enforce_abc_normal_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b0d89d16206bf9a18ae27de895e5a29f59ace830 --- /dev/null +++ b/xpm_test/xpm_enforce_abc_normal_test.cpp @@ -0,0 +1,381 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * 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 "xpm_enforce_abc_normal_test.h" + +#include "file_ex.h" +#include "xpm_common.h" +#include "xpm_elf.h" +#include "xpm_log.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace std::chrono; +using namespace testing; +using namespace testing::ext; + +namespace OHOS { +namespace Security { +namespace XpmUnitTest { +static int g_fd; +static struct XpmRegionArea g_area; +static unsigned long g_dataOffset, g_dataSize; +static unsigned long g_codeOffset, g_codeSize; + +void XpmEnforceAbcNormalTest::SetUpTestCase() +{ + SaveStringToFile(SELINUX_MODE_PATH, PERMISSIVE_MODE); + g_fd = open(XPM_LIB_PATH.c_str(), O_RDWR); + + int ret = GetDataSegment(XPM_LIB_PATH.c_str(), &g_dataOffset, &g_dataSize); + ASSERT_EQ(0, ret) << "GetDataSegment failed: " << ret; + + ret = GetCodeSegment(XPM_LIB_PATH.c_str(), &g_codeOffset, &g_codeSize); + ASSERT_EQ(0, ret) << "GetCodeSegment failed: " << ret; + + ret = InitXpmRegion(&g_area); + ASSERT_EQ(0, ret) << "InitXpmRegion failed: " << ret; + + SaveStringToFile(XPM_DEBUG_FS_MODE_PATH, ENFORCE_MODE); +} + +void XpmEnforceAbcNormalTest::TearDownTestCase() +{ + close(g_fd); + SaveStringToFile(XPM_DEBUG_FS_MODE_PATH, PERMISSIVE_MODE); + SaveStringToFile(SELINUX_MODE_PATH, ENFORCE_MODE); +} + +void XpmEnforceAbcNormalTest::SetUp() +{ +} + +void XpmEnforceAbcNormalTest::TearDown() +{ +} + +/** + * @tc.name: XpmRegionAllocTest + * @tc.desc: 安全内存分配测试 + * tc.result: 分配成功,且进程对应/proc/pid/xpm_region范围有值 + */ +HWTEST_F(XpmEnforceAbcNormalTest, XpmRegionAllocTest, TestSize.Level0) +{ + struct XpmRegionArea area = {0}; + + int ret = InitXpmRegion(&area); + EXPECT_EQ(0, ret); + + EXPECT_NE(0UL, area.start); + EXPECT_NE(0UL, area.end); +} + +/** + * @tc.name: XpmRegionAllocMultiTest + * @tc.desc: 安全内存多次分配测试 + * tc.result: 调用成功,但是安全内存并未重新分配 + */ +HWTEST_F(XpmEnforceAbcNormalTest, XpmRegionAllocMultiTest, TestSize.Level0) +{ + struct XpmRegionArea area1 = {0}; + struct XpmRegionArea area2 = {0}; + + // first time + int ret = InitXpmRegion(&area1); + EXPECT_EQ(0, ret); + + // second time + ret = InitXpmRegion(&area2); + EXPECT_EQ(0, ret); + + EXPECT_EQ(area1.start, area2.start); + EXPECT_EQ(area2.end, area2.end); +} + +/** + * @tc.number: 30 + * @tc.name: FileMmapXpmFlagTest + * @tc.desc: ABC代码指定MAP_XPM映射到安全内存 + * @tc.result: ABC代码映射成功,映射地址在安全内存范围内 + */ +HWTEST_F(XpmEnforceAbcNormalTest, FileMmapXpmFlagTest, TestSize.Level0) +{ + // mmap with MAP_XPM flag + void *addr = mmap(NULL, g_dataSize, PROT_READ, MAP_PRIVATE | MAP_XPM, g_fd, g_dataOffset & PAGE_MASK); + EXPECT_NE(MAP_FAILED, addr); + + // release resource + munmap(addr, g_dataSize); +} + +/** + * @tc.number: 31 + * @tc.name: FileMmapXpmFlagLimitTest + * @tc.desc: ABC代码指定MAP_XPM映射超过安全内存大小的size到安全内存 + * @tc.result: ABC代码映射失败 + */ +HWTEST_F(XpmEnforceAbcNormalTest, FileMmapXpmFlagLimitTest, TestSize.Level0) +{ + // mmap with MAP_XPM flag + void *addr = mmap(NULL, XPM_REGION_LEN + PAGE_SIZE, PROT_READ, MAP_PRIVATE | MAP_XPM, g_fd, g_dataOffset & PAGE_MASK); + EXPECT_EQ(MAP_FAILED, addr); +} + +/** + * @tc.number: 32 + * @tc.name: FileMmapXpmAddrTest + * @tc.desc: ABC代码指定MAP_XPM映射到安全内存 + * @tc.result: ABC代码映射成功,映射地址在安全内存范围内 + */ +HWTEST_F(XpmEnforceAbcNormalTest, FileMmapXpmAddrTest, TestSize.Level0) +{ + // mmap with MAP_XPM flag + void *addr = mmap((void *)g_area.start, g_dataSize, PROT_READ, MAP_PRIVATE, g_fd, g_dataOffset & PAGE_MASK); + EXPECT_NE(MAP_FAILED, addr); + + bool ret = IsXpmRegionOuter((unsigned long)addr, (unsigned long)addr + g_dataSize); + EXPECT_TRUE(ret); + + // release resource + munmap(addr, g_dataSize); +} + +/** + * @tc.number: 32 + * @tc.name: FileMmapXpmAddrTest + * @tc.desc: ABC代码指定MAP_XPM映射到安全内存 + * @tc.result: ABC代码映射成功,映射地址在安全内存范围内 + */ +HWTEST_F(XpmEnforceAbcNormalTest, FileMmapXpmAddrAndFixedFlagTest, TestSize.Level0) +{ + void *addr = mmap((void *)g_area.start, g_dataSize, PROT_READ, MAP_PRIVATE | MAP_FIXED, g_fd, g_dataOffset & PAGE_MASK); + EXPECT_EQ(MAP_FAILED, addr); + + addr = mmap((void *)(g_area.start - PAGE_SIZE), 2 * PAGE_SIZE, PROT_READ, MAP_PRIVATE | MAP_FIXED, g_fd, g_dataOffset & PAGE_MASK); + EXPECT_EQ(MAP_FAILED, addr); + + addr = mmap((void *)(g_area.end - PAGE_SIZE), 2 * PAGE_SIZE, PROT_READ, MAP_PRIVATE | MAP_FIXED, g_fd, g_dataOffset & PAGE_MASK); + EXPECT_EQ(MAP_FAILED, addr); +} + +/** + * @tc.number: 33 + * @tc.name: FileMmapAddrAndXpmFlagTest + * @tc.desc: ABC代码指定地址&MAP_XPM标识文件映射到安全内存 + * @tc.result: ABC代码映射失败,安全内存映射不允许指定地址 + */ +HWTEST_F(XpmEnforceAbcNormalTest, FileMmapAddrAndXpmFlagTest, TestSize.Level0) +{ + // mmap xpm region not allow specify addr + void *addr = mmap((void *)g_area.start, g_dataSize, PROT_READ, MAP_PRIVATE | MAP_XPM, g_fd, g_dataOffset & PAGE_MASK); + EXPECT_EQ(MAP_FAILED, addr); +} + +/** + * @tc.number: 34 + * @tc.name: FileMmapRoTest + * @tc.desc: ABC代码映射只读权限到安全内存 + * @tc.result: ABC代码映射成功,安全内存允许映射读权限 + */ +HWTEST_F(XpmEnforceAbcNormalTest, FileMmapRoTest, TestSize.Level0) +{ + // mmap success in xpm region at enforce mode + void *addr = mmap(NULL, g_dataSize, PROT_READ, MAP_PRIVATE | MAP_XPM, g_fd, g_dataOffset & PAGE_MASK); + EXPECT_NE(MAP_FAILED, addr); + + bool ret = IsXpmRegionInner((unsigned long)addr, (unsigned long)addr + g_dataSize); + EXPECT_TRUE(ret); + + // release resource + munmap(addr, g_dataSize); +} + +/** + * @tc.number: 35 + * @tc.name: FileMmapRwxTest + * @tc.desc: ABC代码映射读&写&执行权限到安全内存 + * @tc.result: ABC代码映射失败,安全内存不允许映射写和执行权限 + */ +HWTEST_F(XpmEnforceAbcNormalTest, FileMmapRwxTest, TestSize.Level0) +{ + // mmap failed in xpm region at enforce mode, has [abc not allow] error + void *addr = mmap(NULL, g_dataSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_XPM, g_fd, g_dataOffset & PAGE_MASK); + ASSERT_EQ(MAP_FAILED, addr); + + addr = mmap(NULL, g_dataSize, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_XPM, g_fd, g_dataOffset & PAGE_MASK); + ASSERT_EQ(MAP_FAILED, addr); + + addr = mmap(NULL, g_dataSize, PROT_READ | PROT_EXEC, MAP_PRIVATE | MAP_XPM, g_fd, g_dataOffset & PAGE_MASK); + ASSERT_EQ(MAP_FAILED, addr); + + addr = mmap(NULL, g_dataSize, PROT_READ | PROT_EXEC, MAP_SHARED | MAP_XPM, g_fd, g_dataOffset & PAGE_MASK); + ASSERT_EQ(MAP_FAILED, addr); + + addr = mmap(NULL, g_dataSize, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_XPM, g_fd, g_dataOffset & PAGE_MASK); + ASSERT_EQ(MAP_FAILED, addr); + + addr = mmap(NULL, g_dataSize, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED | MAP_XPM, g_fd, g_dataOffset & PAGE_MASK); + ASSERT_EQ(MAP_FAILED, addr); +} + +/** + * @tc.number 36 + * @tc.name: FileRemapXpmRegionLimitTest + * @tc.desc: ABC代码重映射超过xpm_region范围的大小到xpm region内 + * @tc.result: ABC代码重映射失败 + */ +HWTEST_F(XpmEnforceAbcNormalTest, FileRemapXpmRegionLimitTest, TestSize.Level0) +{ + void *addr1 = mmap(NULL, g_dataSize, PROT_READ, MAP_PRIVATE, g_fd, g_dataOffset & PAGE_MASK); + EXPECT_NE(MAP_FAILED, addr1); + + void *addr2 = mremap(addr1, g_dataSize, XPM_REGION_LEN + PAGE_SIZE, MREMAP_MAYMOVE | MREMAP_FIXED, g_area.start); + EXPECT_EQ(MAP_FAILED, addr2); + EXPECT_EQ(EFAULT, errno); + + addr2 = mremap(addr1, g_dataSize, XPM_REGION_LEN, MREMAP_MAYMOVE | MREMAP_FIXED, g_area.start - PAGE_SIZE); + EXPECT_EQ(MAP_FAILED, addr2); + EXPECT_EQ(EFAULT, errno); + + addr2 = mremap(addr1, g_dataSize, XPM_REGION_LEN, MREMAP_MAYMOVE | MREMAP_FIXED, g_area.start + PAGE_SIZE); + EXPECT_EQ(MAP_FAILED, addr2); + EXPECT_EQ(EFAULT, errno); + + int ret = AccessData(addr1, OP_READ); + EXPECT_EQ(0, ret); + + // release resource + munmap(addr1, g_dataSize); +} + +/** + * @tc.number 39 + * @tc.name: FileRemapDataXpmRegionToOutRxTest + * @tc.desc: ABC数据段重映射到xpm region外,并添加执行权限 + * @tc.result: ABC数据段映射失败,数据段无法添加执行权限 + */ +HWTEST_F(XpmEnforceAbcNormalTest, FileRemapDataXpmRegionToOutRxTest, TestSize.Level0) +{ + // 1. 映射为r-- + void *addr1 = mmap(NULL, g_dataSize, PROT_READ, MAP_SHARED | MAP_XPM, g_fd, g_dataOffset & PAGE_MASK); + EXPECT_NE(MAP_FAILED, addr1); + + // 2.映射为r-x + void *addr2 = mmap(NULL, g_dataSize, PROT_READ | PROT_EXEC, MAP_SHARED, g_fd, g_dataOffset & PAGE_MASK); + EXPECT_EQ(MAP_FAILED, addr2); + + // release resource + munmap(addr1, g_dataSize); +} + +/** + * @tc.number 40 + * @tc.name: FileRemapCodeXpmRegionToOutRxTest + * @tc.desc: ABC数据段重映射到xpm region外,并添加执行权限 + * @tc.result: ABC数据段映射失败,数据段无法添加执行权限 + */ +HWTEST_F(XpmEnforceAbcNormalTest, FileRemapCodeXpmRegionToOutRxTest, TestSize.Level0) +{ + // 1. 映射XPM内存 + void *addr1 = mmap(NULL, g_codeSize, PROT_READ, MAP_SHARED | MAP_XPM, g_fd, g_codeOffset & PAGE_MASK); + EXPECT_NE(MAP_FAILED, addr1); + + // 2. 映射XPM内存外 + void *addr2 = mmap(NULL, g_codeSize, PROT_READ | PROT_EXEC, MAP_SHARED, g_fd, g_codeOffset & PAGE_MASK); + EXPECT_NE(MAP_FAILED, addr2); + + int ret = ExecSumFunPtr(addr2); + EXPECT_EQ(0, ret); + + // release resource + munmap(addr1, g_codeSize); + munmap(addr2, g_codeSize); +} + +/** + * @tc.number 41 + * @tc.name: FileMprotectRwxTest + * @tc.desc: ABC代码通过mprotect添加写或执行权限 + * @tc.result: ABC代码在添加写或执行权限时失败,安全内存无法添加写&执行权限 + */ +HWTEST_F(XpmEnforceAbcNormalTest, FileMprotectRwxTest, TestSize.Level0) +{ + // 1. 映射数据到安全内存区域 + void *addr = mmap(NULL, g_dataSize, PROT_READ, MAP_PRIVATE | MAP_XPM, g_fd, g_dataOffset & PAGE_MASK); + EXPECT_NE(MAP_FAILED, addr); + + // 2. 增加写权限 + int ret = mprotect(addr, g_dataSize, PROT_READ | PROT_WRITE); + EXPECT_EQ(-1, ret); + + // 3. 增加执行权限 + ret = mprotect(addr, g_dataSize, PROT_READ | PROT_EXEC); + EXPECT_EQ(-1, ret); + + // 4. 增加写&执行权限 + ret = mprotect(addr, g_dataSize, PROT_READ | PROT_WRITE | PROT_EXEC); + EXPECT_EQ(-1, ret); + + // release resource + munmap(addr, g_dataSize); +} + +/** + * @tc.number: 42 + * @tc.name: AnonMmapXpmFlagTest + * @tc.desc: ABC代码使用MAP_XPM匿名映射到安全内存(私有映射&共享映射) + * @tc.result: ABC代码映射失败,安全内存不允许匿名映射 + */ +HWTEST_F(XpmEnforceAbcNormalTest, AnonMmapXpmFlagTest, TestSize.Level0) +{ + // mmap failed with MAP_XPM flag at enforce mode (MAP_PRIVATE or MAP_SHARED) + void *addr = mmap(NULL, ANON_SIZE, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS | MAP_XPM, -1, 0); + ASSERT_EQ(MAP_FAILED, addr); + + addr = mmap(NULL, ANON_SIZE, PROT_READ, MAP_SHARED | MAP_ANONYMOUS | MAP_XPM, -1, 0); + ASSERT_EQ(MAP_FAILED, addr); + + addr = mmap(NULL, ANON_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS | MAP_XPM, -1, 0); + ASSERT_EQ(MAP_FAILED, addr); +} + +/** + * @tc.number: 43 + * @tc.name: AnonMmapXpmAddrTest + * @tc.desc: ABC代码指定安全内存地址映射内存 + * @tc.result: ABC代码映射成功,映射区域不在安全内存中 + */ +HWTEST_F(XpmEnforceAbcNormalTest, AnonMmapXpmAddrTest, TestSize.Level0) +{ + // 1.指定xpm_region内地址映射安全内存 + void *addr = mmap((void *)g_area.start, ANON_SIZE, PROT_READ, MAP_SHARED | MAP_ANONYMOUS, -1, 0); + ASSERT_NE(MAP_FAILED, addr); + + bool ret = IsXpmRegionOuter((unsigned long)addr, (unsigned long)addr + PAGE_SIZE); + EXPECT_TRUE(ret); + munmap(addr, PAGE_SIZE); +} + +} // namespace XpmUnitTest +} // namespace Security +} // namespace OHOS \ No newline at end of file diff --git a/xpm_test/xpm_enforce_abc_normal_test.h b/xpm_test/xpm_enforce_abc_normal_test.h new file mode 100644 index 0000000000000000000000000000000000000000..a2204069393326f10fc1729e2f6d6b5e361b8a59 --- /dev/null +++ b/xpm_test/xpm_enforce_abc_normal_test.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 XPM_ENFORCE_ABC_NORMAL_TEST +#define XPM_ENFORCE_ABC_NORMAL_TEST + +#include + +namespace OHOS { +namespace Security { +namespace XpmUnitTest { +using namespace testing::ext; +class XpmEnforceAbcNormalTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp() override; + void TearDown() override; +}; +} // namespace XpmUnitTest +} // namespace Security +} // namespace OHOS + +#endif // XPM_ENFORCE_ABC_NORMAL_TEST \ No newline at end of file diff --git a/xpm_test/xpm_enforce_bin_normal_test.cpp b/xpm_test/xpm_enforce_bin_normal_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..05423f13ac8bbe5d0beabfc52742848233a613d5 --- /dev/null +++ b/xpm_test/xpm_enforce_bin_normal_test.cpp @@ -0,0 +1,453 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * 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 "xpm_enforce_bin_normal_test.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "file_ex.h" +#include "xpm_common.h" +#include "xpm_elf.h" +#include "xpm_log.h" + +using namespace std; +using namespace std::chrono; +using namespace testing; +using namespace testing::ext; + +namespace OHOS { +namespace Security { +namespace XpmUnitTest { +static int g_fd; +static unsigned long g_dataOffset, g_dataSize; +static unsigned long g_codeOffset, g_codeSize; + +void XpmEnforceBinNormalTest::SetUpTestCase() +{ + SaveStringToFile(SELINUX_MODE_PATH, PERMISSIVE_MODE); + g_fd = open(XPM_LIB_PATH.c_str(), O_RDWR); + ASSERT_NE(g_fd, -1) << "open xpm lib failed: " << strerror(errno); + + int ret = GetDataSegment(XPM_LIB_PATH.c_str(), &g_dataOffset, &g_dataSize); + ASSERT_EQ(0, ret) << "GetDataSegment failed: " << ret; + + ret = GetCodeSegment(XPM_LIB_PATH.c_str(), &g_codeOffset, &g_codeSize); + ASSERT_EQ(0, ret) << "GetCodeSegment failed: " << ret; + + SaveStringToFile(XPM_DEBUG_FS_MODE_PATH, ENFORCE_MODE); +} + +void XpmEnforceBinNormalTest::TearDownTestCase() +{ + close(g_fd); + SaveStringToFile(XPM_DEBUG_FS_MODE_PATH, PERMISSIVE_MODE); + SaveStringToFile(SELINUX_MODE_PATH, ENFORCE_MODE); +} + +void XpmEnforceBinNormalTest::SetUp() +{ +} + +void XpmEnforceBinNormalTest::TearDown() +{ +} + +/** + * @tc.number 2 + * @tc.name: FileMmapDataToRxTest + * @tc.desc: 二进制普通文件数据段文件映射到r-x权限内存 + * @tc.result: 映射失败,数据段不允许映射执行权限 + */ +HWTEST_F(XpmEnforceBinNormalTest, FileMmapDataToRxTest, TestSize.Level0) +{ + // mmap failed, has [signature] error + void *addr = mmap(NULL, g_dataSize, PROT_READ | PROT_EXEC, MAP_PRIVATE, g_fd, g_dataOffset & PAGE_MASK); + EXPECT_EQ(MAP_FAILED, addr); +} + +/** + * @tc.number 3 + * @tc.name: FileMmapCodeToRxTest + * @tc.desc: 二进制普通文件代码段文件映射到r-x权限内存 + * @tc.result: 映射成功,代码段允许映射执行权限 + */ +HWTEST_F(XpmEnforceBinNormalTest, FileMmapCodeToRxTest, TestSize.Level0) +{ + // mmap success at enforce mode + void *addr = mmap(NULL, g_codeSize, PROT_READ | PROT_EXEC, MAP_PRIVATE, g_fd, g_codeOffset & PAGE_MASK); + EXPECT_NE(MAP_FAILED, addr); + + // release resource + munmap(addr, g_codeSize); +} + +/** + * @tc.number 4 + * @tc.name: FileMmapDataToRwxTest + * @tc.desc: 二进制普通文件数据段文件映射到rwx权限内存 + * @tc.result: 映射失败,文件映射不允许同时映射wx权限 + */ +HWTEST_F(XpmEnforceBinNormalTest, FileMmapDataToRwxTest, TestSize.Level0) +{ + // mmap failed at enforce mode, has [protection] error + void *addr = mmap(NULL, g_dataSize, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE, g_fd, g_dataOffset & PAGE_MASK); + EXPECT_EQ(MAP_FAILED, addr); +} + +/** + * @tc.number 5 + * @tc.name: FileMmapCodeToRwxTest + * @tc.desc: 二进制普通文件代码段文件映射到rwx权限内存 + * @tc.result: 映射失败,文件映射不允许同时映射wx权限 + */ +HWTEST_F(XpmEnforceBinNormalTest, FileMmapCodeToRwxTest, TestSize.Level0) +{ + // mmap failed at enforce mode, has [protection] error + void *addr = mmap(NULL, g_codeSize, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE, g_fd, g_codeOffset & PAGE_MASK); + EXPECT_EQ(MAP_FAILED, addr); +} + +/** + * @tc.number 6 + * @tc.name: FileMprotectDataRoToRxTest + * @tc.desc: 二进制普通文件数据段文件映射的r--权限内存通过mprotect修改为r-x权限 + * @tc.result: 修改操作失败,数据段不允许映射x权限 + */ +HWTEST_F(XpmEnforceBinNormalTest, FileMprotectDataRoToRxTest, TestSize.Level0) +{ + void *addr = mmap(NULL, g_dataSize, PROT_READ, MAP_PRIVATE, g_fd, g_dataOffset & PAGE_MASK); + EXPECT_NE(MAP_FAILED, addr); + + // mprotect failed at enforce mode, has [signature] error + int ret = mprotect(addr, g_dataSize, PROT_READ | PROT_EXEC); + EXPECT_NE(0, ret); + + // release resource + munmap(addr, g_dataSize); +} + +/** + * @tc.number 7 + * @tc.name: FileMprotectDataRwToRwxTest + * @tc.desc: 二进制普通文件数据段文件映射的rw-权限内存通过mprotect修改为rwx权限 + * @tc.result: 修改操作失败,文件映射不允许同时映射wx权限 + */ +HWTEST_F(XpmEnforceBinNormalTest, FileMprotectDataRwToRwxTest, TestSize.Level0) +{ + void *addr = mmap(NULL, g_dataSize, PROT_READ | PROT_WRITE, MAP_PRIVATE, g_fd, g_dataOffset & PAGE_MASK); + EXPECT_NE(MAP_FAILED, addr); + + // mprotect failed at permissive mode, has [protection] error + int ret = mprotect(addr, g_dataSize, PROT_READ | PROT_WRITE | PROT_EXEC); + EXPECT_NE(0, ret); + + // release resource + munmap(addr, g_dataSize); +} + +/** + * @tc.number 8 + * @tc.name: FileMprotectCodeRoToRxTest + * @tc.desc: 二进制普通文件代码段文件映射的r--权限内存通过mprotect修改为r-x权限 + * @tc.result: 修改操作成功,代码段允许映射rx权限 + */ +HWTEST_F(XpmEnforceBinNormalTest, FileMprotectCodeRoToRxTest, TestSize.Level0) +{ + void *addr = mmap(NULL, g_codeSize, PROT_READ, MAP_PRIVATE, g_fd, g_codeOffset & PAGE_MASK); + EXPECT_NE(MAP_FAILED, addr); + + // mprotect success at enforce mode + int ret = mprotect(addr, g_codeSize, PROT_READ | PROT_EXEC); + EXPECT_EQ(0, ret); + + // release resource + munmap(addr, g_codeSize); +} + +/** + * @tc.number 9 + * @tc.name: FileMprotectCodeRxToRwxTest + * @tc.desc: 二进制普通文件代码段文件映射的r-x权限内存通过mprotect修改为rwx权限 + * @tc.result: 修改操作失败,代码段允许映射同时映射wx权限 + */ +HWTEST_F(XpmEnforceBinNormalTest, FileMprotectCodeRxToRwxTest, TestSize.Level0) +{ + void *addr = mmap(NULL, g_codeSize, PROT_READ | PROT_EXEC, MAP_PRIVATE, g_fd, g_codeOffset & PAGE_MASK); + EXPECT_NE(MAP_FAILED, addr); + + // mprotect failed at enforce mode, has [protection] error + int ret = mprotect(addr, g_codeSize, PROT_READ | PROT_WRITE | PROT_EXEC); + EXPECT_NE(0, ret); + + // release resource + munmap(addr, g_codeSize); +} + +/** + * @tc.number 10 + * @tc.name: FileMprotectDataRwToRwxTest + * @tc.desc: 二进制普通文件代码段文件映射的rw-权限内存通过mprotect修改为rwx权限 + * @tc.result: 修改操作失败,代码段允许映射同时映射wx权限 + */ +HWTEST_F(XpmEnforceBinNormalTest, FileMprotectCodeRwToRwxTest, TestSize.Level0) +{ + void *addr = mmap(NULL, g_codeSize, PROT_READ | PROT_WRITE, MAP_PRIVATE, g_fd, g_codeOffset & PAGE_MASK); + EXPECT_NE(MAP_FAILED, addr); + + // mprotect failed at enforce mode, has [protection] error + int ret = mprotect(addr, g_codeSize, PROT_READ | PROT_WRITE | PROT_EXEC); + EXPECT_NE(0, ret); + + // release resource + munmap(addr, g_codeSize); +} + +/** + * @tc.number 12 + * @tc.name: FileMprotectDataRwToRwxTest + * @tc.desc: 二进制普通文件数据段文件映射的r--权限内存通过mremap修改为r-x权限 + * @tc.result: 修改操作失败,数据段不允许映射x权限 + */ +HWTEST_F(XpmEnforceBinNormalTest, FileRemapDataRoToRxTest, TestSize.Level0) +{ + void *addr1 = mmap(NULL, g_dataSize, PROT_READ | PROT_WRITE, MAP_PRIVATE, g_fd, g_dataOffset & PAGE_MASK); + EXPECT_NE(MAP_FAILED, addr1); + + void *addr2 = mremap(addr1, g_dataSize, g_dataSize, MREMAP_MAYMOVE); + EXPECT_NE(MAP_FAILED, addr2); + + // mprotect failed at enforce mode, has [signature] error + int ret = mprotect(addr2, g_dataSize, PROT_READ | PROT_EXEC); + EXPECT_NE(0, ret); + + // release resource + munmap(addr2, g_dataSize); +} + +/** + * @tc.number 13 + * @tc.name: FileRemapDataRwToRxTest + * @tc.desc: 二进制普通文件数据段文件映射的rw-权限内存通过mremap修改为r-x权限 + * @tc.result: 修改操作失败,数据段不允许映射x权限 + */ +HWTEST_F(XpmEnforceBinNormalTest, FileRemapDataRwToRxTest, TestSize.Level0) +{ + void *addr1 = mmap(NULL, g_dataSize, PROT_READ | PROT_WRITE, MAP_PRIVATE, g_fd, g_dataOffset & PAGE_MASK); + EXPECT_NE(MAP_FAILED, addr1); + + void *addr2 = mremap(addr1, g_dataSize, g_dataSize, MREMAP_MAYMOVE); + EXPECT_NE(MAP_FAILED, addr2); + + // mprotect failed at enforce mode, has [signature] error + int ret = mprotect(addr2, g_dataSize, PROT_READ | PROT_EXEC); + EXPECT_NE(0, ret); + + // release resource + munmap(addr2, g_dataSize); +} + +/** + * @tc.number 14 + * @tc.name: FileRemapDataRwToRwxTest + * @tc.desc: 二进制普通文件数据段文件映射的rw-权限内存通过mremap修改为rwx权限 + * @tc.result: 修改操作失败,文件映射不允许wx权限 + */ +HWTEST_F(XpmEnforceBinNormalTest, FileRemapDataRwToRwxTest, TestSize.Level0) +{ + void *addr1 = mmap(NULL, g_dataSize, PROT_READ | PROT_WRITE, MAP_PRIVATE, g_fd, g_dataOffset & PAGE_MASK); + EXPECT_NE(MAP_FAILED, addr1); + + void *addr2 = mremap(addr1, g_dataSize, g_dataSize, MREMAP_MAYMOVE); + EXPECT_NE(MAP_FAILED, addr2); + + // mprotect failed at enforce mode, has [protection] error + int ret = mprotect(addr1, g_dataSize, PROT_READ | PROT_WRITE | PROT_EXEC); + EXPECT_NE(0, ret); + + // release resource + munmap(addr2, g_dataSize); +} + +/** + * @tc.number 15 + * @tc.name: FileRemapCodeRoToRxTest + * @tc.desc: 二进制普通文件代码段文件映射的r--权限内存通过mremap修改为r-x权限 + * @tc.result: 修改操作成功,代码段允许映射x权限 + */ +HWTEST_F(XpmEnforceBinNormalTest, FileRemapCodeRoToRxTest, TestSize.Level0) +{ + void *addr1 = mmap(NULL, g_codeSize, PROT_READ, MAP_PRIVATE, g_fd, g_codeOffset & PAGE_MASK); + EXPECT_NE(MAP_FAILED, addr1); + + void *addr2 = mremap(addr1, g_codeSize, g_codeSize, MREMAP_MAYMOVE); + EXPECT_NE(MAP_FAILED, addr2); + + // mprotect success at enforce mode + int ret = mprotect(addr2, g_codeSize, PROT_READ | PROT_EXEC); + EXPECT_EQ(0, ret); + + // release resource + munmap(addr2, g_codeSize); +} + +/** + * @tc.number 16 + * @tc.name: FileRemapCodeRwToRwxTest + * @tc.desc: 二进制普通文件代码段文件映射的rw-权限内存通过mremap修改为rwx权限 + * @tc.result: 修改操作失败,映射不允许同时拥有wx权限 + */ +HWTEST_F(XpmEnforceBinNormalTest, FileRemapCodeRwToRwxTest, TestSize.Level0) +{ + void *addr1 = mmap(NULL, g_codeSize, PROT_READ | PROT_WRITE, MAP_PRIVATE, g_fd, g_codeOffset & PAGE_MASK); + ASSERT_NE(MAP_FAILED, addr1); + + void *addr2 = mremap(addr1, g_codeSize, g_codeSize, MREMAP_MAYMOVE); + ASSERT_NE(MAP_FAILED, addr2); + + // mprotect success at enforce mode + int ret = mprotect(addr2, g_codeSize, PROT_READ | PROT_WRITE | PROT_EXEC); + EXPECT_NE(0, ret); + + // release resource + munmap(addr2, g_codeSize); +} + +/** + * @tc.number 17 + * @tc.name: FileMprotectCodeRwToRwxTest + * @tc.desc: 二进制普通文件代码段文件映射的rw-权限内存通过mremap修改为r-x权限 + * @tc.result: 修改操作成功,执行代码段时失败,代码段不允许先设置rw权限,后设置rx权限 + */ +HWTEST_F(XpmEnforceBinNormalTest, FileRemapCodeRwToRxTest, TestSize.Level0) +{ + void *addr1 = mmap(NULL, g_codeSize, PROT_READ | PROT_WRITE, MAP_PRIVATE, g_fd, g_codeOffset & PAGE_MASK); + ASSERT_NE(MAP_FAILED, addr1); + + void *addr2 = mremap(addr1, g_codeSize, g_codeSize, MREMAP_MAYMOVE); + ASSERT_NE(MAP_FAILED, addr2); + + // mprotect success at enforce mode + int ret = mprotect(addr2, g_codeSize, PROT_READ | PROT_EXEC); + EXPECT_EQ(0, ret); + + // release resource + munmap(addr2, g_codeSize); +} + +/** + * @tc.number 18 + * @tc.name: AnonMmapRwTest + * @tc.desc: 二进制匿名映射rw-权限内存 + * @tc.result: 匿名映射成功,代码执行权限管控允许映射rw-匿名内存 + */ +HWTEST_F(XpmEnforceBinNormalTest, AnonMmapRwTest, TestSize.Level0) +{ + void *addr = mmap(NULL, ANON_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + EXPECT_NE(MAP_FAILED, addr); + + // release resource + munmap(addr, ANON_SIZE); +} + +/** + * @tc.number 19 + * @tc.name: AnonMmapRwxTest + * @tc.desc: 二进制匿名映射rwx权限内存 + * @tc.result: 匿名映射失败,匿名映射不允许x权限 + */ +HWTEST_F(XpmEnforceBinNormalTest, AnonMmapRwxTest, TestSize.Level0) +{ + void *addr = mmap(NULL, ANON_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + EXPECT_EQ(MAP_FAILED, addr); +} + +/** + * @tc.number 20 + * @tc.name: AnonMprotectRwToRwxTest + * @tc.desc: 二进制匿名映射的rw权限内存通过mprotect修改为rwx匿名内存 + * @tc.result: 修改匿名内存为rwx失败,匿名映射不允许x权限 + */ +HWTEST_F(XpmEnforceBinNormalTest, AnonMprotectRwToRwxTest, TestSize.Level0) +{ + // 1. 匿名映射映射rw-内存 + void *addr = mmap(NULL, ANON_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + EXPECT_NE(MAP_FAILED, addr); + + // 2. 修改匿名内存为rwx + int ret = mprotect(addr, ANON_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC); + EXPECT_NE(0, ret); + + // release resource + munmap(addr, ANON_SIZE); +} + +/** + * @tc.number 21 + * @tc.name: AnonMprotectRwToRwxTest + * @tc.desc: 二进制匿名映射的rw-权限内存通过mprotect修改为r--匿名内存,之后再修改为r-x匿名内存 + * @tc.result: 修改匿名内存为rx失败,匿名映射不允许x权限 + */ +HWTEST_F(XpmEnforceBinNormalTest, AnonMprotectRwToRoToRxTest, TestSize.Level0) +{ + // 1. 匿名映射映射rw-内存 + void *addr = mmap(NULL, ANON_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + EXPECT_NE(MAP_FAILED, addr); + + // 2. 修改匿名内存为r-- + int ret = mprotect(addr, ANON_SIZE, PROT_READ); + EXPECT_EQ(0, ret); + + // 3. 修改匿名内存为r-x + ret = mprotect(addr, ANON_SIZE, PROT_READ | PROT_EXEC); + EXPECT_NE(0, ret); + + // release resource + munmap(addr, ANON_SIZE); +} + +/** + * @tc.number 22 + * @tc.name: AnonRmapRwToRxTest + * @tc.desc: 二进制匿名映射的rw-权限内存重映射到r-x匿名内存 + * @tc.result: 重映射到r-x失败,匿名映射不允许x权限 + */ +HWTEST_F(XpmEnforceBinNormalTest, AnonRmapRwToRxTest, TestSize.Level0) +{ + // 1. 匿名映射映射rw-内存 + void *addr1 = mmap(NULL, ANON_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + EXPECT_NE(MAP_FAILED, addr1); + + // 2. 重映射匿名内存 + void *addr2 = mremap(addr1, ANON_SIZE, NEW_ANON_SIZE, MREMAP_MAYMOVE); + EXPECT_NE(MAP_FAILED, addr2); + + // 3. 修改匿名内存为r-x + int ret = mprotect(addr2, NEW_ANON_SIZE, PROT_READ | PROT_EXEC); + EXPECT_NE(0, ret); + + // release resource + munmap(addr2, ANON_SIZE); +} + +} // namespace XpmUnitTest +} // namespace Security +} // namespace OHOS \ No newline at end of file diff --git a/xpm_test/xpm_enforce_bin_normal_test.h b/xpm_test/xpm_enforce_bin_normal_test.h new file mode 100644 index 0000000000000000000000000000000000000000..f4dcabb6d1468189b112be51f9f6b71b67d9975e --- /dev/null +++ b/xpm_test/xpm_enforce_bin_normal_test.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 XPM_ENFORCE_BIN_NORMAL_TEST +#define XPM_ENFORCE_BIN_NORMAL_TEST + +#include + +namespace OHOS { +namespace Security { +namespace XpmUnitTest { +using namespace testing::ext; +class XpmEnforceBinNormalTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp() override; + void TearDown() override; +}; +} // namespace XpmUnitTest +} // namespace Security +} // namespace OHOS + +#endif // XPM_ENFORCE_BIN_NORMAL_TEST \ No newline at end of file diff --git a/xpm_test/xpm_enforce_bin_webview_test.cpp b/xpm_test/xpm_enforce_bin_webview_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..91fcba28e113af5962f49c410f0796ef67a9e2c0 --- /dev/null +++ b/xpm_test/xpm_enforce_bin_webview_test.cpp @@ -0,0 +1,459 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * 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 "xpm_enforce_bin_webview_test.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "selinux/selinux.h" +#include "file_ex.h" +#include "xpm_common.h" +#include "xpm_elf.h" +#include "xpm_log.h" + +using namespace std; +using namespace std::chrono; +using namespace testing; +using namespace testing::ext; + +namespace OHOS { +namespace Security { +namespace XpmUnitTest { +static int g_fd; +static unsigned long g_dataOffset, g_dataSize; +static unsigned long g_codeOffset, g_codeSize; + +void XpmEnforceBinWebviewTest::SetUpTestCase() +{ + SaveStringToFile(SELINUX_MODE_PATH, PERMISSIVE_MODE); + + g_fd = open(XPM_LIB_PATH.c_str(), O_RDWR); + ASSERT_NE(g_fd, -1) << "open xpm lib failed: " << strerror(errno); + + int ret = GetDataSegment(XPM_LIB_PATH.c_str(), &g_dataOffset, &g_dataSize); + ASSERT_EQ(0, ret) << "GetDataSegment failed: " << ret; + + ret = GetCodeSegment(XPM_LIB_PATH.c_str(), &g_codeOffset, &g_codeSize); + ASSERT_EQ(0, ret) << "GetCodeSegment failed: " << ret; + + ret = SetCon(SELINUX_TYPE_NWEBSPAWN.c_str()); + ASSERT_EQ(0, ret) << "SetCon failed: " << strerror(errno); + + SaveStringToFile(XPM_DEBUG_FS_MODE_PATH, ENFORCE_MODE); +} + +void XpmEnforceBinWebviewTest::TearDownTestCase() +{ + close(g_fd); + SetCon(SELINUX_TYPE_SH.c_str()); + SaveStringToFile(XPM_DEBUG_FS_MODE_PATH, PERMISSIVE_MODE); + SaveStringToFile(SELINUX_MODE_PATH, ENFORCE_MODE); +} + +void XpmEnforceBinWebviewTest::SetUp() +{ +} + +void XpmEnforceBinWebviewTest::TearDown() +{ +} + +/** + * @tc.number 2 + * @tc.name: FileMmapDataToRxTest + * @tc.desc: Webview数据段文件映射到r-x权限内存 + * @tc.result: 映射失败,数据段不允许映射执行权限(同普通进程) + */ +HWTEST_F(XpmEnforceBinWebviewTest, FileMmapDataToRxTest, TestSize.Level0) +{ + // mmap failed, has [signature] error + void *addr = mmap(NULL, g_dataSize, PROT_READ | PROT_EXEC, MAP_PRIVATE, g_fd, g_dataOffset & PAGE_MASK); + EXPECT_EQ(MAP_FAILED, addr); +} + +/** + * @tc.number 3 + * @tc.name: FileMmapCodeToRxTest + * @tc.desc: Webview代码段文件映射到r-x权限内存 + * @tc.result: 映射成功,代码段允许映射执行权限(同普通进程) + */ +HWTEST_F(XpmEnforceBinWebviewTest, FileMmapCodeToRxTest, TestSize.Level0) +{ + // mmap success at enforce mode + void *addr = mmap(NULL, g_codeSize, PROT_READ | PROT_EXEC, MAP_PRIVATE, g_fd, g_codeOffset & PAGE_MASK); + EXPECT_NE(MAP_FAILED, addr); + + // release resource + munmap(addr, g_codeSize); +} + +/** + * @tc.number 4 + * @tc.name: FileMmapDataToRwxTest + * @tc.desc: Webview数据段文件映射到rwx权限内存 + * @tc.result: 映射失败,文件映射不允许同时映射wx权限(同普通进程) + */ +HWTEST_F(XpmEnforceBinWebviewTest, FileMmapDataToRwxTest, TestSize.Level0) +{ + // mmap failed at enforce mode, has [protection] error + void *addr = mmap(NULL, g_dataSize, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE, g_fd, g_dataOffset & PAGE_MASK); + EXPECT_EQ(MAP_FAILED, addr); +} + +/** + * @tc.number 5 + * @tc.name: FileMmapCodeToRwxTest + * @tc.desc: 二Webview代码段文件映射到rwx权限内存 + * @tc.result: 映射失败,文件映射不允许同时映射wx权限(同普通进程) + */ +HWTEST_F(XpmEnforceBinWebviewTest, FileMmapCodeToRwxTest, TestSize.Level0) +{ + // mmap failed at enforce mode, has [protection] error + void *addr = mmap(NULL, g_codeSize, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE, g_fd, g_codeOffset & PAGE_MASK); + EXPECT_EQ(MAP_FAILED, addr); +} + +/** + * @tc.number 6 + * @tc.name: FileMprotectDataRoToRxTest + * @tc.desc: Webview数据段文件映射的r--权限内存通过mprotect修改为r-x权限 + * @tc.result: 修改操作失败,数据段不允许映射x权限(同普通进程) + */ +HWTEST_F(XpmEnforceBinWebviewTest, FileMprotectDataRoToRxTest, TestSize.Level0) +{ + void *addr = mmap(NULL, g_dataSize, PROT_READ, MAP_PRIVATE, g_fd, g_dataOffset & PAGE_MASK); + EXPECT_NE(MAP_FAILED, addr); + + // mprotect failed at enforce mode, has [signature] error + int ret = mprotect(addr, g_dataSize, PROT_READ | PROT_EXEC); + EXPECT_NE(0, ret); + + // release resource + munmap(addr, g_dataSize); +} + +/** + * @tc.number 7 + * @tc.name: FileMprotectDataRwToRwxTest + * @tc.desc: Webview数据段文件映射的rw-权限内存通过mprotect修改为rwx权限 + * @tc.result: 修改操作失败,数据段不允许映射x权限(同普通进程) + */ +HWTEST_F(XpmEnforceBinWebviewTest, FileMprotectDataRwToRwxTest, TestSize.Level0) +{ + void *addr = mmap(NULL, g_dataSize, PROT_READ | PROT_WRITE, MAP_PRIVATE, g_fd, g_dataOffset & PAGE_MASK); + EXPECT_NE(MAP_FAILED, addr); + + // mprotect failed at permissive mode, has [protection] error + int ret = mprotect(addr, g_dataSize, PROT_READ | PROT_WRITE | PROT_EXEC); + EXPECT_NE(0, ret); + + // release resource + munmap(addr, g_dataSize); +} + +/** + * @tc.number 8 + * @tc.name: FileMprotectCodeRoToRxTest + * @tc.desc: Webview代码段文件映射的r--权限内存通过mprotect修改为r-x权限 + * @tc.result: 修改操作成功,代码段允许映射rx权限(同普通进程) + */ +HWTEST_F(XpmEnforceBinWebviewTest, FileMprotectCodeRoToRxTest, TestSize.Level0) +{ + void *addr = mmap(NULL, g_codeSize, PROT_READ, MAP_PRIVATE, g_fd, g_codeOffset & PAGE_MASK); + EXPECT_NE(MAP_FAILED, addr); + + // mprotect success at enforce mode + int ret = mprotect(addr, g_codeSize, PROT_READ | PROT_EXEC); + EXPECT_EQ(0, ret); + + // release resource + munmap(addr, g_codeSize); +} + +/** + * @tc.number 9 + * @tc.name: FileMprotectCodeRxToRwxTest + * @tc.desc: Webview代码段文件映射的r-x权限内存通过mprotect修改为rwx权限 + * @tc.result: 修改操作失败,代码段允许映射同时映射wx权限(同普通进程) + */ +HWTEST_F(XpmEnforceBinWebviewTest, FileMprotectCodeRxToRwxTest, TestSize.Level0) +{ + void *addr = mmap(NULL, g_codeSize, PROT_READ | PROT_EXEC, MAP_PRIVATE, g_fd, g_codeOffset & PAGE_MASK); + EXPECT_NE(MAP_FAILED, addr); + + // mprotect failed at enforce mode, has [protection] error + int ret = mprotect(addr, g_codeSize, PROT_READ | PROT_WRITE | PROT_EXEC); + EXPECT_NE(0, ret); + + // release resource + munmap(addr, g_codeSize); +} + +/** + * @tc.number 10 + * @tc.name: FileMprotectDataRwToRwxTest + * @tc.desc: Webview代码段文件映射的rw-权限内存通过mprotect修改为rwx权限 + * @tc.result: 修改操作失败,代码段允许映射同时映射wx权限(同普通进程) + */ +HWTEST_F(XpmEnforceBinWebviewTest, FileMprotectCodeRwToRwxTest, TestSize.Level0) +{ + void *addr = mmap(NULL, g_codeSize, PROT_READ | PROT_WRITE, MAP_PRIVATE, g_fd, g_codeOffset & PAGE_MASK); + EXPECT_NE(MAP_FAILED, addr); + + // mprotect failed at enforce mode, has [protection] error + int ret = mprotect(addr, g_codeSize, PROT_READ | PROT_WRITE | PROT_EXEC); + EXPECT_NE(0, ret); + + // release resource + munmap(addr, g_codeSize); +} + +/** + * @tc.number 12 + * @tc.name: FileMprotectDataRwToRwxTest + * @tc.desc: Webview数据段文件映射的r--权限内存通过mremap修改为r-x权限 + * @tc.result: 修改操作失败,数据段不允许映射x权限(同普通进程) + */ +HWTEST_F(XpmEnforceBinWebviewTest, FileRemapDataRoToRxTest, TestSize.Level0) +{ + void *addr1 = mmap(NULL, g_dataSize, PROT_READ | PROT_WRITE, MAP_PRIVATE, g_fd, g_dataOffset & PAGE_MASK); + EXPECT_NE(MAP_FAILED, addr1); + + void *addr2 = mremap(addr1, g_dataSize, g_dataSize, MREMAP_MAYMOVE); + EXPECT_NE(MAP_FAILED, addr2); + + // mprotect failed at enforce mode, has [signature] error + int ret = mprotect(addr2, g_dataSize, PROT_READ | PROT_EXEC); + EXPECT_NE(0, ret); + + // release resource + munmap(addr2, g_dataSize); +} + +/** + * @tc.number 13 + * @tc.name: FileRemapDataRwToRxTest + * @tc.desc: Webview数据段文件映射的rw-权限内存通过mremap修改为r-x权限 + * @tc.result: 修改操作失败,数据段不允许映射x权限(同普通进程) + */ +HWTEST_F(XpmEnforceBinWebviewTest, FileRemapDataRwToRxTest, TestSize.Level0) +{ + void *addr1 = mmap(NULL, g_dataSize, PROT_READ | PROT_WRITE, MAP_PRIVATE, g_fd, g_dataOffset & PAGE_MASK); + EXPECT_NE(MAP_FAILED, addr1); + + void *addr2 = mremap(addr1, g_dataSize, g_dataSize, MREMAP_MAYMOVE); + EXPECT_NE(MAP_FAILED, addr2); + + // mprotect failed at enforce mode, has [signature] error + int ret = mprotect(addr2, g_dataSize, PROT_READ | PROT_EXEC); + EXPECT_NE(0, ret); + + // release resource + munmap(addr2, g_dataSize); +} + +/** + * @tc.number 14 + * @tc.name: FileRemapDataRwToRwxTest + * @tc.desc: Webview数据段文件映射的rw-权限内存通过mremap修改为rwx权限 + * @tc.result: 修改操作失败,数据段不允许映射x权限(同普通进程) + */ +HWTEST_F(XpmEnforceBinWebviewTest, FileRemapDataRwToRwxTest, TestSize.Level0) +{ + void *addr1 = mmap(NULL, g_dataSize, PROT_READ | PROT_WRITE, MAP_PRIVATE, g_fd, g_dataOffset & PAGE_MASK); + EXPECT_NE(MAP_FAILED, addr1); + + void *addr2 = mremap(addr1, g_dataSize, g_dataSize, MREMAP_MAYMOVE); + EXPECT_NE(MAP_FAILED, addr2); + + // mprotect failed at enforce mode, has [protection] error + int ret = mprotect(addr1, g_dataSize, PROT_READ | PROT_WRITE | PROT_EXEC); + EXPECT_NE(0, ret); + + // release resource + munmap(addr2, g_dataSize); +} + +/** + * @tc.number 15 + * @tc.name: FileRemapCodeRoToRxTest + * @tc.desc: Webview代码段文件映射的r--权限内存通过mremap修改为r-x权限 + * @tc.result: 修改操作成功,代码段允许映射x权限(同普通进程) + */ +HWTEST_F(XpmEnforceBinWebviewTest, FileRemapCodeRoToRxTest, TestSize.Level0) +{ + void *addr1 = mmap(NULL, g_codeSize, PROT_READ, MAP_PRIVATE, g_fd, g_codeOffset & PAGE_MASK); + EXPECT_NE(MAP_FAILED, addr1); + + void *addr2 = mremap(addr1, g_codeSize, g_codeSize, MREMAP_MAYMOVE); + EXPECT_NE(MAP_FAILED, addr2); + + // mprotect success at enforce mode + int ret = mprotect(addr2, g_codeSize, PROT_READ | PROT_EXEC); + EXPECT_EQ(0, ret); + + // release resource + munmap(addr2, g_codeSize); +} + +/** + * @tc.number 16 + * @tc.name: FileRemapCodeRwToRwxTest + * @tc.desc: Webview代码段文件映射的rw-权限内存通过mremap修改为rwx权限 + * @tc.result: 修改操作失败,映射不允许同时拥有wx权限(同普通进程) + */ +HWTEST_F(XpmEnforceBinWebviewTest, FileRemapCodeRwToRwxTest, TestSize.Level0) +{ + void *addr1 = mmap(NULL, g_codeSize, PROT_READ | PROT_WRITE, MAP_PRIVATE, g_fd, g_codeOffset & PAGE_MASK); + ASSERT_NE(MAP_FAILED, addr1); + + void *addr2 = mremap(addr1, g_codeSize, g_codeSize, MREMAP_MAYMOVE); + ASSERT_NE(MAP_FAILED, addr2); + + // mprotect success at enforce mode + int ret = mprotect(addr2, g_codeSize, PROT_READ | PROT_WRITE | PROT_EXEC); + EXPECT_NE(0, ret); + + // release resource + munmap(addr2, g_codeSize); +} + +/** + * @tc.number 17 + * @tc.name: FileMprotectCodeRwToRwxTest + * @tc.desc: Webview代码段文件映射的rw-权限内存通过mremap修改为r-x权限 + * @tc.result: 修改操作成功,执行代码段时失败,代码段不允许先设置rw权限,后设置rx权限(同普通进程) + */ +HWTEST_F(XpmEnforceBinWebviewTest, FileRemapCodeRwToRxTest, TestSize.Level0) +{ + void *addr1 = mmap(NULL, g_codeSize, PROT_READ | PROT_WRITE, MAP_PRIVATE, g_fd, g_codeOffset & PAGE_MASK); + ASSERT_NE(MAP_FAILED, addr1); + + void *addr2 = mremap(addr1, g_codeSize, g_codeSize, MREMAP_MAYMOVE); + ASSERT_NE(MAP_FAILED, addr2); + + // mprotect success at enforce mode + int ret = mprotect(addr2, g_codeSize, PROT_READ | PROT_EXEC); + EXPECT_EQ(0, ret); + + // release resource + munmap(addr2, g_codeSize); +} + +/** + * @tc.number 18 + * @tc.name: AnonMmapRwTest + * @tc.desc: Webview匿名映射rw-权限内存 + * @tc.result: 匿名映射成功,rw-匿名内存不管控 + */ +HWTEST_F(XpmEnforceBinWebviewTest, AnonMmapRwTest, TestSize.Level0) +{ + void *addr = mmap(NULL, ANON_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + EXPECT_NE(MAP_FAILED, addr); + + // release resource + munmap(addr, ANON_SIZE); +} + +/** + * @tc.number 19 + * @tc.name: AnonMmapRwxTest + * @tc.desc: weebview匿名映射rwx权限内存 + * @tc.result: 匿名映射成功,webview匿名映射x权限内存(同debug_hap进程) + */ +HWTEST_F(XpmEnforceBinWebviewTest, AnonMmapRwxTest, TestSize.Level0) +{ + void *addr = mmap(NULL, ANON_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + EXPECT_NE(MAP_FAILED, addr); +} + +/** + * @tc.number 20 + * @tc.name: AnonMprotectRwToRwxTest + * @tc.desc: webview匿名映射的rw权限内存通过mprotect修改为rwx匿名内存 + * @tc.result: 修改webview匿名内存为rwx成功,webview匿名映射x权限内存(同debug_hap进程) + */ +HWTEST_F(XpmEnforceBinWebviewTest, AnonMprotectRwToRwxTest, TestSize.Level0) +{ + // 1. 匿名映射映射rw-内存 + void *addr = mmap(NULL, ANON_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + EXPECT_NE(MAP_FAILED, addr); + + // 2. 修改匿名内存为rwx + int ret = mprotect(addr, ANON_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC); + EXPECT_EQ(0, ret); + + // release resource + munmap(addr, ANON_SIZE); +} + +/** + * @tc.number 21 + * @tc.name: AnonMprotectRwToRwxTest + * @tc.desc: webview匿名映射的rw-权限内存通过mprotect修改为r--匿名内存,之后再修改为r-x匿名内存 + * @tc.result: 修改匿名内存为rx成功,webview匿名映射x权限内存(同debug_hap进程) + */ +HWTEST_F(XpmEnforceBinWebviewTest, AnonMprotectRwToRoToRxTest, TestSize.Level0) +{ + // 1. 匿名映射映射rw-内存 + void *addr = mmap(NULL, ANON_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + EXPECT_NE(MAP_FAILED, addr); + + // 2. 修改匿名内存为r-- + int ret = mprotect(addr, ANON_SIZE, PROT_READ); + EXPECT_EQ(0, ret); + + // 3. 修改匿名内存为r-x + ret = mprotect(addr, ANON_SIZE, PROT_READ | PROT_EXEC); + EXPECT_EQ(0, ret); + + // release resource + munmap(addr, ANON_SIZE); +} + +/** + * @tc.number 22 + * @tc.name: AnonRmapRwToRxTest + * @tc.desc: webview匿名映射的rw-权限内存重映射到r-x匿名内存 + * @tc.result: 重映射到r-x成功,webview匿名映射x权限内存(同debug_hap进程) + */ +HWTEST_F(XpmEnforceBinWebviewTest, AnonRmapRwToRxTest, TestSize.Level0) +{ + // 1. 匿名映射映射rw-内存 + void *addr1 = mmap(NULL, ANON_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + EXPECT_NE(MAP_FAILED, addr1); + + // 2. 重映射匿名内存 + void *addr2 = mremap(addr1, ANON_SIZE, NEW_ANON_SIZE, MREMAP_MAYMOVE); + EXPECT_NE(MAP_FAILED, addr2); + + // 3. 修改匿名内存为r-x + int ret = mprotect(addr2, NEW_ANON_SIZE, PROT_READ | PROT_EXEC); + EXPECT_EQ(0, ret); + + // release resource + munmap(addr2, ANON_SIZE); +} + +} // namespace XpmUnitTest +} // namespace Security +} // namespace OHOS \ No newline at end of file diff --git a/xpm_test/xpm_enforce_bin_webview_test.h b/xpm_test/xpm_enforce_bin_webview_test.h new file mode 100644 index 0000000000000000000000000000000000000000..e829420ae22df54f349451fb6247bb7bd28e173c --- /dev/null +++ b/xpm_test/xpm_enforce_bin_webview_test.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 XPM_ENFORCE_BIN_WEBVIEW_TEST +#define XPM_ENFORCE_BIN_WEBVIEW_TEST + +#include + +namespace OHOS { +namespace Security { +namespace XpmUnitTest { +using namespace testing::ext; +class XpmEnforceBinWebviewTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp() override; + void TearDown() override; +}; +} // namespace XpmUnitTest +} // namespace Security +} // namespace OHOS + +#endif // XPM_ENFORCE_BIN_WEBVIEW_TEST \ No newline at end of file diff --git a/xpm_test/xpm_enforce_test.cpp b/xpm_test/xpm_enforce_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fbdad7021f2f833c607a95d3c797d21b9f7cfbd2 --- /dev/null +++ b/xpm_test/xpm_enforce_test.cpp @@ -0,0 +1,1358 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * 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 "xpm_enforce_test.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "file_ex.h" +#include "xpm_common.h" +#include "xpm_elf.h" +#include "xpm_log.h" + +using namespace std; +using namespace std::chrono; +using namespace testing; +using namespace testing::ext; + +namespace OHOS { +namespace Security { +namespace XpmUnitTest { +#define XPM_LIB_PATH "/system/lib64/libxpm.z.so" + +void XpmEnforceTest::SetUpTestCase() +{ + SaveStringToFile(XPM_DEBUG_FS_MODE_PATH, "1"); +} +void XpmEnforceTest::TearDownTestCase() +{ + SaveStringToFile(XPM_DEBUG_FS_MODE_PATH, "0"); +} +void XpmEnforceTest::SetUp() +{ +} +void XpmEnforceTest::TearDown() +{ +} + +/** + * @tc.number 2 + * @tc.name: BIN_NormalFileMmapDataToRxTest + * @tc.desc: 二进制普通文件数据段文件映射到r-x权限内存 + * @tc.result: 映射失败,数据段不允许映射执行权限 + */ +HWTEST_F(XpmEnforceTest, BIN_NormalFileMmapDataToRxTest, TestSize.Level0) +{ + unsigned long offset, size; + + // get lib code segment + int ret = XpmElf::GetDataSegment(const_cast(XPM_LIB_PATH), &offset, &size); + EXPECT_EQ(0, ret); + + int fd = open(const_cast(XPM_LIB_PATH), O_RDWR); + ASSERT_NE(fd, -1) << "open xpm lib failed: " << strerror(errno); + + // mmap failed at enforce mode, has [signature] error + void *addr = mmap(NULL, size, PROT_READ | PROT_EXEC, MAP_PRIVATE, fd, offset & PAGE_MASK); + EXPECT_EQ(MAP_FAILED, addr); + + // release resource + close(fd); +} + +/** + * @tc.number 3 + * @tc.name: BIN_NormalFileMmapCodeToRxTest + * @tc.desc: 二进制普通文件代码段文件映射到r-x权限内存 + * @tc.result: 映射成功,代码段允许映射执行权限 + */ +HWTEST_F(XpmEnforceTest, BIN_NormalFileMmapCodeToRxTest, TestSize.Level0) +{ + unsigned long offset, size; + + // get lib code segment + int ret = XpmElf::GetCodeSegment(const_cast(XPM_LIB_PATH), &offset, &size); + EXPECT_EQ(0, ret); + + int fd = open(const_cast(XPM_LIB_PATH), O_RDWR); + ASSERT_NE(fd, -1) << "open xpm lib failed: " << strerror(errno); + + // mmap success at enforce mode + void *addr = mmap(NULL, size, PROT_READ | PROT_EXEC, MAP_PRIVATE, fd, offset & PAGE_MASK); + EXPECT_NE(MAP_FAILED, addr); + + // release resource + munmap(addr, size); + close(fd); +} + +/** + * @tc.number 4 + * @tc.name: BIN_NormalFileMmapDataToRwxTest + * @tc.desc: 二进制普通文件数据段文件映射到rwx权限内存 + * @tc.result: 映射失败,文件映射不允许同时映射wx权限 + */ +HWTEST_F(XpmEnforceTest, BIN_NormalFileMmapDataToRwxTest, TestSize.Level0) +{ + unsigned long offset, size; + + // get lib code segment + int ret = XpmElf::GetDataSegment(const_cast(XPM_LIB_PATH), &offset, &size); + EXPECT_EQ(0, ret); + + int fd = open(const_cast(XPM_LIB_PATH), O_RDWR); + ASSERT_NE(fd, -1) << "open xpm lib failed: " << strerror(errno); + + // mmap failed at enforce mode, has [protection] error + void *addr = mmap(NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE, fd, offset & PAGE_MASK); + EXPECT_EQ(MAP_FAILED, addr); + + // release resource + close(fd); +} + +/** + * @tc.number 5 + * @tc.name: BIN_NormalFileMmapCodeToRwxTest + * @tc.desc: 二进制普通文件代码段文件映射到rwx权限内存 + * @tc.result: 映射失败,文件映射不允许同时映射wx权限 + */ +HWTEST_F(XpmEnforceTest, BIN_NormalFileMmapCodeToRwxTest, TestSize.Level0) +{ + unsigned long offset, size; + + // get lib code segment + int ret = XpmElf::GetCodeSegment(const_cast(XPM_LIB_PATH), &offset, &size); + EXPECT_EQ(0, ret); + + int fd = open(const_cast(XPM_LIB_PATH), O_RDWR); + ASSERT_NE(fd, -1) << "open xpm lib failed: " << strerror(errno); + + // mmap failed at enforce mode, has [protection] error + void *addr = mmap(NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE, fd, offset & PAGE_MASK); + EXPECT_EQ(MAP_FAILED, addr); + + // release resource + close(fd); +} + +/** + * @tc.number 6 + * @tc.name: BIN_NormalFileMprotectDataRoToRxTest + * @tc.desc: 二进制普通文件数据段文件映射的r--权限内存通过mprotect修改为r-x权限 + * @tc.result: 修改操作失败,数据段不允许映射x权限 + */ +HWTEST_F(XpmEnforceTest, BIN_NormalFileMprotectDataRoToRxTest, TestSize.Level0) +{ + unsigned long offset, size; + + // get lib code segment + int ret = XpmElf::GetDataSegment(const_cast(XPM_LIB_PATH), &offset, &size); + EXPECT_EQ(0, ret); + + int fd = open(const_cast(XPM_LIB_PATH), O_RDWR); + ASSERT_NE(fd, -1) << "open xpm lib failed: " << strerror(errno); + + void *addr = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, offset & PAGE_MASK); + EXPECT_NE(MAP_FAILED, addr); + + // mprotect failed at enforce mode, has [signature] error + ret = mprotect(addr, size, PROT_READ | PROT_EXEC); + EXPECT_NE(0, ret); + + // release resource + munmap(addr, size); + close(fd); +} + +/** + * @tc.number 7 + * @tc.name: BIN_NormalFileMprotectDataRwToRwxTest + * @tc.desc: 二进制普通文件数据段文件映射的rw-权限内存通过mprotect修改为rwx权限 + * @tc.result: 修改操作失败,数据段不允许映射x权限 + */ +HWTEST_F(XpmEnforceTest, BIN_NormalFileMprotectDataRwToRwxTest, TestSize.Level0) +{ + unsigned long offset, size; + + // get lib code segment + int ret = XpmElf::GetDataSegment(const_cast(XPM_LIB_PATH), &offset, &size); + EXPECT_EQ(0, ret); + + int fd = open(const_cast(XPM_LIB_PATH), O_RDWR); + ASSERT_NE(fd, -1) << "open xpm lib failed: " << strerror(errno); + + void *addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, offset & PAGE_MASK); + EXPECT_NE(MAP_FAILED, addr); + + // mprotect failed at permissive mode, has [protection] error + ret = mprotect(addr, size, PROT_READ | PROT_WRITE | PROT_EXEC); + EXPECT_NE(0, ret); + + // release resource + munmap(addr, size); + close(fd); +} + +/** + * @tc.number 8 + * @tc.name: BIN_NormalFileMprotectDataRwToRwxTest + * @tc.desc: 二进制普通文件代码段文件映射的r--权限内存通过mprotect修改为r-x权限 + * @tc.result: 修改操作成功,代码段允许映射rx权限 + */ +HWTEST_F(XpmEnforceTest, BIN_NormalFileMprotectCodeRoToRxTest, TestSize.Level0) +{ + unsigned long offset, size; + + // get lib code segment + int ret = XpmElf::GetCodeSegment(const_cast(XPM_LIB_PATH), &offset, &size); + EXPECT_EQ(0, ret); + + int fd = open(const_cast(XPM_LIB_PATH), O_RDWR); + ASSERT_NE(fd, -1) << "open xpm lib failed: " << strerror(errno); + + void *addr = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, offset & PAGE_MASK); + EXPECT_NE(MAP_FAILED, addr); + + // mprotect success at enforce mode + ret = mprotect(addr, size, PROT_READ | PROT_EXEC); + EXPECT_EQ(0, ret); + + // release resource + munmap(addr, size); + close(fd); +} + +/** + * @tc.number 9 + * @tc.name: BIN_NormalFileMprotectCodeRxToRwxTest + * @tc.desc: 二进制普通文件代码段文件映射的r-x权限内存通过mprotect修改为rwx权限 + * @tc.result: 修改操作失败,代码段允许映射同时映射wx权限 + */ +HWTEST_F(XpmEnforceTest, BIN_NormalFileMprotectCodeRxToRwxTest, TestSize.Level0) +{ + unsigned long offset, size; + + // get lib code segment + int ret = XpmElf::GetCodeSegment(const_cast(XPM_LIB_PATH), &offset, &size); + EXPECT_EQ(0, ret); + + int fd = open(const_cast(XPM_LIB_PATH), O_RDWR); + ASSERT_NE(fd, -1) << "open xpm lib failed: " << strerror(errno); + + void *addr = mmap(NULL, size, PROT_READ | PROT_EXEC, MAP_PRIVATE, fd, offset & PAGE_MASK); + EXPECT_NE(MAP_FAILED, addr); + + // mprotect failed at enforce mode, has [protection] error + ret = mprotect(addr, size, PROT_READ | PROT_WRITE | PROT_EXEC); + EXPECT_NE(0, ret); + + // release resource + munmap(addr, size); + close(fd); +} + +/** + * @tc.number 10 + * @tc.name: BIN_NormalFileMprotectDataRwToRwxTest + * @tc.desc: 二进制普通文件代码段文件映射的rw-权限内存通过mprotect修改为rwx权限 + * @tc.result: 修改操作失败,代码段允许映射同时映射wx权限 + */ +HWTEST_F(XpmEnforceTest, BIN_NormalFileMprotectCodeRwToRwxTest, TestSize.Level0) +{ + unsigned long offset, size; + + // get lib code segment + int ret = XpmElf::GetCodeSegment(const_cast(XPM_LIB_PATH), &offset, &size); + EXPECT_EQ(0, ret); + + int fd = open(const_cast(XPM_LIB_PATH), O_RDWR); + ASSERT_NE(fd, -1) << "open xpm lib failed: " << strerror(errno); + + void *addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, offset & PAGE_MASK); + EXPECT_NE(MAP_FAILED, addr); + + // mprotect failed at enforce mode, has [protection] error + ret = mprotect(addr, size, PROT_READ | PROT_WRITE | PROT_EXEC); + EXPECT_NE(0, ret); + munmap(addr, size); + + // release resource + close(fd); +} + +/** + * @tc.number 12 + * @tc.name: BIN_NormalFileMprotectDataRwToRwxTest + * @tc.desc: 二进制普通文件数据段文件映射的r--权限内存通过mremap修改为r-x权限 + * @tc.result: 修改操作失败,数据段不允许映射x权限 + */ +HWTEST_F(XpmEnforceTest, BIN_NormalFileRemapDataRoToRxTest, TestSize.Level0) +{ + unsigned long offset, size; + + // get lib code segment + int ret = XpmElf::GetDataSegment(const_cast(XPM_LIB_PATH), &offset, &size); + EXPECT_EQ(0, ret); + + int fd = open(const_cast(XPM_LIB_PATH), O_RDWR); + ASSERT_NE(fd, -1) << "open xpm lib failed: " << strerror(errno); + + void *addr1 = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, offset & PAGE_MASK); + EXPECT_NE(MAP_FAILED, addr1); + + void *addr2 = mremap(addr1, size, size, MREMAP_MAYMOVE); + EXPECT_NE(MAP_FAILED, addr2); + + // mprotect failed at enforce mode, has [signature] error + ret = mprotect(addr2, size, PROT_READ | PROT_EXEC); + EXPECT_NE(0, ret); + + // release resource + munmap(addr2, size); + close(fd); +} + +/** + * @tc.number 13 + * @tc.name: BIN_NormalFileRemapDataRwToRxTest + * @tc.desc: 二进制普通文件数据段文件映射的rw-权限内存通过mremap修改为r-x权限 + * @tc.result: 修改操作失败,数据段不允许映射x权限 + */ +HWTEST_F(XpmEnforceTest, BIN_NormalFileRemapDataRwToRxTest, TestSize.Level0) +{ + unsigned long offset, size; + + // get lib code segment + int ret = XpmElf::GetDataSegment(const_cast(XPM_LIB_PATH), &offset, &size); + EXPECT_EQ(0, ret); + + int fd = open(const_cast(XPM_LIB_PATH), O_RDWR); + ASSERT_NE(fd, -1) << "open xpm lib failed: " << strerror(errno); + + void *addr1 = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, offset & PAGE_MASK); + EXPECT_NE(MAP_FAILED, addr1); + + void *addr2 = mremap(addr1, size, size, MREMAP_MAYMOVE); + EXPECT_NE(MAP_FAILED, addr2); + + // mprotect failed at enforce mode, has [signature] error + ret = mprotect(addr2, size, PROT_READ | PROT_EXEC); + EXPECT_NE(0, ret); + + // release resource + munmap(addr2, size); + close(fd); +} + +/** + * @tc.number 14 + * @tc.name: BIN_NormalFileRemapDataRwToRwxTest + * @tc.desc: 二进制普通文件数据段文件映射的rw-权限内存通过mremap修改为rwx权限 + * @tc.result: 修改操作失败,数据段不允许映射x权限 + */ +HWTEST_F(XpmEnforceTest, BIN_NormalFileRemapDataRwToRwxTest, TestSize.Level0) +{ + unsigned long offset, size; + + // get lib code segment + int ret = XpmElf::GetDataSegment(const_cast(XPM_LIB_PATH), &offset, &size); + EXPECT_EQ(0, ret); + + int fd = open(const_cast(XPM_LIB_PATH), O_RDWR); + ASSERT_NE(fd, -1) << "open xpm lib failed: " << strerror(errno); + + void *addr1 = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, offset & PAGE_MASK); + EXPECT_NE(MAP_FAILED, addr1); + + void *addr2 = mremap(addr1, size, size, MREMAP_MAYMOVE); + EXPECT_NE(MAP_FAILED, addr2); + + // mprotect failed at enforce mode, has [protection] error + ret = mprotect(addr1, size, PROT_READ | PROT_WRITE | PROT_EXEC); + EXPECT_NE(0, ret); + + // release resource + munmap(addr2, size); + close(fd); +} + +/** + * @tc.number 15 + * @tc.name: BIN_NormalFileMprotectCodeRwToRwxTest + * @tc.desc: 二进制普通文件代码段文件映射的r--权限内存通过mremap修改为r-x权限 + * @tc.result: 修改操作成功,代码段允许映射x权限 + */ +HWTEST_F(XpmEnforceTest, BIN_NormalFileRemapCodeRoToRxTest, TestSize.Level0) +{ + unsigned long offset, size; + + // get lib code segment + int ret = XpmElf::GetCodeSegment(const_cast(XPM_LIB_PATH), &offset, &size); + EXPECT_EQ(0, ret); + + int fd = open(const_cast(XPM_LIB_PATH), O_RDWR); + ASSERT_NE(fd, -1) << "open xpm lib failed: " << strerror(errno); + + void *addr1 = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, offset & PAGE_MASK); + EXPECT_NE(MAP_FAILED, addr1); + + void *addr2 = mremap(addr1, size, size, MREMAP_MAYMOVE); + EXPECT_NE(MAP_FAILED, addr2); + + // mprotect success at enforce mode + ret = mprotect(addr2, size, PROT_READ | PROT_EXEC); + EXPECT_EQ(0, ret); + + // release resource + munmap(addr2, size); + close(fd); +} + +/** + * @tc.number 16 + * @tc.name: BIN_NormalFileRemapCodeRwToRwxTest + * @tc.desc: 二进制普通文件代码段文件映射的rw-权限内存通过mremap修改为rwx权限 + * @tc.result: 修改操作失败,映射不允许同时拥有wx权限 + */ +HWTEST_F(XpmEnforceTest, BIN_NormalFileRemapCodeRwToRwxTest, TestSize.Level0) +{ + unsigned long offset, size; + + // get lib code segment + int ret = XpmElf::GetCodeSegment(const_cast(XPM_LIB_PATH), &offset, &size); + EXPECT_EQ(0, ret); + + int fd = open(const_cast(XPM_LIB_PATH), O_RDWR); + ASSERT_NE(fd, -1) << "open xpm lib failed: " << strerror(errno); + + void *addr1 = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, offset & PAGE_MASK); + ASSERT_NE(MAP_FAILED, addr1); + + void *addr2 = mremap(addr1, size, size, MREMAP_MAYMOVE); + ASSERT_NE(MAP_FAILED, addr2); + + // mprotect success at enforce mode + ret = mprotect(addr2, size, PROT_READ | PROT_WRITE | PROT_EXEC); + EXPECT_NE(0, ret); + + // release resource + munmap(addr2, size); + close(fd); +} + +/** + * @tc.number 17 + * @tc.name: BIN_NormalFileMprotectCodeRwToRwxTest + * @tc.desc: 二进制普通文件代码段文件映射的rw-权限内存通过mremap修改为r-x权限 + * @tc.result: 修改操作成功,执行代码段时失败,代码段不允许先设置rw权限,后设置rx权限 + */ +HWTEST_F(XpmEnforceTest, BIN_NormalFileRemapCodeRwToRxTest, TestSize.Level0) +{ + unsigned long offset, size; + + // get lib code segment + int ret = XpmElf::GetCodeSegment(const_cast(XPM_LIB_PATH), &offset, &size); + EXPECT_EQ(0, ret); + + int fd = open(const_cast(XPM_LIB_PATH), O_RDWR); + ASSERT_NE(fd, -1) << "open xpm lib failed: " << strerror(errno); + + void *addr1 = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, offset & PAGE_MASK); + ASSERT_NE(MAP_FAILED, addr1); + + void *addr2 = mremap(addr1, size, size, MREMAP_MAYMOVE); + ASSERT_NE(MAP_FAILED, addr2); + + // mprotect success at enforce mode + ret = mprotect(addr2, size, PROT_READ | PROT_EXEC); + EXPECT_EQ(0, ret); + + // release resource + munmap(addr2, size); + close(fd); +} + +/** + * @tc.number 18 + * @tc.name: BIN_NormalAnonMmapRwTest + * @tc.desc: 二进制匿名映射rw-权限内存 + * @tc.result: 匿名映射成功,代码执行权限管控允许映射rw-匿名内存 + */ +HWTEST_F(XpmEnforceTest, BIN_NormalAnonMmapRwTest, TestSize.Level0) +{ + void *addr = mmap(NULL, ANON_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + EXPECT_NE(MAP_FAILED, addr); + + // release resource + munmap(addr, ANON_SIZE); +} + +/** + * @tc.number 19 + * @tc.name: BIN_NormalAnonMmapRwxTest + * @tc.desc: 二进制匿名映射rwx权限内存 + * @tc.result: 匿名映射失败,匿名映射不允许x权限 + */ +HWTEST_F(XpmEnforceTest, BIN_NormalAnonMmapRwxTest, TestSize.Level0) +{ + void *addr = mmap(NULL, ANON_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + EXPECT_EQ(MAP_FAILED, addr); +} + +/** + * @tc.number 20 + * @tc.name: BIN_NormalAnonMprotectRwToRwxTest + * @tc.desc: 二进制匿名映射的rw权限内存通过mprotect修改为rwx匿名内存 + * @tc.result: 修改匿名内存为rwx失败,匿名映射不允许x权限 + */ +HWTEST_F(XpmEnforceTest, BIN_NormalAnonMprotectRwToRwxTest, TestSize.Level0) +{ + // 1. 匿名映射映射rw-内存 + void *addr = mmap(NULL, ANON_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + EXPECT_NE(MAP_FAILED, addr); + + // 2. 修改匿名内存为rwx + int ret = mprotect(addr, ANON_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC); + EXPECT_NE(0, ret); + + // release resource + munmap(addr, ANON_SIZE); +} + +/** + * @tc.number 21 + * @tc.name: BIN_NormalAnonMprotectRwToRwxTest + * @tc.desc: 二进制匿名映射的rw-权限内存通过mprotect修改为r--匿名内存,之后再修改为r-x匿名内存 + * @tc.result: 修改匿名内存为rx失败,匿名映射不允许x权限 + */ +HWTEST_F(XpmEnforceTest, BIN_NormalAnonMprotectRwToRoToRxTest, TestSize.Level0) +{ + // 1. 匿名映射映射rw-内存 + void *addr = mmap(NULL, ANON_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + EXPECT_NE(MAP_FAILED, addr); + + // 2. 修改匿名内存为r-- + int ret = mprotect(addr, ANON_SIZE, PROT_READ); + EXPECT_EQ(0, ret); + + // 3. 修改匿名内存为r-x + ret = mprotect(addr, ANON_SIZE, PROT_READ | PROT_EXEC); + EXPECT_NE(0, ret); + + // release resource + munmap(addr, ANON_SIZE); +} + +/** + * @tc.number 22 + * @tc.name: BIN_NormalAnonRmapRwToRxTest + * @tc.desc: 二进制匿名映射的rw-权限内存重映射到r-x匿名内存 + * @tc.result: 重映射到r-x失败,匿名映射不允许x权限 + */ +HWTEST_F(XpmEnforceTest, BIN_NormalAnonRmapRwToRxTest, TestSize.Level0) +{ + // 1. 匿名映射映射rw-内存 + void *addr1 = mmap(NULL, ANON_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + EXPECT_NE(MAP_FAILED, addr1); + + // 2. 重映射匿名内存 + void *addr2 = mremap(addr1, ANON_SIZE, NEW_ANON_SIZE, MREMAP_MAYMOVE); + EXPECT_NE(MAP_FAILED, addr2); + + // 3. 修改匿名内存为r-x + int ret = mprotect(addr2, NEW_ANON_SIZE, PROT_READ | PROT_EXEC); + EXPECT_NE(0, ret); + + // release resource + munmap(addr2, ANON_SIZE); +} + +/** + * @tc.name: XpmRegionAllocTest + * @tc.desc: 安全内存分配测试 + * tc.result: 分配成功,且进程对应/proc/pid/xpm_region范围有值 + */ +HWTEST_F(XpmEnforceTest, XpmRegionAllocTest, TestSize.Level0) +{ + struct XpmRegionArea area = {0}; + + int ret = XpmCommon::InitXpmRegion(&area); + EXPECT_EQ(0, ret); + + EXPECT_NE(0UL, area.start); + EXPECT_NE(0UL, area.end); +} + +/** + * @tc.name: XpmRegionAllocMultiTest + * @tc.desc: 安全内存多次分配测试 + * tc.result: 调用成功,但是安全内存并未重新分配 + */ +HWTEST_F(XpmEnforceTest, XpmRegionAllocMultiTest, TestSize.Level0) +{ + struct XpmRegionArea area1 = {0}; + struct XpmRegionArea area2 = {0}; + + // first time + int ret = XpmCommon::InitXpmRegion(&area1); + EXPECT_EQ(0, ret); + + // second time + ret = XpmCommon::InitXpmRegion(&area2); + EXPECT_EQ(0, ret); + + EXPECT_EQ(area1.start, area2.start); + EXPECT_EQ(area2.end, area2.end); +} + +/** + * @tc.number: 30 + * @tc.name: ABC_FileMmapXpmFlagTest + * @tc.desc: ABC代码指定MAP_XPM映射到安全内存 + * @tc.result: ABC代码映射成功,映射地址在安全内存范围内 + */ +HWTEST_F(XpmEnforceTest, ABC_FileMmapXpmFlagTest, TestSize.Level0) +{ + unsigned long offset, size; + struct XpmRegionArea area = {0}; + + // init xpm region + int ret = XpmCommon::InitXpmRegion(&area); + EXPECT_EQ(0, ret); + + // get lib code segment + ret = XpmElf::GetDataSegment(const_cast(XPM_LIB_PATH), &offset, &size); + EXPECT_EQ(0, ret); + + int fd = open(const_cast(XPM_LIB_PATH), O_RDWR); + ASSERT_NE(fd, -1) << "open xpm lib failed: " << strerror(errno); + + // mmap with MAP_XPM flag + void *addr = mmap(NULL, size, PROT_READ, MAP_PRIVATE | MAP_XPM, fd, offset & PAGE_MASK); + EXPECT_NE(MAP_FAILED, addr); + + // release resource + munmap(addr, size); + close(fd); +} + +/** + * @tc.number: 31 + * @tc.name: ABC_FileMmapXpmFlagLimitTest + * @tc.desc: ABC代码指定MAP_XPM映射超过安全内存大小的size到安全内存 + * @tc.result: ABC代码映射失败 + */ +HWTEST_F(XpmEnforceTest, 1ABC_FileMmapXpmFlagLimitTest, TestSize.Level0) +{ + unsigned long offset, size; + struct XpmRegionArea area = {0}; + + // init xpm region + int ret = XpmCommon::InitXpmRegion(&area); + EXPECT_EQ(0, ret); + + // get lib code segment + ret = XpmElf::GetDataSegment(const_cast(XPM_LIB_PATH), &offset, &size); + EXPECT_EQ(0, ret); + + int fd = open(const_cast(XPM_LIB_PATH), O_RDWR); + ASSERT_NE(fd, -1) << "open xpm lib failed: " << strerror(errno); + + // mmap with MAP_XPM flag + void *addr = mmap(NULL, (unsigned long)(1UL << 37), PROT_READ, MAP_PRIVATE | MAP_XPM, fd, offset & PAGE_MASK); + printf("addr = 0x%lx, %s\n", (unsigned long)addr, strerror(errno)); + EXPECT_EQ(MAP_FAILED, addr); + + // release resource + close(fd); +} + +/** + * @tc.number: 32 + * @tc.name: ABC_FileMmapXpmAddrTest + * @tc.desc: ABC代码指定MAP_XPM映射到安全内存 + * @tc.result: ABC代码映射成功,映射地址在安全内存范围内 + */ +HWTEST_F(XpmEnforceTest, ABC_FileMmapXpmAddrTest, TestSize.Level0) +{ + unsigned long offset, size; + struct XpmRegionArea area = {0}; + + // init xpm region + int ret = XpmCommon::InitXpmRegion(&area); + EXPECT_EQ(0, ret); + + // get lib code segment + ret = XpmElf::GetDataSegment(const_cast(XPM_LIB_PATH), &offset, &size); + EXPECT_EQ(0, ret); + + int fd = open(const_cast(XPM_LIB_PATH), O_RDWR); + ASSERT_NE(fd, -1) << "open xpm lib failed: " << strerror(errno); + + // mmap with MAP_XPM flag + void *addr = mmap(reinterpret_cast(area.start), size, PROT_READ, MAP_PRIVATE, fd, offset & PAGE_MASK); + EXPECT_NE(MAP_FAILED, addr); + + bool res = XpmCommon::IsXpmRegionOuter((unsigned long)addr, (unsigned long)addr + size); + EXPECT_TRUE(res); + + // release resource + munmap(addr, size); + close(fd); +} + +/** + * @tc.number: 33 + * @tc.name: ABC_FileMmapAddrAndXpmFlagTest + * @tc.desc: ABC代码指定地址&MAP_XPM标识文件映射到安全内存 + * @tc.result: ABC代码映射失败,安全内存映射不允许指定地址 + */ +HWTEST_F(XpmEnforceTest, ABC_FileMmapAddrAndXpmFlagTest, TestSize.Level0) +{ + unsigned long offset, size; + struct XpmRegionArea area = {0}; + + // init xpm region + int ret = XpmCommon::InitXpmRegion(&area); + EXPECT_EQ(0, ret); + + // get lib code segment + ret = XpmElf::GetDataSegment(const_cast(XPM_LIB_PATH), &offset, &size); + EXPECT_EQ(0, ret); + + int fd = open(const_cast(XPM_LIB_PATH), O_RDWR); + ASSERT_NE(fd, -1) << "open xpm lib failed: " << strerror(errno); + + // mmap xpm region not allow specify addr + void *addr = mmap(reinterpret_cast(area.start), size, PROT_READ, + MAP_PRIVATE | MAP_XPM, fd, offset & PAGE_MASK); + EXPECT_EQ(MAP_FAILED, addr); + + // release resource + close(fd); +} + +/** + * @tc.number: 34 + * @tc.name: ABC_FileMmapRoTest + * @tc.desc: ABC代码映射只读权限到安全内存 + * @tc.result: ABC代码映射成功,安全内存允许映射读权限 + */ +HWTEST_F(XpmEnforceTest, ABC_FileMmapRoTest, TestSize.Level0) +{ + unsigned long offset, size; + struct XpmRegionArea area = {0}; + + // init xpm region + int ret = XpmCommon::InitXpmRegion(&area); + EXPECT_EQ(0, ret); + + // get lib code segment + ret = XpmElf::GetDataSegment(const_cast(XPM_LIB_PATH), &offset, &size); + EXPECT_EQ(0, ret); + + int fd = open(const_cast(XPM_LIB_PATH), O_RDWR); + ASSERT_NE(fd, -1) << "open xpm lib failed: " << strerror(errno); + + // mmap success in xpm region at enforce mode + void *addr = mmap(NULL, size, PROT_READ, MAP_PRIVATE | MAP_XPM, fd, offset & PAGE_MASK); + ASSERT_NE(MAP_FAILED, addr); + EXPECT_GE(addr, reinterpret_cast(area.start)); + EXPECT_LE(addr, reinterpret_cast(area.end)); + munmap(addr, size); + + // release resource + close(fd); +} + +/** + * @tc.number: 35 + * @tc.name: ABC_FileMmapRwxTest + * @tc.desc: ABC代码映射读&写&执行权限到安全内存 + * @tc.result: ABC代码映射失败,安全内存不允许映射写和执行权限 + */ +HWTEST_F(XpmEnforceTest, ABC_FileMmapRwxTest, TestSize.Level0) +{ + unsigned long offset, size; + struct XpmRegionArea area = {0}; + + // init xpm region + int ret = XpmCommon::InitXpmRegion(&area); + EXPECT_EQ(0, ret); + + // get lib code segment + ret = XpmElf::GetDataSegment(const_cast(XPM_LIB_PATH), &offset, &size); + EXPECT_EQ(0, ret); + + int fd = open(const_cast(XPM_LIB_PATH), O_RDWR); + ASSERT_NE(fd, -1) << "open xpm lib failed: " << strerror(errno); + + // mmap failed in xpm region at enforce mode, has [abc not allow] error + void *addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_XPM, fd, offset & PAGE_MASK); + ASSERT_EQ(MAP_FAILED, addr); + + addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_XPM, fd, offset & PAGE_MASK); + ASSERT_EQ(MAP_FAILED, addr); + + addr = mmap(NULL, size, PROT_READ | PROT_EXEC, MAP_PRIVATE | MAP_XPM, fd, offset & PAGE_MASK); + ASSERT_EQ(MAP_FAILED, addr); + + addr = mmap(NULL, size, PROT_READ | PROT_EXEC, MAP_SHARED | MAP_XPM, fd, offset & PAGE_MASK); + ASSERT_EQ(MAP_FAILED, addr); + + addr = mmap(NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_XPM, fd, offset & PAGE_MASK); + ASSERT_EQ(MAP_FAILED, addr); + + addr = mmap(NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED | MAP_XPM, fd, offset & PAGE_MASK); + ASSERT_EQ(MAP_FAILED, addr); + + // release resource + close(fd); +} + +/** + * @tc.number 36 + * @tc.name: ABC_FileRemapXpmReginLimitTest + * @tc.desc: ABC代码重映射超过xpm_region范围的大小到xpm region内 + * @tc.result: ABC代码重映射失败 + */ +HWTEST_F(XpmEnforceTest, 1ABC_FileRemapXpmReginLimitTest, TestSize.Level0) +{ + unsigned long offset, size; + struct XpmRegionArea area = {0}; + + // init xpm region + int ret = XpmCommon::InitXpmRegion(&area); + EXPECT_EQ(0, ret); + + // get lib code segment + ret = XpmElf::GetDataSegment(const_cast(XPM_LIB_PATH), &offset, &size); + EXPECT_EQ(0, ret); + + int fd = open(const_cast(XPM_LIB_PATH), O_RDWR); + ASSERT_NE(fd, -1) << "open xpm lib failed: " << strerror(errno); + + void *addr1 = mmap(NULL, size, PROT_READ, MAP_PRIVATE | MAP_XPM, fd, offset & PAGE_MASK); + EXPECT_NE(MAP_FAILED, addr1); + + void *addr2 = mremap(addr1, size, XPM_REGION_LEN + 1, MREMAP_MAYMOVE); + EXPECT_EQ(MAP_FAILED, addr2); + + // release resource + munmap(addr1, size); + close(fd); +} + +/** + * @tc.number 37 + * @tc.name: ABC_FileRemapRoToRwTest + * @tc.desc: ABC代码同时映射到xpm region外,并设置写权限 + * @tc.result: ABC代码映射成功,但在尝试写的时候,缺页中断处理产生XPM完整性保护异常 + */ +HWTEST_F(XpmEnforceTest, ABC_FileRemapRoToRwTest, TestSize.Level0) +{ + unsigned long offset, size; + struct XpmRegionArea area = {0}; + + // init xpm region + int ret = XpmCommon::InitXpmRegion(&area); + EXPECT_EQ(0, ret); + + // get lib code segment + ret = XpmElf::GetDataSegment(const_cast(XPM_LIB_PATH), &offset, &size); + EXPECT_EQ(0, ret); + + int fd = open(const_cast(XPM_LIB_PATH), O_RDWR); + ASSERT_NE(fd, -1) << "open xpm lib failed: " << strerror(errno); + + // 1. 映射为r-- + void *addr1 = mmap(NULL, size, PROT_READ, MAP_SHARED | MAP_XPM, fd, offset & PAGE_MASK); + EXPECT_NE(MAP_FAILED, addr1); + + // 2. 可以读操作 + ret = XpmCommon::AccessData(addr1, OP_READ); + EXPECT_EQ(0, ret); + + // 3. remap到外部r-w区域 + void *addr2 = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset & PAGE_MASK); + EXPECT_NE(MAP_FAILED, addr2); + + XpmCommon::AccessData(addr2, OP_WRITE); + // 4. 写操作异常 + // EXPECT_EXIT(XpmCommon::AccessData((unsigned long)addr2, OP_WRITE), KilledBySignal(SIGSEGV), ""); + + // release resource + munmap(addr1, size); + munmap(addr2, size); + close(fd); +} + +/** + * @tc.number 39 + * @tc.name: ABC_FileRemapDataXpmRegionToOutRxTest + * @tc.desc: ABC数据段重映射到xpm region外,并添加执行权限 + * @tc.result: ABC数据段映射失败,数据段无法添加执行权限 + */ +HWTEST_F(XpmEnforceTest, ABC_FileRemapDataXpmRegionToOutRxTest, TestSize.Level0) +{ + unsigned long offset, size; + struct XpmRegionArea area = {0}; + + // init xpm region + int ret = XpmCommon::InitXpmRegion(&area); + EXPECT_EQ(0, ret); + + // get lib code segment + ret = XpmElf::GetDataSegment(const_cast(XPM_LIB_PATH), &offset, &size); + EXPECT_EQ(0, ret); + + int fd = open(const_cast(XPM_LIB_PATH), O_RDWR); + ASSERT_NE(fd, -1) << "open xpm lib failed: " << strerror(errno); + + // 1. 映射为r-- + void *addr1 = mmap(NULL, size, PROT_READ, MAP_SHARED | MAP_XPM, fd, offset & PAGE_MASK); + EXPECT_NE(MAP_FAILED, addr1); + + void *addr2 = mmap(NULL, size, PROT_READ | PROT_EXEC, MAP_SHARED, fd, offset & PAGE_MASK); + EXPECT_EQ(MAP_FAILED, addr2); + + // release resource + munmap(addr1, size); + close(fd); +} + +/** + * @tc.number 40 + * @tc.name: ABC_FileRemapCodeXpmRegionToOutRxTest + * @tc.desc: ABC数据段重映射到xpm region外,并添加执行权限 + * @tc.result: ABC数据段映射失败,数据段无法添加执行权限 + */ +HWTEST_F(XpmEnforceTest, ABC_FileRemapCodeXpmRegionToOutRxTest, TestSize.Level0) +{ + unsigned long offset, size; + struct XpmRegionArea area = {0}; + + // init xpm region + int ret = XpmCommon::InitXpmRegion(&area); + EXPECT_EQ(0, ret); + + // get lib code segment + ret = XpmElf::GetCodeSegment(const_cast(XPM_LIB_PATH), &offset, &size); + EXPECT_EQ(0, ret); + + int fd = open(const_cast(XPM_LIB_PATH), O_RDWR); + ASSERT_NE(fd, -1) << "open xpm lib failed: " << strerror(errno); + + // 1. 映射XPM内存 + void *addr1 = mmap(NULL, size, PROT_READ, MAP_SHARED | MAP_XPM, fd, offset & PAGE_MASK); + EXPECT_NE(MAP_FAILED, addr1); + + // 2. 映射XPM内存外 + void *addr2 = mmap(NULL, size, PROT_READ | PROT_EXEC, MAP_SHARED, fd, offset & PAGE_MASK); + EXPECT_NE(MAP_FAILED, addr2); + + ret = XpmCommon::ExecSumFunPtr(addr2); + EXPECT_EQ(0, ret); + + // release resource + munmap(addr1, size); + munmap(addr2, size); + close(fd); +} + +/** + * @tc.number 41 + * @tc.name: ABC_FileMprotectRwxTest + * @tc.desc: ABC代码通过mprotect添加写或执行权限 + * @tc.result: ABC代码在添加写或执行权限时失败,安全内存无法添加写&执行权限 + */ +HWTEST_F(XpmEnforceTest, ABC_FileMprotectRwxTest, TestSize.Level0) +{ + unsigned long offset, size; + struct XpmRegionArea area = {0}; + + // init xpm region + int ret = XpmCommon::InitXpmRegion(&area); + EXPECT_EQ(0, ret); + + // get lib code segment + ret = XpmElf::GetDataSegment(const_cast(XPM_LIB_PATH), &offset, &size); + EXPECT_EQ(0, ret); + + int fd = open(const_cast(XPM_LIB_PATH), O_RDWR); + ASSERT_NE(fd, -1) << "open xpm lib failed: " << strerror(errno); + + // 1. 映射数据到安全内存区域 + void *addr = mmap(NULL, size, PROT_READ, MAP_PRIVATE | MAP_XPM, fd, offset & PAGE_MASK); + EXPECT_NE(MAP_FAILED, addr); + + // 2. 增加写权限 + ret = mprotect(addr, offset, PROT_READ | PROT_WRITE); + EXPECT_EQ(-1, ret); + + // 3. 增加执行权限 + ret = mprotect(addr, size, PROT_READ | PROT_EXEC); + EXPECT_EQ(-1, ret); + + // 4. 增加写&执行权限 + ret = mprotect(addr, size, PROT_READ | PROT_WRITE | PROT_EXEC); + EXPECT_EQ(-1, ret); + + // release resource + munmap(addr, size); + close(fd); +} + +/** + * @tc.number: 42 + * @tc.name: ABC_AnonMmapXpmFlagTest + * @tc.desc: ABC代码使用MAP_XPM匿名映射到安全内存(私有映射&共享映射) + * @tc.result: ABC代码映射失败,安全内存不允许匿名映射 + */ +HWTEST_F(XpmEnforceTest, ABC_AnonMmapXpmFlagTest, TestSize.Level0) +{ + struct XpmRegionArea area = {0}; + + // init xpm region + int ret = XpmCommon::InitXpmRegion(&area); + EXPECT_EQ(0, ret); + + // mmap failed with MAP_XPM flag at enforce mode (MAP_PRIVATE or MAP_SHARED) + void *addr = mmap(NULL, PAGE_SIZE, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS | MAP_XPM, -1, 0); + ASSERT_EQ(MAP_FAILED, addr); + + addr = mmap(NULL, PAGE_SIZE, PROT_READ, MAP_SHARED | MAP_ANONYMOUS | MAP_XPM, -1, 0); + ASSERT_EQ(MAP_FAILED, addr); + + addr = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS | MAP_XPM, -1, 0); + ASSERT_EQ(MAP_FAILED, addr); +} + +/** + * @tc.number: 43 + * @tc.name: ABC_AnonMmapXpmAddrTest + * @tc.desc: ABC代码指定安全内存地址映射内存 + * @tc.result: ABC代码映射成功,映射区域不在安全内存中 + */ +HWTEST_F(XpmEnforceTest, ABC_AnonMmapXpmAddrTest, TestSize.Level0) +{ + struct XpmRegionArea area = {0}; + + // init xpm region + int ret = XpmCommon::InitXpmRegion(&area); + EXPECT_EQ(0, ret); + + // mmap success use xpm region addr at enforce mode, but region addr is not in xpm region + void *addr = mmap(reinterpret_cast(area.start), PAGE_SIZE, PROT_READ, MAP_SHARED | MAP_ANONYMOUS, -1, 0); + ASSERT_NE(MAP_FAILED, addr); + + bool res = XpmCommon::IsXpmRegionOuter((unsigned long)addr, (unsigned long)addr + PAGE_SIZE); + EXPECT_TRUE(res); + munmap(addr, PAGE_SIZE); +} + +/** + * @tc.number: 43 + * @tc.name: ABC_AnonMmapXpmAddrTest + * @tc.desc: ABC代码指定安全内存地址映射内存 + * @tc.result: ABC代码映射成功,映射区域不在安全内存中 + */ +HWTEST_F(XpmEnforceTest, ABC_DebugMmapXpmAddrTest, TestSize.Level0) +{ + struct XpmRegionArea area = {0}; + + // init xpm region + int ret = XpmCommon::InitXpmRegion(&area); + EXPECT_EQ(0, ret); + + // mmap success use xpm region addr at enforce mode, but region addr is not in xpm region + void *addr = mmap(reinterpret_cast(area.start), PAGE_SIZE, PROT_READ, MAP_SHARED | MAP_ANONYMOUS, -1, 0); + ASSERT_NE(MAP_FAILED, addr); + + bool res = XpmCommon::IsXpmRegionOuter((unsigned long)addr, (unsigned long)addr + PAGE_SIZE); + EXPECT_TRUE(res); + munmap(addr, PAGE_SIZE); +} + + + +// 11.解析文件得到代码段信息 +// 应用为映射代码段内容(代码)的可写区域(rw-) +// 先删除(mprotect)可写权权限(r--) +// 然后增加(mprotect)可执行权限(r-x) +// 映射操作会被放行,在运行时,页完整性阻止执行 +HWTEST_F(XpmEnforceTest, BinaryCodeMprotectRWToROToRXTest11, TestSize.Level0) +{ + int ret, fd; + void *addr; + unsigned long offset, size; + + ret = XpmElf::GetCodeSegment(const_cast(XPM_LIB_PATH), &offset, &size); + EXPECT_EQ(0, ret); + + fd = open(const_cast(XPM_LIB_PATH), O_RDWR); + + //1. 映射代码为rw- + addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, offset & PAGE_MASK); + EXPECT_NE(MAP_FAILED, addr); + + //1.1 修改代码内容, 触发页污点 + ret = XpmCommon::AccessData(addr, true); + EXPECT_NE(0, ret); //通过 + + //2. 删除代码写权限 --> r-- + ret = mprotect(addr, offset, PROT_READ); + EXPECT_EQ(0, ret); + + //3. 增加代码执行权限 --> r-x + ret = mprotect(addr, offset, PROT_READ | PROT_EXEC); + EXPECT_EQ(0, ret); + + //4. 执行对应代码 + ret = XpmCommon::ExecSumFunPtr(addr); + EXPECT_EQ(0, ret); //拦截 + + munmap(addr, size); + close(fd); +} + +// 12.解析文件得到代码段信息, +// 应用将映射非代码段内容(数据)的只读区域(r--) +// 重映射(rmap)到可执行权限(r-x) +// 拒绝操作 +HWTEST_F(XpmEnforceTest, BinaryDataRmapROToRXTest12, TestSize.Level0) +{ + unsigned long offset, size; + int ret, fd; + void *addr; + + ret = XpmElf::GetDataSegment(const_cast(XPM_LIB_PATH), &offset, &size); + EXPECT_EQ(0, ret); + + fd = open(const_cast(XPM_LIB_PATH), O_RDWR); + + //1. 将代码映射为r-- + addr = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, offset); + EXPECT_NE(MAP_FAILED, addr); + + //2. 重映射到可执行区--> r-- + addr = mremap(addr, size, size, MREMAP_MAYMOVE); + EXPECT_NE(MAP_FAILED, addr); + + //3. 增加代码执行权限 --> r-x + //数据被映射为代码,未通过文件权限检查,操作被拦截 + ret = mprotect(addr, size, PROT_READ | PROT_EXEC); + EXPECT_EQ(-1, ret); //拦截 + + munmap(addr, size); + close(fd); +} + +// 17.解析文件得到代码段信息 +// 应用将映射代码段内容(代码)的可写区域(rw-) +// 更新代码内容,重映射(rmap)到可执行权限(r-x) +// 操作允许通过,但是在运行时,由于完整性保护,页内容被禁止执行 +HWTEST_F(XpmEnforceTest, BinaryCodeRmapRWToRXTest17, TestSize.Level0) +{ + unsigned long offset, size; + int ret, fd; + void *addr; + + ret = XpmElf::GetCodeSegment(const_cast(XPM_LIB_PATH), &offset, &size); + EXPECT_EQ(0, ret); + + fd = open(const_cast(XPM_LIB_PATH), O_RDWR); + + //1. 将代码映射为rw- + addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, offset); + EXPECT_NE(MAP_FAILED, addr); + + //1.1 更新代码 + ret = XpmCommon::AccessData(addr, true); + EXPECT_NE(0, ret); //通过 + + //2. 重映射到可执行区 + addr = mremap(addr, size, size, MREMAP_MAYMOVE); + EXPECT_NE(MAP_FAILED, addr); + + //3. 增加代码执行权限 --> r-x + ret = mprotect(addr, size, PROT_READ | PROT_EXEC); + EXPECT_EQ(0, ret); + + //执行代码失败 + ret = XpmCommon::ExecSumFunPtr(addr); + EXPECT_EQ(0, ret); //拦截 + + munmap(addr, size); + close(fd); +} + +// 23.webview进程申请匿名内存可执行内存,(rwx) +// 操作允许 +HWTEST_F(XpmEnforceTest, WebViewAnonMmapRWXTest23, TestSize.Level0) +{ + void *addr; + + int ret = XpmCommon::SetCon(const_cast(SELINUX_TYPE_NWEBSPAWN)); + EXPECT_EQ(0, ret); + //1. 将代码映射为rwx + addr = mmap(NULL, ANON_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + EXPECT_NE(MAP_FAILED, addr); //通过 + + ret = XpmCommon::SetCon(const_cast(SELINUX_TYPE_SH)); + EXPECT_EQ(0, ret); +} + +// 24.webview进程申请匿名内存 +// 设置权限(rw-) +// 增加执行权限(rwx) +// 操作允许 +HWTEST_F(XpmEnforceTest, WebViewAnonMprotectRWToRWXTest24, TestSize.Level0) +{ + void *addr; + int ret; + + //1. 申请匿名rw- + addr = mmap(NULL, ANON_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); + EXPECT_NE(MAP_FAILED, addr); + + //2. 修改为rwx + ret = mprotect(addr, ANON_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC); + EXPECT_EQ(0, ret); //通过 +} + +// 25.webview进程修改匿名内存权限(rw-) +// 删除写权限(r--) +// 增加执行权限(r-x) +// 操作通过 +HWTEST_F(XpmEnforceTest, WebViewAnonMprotectRWToROToRXTest25, TestSize.Level0) +{ + void *addr; + int ret; + + //1. 申请匿名rw- + addr = mmap(NULL, ANON_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); + EXPECT_NE(MAP_FAILED, addr); + + //2. 修改为r-- + ret = mprotect(addr, ANON_SIZE, PROT_READ); + EXPECT_EQ(0, ret); + + //3. 修改为r-x + ret = mprotect(addr, ANON_SIZE, PROT_READ|PROT_EXEC); + EXPECT_EQ(0, ret); //通过 +} + +// 26.webview进程重映射匿名内存权限(rw-) +// 重新映射到可写可执行内存(rwx) +// 操作通过 +HWTEST_F(XpmEnforceTest, WebViewAnonRmapRWToRWXTest26, TestSize.Level0) +{ + void *addr; + int ret; + + //1. 将代码映射为rw- + addr = mmap(NULL, ANON_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); + EXPECT_NE(MAP_FAILED, addr); + + //2. 重映射 + addr = mremap(addr, ANON_SIZE, NEW_ANON_SIZE, MREMAP_MAYMOVE); + EXPECT_NE(MAP_FAILED, addr); + + //2.1 增加X权限 + ret = mprotect(addr, NEW_ANON_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC); + EXPECT_EQ(0, ret); //通过 +} + +// 27.webview进程重映射匿名内存权限(rw-) +// 重新映射到可执行内存(r-x) +// 操作通过 +HWTEST_F(XpmEnforceTest, WebViewAnonRmapRWToRXTest27, TestSize.Level0) +{ + void *addr; + int ret; + + //1. 将代码映射为rw- + addr = mmap(NULL, ANON_SIZE, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); + EXPECT_NE(MAP_FAILED, addr); + + //2. 重映射 + addr = mremap(addr, ANON_SIZE, NEW_ANON_SIZE, MREMAP_MAYMOVE); + EXPECT_NE(MAP_FAILED, addr); + + //2.1 增加X权限 + ret = mprotect(addr, NEW_ANON_SIZE, PROT_READ | PROT_EXEC); + EXPECT_EQ(0, ret); //通过 +} + +// 33.应用重映射(rmap) +// XPM region外(RW-)的abc代码到安全内存区, +// 然后remap到xpm_region内(R--),相关映射操作可通过, +// 在修改对应页后(write_tainted)再映射到XPM region(readonly)时,在访问时,会产生页冲突 +HWTEST_F(XpmEnforceTest, SharedABCRmapRWToROTest33, TestSize.Level0) +{ + unsigned long offset, size; + void *in_region_addr, *out_region_addr; + struct XpmRegionArea area = {0}; + + // init xpm region + int ret = XpmCommon::InitXpmRegion(&area); + EXPECT_EQ(0, ret); + + // get lib code segment + ret = XpmElf::GetDataSegment(const_cast(XPM_LIB_PATH), + &offset, &size); + EXPECT_EQ(0, ret); + + int fd = open(const_cast(XPM_LIB_PATH), O_RDWR); + ASSERT_NE(fd, -1) << "open xpm lib failed: " << strerror(errno); + + //1. region外映射为rw- + out_region_addr = mmap(NULL, + size, PROT_READ | PROT_WRITE, MAP_SHARED, + fd, offset & PAGE_MASK); + EXPECT_NE(MAP_FAILED, out_region_addr); + + //2. 映射到region内r--区域 + in_region_addr = mmap(NULL, + size, PROT_READ, MAP_SHARED | MAP_XPM, + fd, offset & PAGE_MASK); + EXPECT_NE(MAP_FAILED, in_region_addr); + + //3.1 可以更新内容 + ret = XpmCommon::AccessData(out_region_addr, true); + EXPECT_NE(0, ret); + + //3. 读数据时异常 + ret = XpmCommon::AccessData(in_region_addr, false); + EXPECT_EQ(0, ret); //拦截 + + munmap(in_region_addr, size); + munmap(out_region_addr, size); + close(fd); +} + +} // namespace XpmUnitTest +} // namespace Security +} // namespace OHOS \ No newline at end of file diff --git a/xpm_test/xpm_enforce_test.h b/xpm_test/xpm_enforce_test.h new file mode 100644 index 0000000000000000000000000000000000000000..6f47fef005eb6cf29d2450864bf3471394b52ab9 --- /dev/null +++ b/xpm_test/xpm_enforce_test.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 XPM_ENFORCE_TEST +#define XPM_ENFORCE_TEST + +#include + +namespace OHOS { +namespace Security { +namespace XpmUnitTest { +using namespace testing::ext; +class XpmEnforceTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp() override; + void TearDown() override; +}; +} // namespace XpmUnitTest +} // namespace Security +} // namespace OHOS + +#endif // XPM_ENFORCE_TEST \ No newline at end of file diff --git a/xpm_test/xpm_integrity_test.cpp b/xpm_test/xpm_integrity_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c80d642409d5333d0659e8e9b55754a9da6ed3e9 --- /dev/null +++ b/xpm_test/xpm_integrity_test.cpp @@ -0,0 +1,327 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * 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 "xpm_integrity_test.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "selinux/selinux.h" +#include "file_ex.h" +#include "xpm_common.h" +#include "xpm_elf.h" +#include "xpm_log.h" + +using namespace std; +using namespace std::chrono; +using namespace testing; +using namespace testing::ext; + +const std::string XPM_RO_LIB_PATH = "/system/lib64/libxpmRO.z.so"; +const std::string XPM_WT_LIB_PATH = "/system/lib64/libxpmWT.z.so"; +const std::string XPM_17_LIB_PATH = "/system/lib64/libxpm17.z.so"; + +namespace OHOS { +namespace Security { +namespace XpmUnitTest { +static int ro_fd; +static int wt_fd; + +static struct XpmRegionArea xpm_area; +static unsigned long ro_dataOffset, ro_dataSize; +static unsigned long ro_codeOffset, ro_codeSize; + +static unsigned long wt_dataOffset, wt_dataSize; +static unsigned long wt_codeOffset, wt_codeSize; + +void XpmIntegrityTest::SetUpTestCase() +{ + int ret; + SaveStringToFile(SELINUX_MODE_PATH, PERMISSIVE_MODE); + std::cout<<"SetUpTestCase"< r-- + ret = mprotect(addr, wt_codeOffset & PAGE_MASK, PROT_READ); + EXPECT_EQ(0, ret); + + //3. 增加代码执行权限 --> r-x + ret = mprotect(addr, wt_codeOffset & PAGE_MASK, PROT_READ | PROT_EXEC); + EXPECT_EQ(0, ret); + +// //4. 执行对应代码, 失败 +// ret = ExecSumFunPtr(addr); + EXPECT_EXIT(ExecSumFunPtr(addr), KilledBySignal(SIGSEGV), ""); + + munmap(addr, wt_codeSize); +} + +// 11.解析文件得到代码段信息.private +// 应用为映射代码段内容(代码)的可写区域(rw-) +// 先删除(mprotect)可写权权限(r--) +// 然后增加(mprotect)可执行权限(r-x) +// 映射操作会被放行,在运行时,页完整性阻止执行 +HWTEST_F(XpmIntegrityTest, PrivateFileMprotectRWToROToRXTest, TestSize.Level0) +{ + int ret; + + //1. 映射代码为rw- + void *addr = mmap(NULL, wt_codeSize, PROT_READ | PROT_WRITE, MAP_PRIVATE, wt_fd, wt_codeOffset & PAGE_MASK); + EXPECT_NE(MAP_FAILED, addr); + + //1.1 修改代码内容, 触发页污点 + ret = AccessData(addr, OP_WRITE); + EXPECT_EQ(0, ret); //通过 + + //2. 删除代码写权限 --> r-- + ret = mprotect(addr, wt_codeOffset & PAGE_MASK, PROT_READ); + EXPECT_EQ(0, ret); + + //3. 增加代码执行权限 --> r-x + ret = mprotect(addr, wt_codeOffset & PAGE_MASK, PROT_READ | PROT_EXEC); + EXPECT_EQ(0, ret); + +// //4. 执行对应代码, 失败 +// ret = ExecSumFunPtr(addr); + EXPECT_EXIT(ExecSumFunPtr(addr), KilledBySignal(SIGSEGV), ""); + + munmap(addr, wt_codeSize); +} + + +/** + * @tc.number 17.shared + * @tc.name: BIN_NormalFileMprotectCodeRwToRwxTest + * @tc.desc: 二进制普通文件代码段文件映射的rw-权限内存通过mremap修改为r-x权限 + * @tc.result: 修改操作成功,执行代码段时失败,代码段不允许先设置rw权限,后设置rx权限 + */ +HWTEST_F(XpmIntegrityTest, SharedFileRemapCodeRwToRxTest, TestSize.Level0) +{ + int ret; + unsigned long offset, size; + + void *addr1 = mmap(NULL, wt_codeSize, PROT_READ | PROT_WRITE, MAP_SHARED, wt_fd, wt_codeOffset & PAGE_MASK); + ASSERT_NE(MAP_FAILED, addr1); + + //1.1 修改代码内容, 触发页污点 + ret = AccessData(addr1, OP_WRITE); + EXPECT_EQ(0, ret); //通过 + + void *addr2 = mmap(NULL, wt_codeSize, PROT_READ | PROT_EXEC, MAP_SHARED, wt_fd, wt_codeOffset & PAGE_MASK); + ASSERT_NE(MAP_FAILED, addr2); + + // void *addr2 = mremap(addr1, wt_codeSize, wt_codeSize, MREMAP_MAYMOVE); + // ASSERT_NE(MAP_FAILED, addr2); + + //4. 执行对应代码, 失败 + EXPECT_EXIT(ExecSumFunPtr(addr2), KilledBySignal(SIGSEGV), ""); + + // release resource + munmap(addr1, wt_codeSize); + munmap(addr2, wt_codeSize); +} + + +/** + * @tc.number 17.private + * @tc.name: BIN_NormalFileMprotectCodeRwToRwxTest + * @tc.desc: 二进制普通文件代码段文件映射的rw-权限内存通过mremap修改为r-x权限 + * @tc.result: 修改操作成功,执行代码段时失败,代码段不允许先设置rw权限,后设置rx权限 + */ +HWTEST_F(XpmIntegrityTest, PrivateFileRemapCodeRwToRxTest, TestSize.Level0) +{ + int ret, fd; + unsigned long offset, size; + + fd = open(XPM_17_LIB_PATH.c_str(), O_RDWR); + ret = GetCodeSegment(XPM_17_LIB_PATH.c_str(), &offset, &size); + ASSERT_EQ(0, ret) << "GetCodeSegment failed: " << ret; + + void *addr1 = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, offset & PAGE_MASK); + ASSERT_NE(MAP_FAILED, addr1); + + //1.1 修改代码内容, 触发页拷贝,对应页被标记为WT + ret = AccessData(addr1, OP_WRITE); + EXPECT_EQ(0, ret); //通过 + + void *addr2 = mmap(NULL, size, PROT_READ | PROT_EXEC, MAP_SHARED, fd, offset & PAGE_MASK); + ASSERT_NE(MAP_FAILED, addr2); + + // void *addr2 = mremap(addr1, wt_codeSize, wt_codeSize, MREMAP_MAYMOVE); + // ASSERT_NE(MAP_FAILED, addr2); + + //4. 执行对应代码, 对应页被标记为RO,可以被执行 + // EXPECT_EXIT(ExecSumFunPtr(addr2), KilledBySignal(SIGSEGV), ""); + ret = ExecSumFunPtr(addr2); + EXPECT_EQ(0, ret); //通过 + + // release resource + munmap(addr1, size); + munmap(addr2, size); + + close(fd); +} + +} // namespace XpmUnitTest +} // namespace Security +} // namespace OHOS \ No newline at end of file diff --git a/xpm_test/xpm_integrity_test.h b/xpm_test/xpm_integrity_test.h new file mode 100644 index 0000000000000000000000000000000000000000..b2d705614259a0af9fafa37f2f0766387f415ed3 --- /dev/null +++ b/xpm_test/xpm_integrity_test.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 XPM_INTEGRITY_TEST +#define XPM_INTEGRITY_TEST + +#include + +namespace OHOS { +namespace Security { +namespace XpmUnitTest { +using namespace testing::ext; +class XpmIntegrityTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp() override; + void TearDown() override; +}; +} // namespace XpmUnitTest +} // namespace Security +} // namespace OHOS + +#endif // XPM_INTEGRITY_TEST \ No newline at end of file diff --git a/xpm_test/xpm_lib.c b/xpm_test/xpm_lib.c new file mode 100644 index 0000000000000000000000000000000000000000..493cf98748c1a357e9421cae1120b2af7322a6af --- /dev/null +++ b/xpm_test/xpm_lib.c @@ -0,0 +1,20 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int a = 1; + +int abc[4096*4] = {0x12345678}; +char *c_str = "abcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmn"; + +int xpm_sum(int b, int c) +{ + int sum = a + b + c; + return sum; +} \ No newline at end of file diff --git a/xpm_test/xpm_lib.h b/xpm_test/xpm_lib.h new file mode 100644 index 0000000000000000000000000000000000000000..448bba765d901656f093e23f6d73d40977039d6a --- /dev/null +++ b/xpm_test/xpm_lib.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 XPM_LIB_H +#define XPM_LIB_H + +#ifdef __cplusplus +extern "C" { +#endif + +int xpm_sum(int b, int c); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/xpm_test/xpm_log.h b/xpm_test/xpm_log.h new file mode 100644 index 0000000000000000000000000000000000000000..97675d5129926a47ec0bc516fee6f60d7fb0b7fd --- /dev/null +++ b/xpm_test/xpm_log.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * 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 XPM_LOG_H +#define XPM_LOG_H + +#include "hilog/log.h" + +#ifndef __cplusplus +#ifdef LOG_TAG +#undef LOG_TAG +#endif +#define LOG_TAG "XPM_TEST" + +#ifdef LOG_DOMAIN +#undef LOG_DOMAIN +#endif +#define LOG_DOMAIN 0xD002F00 + +#define XPM_LOG_DEBUG(fmt, ...) HILOG_DEBUG(LOG_CORE, "[%{public}s]:" fmt, __func__, ##__VA_ARGS__) +#define XPM_LOG_INFO(fmt, ...) HILOG_INFO(LOG_CORE, "[%{public}s]:" fmt, __func__, ##__VA_ARGS__) +#define XPM_LOG_WARN(fmt, ...) HILOG_WARN(LOG_CORE, "[%{public}s]:" fmt, __func__, ##__VA_ARGS__) +#define XPM_LOG_ERROR(fmt, ...) HILOG_ERROR(LOG_CORE, "[%{public}s]:" fmt, __func__, ##__VA_ARGS__) +#define XPM_LOG_FATAL(fmt, ...) HILOG_FATAL(LOG_CORE, "[%{public}s]:" fmt, __func__, ##__VA_ARGS__) + +#else // __cplusplus +static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, 0xD002F00, "XPM_TEST"}; + +#define XPM_LOG_DEBUG(fmt, ...) \ + OHOS::HiviewDFX::HiLog::Debug(LABEL, "[%{public}s]:" fmt, __func__, ##__VA_ARGS__) +#define XPM_LOG_INFO(fmt, ...) \ + OHOS::HiviewDFX::HiLog::Info(LABEL, "[%{public}s]:" fmt, __func__, ##__VA_ARGS__) +#define XPM_LOG_WARN(fmt, ...) \ + OHOS::HiviewDFX::HiLog::Warn(LABEL, "[%{public}s]:" fmt, __func__, ##__VA_ARGS__) +#define XPM_LOG_ERROR(fmt, ...) \ + OHOS::HiviewDFX::HiLog::Error(LABEL, "[%{public}s]:" fmt, __func__, ##__VA_ARGS__) +#define XPM_LOG_FATAL(fmt, ...) \ + OHOS::HiviewDFX::HiLog::Fatal(LABEL, "[%{public}s]:" fmt, __func__, ##__VA_ARGS__) + +#endif // __cplusplus +#endif // XPM_LOG_H diff --git a/xpm_test/xpm_permissive_test.cpp b/xpm_test/xpm_permissive_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b4726f13c52477f3e33abb9e29f61d2d1afdaed0 --- /dev/null +++ b/xpm_test/xpm_permissive_test.cpp @@ -0,0 +1,626 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * 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 "xpm_permissive_test.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "file_ex.h" +#include "xpm_common.h" +#include "xpm_elf.h" +#include "xpm_log.h" + +using namespace std; +using namespace std::chrono; +using namespace testing; +using namespace testing::ext; + +namespace OHOS { +namespace Security { +namespace XpmUnitTest { +#define XPM_LIB_PATH "/system/lib64/libxpm.z.so" + +void XpmPermissiveTest::SetUpTestCase() +{ + SaveStringToFile(XPM_DEBUG_FS_MODE_PATH, "0"); +} +void XpmPermissiveTest::TearDownTestCase() +{ + SaveStringToFile(XPM_DEBUG_FS_MODE_PATH, "0"); +} +void XpmPermissiveTest::SetUp() +{ +} +void XpmPermissiveTest::TearDown() +{ +} + +/** + * @tc.name: XpmRegionAllocTest + * @tc.desc: xpm region alloc test + */ +HWTEST_F(XpmPermissiveTest, XpmRegionAllocTest, TestSize.Level0) +{ + struct XpmRegionArea area = {0}; + + int ret = InitXpmRegion(&area); + EXPECT_EQ(0, ret); + + EXPECT_NE(0UL, area.start); + EXPECT_NE(0UL, area.end); +} + +/** + * @tc.name: XpmRegionAllocMultiTest + * @tc.desc: xpm region multiple alloc test + */ +HWTEST_F(XpmPermissiveTest, XpmRegionAllocMultiTest, TestSize.Level0) +{ + struct XpmRegionArea area1 = {0}; + struct XpmRegionArea area2 = {0}; + + // first time + int ret = InitXpmRegion(&area1); + EXPECT_EQ(0, ret); + + // second time + ret = InitXpmRegion(&area2); + EXPECT_EQ(0, ret); + + EXPECT_EQ(area1.start, area2.start); + EXPECT_EQ(area2.end, area2.end); +} + +/** + * @tc.name: XpmRegionFileMmapAddrTest + * @tc.desc: file mmap to xpm region with addr test + */ +HWTEST_F(XpmPermissiveTest, XpmRegionFileMmapAddrTest, TestSize.Level0) +{ + unsigned long offset, size; + struct XpmRegionArea area = {0}; + + // init xpm region + int ret = InitXpmRegion(&area); + EXPECT_EQ(0, ret); + + // get lib code segment + ret = GetDataSegment(const_cast(XPM_LIB_PATH), &offset, &size); + EXPECT_EQ(0, ret); + + int fd = open(const_cast(XPM_LIB_PATH), O_RDWR); + ASSERT_NE(fd, -1) << "open xpm lib failed: " << strerror(errno); + + // mmap xpm region not allow specify addr + void *addr = mmap(reinterpret_cast(area.start), size, PROT_READ, + MAP_PRIVATE | MAP_XPM, fd, offset & PAGE_MASK); + EXPECT_EQ(MAP_FAILED, addr); + + // release resource + close(fd); +} + +/** + * @tc.name: XpmRegionFileMmapRoTest + * @tc.desc: file mmap to xpm region with (read) permission test + */ +HWTEST_F(XpmPermissiveTest, XpmRegionFileMmapRoTest, TestSize.Level0) +{ + unsigned long offset, size; + struct XpmRegionArea area = {0}; + + // init xpm region + int ret = InitXpmRegion(&area); + EXPECT_EQ(0, ret); + + // get lib code segment + ret = GetDataSegment(const_cast(XPM_LIB_PATH), &offset, &size); + EXPECT_EQ(0, ret); + + int fd = open(const_cast(XPM_LIB_PATH), O_RDWR); + ASSERT_NE(fd, -1) << "open xpm lib failed: " << strerror(errno); + + // mmap success in xpm region at permissive mode + void *addr = mmap(NULL, size, PROT_READ, MAP_PRIVATE | MAP_XPM, fd, offset & PAGE_MASK); + ASSERT_NE(MAP_FAILED, addr); + EXPECT_GE(addr, reinterpret_cast(area.start)); + EXPECT_LE(addr, reinterpret_cast(area.end)); + munmap(addr, size); + + // release resource + close(fd); +} + +/** + * @tc.name: XpmRegionFileMmapRxTest + * @tc.desc: file mmap to xpm region with (read & exec) permission test + */ +HWTEST_F(XpmPermissiveTest, XpmRegionFileMmapRxTest, TestSize.Level0) +{ + unsigned long offset, size; + struct XpmRegionArea area = {0}; + + // init xpm region + int ret = InitXpmRegion(&area); + EXPECT_EQ(0, ret); + + // get lib code segment + ret = GetDataSegment(const_cast(XPM_LIB_PATH), &offset, &size); + EXPECT_EQ(0, ret); + + int fd = open(const_cast(XPM_LIB_PATH), O_RDWR); + ASSERT_NE(fd, -1) << "open xpm lib failed: " << strerror(errno); + + // mmap success in xpm region at permissive mode, has [abc not allow] error + void *addr = mmap(NULL, size, PROT_READ | PROT_EXEC, MAP_PRIVATE | MAP_XPM, fd, offset & PAGE_MASK); + ASSERT_NE(MAP_FAILED, addr); + munmap(addr, size); + + // release resource + close(fd); +} + +/** + * @tc.name: XpmRegionFileMmapRwTest + * @tc.desc: file mmap to xpm region with (read & exec) permission test + */ +HWTEST_F(XpmPermissiveTest, XpmRegionFileMmapRwTest, TestSize.Level0) +{ + unsigned long offset, size; + struct XpmRegionArea area = {0}; + + // init xpm region + int ret = InitXpmRegion(&area); + EXPECT_EQ(0, ret); + + // get lib code segment + ret = GetDataSegment(const_cast(XPM_LIB_PATH), &offset, &size); + EXPECT_EQ(0, ret); + + int fd = open(const_cast(XPM_LIB_PATH), O_RDWR); + ASSERT_NE(fd, -1) << "open xpm lib failed: " << strerror(errno); + + // mmap success in xpm region at permissive mode, has [abc not allow] error + void *addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_XPM, fd, offset & PAGE_MASK); + ASSERT_NE(MAP_FAILED, addr); + munmap(addr, size); + + // release resource + close(fd); +} + +/** + * @tc.name: XpmRegionFileMmapRwxTest + * @tc.desc: file mmap to xpm region (read & write & exec) permission test + */ +HWTEST_F(XpmPermissiveTest, XpmRegionFileMmapRwxTest, TestSize.Level0) +{ + unsigned long offset, size; + struct XpmRegionArea area = {0}; + + // init xpm region + int ret = InitXpmRegion(&area); + EXPECT_EQ(0, ret); + + // get lib code segment + ret = GetDataSegment(const_cast(XPM_LIB_PATH), &offset, &size); + EXPECT_EQ(0, ret); + + int fd = open(const_cast(XPM_LIB_PATH), O_RDWR); + ASSERT_NE(fd, -1) << "open xpm lib failed: " << strerror(errno); + + // mmap success in xpm region at permissive mode, has [abc not allow] error + void *addr = mmap(NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_XPM, fd, offset & PAGE_MASK); + ASSERT_NE(MAP_FAILED, addr); + munmap(addr, size); + + // release resource + close(fd); +} + +/** + * @tc.name: NormalFileMmapDataRxTest + * @tc.desc: file mmap data to (read & exec) permission test + */ +HWTEST_F(XpmPermissiveTest, NormalFileMmapDataRxTest, TestSize.Level0) +{ + unsigned long offset, size; + + // get lib code segment + int ret = GetDataSegment(const_cast(XPM_LIB_PATH), &offset, &size); + EXPECT_EQ(0, ret); + + int fd = open(const_cast(XPM_LIB_PATH), O_RDWR); + ASSERT_NE(fd, -1) << "open xpm lib failed: " << strerror(errno); + + // mmap success at permissive mode, has [signature] error + void *addr = mmap(NULL, size, PROT_READ | PROT_EXEC, MAP_PRIVATE, fd, offset & PAGE_MASK); + ASSERT_NE(MAP_FAILED, addr); + munmap(addr, size); + + // release resource + close(fd); +} + +/** + * @tc.name: NormalFileMmapCodeRXTest + * @tc.desc: file mmap code to (read & exec) permission test + */ +HWTEST_F(XpmPermissiveTest, NormalFileMmapCodeRxTest, TestSize.Level0) +{ + unsigned long offset, size; + + // get lib code segment + int ret = GetCodeSegment(const_cast(XPM_LIB_PATH), &offset, &size); + EXPECT_EQ(0, ret); + + int fd = open(const_cast(XPM_LIB_PATH), O_RDWR); + ASSERT_NE(fd, -1) << "open xpm lib failed: " << strerror(errno); + + // mmap success at permissive mode + void *addr = mmap(NULL, size, PROT_READ | PROT_EXEC, MAP_PRIVATE, fd, offset & PAGE_MASK); + ASSERT_NE(MAP_FAILED, addr); + munmap(addr, size); + + // release resource + close(fd); +} + +/** + * @tc.name: NormalFileMmapDataRWXTest + * @tc.desc: file mmap data to (read & write & exec) permission test + */ +HWTEST_F(XpmPermissiveTest, NormalFileMmapDataRwxTest, TestSize.Level0) +{ + unsigned long offset, size; + + // get lib code segment + int ret = GetDataSegment(const_cast(XPM_LIB_PATH), &offset, &size); + EXPECT_EQ(0, ret); + + int fd = open(const_cast(XPM_LIB_PATH), O_RDWR); + ASSERT_NE(fd, -1) << "open xpm lib failed: " << strerror(errno); + + // mmap success at permissive mode, has [signature & protection] error + void *addr = mmap(NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE, fd, offset & PAGE_MASK); + ASSERT_NE(MAP_FAILED, addr); + munmap(addr, size); + + // release resource + close(fd); +} + +/** + * @tc.name: NormalFileMmapCodeRWXTest + * @tc.desc: file mmap code to read & write &exec permission test + */ +HWTEST_F(XpmPermissiveTest, NormalFileMmapCodeRwxTest, TestSize.Level0) +{ + unsigned long offset, size; + + // get lib code segment + int ret = GetCodeSegment(const_cast(XPM_LIB_PATH), &offset, &size); + EXPECT_EQ(0, ret); + + int fd = open(const_cast(XPM_LIB_PATH), O_RDWR); + ASSERT_NE(fd, -1) << "open xpm lib failed: " << strerror(errno); + + // mmap success at permissive mode, has [protection] error + void *addr = mmap(NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE, fd, offset & PAGE_MASK); + ASSERT_NE(MAP_FAILED, addr); + munmap(addr, size); + + // release resource + close(fd); +} + +/** + * @tc.name: NormalFileMprotectDataRoToRxTest + * @tc.desc: file mprotect data (r--) -> (r-x) permission test + */ +HWTEST_F(XpmPermissiveTest, NormalFileMprotectDataRoToRxTest, TestSize.Level0) +{ + unsigned long offset, size; + + // get lib code segment + int ret = GetDataSegment(const_cast(XPM_LIB_PATH), &offset, &size); + EXPECT_EQ(0, ret); + + int fd = open(const_cast(XPM_LIB_PATH), O_RDWR); + ASSERT_NE(fd, -1) << "open xpm lib failed: " << strerror(errno); + + void *addr = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, offset & PAGE_MASK); + ASSERT_NE(MAP_FAILED, addr); + + // mprotect success at permissive mode, has [signature] error + ret = mprotect(addr, size, PROT_READ | PROT_EXEC); + EXPECT_EQ(0, ret); + munmap(addr, size); + + // release resource + close(fd); +} + +/** + * @tc.name: NormalFileMprotectDataRwToRwxTest + * @tc.desc: file mprotect data (rw-) -> (rwx) permission test + */ +HWTEST_F(XpmPermissiveTest, NormalFileMprotectDataRwToRwxTest, TestSize.Level0) +{ + unsigned long offset, size; + + // get lib code segment + int ret = GetDataSegment(const_cast(XPM_LIB_PATH), &offset, &size); + EXPECT_EQ(0, ret); + + int fd = open(const_cast(XPM_LIB_PATH), O_RDWR); + ASSERT_NE(fd, -1) << "open xpm lib failed: " << strerror(errno); + + void *addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, offset & PAGE_MASK); + ASSERT_NE(MAP_FAILED, addr); + + // mprotect success at permissive mode, has [signature & protection] error + ret = mprotect(addr, size, PROT_READ | PROT_WRITE | PROT_EXEC); + EXPECT_EQ(0, ret); + munmap(addr, size); + + // release resource + close(fd); +} + +/** + * @tc.name: NormalFileMprotectCodeRoToRxTest + * @tc.desc: file mprotect code (r--) -> (r-x) permission test + */ +HWTEST_F(XpmPermissiveTest, NormalFileMprotectCodeRoToRxTest, TestSize.Level0) +{ + unsigned long offset, size; + + // get lib code segment + int ret = GetCodeSegment(const_cast(XPM_LIB_PATH), &offset, &size); + EXPECT_EQ(0, ret); + + int fd = open(const_cast(XPM_LIB_PATH), O_RDWR); + ASSERT_NE(fd, -1) << "open xpm lib failed: " << strerror(errno); + + void *addr = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, offset & PAGE_MASK); + ASSERT_NE(MAP_FAILED, addr); + + // mprotect success at permissive mode + ret = mprotect(addr, size, PROT_READ | PROT_EXEC); + EXPECT_EQ(0, ret); + munmap(addr, size); + + // release resource + close(fd); +} + +/** + * @tc.name: NormalFileMprotectCodeRwToRwxTest + * @tc.desc: file mprotect data (rw-) -> (rwx) permission test + */ +HWTEST_F(XpmPermissiveTest, NormalFileMprotectCodeRwToRwxTest, TestSize.Level0) +{ + unsigned long offset, size; + + // get lib code segment + int ret = GetCodeSegment(const_cast(XPM_LIB_PATH), &offset, &size); + EXPECT_EQ(0, ret); + + int fd = open(const_cast(XPM_LIB_PATH), O_RDWR); + ASSERT_NE(fd, -1) << "open xpm lib failed: " << strerror(errno); + + void *addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, offset & PAGE_MASK); + ASSERT_NE(MAP_FAILED, addr); + + // mprotect success at permissive mode, has [protection] error + ret = mprotect(addr, size, PROT_READ | PROT_WRITE | PROT_EXEC); + EXPECT_EQ(0, ret); + munmap(addr, size); + + // release resource + close(fd); +} + +/** + * @tc.name: NormalFileRemapDataRoToRxTest + * @tc.desc: file mremap data (r--) -> (r-x) permission test + */ +HWTEST_F(XpmPermissiveTest, NormalFileRemapDataRoToRxTest, TestSize.Level0) +{ + unsigned long offset, size; + + // get lib code segment + int ret = GetDataSegment(const_cast(XPM_LIB_PATH), &offset, &size); + EXPECT_EQ(0, ret); + + int fd = open(const_cast(XPM_LIB_PATH), O_RDWR); + ASSERT_NE(fd, -1) << "open xpm lib failed: " << strerror(errno); + + void *addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, offset & PAGE_MASK); + ASSERT_NE(MAP_FAILED, addr); + + addr = mremap(addr, size, size, MREMAP_MAYMOVE); + ASSERT_NE(MAP_FAILED, addr); + + // mprotect success at permissive mode, has [signature] error + ret = mprotect(addr, size, PROT_READ | PROT_EXEC); + EXPECT_EQ(0, ret); + munmap(addr, size); + + // release resource + close(fd); +} + +/** + * @tc.name: NormalFileRemapDataRwToRwxTest + * @tc.desc: file mremap data (rw-) -> (r-x) permission test + */ +HWTEST_F(XpmPermissiveTest, NormalFileRemapDataRwToRxTest, TestSize.Level0) +{ + unsigned long offset, size; + + // get lib code segment + int ret = GetDataSegment(const_cast(XPM_LIB_PATH), &offset, &size); + EXPECT_EQ(0, ret); + + int fd = open(const_cast(XPM_LIB_PATH), O_RDWR); + ASSERT_NE(fd, -1) << "open xpm lib failed: " << strerror(errno); + + void *addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, offset & PAGE_MASK); + ASSERT_NE(MAP_FAILED, addr); + + addr = mremap(addr, size, size, MREMAP_MAYMOVE); + ASSERT_NE(MAP_FAILED, addr); + + // mprotect success at permissive mode, has [signature] error + ret = mprotect(addr, size, PROT_READ | PROT_EXEC); + EXPECT_EQ(0, ret); + munmap(addr, size); + + // release resource + close(fd); +} + +/** + * @tc.name: NormalFileRemapDataRwToRwxTest + * @tc.desc: file mremap data (rw-) -> (rwx) permission test + */ +HWTEST_F(XpmPermissiveTest, NormalFileRemapDataRwToRwxTest, TestSize.Level0) +{ + unsigned long offset, size; + + // get lib code segment + int ret = GetDataSegment(const_cast(XPM_LIB_PATH), &offset, &size); + EXPECT_EQ(0, ret); + + int fd = open(const_cast(XPM_LIB_PATH), O_RDWR); + ASSERT_NE(fd, -1) << "open xpm lib failed: " << strerror(errno); + + void *addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, offset & PAGE_MASK); + ASSERT_NE(MAP_FAILED, addr); + + addr = mremap(addr, size, size, MREMAP_MAYMOVE); + ASSERT_NE(MAP_FAILED, addr); + + // mprotect success at permissive mode, has [signature & protection] error + ret = mprotect(addr, size, PROT_READ | PROT_WRITE | PROT_EXEC); + EXPECT_EQ(0, ret); + munmap(addr, size); + + // release resource + close(fd); +} + +/** + * @tc.name: NormalFileRemapCodeRoToRxTest + * @tc.desc: file mremap code (r--) -> (r-x) permission test + */ +HWTEST_F(XpmPermissiveTest, NormalFileRemapCodeRoToRxTest, TestSize.Level0) +{ + unsigned long offset, size; + + // get lib code segment + int ret = GetCodeSegment(const_cast(XPM_LIB_PATH), &offset, &size); + EXPECT_EQ(0, ret); + + int fd = open(const_cast(XPM_LIB_PATH), O_RDWR); + ASSERT_NE(fd, -1) << "open xpm lib failed: " << strerror(errno); + + void *addr = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, offset & PAGE_MASK); + ASSERT_NE(MAP_FAILED, addr); + + addr = mremap(addr, size, size, MREMAP_MAYMOVE); + ASSERT_NE(MAP_FAILED, addr); + + // mprotect success at permissive mode + ret = mprotect(addr, size, PROT_READ | PROT_EXEC); + EXPECT_EQ(0, ret); + munmap(addr, size); + + // release resource + close(fd); +} + +/** + * @tc.name: NormalFileRemapCodeRwToRxTest + * @tc.desc: file mremap code (rw-) -> (r-x) permission test + */ +HWTEST_F(XpmPermissiveTest, NormalFileRemapCodeRwToRxTest, TestSize.Level0) +{ + unsigned long offset, size; + + // get lib code segment + int ret = GetCodeSegment(const_cast(XPM_LIB_PATH), &offset, &size); + EXPECT_EQ(0, ret); + + int fd = open(const_cast(XPM_LIB_PATH), O_RDWR); + ASSERT_NE(fd, -1) << "open xpm lib failed: " << strerror(errno); + + void *addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, offset & PAGE_MASK); + ASSERT_NE(MAP_FAILED, addr); + + addr = mremap(addr, size, size, MREMAP_MAYMOVE); + ASSERT_NE(MAP_FAILED, addr); + + // mprotect success at permissive mode + ret = mprotect(addr, size, PROT_READ | PROT_EXEC); + EXPECT_EQ(0, ret); + munmap(addr, size); + + // release resource + close(fd); +} + +/** + * @tc.name: NormalFileRemapCodeRwToRwxTest + * @tc.desc: file mremap code (rw-) -> (rwx) permission test + */ +HWTEST_F(XpmPermissiveTest, NormalFileRemapCodeRwToRwxTest, TestSize.Level0) +{ + unsigned long offset, size; + + // get lib code segment + int ret = GetCodeSegment(const_cast(XPM_LIB_PATH), &offset, &size); + EXPECT_EQ(0, ret); + + int fd = open(const_cast(XPM_LIB_PATH), O_RDWR); + ASSERT_NE(fd, -1) << "open xpm lib failed: " << strerror(errno); + + void *addr = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, offset & PAGE_MASK); + ASSERT_NE(MAP_FAILED, addr); + + addr = mremap(addr, size, size, MREMAP_MAYMOVE); + ASSERT_NE(MAP_FAILED, addr); + + // mprotect success at permissive mode, has [protection] error + ret = mprotect(addr, size, PROT_READ | PROT_WRITE | PROT_EXEC); + EXPECT_EQ(0, ret); + munmap(addr, size); + + // release resource + close(fd); +} + +} // namespace XpmUnitTest +} // namespace Security +} // namespace OHOS \ No newline at end of file diff --git a/xpm_test/xpm_permissive_test.h b/xpm_test/xpm_permissive_test.h new file mode 100644 index 0000000000000000000000000000000000000000..2a505d3c9c6755208a412695b84c20d35f8d8198 --- /dev/null +++ b/xpm_test/xpm_permissive_test.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 XPM_PERMISSIVE_TEST +#define XPM_PERMISSIVE_TEST + +#include + +namespace OHOS { +namespace Security { +namespace XpmUnitTest { +using namespace testing::ext; +class XpmPermissiveTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp() override; + void TearDown() override; +}; +} // namespace XpmUnitTest +} // namespace Security +} // namespace OHOS + +#endif // XPM_PERMISSIVE_TEST \ No newline at end of file