From 3961dc5ba00d269e50481a4bf71e9740b561b556 Mon Sep 17 00:00:00 2001 From: yinchuang Date: Mon, 7 Aug 2023 11:23:15 +0800 Subject: [PATCH] Add cfi test Issue:I7R13O Signed-off-by: yinchuang Test:libctest --- libc-test/src/common/cfi_util.h | 105 ++++++++++++ libc-test/src/functionalext/ldso_cfi/BUILD.gn | 62 +++++++ .../ldso_cfi/cfi_avaiable_schemes_test.cpp | 156 ++++++++++++++++++ .../ldso_cfi/crossdso/cfi_test_exe.cpp | 59 +++++++ .../ldso_cfi/crossdso/cfi_test_lib.cpp | 36 ++++ 5 files changed, 418 insertions(+) create mode 100644 libc-test/src/common/cfi_util.h create mode 100644 libc-test/src/functionalext/ldso_cfi/cfi_avaiable_schemes_test.cpp create mode 100644 libc-test/src/functionalext/ldso_cfi/crossdso/cfi_test_exe.cpp create mode 100644 libc-test/src/functionalext/ldso_cfi/crossdso/cfi_test_lib.cpp diff --git a/libc-test/src/common/cfi_util.h b/libc-test/src/common/cfi_util.h new file mode 100644 index 00000000..88083c94 --- /dev/null +++ b/libc-test/src/common/cfi_util.h @@ -0,0 +1,105 @@ +/** + * 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. + */ + +#include +#include +#include +extern "C" { + #include "test.h" +} + +#define UBSAN_LOG_DIR "/data/log/sanitizer/ubsan/" +#define UBSAN_LOG_TAG "ubsan" +#define DEBUG 0 +#define BUFFER_SIZE 4096 + +static void ShowCfiLogFile() +{ + DIR *dir; + struct dirent *ptr; + dir = opendir(UBSAN_LOG_DIR); + while ((ptr = readdir(dir)) != NULL) { + if (strstr(ptr->d_name, UBSAN_LOG_TAG) != NULL) { + printf("%s: %s\n", UBSAN_LOG_DIR, ptr->d_name); + } + } + closedir(dir); +} + +static void ClearCfiLog() +{ + DIR *dir; + struct dirent *ptr; + dir = opendir(UBSAN_LOG_DIR); + while ((ptr = readdir(dir)) != NULL) { + if (strstr(ptr->d_name, UBSAN_LOG_TAG) != NULL) { + char tmp[BUFFER_SIZE] = UBSAN_LOG_DIR; + strcat(tmp, ptr->d_name); + remove(tmp); + } + } + closedir(dir); +} + +static void CheckCfiLog(char *file, const char *needle) +{ + if (DEBUG) { + printf("[cfi checking]:%s\n", file); + } + char buffer[BUFFER_SIZE]; + FILE *fp = fopen(file, "r"); + if (!fp) { + return; + } + if (fseek(fp, 0, SEEK_END) == -1) { + return; + } + int size = ftell(fp); + if (size <= 0) { + fclose(fp); + t_error("FAIL %s size is <=0!\n", file); + } + if (fseek(fp, 0, SEEK_SET) == -1) { + fclose(fp); + return; + } + int rsize = fread(buffer, 1, size, fp); + if (rsize == 0) { + fclose(fp); + return; + } + + if (strstr(buffer, needle) != NULL) { + printf("[cfi checking] %s is ok.\n", needle); + } else { + t_error("FAIL %s is failed!\n", needle); + } + fclose(fp); +} + +static void FindAndCheck(const char *pattern) +{ + DIR *dir; + struct dirent *ptr; + dir = opendir(UBSAN_LOG_DIR); + while ((ptr = readdir(dir)) != NULL) { + if (strstr(ptr->d_name, UBSAN_LOG_TAG) != NULL) { + char tmp[BUFFER_SIZE] = UBSAN_LOG_DIR; + strcat(tmp, ptr->d_name); + CheckCfiLog(tmp, pattern); + } + } + closedir(dir); +} \ No newline at end of file diff --git a/libc-test/src/functionalext/ldso_cfi/BUILD.gn b/libc-test/src/functionalext/ldso_cfi/BUILD.gn index 17ed34de..c003fe86 100644 --- a/libc-test/src/functionalext/ldso_cfi/BUILD.gn +++ b/libc-test/src/functionalext/ldso_cfi/BUILD.gn @@ -16,6 +16,9 @@ import("../../../test_template.gni") group("ldso_cfi_test") { testonly = true deps = [ + ":cfi_avaiable_schemes_test", + ":cfi_cross_dso_test_exe", + ":cfi_cross_dso_test_lib", ":ldso_cfi_check", ":ldso_cfi_test_lib", ] @@ -44,3 +47,62 @@ ohos_shared_library("ldso_cfi_test_lib") { subsystem_name = "musl" part_name = "libc-test-lib" } + +ohos_shared_library("cfi_cross_dso_test_lib") { + sanitize = { + cfi = true + cfi_cross_dso = true + debug = true + } + subsystem_name = "musl" + part_name = "libc-test" + include_dirs = [ + "../common", + "//third_party/musl/porting/linux/user/include", + "//third_party/musl/porting/linux/user/ldso", + "//third_party/musl/libc-test/src/common", + ] + use_rtti = true + + sources = [ "./crossdso/cfi_test_lib.cpp" ] +} + +ohos_executable("cfi_cross_dso_test_exe") { + sanitize = { + cfi = true + cfi_cross_dso = true + debug = true + } + subsystem_name = "musl" + part_name = "libc-test" + include_dirs = [ + "../common", + "//third_party/musl/porting/linux/user/include", + "//third_party/musl/porting/linux/user/ldso", + "//third_party/musl/libc-test/src/common", + ] + use_rtti = true + + sources = [ "./crossdso/cfi_test_exe.cpp" ] + configs = [ "//third_party/musl/libc-test/src/common:config_runtest" ] +} + +ohos_executable("cfi_avaiable_schemes_test") { + sanitize = { + cfi = true + cfi_cross_dso = true + debug = true + } + subsystem_name = "musl" + part_name = "libc-test" + include_dirs = [ + "../common", + "//third_party/musl/porting/linux/user/include", + "//third_party/musl/porting/linux/user/ldso", + "//third_party/musl/libc-test/src/common", + ] + use_rtti = true + + sources = [ "cfi_avaiable_schemes_test.cpp" ] + configs = [ "//third_party/musl/libc-test/src/common:config_runtest" ] +} diff --git a/libc-test/src/functionalext/ldso_cfi/cfi_avaiable_schemes_test.cpp b/libc-test/src/functionalext/ldso_cfi/cfi_avaiable_schemes_test.cpp new file mode 100644 index 00000000..9a059a14 --- /dev/null +++ b/libc-test/src/functionalext/ldso_cfi/cfi_avaiable_schemes_test.cpp @@ -0,0 +1,156 @@ +/** + * 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. + */ + +#include "cfi_util.h" + +struct A { + virtual void Test(); +}; + +void A::Test() +{ + printf("A::Test()\n"); +} + +struct B : A { + virtual void Test(); +}; + +void B::Test() +{ + printf("B::Test()\n"); +} + +struct C : A { +}; + +struct D { + virtual void Test(); +}; + +void D::Test() +{ + printf("D::Test()\n"); +} + +struct CallTestA { + virtual void VcallFunc(); + void CallFunc(); +}; + +void CallTestA::VcallFunc() +{ + printf("CallTestA::VcallFunc()\n"); +} + +void CallTestA::CallFunc() +{ + printf("CallTestA::CallFunc()\n"); +} + +struct CallTestB { + virtual void VcallFunc(); + void CallFunc(); +}; + +void CallTestB::VcallFunc() +{ + printf("CallTestB::VcallFunc()\n"); +} + +void CallTestB::CallFunc() +{ + printf("CallTestB::CallFunc()\n"); +} + +void CfiCastStrict() +{ + C *c = new C; + A a; + c = static_cast(&a); +} + +void CfiDerivedCast() +{ + B *b = new B; + A a; + b = static_cast(&a); +} + +void CfiUnrelatedCast() +{ + D *d = new D; + A a; + d = ((D *)&a); +} + +void Icall() +{ + printf("Icall()\n"); +} + +void CfiIcall() +{ + ((void (*)(int))Icall)(42); +} + +void CfiVcall() +{ + CallTestA *a; + void *p = (void *)(new CallTestB()); + memcpy(&a, &p, sizeof(a)); + a->VcallFunc(); +} + +void CfiNvcall() +{ + CallTestA *a; + void *p = (void *)(new CallTestB()); + memcpy(&a, &p, sizeof(a)); + a->CallFunc(); +} + + +int main() +{ + if (DEBUG) { + ShowCfiLogFile(); + } + ClearCfiLog(); + if (DEBUG) { + ShowCfiLogFile(); + } + // clang allow it by default. It can be disabled with -fsanitize=cfi-cast-strict. + CfiCastStrict(); + + CfiDerivedCast(); + FindAndCheck("runtime error: control flow integrity check for type 'B' failed during base-to-derived cast"); + + CfiUnrelatedCast(); + FindAndCheck("runtime error: control flow integrity check for type 'D' failed during cast to unrelated type"); + + CfiNvcall(); + FindAndCheck("runtime error: control flow integrity check for type 'CallTestA' failed during non-virtual call"); + + CfiVcall(); + FindAndCheck("runtime error: control flow integrity check for type 'CallTestA' failed during virtual call"); + + CfiIcall(); + FindAndCheck("runtime error: control flow integrity check for type 'void (int)' failed during indirect function call"); + + if (DEBUG) { + ShowCfiLogFile(); + } +} diff --git a/libc-test/src/functionalext/ldso_cfi/crossdso/cfi_test_exe.cpp b/libc-test/src/functionalext/ldso_cfi/crossdso/cfi_test_exe.cpp new file mode 100644 index 00000000..233aa5e4 --- /dev/null +++ b/libc-test/src/functionalext/ldso_cfi/crossdso/cfi_test_exe.cpp @@ -0,0 +1,59 @@ +/** + * 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. + */ + +#include +#include +#include +#include "cfi_util.h" + +struct AA { + virtual void Test(); +}; + +void AA::Test() +{ + printf("AA::Test()\n"); +} + +void ChangeToAnotherObj() +{ + AA *a = new AA; + void *handle = dlopen("libcfi_cross_dso_test_lib.z.so", RTLD_NOW); + if (handle == nullptr) { + return; + } + void *(*create_B)() = (void *(*)())dlsym(handle, "CreateObj"); + void *p = create_B(); + a->Test(); + memcpy(&a, &p, sizeof(void *)); + a->Test(); +} + +int main() +{ + if (DEBUG) { + ShowCfiLogFile(); + } + ClearCfiLog(); + if (DEBUG) { + ShowCfiLogFile(); + } + ChangeToAnotherObj(); + FindAndCheck("runtime error: control flow integrity check for type 'AA' failed during virtual call"); + if (DEBUG) { + ShowCfiLogFile(); + } + return 0; +} \ No newline at end of file diff --git a/libc-test/src/functionalext/ldso_cfi/crossdso/cfi_test_lib.cpp b/libc-test/src/functionalext/ldso_cfi/crossdso/cfi_test_lib.cpp new file mode 100644 index 00000000..680209dc --- /dev/null +++ b/libc-test/src/functionalext/ldso_cfi/crossdso/cfi_test_lib.cpp @@ -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. + */ + +#include + +struct BB { + void Func(); + virtual void Test(); +}; + +void BB::Test() +{ + printf("BB::Test()\n"); +} + +void BB::Func() +{ + printf("BB::Func()\n"); +} + +extern"C" void* CreateObj() +{ + return new BB; +} \ No newline at end of file -- GitLab