提交 06a8b337 编写于 作者: D dhy308

Add support for CFI Cross-Dso.

Issue: I6A9R5
Test: libc-test pass
Signed-off-by: Ndhy308 <tony.gan@huawei.com>
上级 344eac92
# 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.
import("../../../test_template.gni")
group("ldso_cfi_test") {
testonly = true
deps = [
":ldso_cfi_check",
":ldso_cfi_test_exe",
":ldso_cfi_test_lib",
":ldso_cfi_test_bad_lib",
]
}
ohos_executable("ldso_cfi_check") {
# cflags = [
# "-fsanitize=cfi",
# "-fsanitize-trap=all",
# "-fno-sanitize-trap=cfi",
# "-flto",
# "-fvisibility=hidden"
# ]
# ldflags = [
# "-fsanitize=cfi",
# "-flto",
# "-fsanitize-trap=all",
# "-fno-sanitize-trap=cfi",
# ]
# cflags_c = ["--coverage"]
# ldflags = ["--coverage"]
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",
]
sources = [
"ldso_cfi_check.c",
]
configs = [ "//third_party/musl/libc-test/src/common:config_runtest" ]
}
ohos_executable("ldso_cfi_test_exe") {
#cflags = [ "-fPIE","-fvisibility=default" ]
#ldflags = [ "-pie","-fvisibility=default" ]
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",
]
sources = [
"ldso_cfi_test_exe.c",
]
configs = [ "//third_party/musl/libc-test/src/common:config_runtest" ]
}
ohos_shared_library("ldso_cfi_test_lib") {
include_dirs = [ "." ]
sources = [ "ldso_cfi_test_lib.c" ]
# cflags_c = ["--coverage"]
# ldflags = ["--coverage"]
output_name = "ldso_cfi_test_lib"
output_extension = "so"
subsystem_name = "musl"
part_name = "libc-test-lib"
}
ohos_shared_library("ldso_cfi_test_bad_lib") {
include_dirs = [ "." ]
sources = [ "ldso_cfi_test_bad_lib.c" ]
# cflags_c = ["--coverage"]
# ldflags = ["--coverage"]
output_name = "ldso_cfi_test_bad_lib"
output_extension = "so"
subsystem_name = "musl"
part_name = "libc-test-lib"
}
/**
* 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 <dlfcn.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <sys/wait.h>
#include "functionalext.h"
#define LIB_PATH "/data/tests/libc-test/src/libldso_cfi_test_lib.so"
#define BAD_LIB_PATH "/data/tests/libc-test/src/libldso_cfi_test_bad_lib.so"
struct dso {
char *mock;
};
extern bool init_cfi_shadow(struct dso *dso_list);
extern bool map_dso_to_cfi_shadow(struct dso *dso);
extern void unmap_dso_from_cfi_shadow(struct dso *dso);
extern void __cfi_slowpath(uint64_t CallSiteTypeId, void *Ptr);
extern void __cfi_slowpath_diag(uint64_t CallSiteTypeId, void *Ptr, void *DiagData);
typedef void(*TEST_FUN)(void);
typedef size_t (*GET_COUNT)();
typedef uint64_t (*GET_TP_ID)();
typedef void* (*GET_LAST_ADDR)();
typedef void* (*GET_LAST_DIAG)();
typedef void* (*GET_GL_ADDR)();
typedef void (*CFI_CHECK)();
typedef char* (*BUF_CHECK)();
GET_COUNT get_count = NULL;
GET_TP_ID get_type_id = NULL;
GET_LAST_ADDR get_address = NULL;
GET_LAST_DIAG get_diag = NULL;
GET_GL_ADDR get_global_address = NULL;
CFI_CHECK cfi_check = NULL;
BUF_CHECK buf_check = NULL;
static void test_func() {}
/**
* @tc.name : cfi_init_test_0001
* @tc.desc : If no dso while initializing the CFI shadow, do nothing and return true.
* @tc.level : Level 1
*/
void cfi_init_test_0001(void)
{
printf("["__FILE__"][Line: %d][%s]: entry\n", __LINE__, __func__);
EXPECT_TRUE("cfi_init_test_0001", init_cfi_shadow(NULL));
}
/**
* @tc.name : cfi_init_test_0002
* @tc.desc : If dso is NULL while mapping to the CFI shadow, do nothing and return true.
* @tc.level : Level 2
*/
void cfi_init_test_0002(void)
{
printf("["__FILE__"][Line: %d][%s]: entry\n", __LINE__, __func__);
EXPECT_TRUE("cfi_init_test_0002", map_dso_to_cfi_shadow(NULL));
}
/**
* @tc.name : cfi_init_test_0003
* @tc.desc : If dso is NULL while unmapping from the CFI shadow, do nothing.
* @tc.level : Level 2
*/
void cfi_init_test_0003(void)
{
printf("["__FILE__"][Line: %d][%s]: entry\n", __LINE__, __func__);
unmap_dso_from_cfi_shadow(NULL);
}
/**
* @tc.name : cfi_slowpath_function_test_0001
* @tc.desc : Loading a dso that contains __cfi_check() symbol, call the __cfi_slowpath() function with
* address inside the DSO, the __cfi_check() function is called.
* @tc.level : Level 1
*/
void cfi_slowpath_function_test_0002(void)
{
printf("["__FILE__"][Line: %d][%s]: entry\n", __LINE__, __func__);
void* handle = dlopen(LIB_PATH, RTLD_LAZY);
EXPECT_PTRNE("cfi_slowpath_function_test_0002", handle, NULL);
*(void **)(&get_count) = dlsym(handle, "get_count");
*(void **)(&get_type_id) = dlsym(handle, "get_type_id");
*(void **)(&get_address) = dlsym(handle, "get_address");
*(void **)(&get_diag) = dlsym(handle, "get_diag");
*(void **)(&get_global_address) = dlsym(handle, "get_global_address");
size_t count = (*get_count)();
__cfi_slowpath(20, (*get_global_address)());
EXPECT_EQ("cfi_slowpath_function_test_0002", 20, (*get_type_id)());
EXPECT_EQ("cfi_slowpath_function_test_0002", (*get_global_address)(), (*get_address)());
EXPECT_EQ("cfi_slowpath_function_test_0002", NULL, (*get_diag)());
EXPECT_EQ("cfi_slowpath_function_test_0002", ++count, (*get_count)());
dlclose(handle);
printf("["__FILE__"][Line: %d][%s]: end\n", __LINE__, __func__);
}
/**
* @tc.name : cfi_slowpath_function_test_0003
* @tc.desc : Loading a dso that contains __cfi_check() symbol, call the __cfi_slowpath() function with
* address belongs to other dso that does not enable Cross-DSO, the __cfi_check() function is
* not called.
* @tc.level : Level 1
*/
void cfi_slowpath_function_test_0003(void)
{
printf("["__FILE__"][Line: %d][%s]: entry\n", __LINE__, __func__);
void* handle = dlopen(LIB_PATH, RTLD_LAZY);
EXPECT_PTRNE("cfi_slowpath_function_test_0003", handle, NULL);
*(void **)(&get_count) = dlsym(handle, "get_count");
*(void **)(&get_type_id) = dlsym(handle, "get_type_id");
*(void **)(&get_address) = dlsym(handle, "get_address");
*(void **)(&get_diag) = dlsym(handle, "get_diag");
*(void **)(&get_global_address) = dlsym(handle, "get_global_address");
__cfi_slowpath(30, (*get_global_address)());
size_t count = (*get_count)();
__cfi_slowpath(40, (void*)(&test_func));
EXPECT_EQ("cfi_slowpath_function_test_0003", 30, (*get_type_id)());
EXPECT_EQ("cfi_slowpath_function_test_0003", (*get_global_address)(), (*get_address)());
EXPECT_EQ("cfi_slowpath_function_test_0003", NULL, (*get_diag)());
EXPECT_EQ("cfi_slowpath_function_test_0003", count, (*get_count)());
dlclose(handle);
printf("["__FILE__"][Line: %d][%s]: end\n", __LINE__, __func__);
}
/**
* @tc.name : cfi_slowpath_function_test_0004
* @tc.desc : Calling __cfi_slowpath() with target_addr = NULL
* @tc.level : Level 2
*/
void cfi_slowpath_function_test_0004(void)
{
printf("["__FILE__"][Line: %d][%s]: entry\n", __LINE__, __func__);
void* handle = dlopen(LIB_PATH, RTLD_LAZY);
EXPECT_PTRNE("cfi_slowpath_function_test_0004", handle, NULL);
*(void **)(&get_count) = dlsym(handle, "get_count");
size_t count = (*get_count)();
__cfi_slowpath(30, NULL);
EXPECT_EQ("cfi_slowpath_function_test_0004", count, (*get_count)());
dlclose(handle);
printf("["__FILE__"][Line: %d][%s]: end\n", __LINE__, __func__);
}
/**
* @tc.name : cfi_slowpath_function_test_0005
* @tc.desc : Loading a dso that contains __cfi_check() symbol, call the __cfi_slowpath() function with
* invalid address, coredump happened.
* not called.
* @tc.level : Level 2
*/
void cfi_slowpath_function_test_0005(void)
{
printf("["__FILE__"][Line: %d][%s]: entry\n", __LINE__, __func__);
void* handle = dlopen(LIB_PATH, RTLD_LAZY);
EXPECT_PTRNE("cfi_slowpath_function_test_0005", handle, NULL);
*(void **)(&get_count) = dlsym(handle, "get_count");
*(void **)(&get_type_id) = dlsym(handle, "get_type_id");
*(void **)(&get_address) = dlsym(handle, "get_address");
*(void **)(&get_diag) = dlsym(handle, "get_diag");
*(void **)(&get_global_address) = dlsym(handle, "get_global_address");
size_t count = (*get_count)();
int status;
pid_t pid;
pid = fork();
if(pid > 0) {
printf("["__FILE__"][Line: %d][%s]: parent process pid = %d\n", __LINE__, __func__, getppid());
wait(&status);
} else if(pid == 0) {
printf("["__FILE__"][Line: %d][%s]: child pid = %d\n", __LINE__, __func__, pid);
__cfi_slowpath(30, (void*)&count);
} else {
printf("["__FILE__"][Line: %d][%s]: fork failed!\n", __LINE__, __func__);
}
dlclose(handle);
printf("["__FILE__"][Line: %d][%s]: end\n", __LINE__, __func__);
}
/**
* @tc.name : cfi_slowpath_function_test_0006
* @tc.desc : Loading a dso which size is larger than 1 LIBRARY_ALIGNMENT(256KB), call the __cfi_slowpath()
* function with address in different LIBRARY_ALIGNMENT range and make sure __cfi_check() is called.
* @tc.level : Level 1
*/
void cfi_slowpath_function_test_0006(void)
{
printf("["__FILE__"][Line: %d][%s]: entry\n", __LINE__, __func__);
void* handle = dlopen(LIB_PATH, RTLD_LAZY);
EXPECT_PTRNE("cfi_slowpath_function_test_0006", handle, NULL);
*(void **)(&get_count) = dlsym(handle, "get_count");
*(void **)(&buf_check) = dlsym(handle, "buf");
size_t count = (*get_count)();
const size_t bss_size = 1024 * 1024;
for (size_t i = 0; i < bss_size; ++i) {
__cfi_slowpath(50, (char*)buf_check + i);
EXPECT_EQ("cfi_slowpath_function_test_0006", ++count, (*get_count)());
}
dlclose(handle);
printf("["__FILE__"][Line: %d][%s]: end\n", __LINE__, __func__);
}
/**
* @tc.name : cfi_slowpath_function_test_0007
* @tc.desc : Loading a dso 2 times
* @tc.level : Level 1
*/
void cfi_slowpath_function_test_0007(void)
{
printf("["__FILE__"][Line: %d][%s]: entry\n", __LINE__, __func__);
void* handle = dlopen(LIB_PATH, RTLD_LAZY);
EXPECT_PTRNE("cfi_slowpath_function_test_0007", handle, NULL);
*(void **)(&get_count) = dlsym(handle, "get_count");
*(void **)(&get_global_address) = dlsym(handle, "get_global_address");
__cfi_slowpath(10, (*get_global_address)());
void* handle2 = dlopen(LIB_PATH, RTLD_LAZY);
EXPECT_PTREQ("cfi_slowpath_function_test_0007", handle, handle2);
*(void **)(&get_count) = dlsym(handle2, "get_count");
*(void **)(&get_type_id) = dlsym(handle2, "get_type_id");
*(void **)(&get_address) = dlsym(handle2, "get_address");
*(void **)(&get_diag) = dlsym(handle2, "get_diag");
*(void **)(&get_global_address) = dlsym(handle2, "get_global_address");
size_t count = (*get_count)();
__cfi_slowpath(20, (*get_global_address)());
EXPECT_EQ("cfi_slowpath_function_test_0002", 20, (*get_type_id)());
EXPECT_EQ("cfi_slowpath_function_test_0002", (*get_global_address)(), (*get_address)());
EXPECT_EQ("cfi_slowpath_function_test_0002", ++count, (*get_count)());
dlclose(handle);
dlclose(handle2);
printf("["__FILE__"][Line: %d][%s]: end\n", __LINE__, __func__);
}
/**
* @tc.name : cfi_slowpath_function_test_0008
* @tc.desc : Calling dso's function after unloading the dso.
* @tc.level : Level 1
*/
void cfi_slowpath_function_test_0008(void)
{
printf("["__FILE__"][Line: %d][%s]: entry\n", __LINE__, __func__);
void* handle = dlopen(LIB_PATH, RTLD_LAZY);
EXPECT_PTRNE("cfi_slowpath_function_test_0008", handle, NULL);
*(void **)(&get_global_address) = dlsym(handle, "get_global_address");
dlclose(handle);
int status;
pid_t pid;
pid = fork();
if(pid > 0) {
printf("["__FILE__"][Line: %d][%s]: parent process pid = %d\n", __LINE__, __func__, getppid());
wait(&status);
} else if(pid == 0) {
printf("["__FILE__"][Line: %d][%s]: child pid = %d\n", __LINE__, __func__, pid);
__cfi_slowpath(30, (*get_global_address)());
} else {
printf("["__FILE__"][Line: %d][%s]: fork failed!\n", __LINE__, __func__);
}
printf("["__FILE__"][Line: %d][%s]: end\n", __LINE__, __func__);
}
/**
* @tc.name : cfi_slowpath_diag_function_test_0001
* @tc.desc : Loading a dso that contains __cfi_check() symbol, call the __cfi_slowpath_diag() function with
* address inside the DSO, the __cfi_check() function is called.
* @tc.level : Level 1
*/
void cfi_slowpath_diag_function_test_0001(void)
{
printf("["__FILE__"][Line: %d][%s]: entry\n", __LINE__, __func__);
void* handle = dlopen(LIB_PATH, RTLD_LAZY);
EXPECT_PTRNE("cfi_slowpath_diag_function_test_0002", handle, NULL);
*(void **)(&get_count) = dlsym(handle, "get_count");
*(void **)(&get_global_address) = dlsym(handle, "get_global_address");
size_t count = (*get_count)();
void* diag_ptr = (void*)(5678);
__cfi_slowpath_diag(10, NULL, diag_ptr);
EXPECT_EQ("cfi_slowpath_diag_function_test_0002", count, (*get_count)());
__cfi_slowpath_diag(10, (*get_global_address)(), NULL);
EXPECT_EQ("cfi_slowpath_diag_function_test_0002", ++count, (*get_count)());
dlclose(handle);
printf("["__FILE__"][Line: %d][%s]: end\n", __LINE__, __func__);
}
TEST_FUN G_Fun_Array[] = {
cfi_init_test_0001,
cfi_init_test_0002,
cfi_init_test_0003,
cfi_slowpath_function_test_0002,
cfi_slowpath_function_test_0003,
cfi_slowpath_function_test_0004,
cfi_slowpath_function_test_0005,
cfi_slowpath_function_test_0006,
cfi_slowpath_function_test_0007,
cfi_slowpath_function_test_0008,
cfi_slowpath_diag_function_test_0001,
};
int main(void)
{
printf("["__FILE__"][Line: %d][%s]: entry\n", __LINE__, __func__);
int num = sizeof(G_Fun_Array)/sizeof(TEST_FUN);
for (int pos = 0; pos < num; ++pos) {
G_Fun_Array[pos]();
}
printf("["__FILE__"][Line: %d][%s]: end\n", __LINE__, __func__);
return 0;
}
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
static size_t g_count = 0;
static uint64_t g_type_id = 0;
static void *g_address = NULL;
static void *g_diag = NULL;
// Make sure the library crosses at least one kLibraryAlignment(=256KB) boundary.
char buf[1024 * 1024];
// Mock a CFI-enabled library without relying on the compiler.
__attribute__((aligned(4096))) void __cfi_check(uint64_t CallSiteTypeId,
void *TargetAddr, void *Diag) {
printf("["__FILE__"][Line: %d][%s]: entry\n", __LINE__, __func__);
++g_count;
g_type_id = CallSiteTypeId;
g_address = TargetAddr;
g_diag = Diag;
}
size_t get_count() {
return g_count;
}
uint64_t get_type_id() {
return g_type_id;
}
void *get_address() {
return g_address;
}
void *get_diag() {
return g_diag;
}
void *get_global_address() {
return &g_count;
}
...@@ -25,4 +25,5 @@ functionalext_list = [ ...@@ -25,4 +25,5 @@ functionalext_list = [
"supplement:functionalext_supplement_test", "supplement:functionalext_supplement_test",
"fortify:functionalext_fortify_test", "fortify:functionalext_fortify_test",
"symver:functionalext_symver_test", "symver:functionalext_symver_test",
"ldso_cfi:ldso_cfi_test",
] ]
...@@ -1668,6 +1668,7 @@ musl_src_ldso = [ ...@@ -1668,6 +1668,7 @@ musl_src_ldso = [
"ldso/ns_config.c", "ldso/ns_config.c",
"ldso/strops.c", "ldso/strops.c",
"ldso/dynlink_rand.c", "ldso/dynlink_rand.c",
"ldso/cfi.c",
"ldso/ld_log.c", "ldso/ld_log.c",
] ]
...@@ -2102,11 +2103,13 @@ musl_src_porting_file = [ ...@@ -2102,11 +2103,13 @@ musl_src_porting_file = [
"crt/arm/crti.s", "crt/arm/crti.s",
"crt/aarch64/crti.s", "crt/aarch64/crti.s",
"crt/crtplus.c", "crt/crtplus.c",
"ldso/cfi.h",
"ldso/ld_log.h", "ldso/ld_log.h",
"ldso/ld_log.c", "ldso/ld_log.c",
"ldso/namespace.c", "ldso/namespace.c",
"ldso/ns_config.c", "ldso/ns_config.c",
"ldso/strops.c", "ldso/strops.c",
"ldso/cfi.c",
"ldso/dynlink_rand.c", "ldso/dynlink_rand.c",
"ldso/dynlink_rand.h", "ldso/dynlink_rand.h",
"src/thread/pthread_create.c", "src/thread/pthread_create.c",
......
#define _GNU_SOURCE
#include <sys/mman.h>
#include <sys/prctl.h>
#include "cfi.h"
#include "ld_log.h"
#include "namespace.h"
/* This module provides support for LLVM CFI Cross-DSO by implementing the __cfi_slowpath() and __cfi_slowpath_diag()
* functions. These two functions will be called before visiting other dso's resources. The responsibility is to
* calculate the __cfi_check() of the target dso, and call it.
* The relationship between __cfi_check and dso addr is:
* __cfi_check = AlignDown(addr, shadow_alignment) + shadow_alignment - (shadow_value - 2) * 4096;
* The shadow_alignment presents the size of memory mapped by one shadow value.
* The shadow_value presents the distance between the __cfi_check() and the the end address of each shadow alignment
* in the dso. It can be presented as a multiple of 4096.
* The CFI shadow is used to store shadow value(s) of each dso.
*/
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
#define ALIGN_UP(a, b) (((a) + (b) - 1) & -(b))
#define ALIGN_DOWN(a, b) ((a) & -(b))
#if DL_FDPIC
#define LADDR(p, v) laddr((p), (v))
#else
#define LADDR(p, v) (void *)((p)->base + (v))
#endif
/* Function ptr for __cfi_check() */
typedef int (*cfi_check_t)(uint64_t, void *, void *);
static const uintptr_t shadow_granularity = LIBRARY_ALIGNMENT_BITS;
static const uintptr_t cfi_check_granularity = 12;
static const uintptr_t shadow_alignment = 1UL << shadow_granularity;
static uintptr_t shadow_size = 0;
/* Start addr of the CFI shadow */
static char *cfi_shadow_start = NULL;
/* List head of all the DSOs loaded by the process */
static struct dso *dso_list_head = NULL;
/* Shadow value */
static const uint16_t sv_invalid = 0;
static const uint16_t sv_uncheck = 1;
static const uint16_t sv_valid_min = 2;
#if defined(__LP64__)
static const uintptr_t max_target_addr = 0xffffffffffff;
#else
static const uintptr_t max_target_addr = 0xffffffff;
#endif
/* Create a cfi shadow */
static bool create_cfi_shadow(void);
/* Map dsos to CFI shadow */
static bool add_dso_to_cfi_shadow(struct dso *dso);
static bool fill_shadow_value_to_shadow(uintptr_t begin, uintptr_t end, uintptr_t cfi_check, uint16_t type);
/* Find the __cfi_check() of target dso and call it */
void __cfi_slowpath(uint64_t call_site_type_id, void *func_ptr);
void __cfi_slowpath_diag(uint64_t call_site_type_id, void *func_ptr, void *diag_data);
static inline uintptr_t addr_to_offset(uintptr_t addr, int bits)
{
/* Convert addr to CFI shadow offset.
* Shift left 1 bit because the shadow value is uint16_t.
*/
return (addr >> bits) << 1;
}
static void set_cfi_shadow_name()
{
LD_LOGI("[%{public}s] start!\n", __FUNCTION__);
prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, cfi_shadow_start, shadow_size, "cfi_shadow:musl");
return;
}
static struct symdef find_cfi_check_sym(struct dso *p)
{
LD_LOGI("[%{public}s] start!\n", __FUNCTION__);
if (p == NULL) {
LD_LOGE("[%{public}s] has null param!\n", __FUNCTION__);
struct symdef emptysym = {0};
return emptysym;
}
ns_t *ns = p->namespace;
struct verinfo verinfo = { .s = "__cfi_check", .v = "", .use_vna_hash = false };
return find_sym2(p, &verinfo, 0, 1, ns);
}
static uintptr_t get_cfi_check_addr(uint16_t value, void* func_ptr)
{
LD_LOGI("[%{public}s] start!\n", __FUNCTION__);
uintptr_t addr = (uintptr_t)func_ptr;
uintptr_t aligned_addr = ALIGN_DOWN(addr, shadow_alignment) + shadow_alignment;
uintptr_t cfi_check_func_addr = aligned_addr - ((uintptr_t)(value - sv_valid_min) << cfi_check_granularity);
#ifdef __arm__
LD_LOGI("[%{public}s] __arm__ defined!\n", __FUNCTION__);
cfi_check_func_addr++;
#endif
LD_LOGI("[%{public}s] the cfi_check_func_addr is %{public}p!\n", __FUNCTION__, cfi_check_func_addr);
return cfi_check_func_addr;
}
static void cfi_slowpath_common(uint64_t call_site_type_id, void *func_ptr, void *diag_data)
{
LD_LOGI("[%{public}s] start!\n", __FUNCTION__);
LD_LOGI("[%{public}s] func_ptr[%{public}p] !\n", __FUNCTION__, func_ptr);
uint16_t value = sv_invalid;
#if defined(__aarch64__)
LD_LOGI("[%{public}s] __aarch64__ defined!\n", __FUNCTION__);
uintptr_t addr = (uintptr_t)func_ptr & ((1ULL << 56) - 1);
#else
LD_LOGI("[%{public}s] __aarch64__ not defined!\n", __FUNCTION__);
uintptr_t addr = func_ptr;
#endif
/* Get shadow value */
uintptr_t offset = addr_to_offset(addr, shadow_granularity);
if (offset > shadow_size) {
value = sv_invalid;
} else {
value = *((uint16_t*)(cfi_shadow_start + offset));
}
LD_LOGI("[%{public}s] the value is 0x%{public}x!\n", __FUNCTION__, value);
struct dso *dso = NULL;
switch (value)
{
case sv_invalid:
dso = (struct dso *)addr2dso((size_t)__builtin_return_address(0));
if (dso == NULL) {
LD_LOGE("[%{public}s] can not find the dso!\n", __FUNCTION__);
__builtin_trap();
}
LD_LOGI("[%{public}s] dso name[%{public}s]!\n", __FUNCTION__, dso->name);
struct symdef cfi_check_sym = find_cfi_check_sym(dso);
if (!cfi_check_sym.sym) {
LD_LOGE("[%{public}s] can not find the __cfi_check in the dso!\n", __FUNCTION__);
__builtin_trap();
}
LD_LOGI("[%{public}s] cfi_check addr[%{public}p]!\n",
__FUNCTION__, LADDR(cfi_check_sym.dso, cfi_check_sym.sym->st_value));
((cfi_check_t)LADDR(cfi_check_sym.dso, cfi_check_sym.sym->st_value))(call_site_type_id, func_ptr, diag_data);
break;
case sv_uncheck:
break;
default:
((cfi_check_t)get_cfi_check_addr(value, func_ptr))(call_site_type_id, func_ptr, diag_data);
break;
}
return;
}
bool init_cfi_shadow(struct dso *dso_list)
{
LD_LOGI("[%{public}s] start!\n", __FUNCTION__);
if (dso_list == NULL) {
LD_LOGW("[%{public}s] has null param!\n", __FUNCTION__);
return true;
}
/* Save the head node of dso list */
dso_list_head = dso_list;
return map_dso_to_cfi_shadow(dso_list);
}
bool map_dso_to_cfi_shadow(struct dso *dso)
{
LD_LOGI("[%{public}s] start!\n", __FUNCTION__);
bool has_cfi_check = false;
if (dso == NULL) {
LD_LOGE("[%{public}s] has null param!\n", __FUNCTION__);
return true;
}
/* Find __cfi_check symbol in dso list */
for (struct dso *p = dso; p; p = p->next) {
if (find_cfi_check_sym(p).sym) {
LD_LOGI("[%{public}s] find __cfi_check function in dso %{public}s!\n", __FUNCTION__, p->name);
has_cfi_check = true;
break;
}
}
/* If the cfi shadow does not exist, create it and map all the dsos and its dependents to it. */
if (cfi_shadow_start == NULL) {
if (has_cfi_check) {
if (!create_cfi_shadow()) {
LD_LOGE("[%{public}s] create cfi shadow failed!\n", __FUNCTION__);
return false;
}
LD_LOGI("[%{public}s] add_dso_to_cfi_shadow with dso_list_head!\n", __FUNCTION__);
add_dso_to_cfi_shadow(dso_list_head);
set_cfi_shadow_name();
}
/* If the cfi shadow exists, map the current dso and its dependents to it. */
} else {
LD_LOGI("[%{public}s] add_dso_to_cfi_shadow with dso!\n", __FUNCTION__);
add_dso_to_cfi_shadow(dso);
set_cfi_shadow_name();
}
return true;
}
void unmap_dso_from_cfi_shadow(struct dso *dso)
{
LD_LOGI("[%{public}s] start!\n", __FUNCTION__);
if (dso == NULL) {
LD_LOGE("[%{public}s] has null param!\n", __FUNCTION__);
return;
}
LD_LOGI("[%{public}s] unmap dso %{public}s from shadow!\n", __FUNCTION__, dso->name);
if (cfi_shadow_start == NULL)
return;
if (dso->map == 0 || dso->map_len == 0)
return;
/* Set the dso's shadow value as invalid. */
fill_shadow_value_to_shadow(dso->map, dso->map + dso->map_len, 0, sv_invalid);
set_cfi_shadow_name();
return;
}
static bool create_cfi_shadow(void)
{
LD_LOGI("[%{public}s] start!\n", __FUNCTION__);
/* Each process can load up to (max_target_addr >> shadow_granularity) dsos. Shift left 1 bit because the shadow
* value is uint16_t. The size passed to mmap() should be aligned with 4096, so shadow_size should be aligned.
*/
shadow_size = ALIGN_UP(((max_target_addr >> shadow_granularity) << 1), PAGE_SIZE);
uintptr_t *mmap_addr = mmap(NULL, shadow_size, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);
if (mmap_addr == MAP_FAILED) {
LD_LOGE("[%{public}s] mmap failed!\n", __FUNCTION__);
return false;
}
cfi_shadow_start = (char*)mmap_addr;
LD_LOGI("[%{public}s] the cfi_shadow_start addr is %{public}p!\n", __FUNCTION__, cfi_shadow_start);
return true;
}
static bool add_dso_to_cfi_shadow(struct dso *dso)
{
LD_LOGI("[%{public}s] start!\n", __FUNCTION__);
for (struct dso *p = dso; p; p = p->next) {
LD_LOGI("[%{public}s] start to deal with dso %{public}s!\n", __FUNCTION__, p->name);
if (p->map == 0 || p->map_len == 0) {
LD_LOGI("[%{public}s] the dso has no data!\n", __FUNCTION__);
continue;
}
struct symdef cfi_check_sym = find_cfi_check_sym(p);
/* If the dso doesn't have __cfi_check(), set it's shadow value unchecked. */
if (!cfi_check_sym.sym) {
LD_LOGI("[%{public}s] the dso has no __cfi_check func, call fill_shadow_value_to_shadow!\n", __FUNCTION__);
if (!fill_shadow_value_to_shadow(p->map, p->map + p->map_len, 0, sv_uncheck)) {
LD_LOGE("[%{public}s] add dso to cfi shadow failed!\n", __FUNCTION__);
return false;
}
/* If the dso has __cfi_check(), set it's shadow value valid. */
} else {
LD_LOGI("[%{public}s] the dso has __cfi_check func,call fill_shadow_value_to_shadow!\n", __FUNCTION__);
uintptr_t end = p->map + p->map_len;
uintptr_t cfi_check = LADDR(cfi_check_sym.dso, cfi_check_sym.sym->st_value);
if (cfi_check == 0) {
LD_LOGE("[%{public}s] the dso has null cfi_check func!\n", __FUNCTION__);
return false;
}
if (!fill_shadow_value_to_shadow(p->map, end, cfi_check, sv_valid_min)) {
LD_LOGE("[%{public}s] add dso to cfi shadow failed!\n", __FUNCTION__);
return false;
}
}
LD_LOGI("[%{public}s] finish to deal with dso %{public}s!\n", __FUNCTION__, p->name);
}
return true;
}
static bool fill_shadow_value_to_shadow(uintptr_t begin, uintptr_t end, uintptr_t cfi_check, uint16_t type)
{
LD_LOGI("[%{public}s] start!\n", __FUNCTION__);
LD_LOGI("[%{public}s] begin[%{public}x] end[%{public}x] cfi_check[%{public}x] type[%{public}x]!\n",
__FUNCTION__, begin, end, cfi_check, type);
if (begin == 0 || end == 0) {
LD_LOGE("[%{public}s] has error param!\n", __FUNCTION__);
return false;
}
/* To ensure the atomicity of the CFI shadow operation, we create a temp_shadow, write the shadow value to
* the temp_shadow, and then write it back to the CFI shadow by mremap().*/
begin = ALIGN_DOWN(MAX(begin, cfi_check), shadow_alignment);
char* shadow_begin = cfi_shadow_start + addr_to_offset(begin, LIBRARY_ALIGNMENT_BITS);
char* shadow_end = (char*)(((uint16_t*)(cfi_shadow_start + addr_to_offset(end - 1, LIBRARY_ALIGNMENT_BITS))) + 1);
char* aligned_shadow_begin = (char*)ALIGN_DOWN((uintptr_t)shadow_begin, PAGE_SIZE);
char* aligned_shadow_end = (char*)ALIGN_UP((uintptr_t)shadow_end, PAGE_SIZE);
uint16_t tmp_shadow_size = aligned_shadow_end - aligned_shadow_begin;
uint16_t offset_begin = shadow_begin - aligned_shadow_begin;
uint16_t offset_end = shadow_end - aligned_shadow_begin;
char* tmp_shadow_start = (char*)mmap(NULL, tmp_shadow_size,
PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (tmp_shadow_start == MAP_FAILED) {
LD_LOGE("[%{public}s] mmap failed!\n", __FUNCTION__);
return false;
}
LD_LOGI("[%{public}s] tmp_shadow_start is %{public}p\t tmp_shadow_size is 0x%{public}x!\n",
__FUNCTION__, tmp_shadow_start, tmp_shadow_size);
memcpy(tmp_shadow_start, aligned_shadow_begin, offset_begin);
memcpy(tmp_shadow_start + offset_end, shadow_end, aligned_shadow_end - shadow_end);
/* If the dso has __cfi_check(), calculate valid shadow value */
if (type == sv_valid_min) {
#ifdef __arm__
uint16_t shadow_value_begin = ((begin + shadow_alignment - (cfi_check - 1))
>> cfi_check_granularity) + sv_valid_min;
#else
uint16_t shadow_value_begin = ((begin + shadow_alignment - cfi_check)
>> cfi_check_granularity) + sv_valid_min;
#endif
LD_LOGI("[%{public}s] shadow_value_begin is 0x%{public}x!\n", __FUNCTION__, shadow_value_begin);
uint16_t shadow_value_step = 1 << (shadow_granularity - cfi_check_granularity);
uint16_t shadow_value = shadow_value_begin;
/* Set shadow_value */
for (uint16_t *shadow_addr = tmp_shadow_start + offset_begin;
shadow_addr != tmp_shadow_start + offset_end; shadow_addr++) {
if (shadow_value < shadow_value_begin) {
*shadow_addr = sv_uncheck;
continue;
}
*shadow_addr = shadow_value;
shadow_value += shadow_value_step;
}
/* in these cases, shadow_value will always be sv_uncheck or sv_invalid */
} else if (type == sv_uncheck || type == sv_invalid) {
/* Set shadow_value */
for (uint16_t *shadow_addr = tmp_shadow_start + offset_begin;
shadow_addr != tmp_shadow_start + offset_end; shadow_addr++) {
*shadow_addr = type;
}
} else {
LD_LOGE("[%{public}s] has error param!\n", __FUNCTION__);
return false;
}
mprotect(tmp_shadow_start, tmp_shadow_size, PROT_READ);
/* Remap temp_shadow to CFI shadow. */
uint16_t* mremap_addr = mremap(tmp_shadow_start, tmp_shadow_size, tmp_shadow_size,
MREMAP_MAYMOVE | MREMAP_FIXED, aligned_shadow_begin);
if (mremap_addr == MAP_FAILED)
{
LD_LOGE("[%{public}s] mremap failed!\n", __FUNCTION__);
return false;
}
LD_LOGI("[%{public}s] fill completed!\n", __FUNCTION__);
return true;
}
void __cfi_slowpath(uint64_t call_site_type_id, void *func_ptr)
{
LD_LOGI("[%{public}s] start!\n", __FUNCTION__);
if (func_ptr == NULL) {
LD_LOGE("[%{public}s] has error param!\n", __FUNCTION__);
return;
}
if (cfi_shadow_start == NULL) {
LD_LOGE("[%{public}s] the cfi_shadow_start is null!\n", __FUNCTION__);
__builtin_trap();
}
cfi_slowpath_common(call_site_type_id, func_ptr, NULL);
return;
}
void __cfi_slowpath_diag(uint64_t call_site_type_id, void *func_ptr, void *diag_data)
{
LD_LOGI("[%{public}s] start!\n", __FUNCTION__);
if (func_ptr == NULL) {
LD_LOGE("[%{public}s] has error param!\n", __FUNCTION__);
return;
}
if (cfi_shadow_start == NULL) {
LD_LOGE("[%{public}s] the cfi_shadow_start is null!\n", __FUNCTION__);
__builtin_trap();
}
cfi_slowpath_common(call_site_type_id, func_ptr, diag_data);
return;
}
\ No newline at end of file
#include "dynlink.h"
/* alignment bits in memory space for dso */
#define LIBRARY_ALIGNMENT_BITS 18
/* minimum unit in memory space for dso */
#define LIBRARY_ALIGNMENT (1UL << LIBRARY_ALIGNMENT_BITS)
/* map all the dso and the dependents to cfi shadow */
bool init_cfi_shadow(struct dso *dso_list);
/* map a dso and the dependents to cfi shadow */
bool map_dso_to_cfi_shadow(struct dso *dso);
/* unmap a dso from cfi shadow */
void unmap_dso_from_cfi_shadow(struct dso *dso);
\ No newline at end of file
...@@ -26,10 +26,12 @@ ...@@ -26,10 +26,12 @@
#include <sys/membarrier.h> #include <sys/membarrier.h>
#include <sys/time.h> #include <sys/time.h>
#include <time.h> #include <time.h>
#include <sys/prctl.h>
#include "dlfcn_ext.h" #include "dlfcn_ext.h"
#include "dynlink_rand.h" #include "dynlink_rand.h"
#include "ld_log.h" #include "ld_log.h"
#include "cfi.h"
#include "libc.h" #include "libc.h"
#include "malloc_impl.h" #include "malloc_impl.h"
#include "namespace.h" #include "namespace.h"
...@@ -88,105 +90,11 @@ struct reserved_address_params { ...@@ -88,105 +90,11 @@ struct reserved_address_params {
#endif #endif
}; };
struct td_index {
size_t args[2];
struct td_index *next;
};
struct verinfo {
const char *s;
const char *v;
bool use_vna_hash;
uint32_t vna_hash;
};
struct sym_info_pair { struct sym_info_pair {
uint_fast32_t sym_h; uint_fast32_t sym_h;
uint32_t sym_l; uint32_t sym_l;
}; };
struct dso {
#if DL_FDPIC
struct fdpic_loadmap *loadmap;
#else
unsigned char *base;
#endif
char *name;
size_t *dynv;
struct dso *next, *prev;
/* add namespace */
ns_t *namespace;
/* mark the dso status */
unsigned int flags;
int cache_sym_index;
struct dso *cache_dso;
Sym *cache_sym;
Phdr *phdr;
int phnum;
size_t phentsize;
Sym *syms;
Elf_Symndx *hashtab;
uint32_t *ghashtab;
int16_t *versym;
Verdef *verdef;
Verneed *verneed;
char *strings;
struct dso *syms_next, *lazy_next;
size_t *lazy, lazy_cnt;
unsigned char *map;
size_t map_len;
dev_t dev;
ino_t ino;
uint64_t file_offset;
char relocated;
char constructed;
char kernel_mapped;
char mark;
char bfs_built;
char runtime_loaded;
char by_dlopen;
struct dso **deps, *needed_by;
size_t ndeps_direct;
size_t next_dep;
int ctor_visitor;
int nr_dlopen;
char *rpath_orig, *rpath;
struct tls_module tls;
size_t tls_id;
size_t relro_start, relro_end;
uintptr_t *new_dtv;
unsigned char *new_tls;
struct td_index *td_index;
struct dso *fini_next;
char *shortname;
#if DL_FDPIC
unsigned char *base;
#else
struct fdpic_loadmap *loadmap;
#endif
struct funcdesc {
void *addr;
size_t *got;
} *funcdescs;
size_t *got;
struct dso **parents;
size_t parents_count;
size_t parents_capacity;
bool is_global;
bool is_reloc_head_so_dep;
struct dso **reloc_can_search_dso_list;
size_t reloc_can_search_dso_count;
size_t reloc_can_search_dso_capacity;
char buf[];
};
struct symdef {
Sym *sym;
struct dso *dso;
};
typedef void (*stage3_func)(size_t *, size_t *); typedef void (*stage3_func)(size_t *, size_t *);
static struct builtin_tls { static struct builtin_tls {
...@@ -264,7 +172,6 @@ static void handle_relro_sharing(struct dso *p, const dl_extinfo *extinfo, ssize ...@@ -264,7 +172,6 @@ static void handle_relro_sharing(struct dso *p, const dl_extinfo *extinfo, ssize
int handle_asan_path_open(int fd, const char *name, ns_t *namespace, char *buf, size_t buf_size); int handle_asan_path_open(int fd, const char *name, ns_t *namespace, char *buf, size_t buf_size);
/* add namespace function */ /* add namespace function */
static void *addr2dso(size_t a);
static void get_sys_path(ns_configor *conf); static void get_sys_path(ns_configor *conf);
static void dlclose_ns(struct dso *p); static void dlclose_ns(struct dso *p);
static bool get_app_path(char *path, size_t size) static bool get_app_path(char *path, size_t size)
...@@ -429,7 +336,7 @@ static void init_namespace(struct dso *app) ...@@ -429,7 +336,7 @@ static void init_namespace(struct dso *app)
/* Compute load address for a virtual address in a given dso. */ /* Compute load address for a virtual address in a given dso. */
#if DL_FDPIC #if DL_FDPIC
static void *laddr(const struct dso *p, size_t v) void *laddr(const struct dso *p, size_t v)
{ {
size_t j=0; size_t j=0;
if (!p->loadmap) return p->base + v; if (!p->loadmap) return p->base + v;
...@@ -799,7 +706,7 @@ static void add_can_search_so_list_in_dso(struct dso *dso_relocating, struct dso ...@@ -799,7 +706,7 @@ static void add_can_search_so_list_in_dso(struct dso *dso_relocating, struct dso
#if defined(__GNUC__) #if defined(__GNUC__)
__attribute__((always_inline)) __attribute__((always_inline))
#endif #endif
static inline struct symdef find_sym2(struct dso *dso, struct verinfo *verinfo, int need_def, int use_deps, ns_t *ns) struct symdef find_sym2(struct dso *dso, struct verinfo *verinfo, int need_def, int use_deps, ns_t *ns)
{ {
struct sym_info_pair s_info_p = gnu_hash(verinfo->s); struct sym_info_pair s_info_p = gnu_hash(verinfo->s);
uint32_t h = 0, gh = s_info_p.sym_h, gho = gh / (8*sizeof(size_t)), *ght; uint32_t h = 0, gh = s_info_p.sym_h, gho = gh / (8*sizeof(size_t)), *ght;
...@@ -1373,19 +1280,45 @@ static void *map_library(int fd, struct dso *dso, struct reserved_address_params ...@@ -1373,19 +1280,45 @@ static void *map_library(int fd, struct dso *dso, struct reserved_address_params
map_flags |= MAP_FIXED; map_flags |= MAP_FIXED;
} }
} }
/* The first time, we map too much, possibly even more than
* the length of the file. This is okay because we will not /* we will find a LIBRARY_ALIGNMENT aligned address as the start of dso
* use the invalid part; we just need to reserve the right * so we need a tmp_map_len as map_len + LIBRARY_ALIGNMENT to make sure
* amount of virtual address space to map over later. */ * we have enough space to shift the dso to the correct location*/
map = DL_NOMMU_SUPPORT size_t tmp_map_len = ALIGN(map_len, LIBRARY_ALIGNMENT) + LIBRARY_ALIGNMENT - PAGE_SIZE;
? mmap((void *)start_addr, map_len, PROT_READ|PROT_WRITE|PROT_EXEC,
MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) /* if reserved_params exists, we should use start_addr as prefered result to do the mmap operation */
: mmap((void *)start_addr, map_len, prot, if (reserved_params) {
map_flags, fd, off_start); map = DL_NOMMU_SUPPORT
if (map==MAP_FAILED) goto error; ? mmap((void *)start_addr, map_len, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)
if (reserved_params && map_len < reserved_params->reserved_size) { : mmap((void *)start_addr, map_len, prot, map_flags, fd, off_start);
reserved_params->reserved_size -= (map_len + (start_addr - (size_t)reserved_params->start_addr)); if (map == MAP_FAILED) {
reserved_params->start_addr = (void *)((uint8_t *)map + map_len); goto error;
}
if (reserved_params && map_len < reserved_params->reserved_size) {
reserved_params->reserved_size -= (map_len + (start_addr - (size_t)reserved_params->start_addr));
reserved_params->start_addr = (void *)((uint8_t *)map + map_len);
}
/* if reserved_params does not exist, we should use real_map as prefered result to do the mmap operation */
} else {
/* use tmp_map_len to mmap enough space for the dso with anonymous mapping */
unsigned char *temp_map = mmap((void *)NULL, tmp_map_len, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (temp_map == MAP_FAILED) {
goto error;
}
/* find the LIBRARY_ALIGNMENT aligned address */
unsigned char *real_map = (unsigned char*)ALIGN((uintptr_t)temp_map, LIBRARY_ALIGNMENT);
/* mummap the space we mmap before so that we can mmap correct space again */
munmap(temp_map, tmp_map_len);
map = DL_NOMMU_SUPPORT
? mmap(real_map, map_len, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)
/* use map_len to mmap correct space for the dso with file mapping */
: mmap(real_map, map_len, prot, map_flags, fd, off_start);
if (map == MAP_FAILED) {
goto error;
}
} }
dso->map = map; dso->map = map;
dso->map_len = map_len; dso->map_len = map_len;
...@@ -2902,6 +2835,13 @@ void __dls3(size_t *sp, size_t *auxv) ...@@ -2902,6 +2835,13 @@ void __dls3(size_t *sp, size_t *auxv)
libc.tls_size = tmp_tls_size; libc.tls_size = tmp_tls_size;
} }
if (!init_cfi_shadow(head)) {
error("[%s] init_cfi_shadow failed: %m", __FUNCTION__);
if (runtime) {
longjmp(*rtld_fail, 1);
}
}
if (ldso_fail) _exit(127); if (ldso_fail) _exit(127);
if (ldd_mode) _exit(0); if (ldd_mode) _exit(0);
...@@ -3202,6 +3142,13 @@ static void *dlopen_impl( ...@@ -3202,6 +3142,13 @@ static void *dlopen_impl(
* relocations resolved to symbol definitions that get removed. */ * relocations resolved to symbol definitions that get removed. */
redo_lazy_relocs(); redo_lazy_relocs();
if (!map_dso_to_cfi_shadow(p)) {
error("[%s] map_dso_to_cfi_shadow failed: %m", __FUNCTION__);
if (runtime) {
longjmp(*rtld_fail, 1);
}
}
if (mode & RTLD_NODELETE) { if (mode & RTLD_NODELETE) {
p->flags |= DSO_FLAGS_NODELETE; p->flags |= DSO_FLAGS_NODELETE;
} }
...@@ -3399,7 +3346,7 @@ hidden int __dl_invalid_handle(void *h) ...@@ -3399,7 +3346,7 @@ hidden int __dl_invalid_handle(void *h)
return 1; return 1;
} }
static void *addr2dso(size_t a) void *addr2dso(size_t a)
{ {
struct dso *p; struct dso *p;
size_t i; size_t i;
...@@ -3554,6 +3501,8 @@ static int dlclose_impl(struct dso *p) ...@@ -3554,6 +3501,8 @@ static int dlclose_impl(struct dso *p)
/* remove dso from namespace */ /* remove dso from namespace */
dlclose_ns(p); dlclose_ns(p);
unmap_dso_from_cfi_shadow(p);
if (p->lazy != NULL) if (p->lazy != NULL)
internal_free(p->lazy); internal_free(p->lazy);
...@@ -4177,20 +4126,48 @@ static bool task_map_library(struct loadtask *task, struct reserved_address_para ...@@ -4177,20 +4126,48 @@ static bool task_map_library(struct loadtask *task, struct reserved_address_para
map_flags |= MAP_FIXED; map_flags |= MAP_FIXED;
} }
} }
/* The first time, we map too much, possibly even more than
* the length of the file. This is okay because we will not /* we will find a LIBRARY_ALIGNMENT aligned address as the start of dso
* use the invalid part; we just need to reserve the right * so we need a tmp_map_len as map_len + LIBRARY_ALIGNMENT to make sure
* amount of virtual address space to map over later. */ * we have enough space to shift the dso to the correct location*/
map = DL_NOMMU_SUPPORT size_t tmp_map_len = ALIGN(map_len, LIBRARY_ALIGNMENT) + LIBRARY_ALIGNMENT - PAGE_SIZE;
/* if reserved_params exists, we should use start_addr as prefered result to do the mmap operation */
if (reserved_params) {
map = DL_NOMMU_SUPPORT
? mmap((void *)start_addr, map_len, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) ? mmap((void *)start_addr, map_len, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)
: mmap((void *)start_addr, map_len, prot, map_flags, task->fd, off_start + task->file_offset); : mmap((void *)start_addr, map_len, prot, map_flags, task->fd, off_start + task->file_offset);
if (map == MAP_FAILED) { if (map == MAP_FAILED) {
LD_LOGE("Error mapping library %{public}s: failed to map fd", task->name); LD_LOGE("Error mapping library %{public}s: failed to map fd", task->name);
goto error; goto error;
} }
if (reserved_params && map_len < reserved_params->reserved_size) { if (reserved_params && map_len < reserved_params->reserved_size) {
reserved_params->reserved_size -= (map_len + (start_addr - (size_t)reserved_params->start_addr)); reserved_params->reserved_size -= (map_len + (start_addr - (size_t)reserved_params->start_addr));
reserved_params->start_addr = (void *)((uint8_t *)map + map_len); reserved_params->start_addr = (void *)((uint8_t *)map + map_len);
}
/* if reserved_params does not exist, we should use real_map as prefered result to do the mmap operation */
} else {
/* use tmp_map_len to mmap enough space for the dso with anonymous mapping */
unsigned char *temp_map = mmap((void *)NULL, tmp_map_len, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (temp_map == MAP_FAILED) {
LD_LOGE("Error mapping library 1 %{public}s: failed to map fd", task->name);
goto error;
}
/* find the LIBRARY_ALIGNMENT aligned address */
unsigned char *real_map = (unsigned char*)ALIGN((uintptr_t)temp_map, LIBRARY_ALIGNMENT);
/* mummap the space we mmap before so that we can mmap correct space again */
munmap(temp_map, tmp_map_len);
map = DL_NOMMU_SUPPORT
? mmap(real_map, map_len, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)
/* use map_len to mmap correct space for the dso with file mapping */
: mmap(real_map, map_len, prot, map_flags, task->fd, off_start + task->file_offset);
if (map == MAP_FAILED) {
LD_LOGE("Error mapping library 3 %{public}s: failed to map fd", task->name);
goto error;
}
} }
task->p->map = map; task->p->map = map;
task->p->map_len = map_len; task->p->map_len = map_len;
......
...@@ -6,6 +6,11 @@ ...@@ -6,6 +6,11 @@
#include <stdint.h> #include <stdint.h>
#include <stddef.h> #include <stddef.h>
#include <stdarg.h> #include <stdarg.h>
#include <link.h>
#include <sys/types.h>
#include <stdlib.h>
#include "libc.h"
#include "../../ldso/namespace.h"
#if UINTPTR_MAX == 0xffffffff #if UINTPTR_MAX == 0xffffffff
typedef Elf32_Ehdr Ehdr; typedef Elf32_Ehdr Ehdr;
...@@ -53,6 +58,100 @@ enum { ...@@ -53,6 +58,100 @@ enum {
REL_FUNCDESC_VAL, REL_FUNCDESC_VAL,
}; };
struct dso {
#if DL_FDPIC
struct fdpic_loadmap *loadmap;
#else
unsigned char *base;
#endif
char *name;
size_t *dynv;
struct dso *next, *prev;
/* add namespace */
ns_t *namespace;
/* mark the dso status */
unsigned int flags;
int cache_sym_index;
struct dso *cache_dso;
Sym *cache_sym;
Phdr *phdr;
int phnum;
size_t phentsize;
Sym *syms;
Elf_Symndx *hashtab;
uint32_t *ghashtab;
int16_t *versym;
Verdef *verdef;
Verneed *verneed;
char *strings;
struct dso *syms_next, *lazy_next;
size_t *lazy, lazy_cnt;
unsigned char *map;
size_t map_len;
dev_t dev;
ino_t ino;
uint64_t file_offset;
char relocated;
char constructed;
char kernel_mapped;
char mark;
char bfs_built;
char runtime_loaded;
char by_dlopen;
struct dso **deps, *needed_by;
size_t ndeps_direct;
size_t next_dep;
int ctor_visitor;
int nr_dlopen;
char *rpath_orig, *rpath;
struct tls_module tls;
size_t tls_id;
size_t relro_start, relro_end;
uintptr_t *new_dtv;
unsigned char *new_tls;
struct td_index *td_index;
struct dso *fini_next;
char *shortname;
#if DL_FDPIC
unsigned char *base;
#else
struct fdpic_loadmap *loadmap;
#endif
struct funcdesc {
void *addr;
size_t *got;
} *funcdescs;
size_t *got;
struct dso **parents;
size_t parents_count;
size_t parents_capacity;
bool is_global;
bool is_reloc_head_so_dep;
struct dso **reloc_can_search_dso_list;
size_t reloc_can_search_dso_count;
size_t reloc_can_search_dso_capacity;
char buf[];
};
struct symdef {
Sym *sym;
struct dso *dso;
};
struct verinfo {
const char *s;
const char *v;
bool use_vna_hash;
uint32_t vna_hash;
};
struct td_index {
size_t args[2];
struct td_index *next;
};
struct fdpic_loadseg { struct fdpic_loadseg {
uintptr_t addr, p_vaddr, p_memsz; uintptr_t addr, p_vaddr, p_memsz;
}; };
...@@ -118,6 +217,13 @@ struct fdpic_dummy_loadmap { ...@@ -118,6 +217,13 @@ struct fdpic_dummy_loadmap {
typedef void (*stage2_func)(unsigned char *, size_t *); typedef void (*stage2_func)(unsigned char *, size_t *);
#if DL_FDPIC
void *laddr(const struct dso *p, size_t v);
#endif
void *addr2dso(size_t a);
struct symdef find_sym2(struct dso *dso, struct verinfo *verinfo, int need_def, int use_deps, ns_t *ns);
hidden void *__dlsym(void *restrict, const char *restrict, void *restrict); hidden void *__dlsym(void *restrict, const char *restrict, void *restrict);
hidden void *__dlvsym(void *restrict, const char *restrict, const char *restrict, void *restrict); hidden void *__dlvsym(void *restrict, const char *restrict, const char *restrict, void *restrict);
hidden int __dlclose(void *p); hidden int __dlclose(void *p);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册