提交 fcfe2e92 编写于 作者: Y yangwenjun

Revert "!284 回退dlopen_ns修改"

This reverts commit fd8c6da6, reversing
changes made to acdab8e8.
Signed-off-by: Nyangwenjun <yangwenjun13@huawei.com>
上级 13539067
......@@ -16,6 +16,8 @@ group("functional_test") {
}
}
test_sharedlib("dlopen_ns_dso") {
}
test_sharedlib("dlopen_dso") {
}
test_sharedlib("dlclose_reset_dso") {
......@@ -31,6 +33,7 @@ group("dso_shared") {
deps = [
":dlclose_reset_dso",
":dlopen_dso",
":dlopen_ns_dso",
":tls_align_dso",
":tls_init_dso",
]
......
#include <dlfcn.h>
#include <stdio.h>
#include <string.h>
#include "test.h"
typedef void(* FUNC)(); // 定义函数指针类型的别名
const char* dllName = "libdlopen_ns_dso.so";
const char* dllName2 = "libdlopen_dso.so";
const char* errPath_ns = "src/common";
// 测试通过so路径打开. 命名空间非严格隔离时,通过路径总是可加载.
void test_open_by_path(const char* dllPath)
{
void* handle = dlopen(dllPath, RTLD_LAZY);
if(!handle)
t_error("dlopen_by_path handle get error %s open failed: %s\n", dllName, dlerror());
if(dlclose(handle))
t_error("dlclose_by_path handle %s close failed : %s \n", dllName, dlerror());
}
//有配置文件时,通过短名称打开
void test_open_by_ini_name()
{
Dl_namespace dlns;
dlns_init(&dlns, "ns1");
void* handle = dlopen_ns(&dlns, dllName, RTLD_LAZY);
if(!dlns_create(&dlns, errPath_ns))
t_error("dlns_create_by_ini_name should failed but succeed \n");
if(!handle)
t_error("dlopen_ns_by_ini_name handle get error %s open failed: %s\n", dllName, dlerror());
if(dlclose(handle))
t_error("dlclose_by_ini_name handle %s close failed : %s \n", dllName, dlerror());
}
//有配置文件时,测试通过api设置的namespace加载
void test_open_by_ini_api()
{
Dl_namespace dlns1, dlns2;
dlns_init(&dlns1, "dlns_test");
dlns_init(&dlns2, "ns1");
dlns_create(&dlns1, NULL);
dlns_inherit(&dlns1, &dlns2 , dllName);
void* handle = dlopen_ns(&dlns1, dllName, RTLD_LAZY);
if(!handle)
t_error("dlopen_ns_by_ini_api handle get error %s open failed: %s\n", dllName, dlerror());
if(dlclose(handle))
t_error("dlclose_by_ini_api handle %s close failed : %s \n", dllName, dlerror());
}
//不同命名空间打开相同so
void test_open_by_sameso_in_diff_ns(char * dllPath_ns)
{
Dl_namespace dlns1, dlns2;
dlns_init(&dlns1, "dlns_test1");
dlns_init(&dlns2, "dlns_test2");
dlns_create(&dlns1, dllPath_ns);
dlns_create(&dlns2, dllPath_ns);
void* handle1 = dlopen_ns(&dlns1, dllName, RTLD_LAZY);
if(!handle1)
t_error("dlopen_ns_by_sameso_diff_ns handle1 get error %s open failed : %s \n", dllName, dlerror());
void* handle2 = dlopen_ns(&dlns2, dllName, RTLD_LAZY);
if(!handle2)
t_error("dlopen_ns_by_sameso_diff_ns handle2 get error %s open failed : %s \n", dllName, dlerror());
if(dlclose(handle1))
t_error("dlclose_by_sameso_diff_ns handle1 %s close failed : %s \n", dllName, dlerror());
if(dlclose(handle2))
t_error("dlclose_by_sameso_diff_ns handle2 %s close failed : %s \n", dllName, dlerror());
}
// 有配置文件时,测试在同一namespace多次加载相同动态库
void test_open_by_ini_mtso_ns()
{
Dl_namespace dlns;
dlns_init(&dlns, "ns1");
void* handle1 = dlopen_ns(&dlns, dllName, RTLD_LAZY);
if(!handle1)
t_error("dlopen_ns_by_ini_mtso_ns handle1 get error %s open failed : %s \n" , dllName, dlerror());
void* handle2 = dlopen_ns(&dlns, dllName, RTLD_LAZY);
if(!handle2)
t_error("dlopen_ns_by_ini_mtso_ns handle2 get error %s open failed : %s \n" , dllName, dlerror());
if(dlclose(handle1) )
t_error("dlclose_by_ini_mtso_ns handle1 %s close failed : %s \n" , dllName, dlerror());
if(dlclose(handle2) )
t_error("dlclose_by_ini_mtso_ns handle2 %s close failed : %s \n" , dllName, dlerror());
}
//测试配置文件,隔离性严格隔离 两个有allowed_libs(其中一个不在env lib permitt 路径中),一个没有allowed_libs
void test_open_ini_separated(char* dllPath)
{
Dl_namespace dlns2, dlns3, dlns4;
// ns2 , ns3 , ns4 为严格隔离情况
// ns2 的 so 在 lib_path 下,设置了 allowed_path
// ns3 的 lib_path 设置的错误路径,无 allowed_path.
// ns4 的 在allowed_lib 下给的是错误的so
dlns_init(&dlns2, "ns2");
dlns_init(&dlns3, "ns3");
dlns_init(&dlns4, "ns4");
void* handle_ns2 = dlopen_ns(&dlns2, dllPath, RTLD_LAZY);
if(!handle_ns2)
t_error("dlopen_ns_by_ini_separated handle_ns2 get error %s open failed : %s \n", dllName, dlerror());
void* handle_ns3 = dlopen_ns(&dlns3, dllPath, RTLD_LAZY);
if(handle_ns3){
t_error("dlopen_ns_by_ini_separated handle_ns3 %s should not open successfully \n", dllName);
dlclose(handle_ns3);
}
if(dlclose(handle_ns2))
t_error("dlclose_by_inherit_transitivity handle_ns2 %s close failed : %s\n", dllName, dlerror());
void* handle_ns4 = dlopen_ns(&dlns4, dllPath, RTLD_LAZY);
if(handle_ns4){
t_error("dlopen_ns_by_ini_separated handle_ns4 %s should not open successfully \n", dllName);
dlclose(handle_ns4);
}
}
//测试配置文件,非严格隔离情况, 传入短名称
void test_open_ini_by_falseseparated(char * dllPath_ns)
{
Dl_namespace dlns5, dlns6;
//API 创建 ns5,ns6 为非严格隔离情况
dlns_init(&dlns5, "ns5");
dlns_init(&dlns6, "ns6");
dlns_create(&dlns5, dllPath_ns);
// ns6 传入lib_path 是错误路径,故打不开so
dlns_create(&dlns6, errPath_ns);
//根据短名称打开
void* handle_ns5 = dlopen_ns(&dlns5, dllName, RTLD_LAZY);
if(!handle_ns5)
t_error("dlopen_ns_by_ini_by_falseseparated handle_ns5 get error %s open failed : %s \n", dllName, dlerror());
void* handle_ns6 = dlopen_ns(&dlns6, dllName, RTLD_LAZY);
if(handle_ns6){
t_error("dlopen_ns_by_ini_separated handle_ns6 %s should not open successfully \n", dllName);
dlclose(handle_ns6);
}
if(dlclose(handle_ns5))
t_error("dlclose_by_ini_by_falseseparated handle_ns5 %s close failed : %s\n", dllName, dlerror());
}
//检查继承是否具有传递性
void test_open_by_inherit_transitivity(char* dllPath_ns)
{
Dl_namespace transitivity_A, transitivity_B, transitivity_C;
dlns_init(&transitivity_A, "transitivity_A");
dlns_init(&transitivity_B, "transitivity_B");
dlns_init(&transitivity_C, "transitivity_C");
dlns_create(&transitivity_A, NULL);
dlns_create(&transitivity_B, NULL);
dlns_create(&transitivity_C, dllPath_ns);
dlns_inherit(&transitivity_A, &transitivity_B, NULL);
dlns_inherit(&transitivity_B, &transitivity_C, dllName);
//如果A能打开,证明有传递性
void* handleA = dlopen_ns(&transitivity_A, dllName, RTLD_LAZY);
if(handleA){
t_error("dlopen_ns_by_inherit_transitivity handleA %s should not open successfully \n", dllName);
dlclose(handleA);
}
void* handleB = dlopen_ns(&transitivity_B, dllName, RTLD_LAZY);
if(!handleB)
t_error("dlopen_ns_by_inherit_transitivity handleB get error %s open failed : %s \n", dllName, dlerror());
void* handleC = dlopen_ns(&transitivity_C, dllName, RTLD_LAZY);
if(!handleC)
t_error("dlopen_ns_by_inherit_transitivity handleC get error %s open failed : %s \n", dllName, dlerror());
if(dlclose(handleC))
t_error("dlclose_by_inherit_transitivity handleC %s close failed : %s\n", dllName, dlerror());
if(dlclose(handleB))
t_error("dlclose_by_inherit_transitivity handleB %s close failed : %s\n", dllName, dlerror());
}
//在配置文件中A没有继承关系,A无法打开的库,通过调用继承接口去B(已加载该库)中尝试加载该库
void test_open_by_ini_no_inherit(char* dllPath_ns)
{
Dl_namespace no_inherit_A, no_inherit_B;
dlns_init(&no_inherit_A, "no_inherit_A"); //配置文件中A没有所继承的ns
dlns_init(&no_inherit_B, "no_inherit_B"); //用于接口中实现与A的继承关系所对应的ns
dlns_create(&no_inherit_A, NULL);
dlns_create(&no_inherit_B, dllPath_ns);
void* handle = dlopen_ns(&no_inherit_A, dllName, RTLD_LAZY); //libdlopenns_dso.so在A中无法找到
if(handle){
t_error("dlopen_ns_by_ini_no_inherit handle %s should not open successfully \n", dllName);
dlclose(handle);
}
void* handle2 = dlopen_ns(&no_inherit_B, dllName, RTLD_LAZY);
if(!handle2)
t_error("dlopen_ns_by_ini_no_inherit handle2 get error %s open failed : %s \n", dllName, dlerror());
dlns_inherit(&no_inherit_A, &no_inherit_B, dllName);
void* handle3 = dlopen_ns(&no_inherit_A, dllName, RTLD_LAZY); //通过B的继承关系再次加载库
if(!handle3)
t_error("dlopen_ns_by_ini_no_inherit handle3 get error %s open failed : %s \n", dllName, dlerror());
if(dlclose(handle3))
t_error("dlclose_by_ini_no_inherit handle3 %s close failed : %s\n", dllName, dlerror());
if(dlclose(handle2))
t_error("dlclose_by_ini_no_inherit handle2 %s close failed : %s\n", dllName, dlerror());
}
//dlns_inherit是否正常工作
void test_open_by_dlns_inherir(char* dllPath_ns)
{
Dl_namespace inherir_A, inherir_B;
dlns_init(&inherir_A, "inherir_A");
dlns_init(&inherir_B, "inherir_B");
dlns_create(&inherir_A, NULL);
dlns_create(&inherir_B, dllPath_ns);
dlns_inherit(&inherir_A, &inherir_B, NULL); //B共享所有库,有A要加载的库
void* handle = dlopen_ns(&inherir_A, dllName, RTLD_LAZY);
if(!handle)
t_error("dlopen_ns_by_dlns_inherir handle get error %s open failed : %s \n", dllName, dlerror());
if(dlclose(handle))
t_error("dlclose_by_dlns_inherir handle %s close failed : %s\n", dllName, dlerror());
dlns_inherit(&inherir_A, &inherir_B, dllName2); //B共享指定库,不是A要加载的库,覆盖原有继承关系
void* handle2 = dlopen_ns(&inherir_A, dllName, RTLD_LAZY);
if(handle2){
t_error("dlopen_ns_by_ini_no_inherit handle2 %s should not open successfully \n", dllName);
dlclose(handle2);
}
}
//A通过B、C共享项获取加载的库
void test_open_by_shared_libs(char* dllPath_ns)
{
Dl_namespace shared_libs_A, shared_libs_B, shared_libs_C;
dlns_init(&shared_libs_A, "shared_libs_A");
dlns_init(&shared_libs_B, "shared_libs_B");
dlns_init(&shared_libs_C, "shared_libs_C");
dlns_create(&shared_libs_A, NULL);
dlns_create(&shared_libs_B, errPath_ns);
dlns_create(&shared_libs_C, dllPath_ns);
dlns_inherit(&shared_libs_A, &shared_libs_B, NULL); //B共享所有库,但无A要加载的库
void* handle = dlopen_ns(&shared_libs_A, dllName, RTLD_LAZY);
if(handle){
t_error("dlopen_ns_by_shared_libs handle %s should not open successfully \n", dllName);
dlclose(handle);
}
void* handle2 = dlopen_ns(&shared_libs_B, dllName, RTLD_LAZY);
if(handle2){
t_error("dlopen_ns_by_shared_libs handle2 %s should not open successfully \n", dllName);
dlclose(handle2);
}
dlns_inherit(&shared_libs_A, &shared_libs_C, "libdlopen_dso.so:libdlopen_ns_dso.so"); //C共享固定库中包含A要加载的库
void* handle3 = dlopen_ns(&shared_libs_C, dllName, RTLD_LAZY);
if(!handle3)
t_error("dlopen_ns_by_shared_libs handle3 get error %s open failed : %s \n", dllName, dlerror());
void* handle4 = dlopen_ns(&shared_libs_A, dllName, RTLD_LAZY);
if(!handle4)
t_error("dlopen_ns_by_shared_libs handle4 get error %s open failed : %s \n", dllName, dlerror());
if(dlclose(handle4))
t_error("dlclose_by_shared_libs handle4 %s close failed : %s\n", dllName, dlerror());
if(dlclose(handle3))
t_error("dlclose_by_shared_libs handle3 %s close failed : %s\n", dllName, dlerror());
}
//add ini inherit test
void test_open_by_iinheritB_shared_libs(char* dllPath_ns)
{
Dl_namespace inherit_B;
dlns_init(&inherit_B, "inherit_B"); //配置文件中B继承自ns2
void* handle = dlopen_ns(&inherit_B, dllName, RTLD_LAZY); //inherit_b将从ns2中获取dllName库
if(!handle){
t_error("dlopen_ns_by_iinheritB_shared_libs handle get error %s open failed : %s \n", dllName, dlerror());
}
if(dlclose(handle))
t_error("dlopen_ns_by_iinheritB_shared_libs handle %s close failed : %s\n", dllName, dlerror());
}
int main(int argc, char *argv[])
{
char buf[512],path[512];
char* i;
//带so的路径
if (!t_pathrel(buf, sizeof buf, argv[0], "libdlopen_ns_dso.so")) {
t_error("failed to obtain relative path to libdlopen_ns_dso.so\n");
return 1;
}
//包含so的路径
if (!t_pathrel(path, sizeof path, argv[0], "")) {
t_error("failed to obtain relative path to path\n");
return 1;
}
path[strlen (path) -1 ] ='\0';
test_open_by_path(buf);
test_open_by_ini_name();
test_open_by_ini_api();
test_open_ini_separated(buf);
test_open_ini_by_falseseparated(path);
test_open_by_dlns_inherir(path);
test_open_by_ini_no_inherit(path);
test_open_by_shared_libs(path);
test_open_by_sameso_in_diff_ns(path);
test_open_by_ini_mtso_ns();
test_open_by_inherit_transitivity(path);
test_open_by_iinheritB_shared_libs(path);
return t_status;
}
\ No newline at end of file
#include <stdio.h>
void sayhello()
{
printf ("hello world!\n");
}
\ No newline at end of file
......@@ -6,6 +6,7 @@ functional_list = [
"crypt",
"dirname",
"dlopen",
"dlopen_ns",
"env",
"fcntl",
"fdopen",
......
......@@ -96,6 +96,11 @@ template("test_unittest") {
#libs += [ "//${root_out_dir}/${test_lib_dir}/libdlopen_dso.so" ]
}
if (target_name == "dlopen_ns") {
ldflags += [ "-rdynamic" ]
#libs += [ "//${root_out_dir}/${test_lib_dir}/libdlopen_ns_dso.so" ]
}
if (target_name == "dlclose_reset") {
ldflags += [ "-rdynamic" ]
#libs += [ "//${root_out_dir}/${test_lib_dir}/libdlclose_reset_dso.so" ]
......
......@@ -1541,6 +1541,9 @@ if (musl_arch == "arm") {
musl_src_ldso = [
"ldso/dlstart.c",
"ldso/dynlink.c",
"ldso/namespace.c",
"ldso/ns_config.c",
"ldso/strops.c",
]
if (musl_arch == "arm") {
......@@ -1837,6 +1840,9 @@ musl_src_porting_file = [
"src/env/__init_tls.c",
"src/internal/pthread_impl.h",
"src/internal/syscall.h",
"ldso/namespace.h",
"ldso/ns_config.h",
"ldso/strops.h",
"src/legacy/ulimit.c",
"src/linux/gettid.c",
"src/malloc/malloc.c",
......@@ -1854,6 +1860,9 @@ musl_src_porting_file = [
"src/exit/atexit.c",
"crt/arm/crti.s",
"crt/aarch64/crti.s",
"ldso/namespace.c",
"ldso/ns_config.c",
"ldso/strops.c",
]
musl_inc_hook_files = [
......
......@@ -25,13 +25,16 @@ void *dlopen(const char *, int);
void *dlsym(void *__restrict, const char *__restrict);
/* namespace apis */
typedef const char* Dl_namespace;
#define NS_NAME_MAX 255
typedef struct {
char name[NS_NAME_MAX+1];
} Dl_namespace;
void dlns_init(Dl_namespace *, const char *);
/* open dso in given namespace which has own lib search paths
* when namespace is null, it's same to dlopen()
* void to use "default" as namespace, which is the default namespace*/
* avoid using "default" as namespace, which is the default namespace */
void *dlopen_ns(Dl_namespace *, const char *, int);
/* create the namespace and set lib search paths of namespace,
......@@ -39,6 +42,13 @@ void *dlopen_ns(Dl_namespace *, const char *, int);
* return error */
int dlns_create(Dl_namespace *, const char *);
/* make one namespace inherit another, and so it can use shared libs by the inherited one.
* param1: namespace, param2: inherited namespace, param3: shared libs.
* the shared libs should be splited by ':'. when it is null or empty, all libs can be shared.
* one namespace can inherit or be inherited by multiple ones.
* When namespaces do not exist, return error */
int dlns_inherit(Dl_namespace *, Dl_namespace *, const char *);
#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
typedef struct {
const char *dli_fname;
......
## Dynamic Linker Namespace
The dynamic linker provides the namespace mechanism which is based on configures and apis.
Shared libraries can be isolated in different namespaces so that libraries with same library name but with different symbols won't conflict. On the other hand, the namespace mechanism provides the flexibility so that some shared libraries can be exported by a linker namespace and used by another linker namespace.
### How does it work
There are two ways to use the linker namespace:
1. Modify and save the namespace configure file </etc/ld-musl-namespace.ini>. When it does not exist or is filled in, a default namespace will be created.
2. Use the apis of namespace in head file <dlfcn.h>, to create a namespace, to set search paths of library, or to use exported libraries of another namespace by inheriting it.
### Usage example
Test usages show some examples of using the linker namespace. The file <ld-musl-namespace.ini> in current directory is configures for test. The file <libc-test/src/functional/dlopen_ns.c> gives usages of how apis and configures work.
......@@ -24,6 +24,9 @@
#include "libc.h"
#include "dynlink.h"
#include "malloc_impl.h"
/* add namespace function */
#include "namespace.h"
#include "ns_config.h"
static void error(const char *, ...);
......@@ -56,7 +59,8 @@ struct dso {
char *name;
size_t *dynv;
struct dso *next, *prev;
/* add namespace */
ns_t *namespace;
/* mark the dso status */
unsigned int flags;
......@@ -160,6 +164,115 @@ extern hidden void (*const __init_array_end)(void), (*const __fini_array_end)(vo
weak_alias(__init_array_start, __init_array_end);
weak_alias(__fini_array_start, __fini_array_end);
/* add namespace function */
static void *addr2dso(size_t a);
static void get_sys_path();
static void dlclose_ns(struct dso *p);
static bool get_app_path(char *path, size_t size)
{
int l = 0;
l = readlink("/proc/self/exe", path, size);
if (l < 0 || l >= size) {
return false;
}
path[l] = 0;
return true;
}
static void init_default_namespace(struct dso *app)
{
ns_t *default_ns = get_default_ns();
memset(default_ns, 0, sizeof *default_ns);
ns_set_name(default_ns, NS_DEFAULT_NAME);
if (env_path) ns_set_env_paths(default_ns, env_path);
if (!sys_path) get_sys_path();
ns_set_lib_paths(default_ns, sys_path);
ns_set_separated(default_ns, false);
app->namespace = default_ns;
ns_add_dso(default_ns, app);
return;
}
static void set_ns_attrs(ns_t *ns, ns_configor *conf)
{
char *lib_paths, *permitted_paths, *allowed_libs;
ns_set_separated(ns, conf->get_separated(ns->ns_name));
lib_paths = conf->get_lib_paths(ns->ns_name);
if (lib_paths) ns_set_lib_paths(ns, lib_paths);
permitted_paths = conf->get_permitted_paths(ns->ns_name);
if (permitted_paths) ns_set_permitted_paths(ns, permitted_paths);
allowed_libs = conf->get_allowed_libs(ns->ns_name);
if (allowed_libs) ns_set_allowed_libs(ns, allowed_libs);
}
static void set_ns_inherits(ns_t *ns, ns_configor *conf)
{
strlist *inherits = conf->get_inherits(ns->ns_name);
if (inherits) {
for (size_t i=0; i<inherits->num; i++) {
ns_t *inherited_ns = find_ns_by_name(inherits->strs[i]);
if (inherited_ns) {
char *shared_libs = conf->get_inherit_shared_libs(ns->ns_name, inherited_ns->ns_name);
ns_add_inherit(ns, inherited_ns, shared_libs);
}
}
strlist_free(inherits);
}
}
static void init_namespace(struct dso *app)
{
char app_path[PATH_MAX+1];
if (!get_app_path(app_path, sizeof app_path)) {
strcpy(app_path, app->name);
}
char *t = strrchr(app_path, '/');
if (t) {
*t = 0;
} else {
app_path[0] = '.';
app_path[1] = 0;
}
init_default_namespace(app);
ns_configor *conf = configor_init();
int ret = conf->parse(NULL, app_path);
if (ret < 0) {
configor_free();
return;
}
/* Init default namespace */
ns_t *d_ns = get_default_ns();
set_ns_attrs(d_ns, conf);
/* Init other namespace */
nslist *nsl = nslist_init();
if (!nsl) {
configor_free();
return;
}
strlist *s_ns = conf->get_namespaces();
if (s_ns) {
for (size_t i=0; i<s_ns->num; i++) {
ns_t *ns = ns_alloc();
ns_set_name(ns, s_ns->strs[i]);
set_ns_attrs(ns, conf);
ns_add_dso(ns, app);
nslist_add_ns(ns);
}
strlist_free(s_ns);
}
/* Set inherited namespace */
set_ns_inherits(d_ns, conf);
for (size_t i=0; i<nsl->num; i++) {
set_ns_inherits(nsl->nss[i], conf);
}
configor_free();
return;
}
static int dl_strcmp(const char *l, const char *r)
{
for (; *l==*r && *l; l++, r++);
......@@ -977,9 +1090,94 @@ static void makefuncdescs(struct dso *p)
}
}
static struct dso *load_library(const char *name, struct dso *needed_by)
static void get_sys_path()
{
char *prefix = 0;
size_t prefix_len;
char *filename = ldso.name;
if (ldso.name[0] == '/') {
char *s, *t, *z;
for (s=t=z=ldso.name; *s; s++)
if (*s=='/') z=t, t=s;
prefix_len = z-ldso.name;
filename = t+1;
if (prefix_len < PATH_MAX)
prefix = ldso.name;
}
if (!prefix) {
prefix = "";
prefix_len = 0;
}
size_t name_len = strchrnul(filename, '.') - filename;
char etc_ldso_path[prefix_len + 1
+ sizeof "/etc/.path" + name_len];
snprintf(etc_ldso_path, sizeof etc_ldso_path,
"%.*s/etc/%.*s.path",
(int)prefix_len, prefix, (int)name_len, filename);
FILE *f = fopen(etc_ldso_path, "rbe");
if (f) {
if (getdelim(&sys_path, (size_t[1]){0}, 0, f) <= 0) {
free(sys_path);
sys_path = "";
}
fclose(f);
} else if (errno != ENOENT) {
sys_path = "";
}
if (!sys_path) sys_path = "/lib:/usr/local/lib:/usr/lib:/lib64";
}
static struct dso *search_dso_by_name(const char *name, const ns_t *ns) {
for (size_t i = 0; i < ns->ns_dsos->num; i++){
struct dso *p = ns->ns_dsos->dsos[i];
if (p->shortname && !strcmp(p->shortname, name)) {
return p;
}
}
return NULL;
}
static struct dso *search_dso_by_fstat(const struct stat *st, const ns_t *ns) {
for (size_t i = 0; i < ns->ns_dsos->num; i++){
struct dso *p = ns->ns_dsos->dsos[i];
if (p->dev == st->st_dev && p->ino == st->st_ino) {
return p;
}
}
return NULL;
}
/* Find loaded so by name */
static struct dso *find_library_by_name(const char *name, const ns_t *ns, bool check_inherited)
{
struct dso *p = search_dso_by_name(name, ns);
if (p) return p;
if (check_inherited && ns->ns_inherits) {
for (size_t i = 0; i < ns->ns_inherits->num; i++){
ns_inherit * inherit = ns->ns_inherits->inherits[i];
p = search_dso_by_name(name, inherit->inherited_ns);
if (p && is_sharable(inherit, name)) return p;
}
}
return NULL;
}
/* Find loaded so by file stat */
static struct dso *find_library_by_fstat(const struct stat *st, const ns_t *ns, bool check_inherited) {
struct dso *p = search_dso_by_fstat(st, ns);
if (p) return p;
if (check_inherited && ns->ns_inherits) {
for (size_t i = 0; i < ns->ns_inherits->num; i++){
ns_inherit *inherit = ns->ns_inherits->inherits[i];
p = search_dso_by_fstat(st, inherit->inherited_ns);
if (p && is_sharable(inherit, p->shortname)) return p;
}
}
return NULL;
}
/* add namespace function */
struct dso *load_library(const char *name, struct dso *needed_by, ns_t *namespace, bool check_inherited)
{
char buf[2*NAME_MAX+2];
char buf[PATH_MAX+1];
const char *pathname;
unsigned char *map;
struct dso *p, temp_dso = {0};
......@@ -1026,6 +1224,8 @@ static struct dso *load_library(const char *name, struct dso *needed_by)
tail->next = &ldso;
ldso.prev = tail;
tail = &ldso;
ldso.namespace = namespace;
ns_add_dso(namespace, &ldso);
}
/* increase libc dlopen refcnt */
a_inc(&ldso.nr_dlopen);
......@@ -1033,81 +1233,61 @@ static struct dso *load_library(const char *name, struct dso *needed_by)
}
if (strchr(name, '/')) {
pathname = name;
fd = open(name, O_RDONLY|O_CLOEXEC);
if (!is_accessible(namespace, pathname)) {
fd = -1;
} else {
fd = open(name, O_RDONLY|O_CLOEXEC);
}
} else {
/* Search for the name to see if it's already loaded */
for (p=head->next; p; p=p->next) {
if (p->shortname && !strcmp(p->shortname, name)) {
a_inc(&p->nr_dlopen);
return p;
}
/* Search in namespace */
p = find_library_by_name(name, namespace, check_inherited);
if (p) {
/* increase dlopen refcnt */
a_inc(&p->nr_dlopen);
return p;
}
if (strlen(name) > NAME_MAX) return 0;
fd = -1;
if (env_path) fd = path_open(name, env_path, buf, sizeof buf);
for (p=needed_by; fd == -1 && p; p=p->needed_by) {
if (namespace->env_paths) fd = path_open(name, namespace->env_paths, buf, sizeof buf);
for (p = needed_by; fd == -1 && p; p = p->needed_by) {
if (fixup_rpath(p, buf, sizeof buf) < 0)
fd = -2; /* Inhibit further search. */
if (p->rpath)
fd = path_open(name, p->rpath, buf, sizeof buf);
}
if (fd == -1) {
if (!sys_path) {
char *prefix = 0;
size_t prefix_len;
char *filename = ldso.name;
if (ldso.name[0]=='/') {
char *s, *t, *z;
for (s=t=z=ldso.name; *s; s++)
if (*s=='/') z=t, t=s;
prefix_len = z-ldso.name;
filename = t+1;
if (prefix_len < PATH_MAX)
prefix = ldso.name;
}
if (!prefix) {
prefix = "";
prefix_len = 0;
}
size_t name_len = strchrnul(filename, '.') - filename;
char etc_ldso_path[prefix_len + 1
+ sizeof "/etc/.path" + name_len];
snprintf(etc_ldso_path, sizeof etc_ldso_path,
"%.*s/etc/%.*s.path",
(int)prefix_len, prefix, (int)name_len, filename);
FILE *f = fopen(etc_ldso_path, "rbe");
if (f) {
if (getdelim(&sys_path, (size_t[1]){0}, 0, f) <= 0) {
free(sys_path);
sys_path = "";
}
fclose(f);
} else if (errno != ENOENT) {
sys_path = "";
}
}
if (!sys_path) sys_path = strdup("/lib:/usr/local/lib:/usr/lib:/lib64");
fd = path_open(name, sys_path, buf, sizeof buf);
if (fd == -1 && namespace->lib_paths) {
fd = path_open(name, namespace->lib_paths, buf, sizeof buf);
}
pathname = buf;
}
if (fd < 0) return 0;
if (fd < 0) {
if (!check_inherited || !namespace->ns_inherits) return 0;
/* Load lib in inherited namespace. Do not check inherited again.*/
for (size_t i = 0; i < namespace->ns_inherits->num; i++) {
ns_inherit *inherit = namespace->ns_inherits->inherits[i];
if (strchr(name, '/')==0 && !is_sharable(inherit, name)) continue;
p = load_library(name, needed_by, inherit->inherited_ns, false);
if (p) return p;
}
return 0;
}
if (fstat(fd, &st) < 0) {
close(fd);
return 0;
}
for (p=head->next; p; p=p->next) {
if (p->dev == st.st_dev && p->ino == st.st_ino) {
/* If this library was previously loaded with a
* pathname but a search found the same inode,
* setup its shortname so it can be found by name. */
if (!p->shortname && pathname != name)
p->shortname = strrchr(p->name, '/')+1;
close(fd);
/* increase dlopen refcnt */
a_inc(&p->nr_dlopen);
return p;
}
/* Search in namespace */
p = find_library_by_fstat(&st, namespace, check_inherited);
if (p) {
/* If this library was previously loaded with a
* pathname but a search found the same inode,
* setup its shortname so it can be found by name. */
if (!p->shortname && pathname != name)
p->shortname = strrchr(p->name, '/')+1;
close(fd);
/* increase dlopen refcnt */
a_inc(&p->nr_dlopen);
return p;
}
map = noload ? 0 : map_library(fd, &temp_dso);
close(fd);
......@@ -1121,7 +1301,7 @@ static struct dso *load_library(const char *name, struct dso *needed_by)
if (find_sym(&temp_dso, "__libc_start_main", 1).sym &&
find_sym(&temp_dso, "stdin", 1).sym) {
unmap_library(&temp_dso);
return load_library("libc.so", needed_by);
return load_library("libc.so", needed_by, namespace, true);
}
/* Past this point, if we haven't reached runtime yet, ldso has
* committed either to use the mapped library or to abort execution.
......@@ -1181,6 +1361,9 @@ static struct dso *load_library(const char *name, struct dso *needed_by)
p->prev = tail;
tail = p;
/* Add dso to namespace */
p->namespace = namespace;
ns_add_dso(namespace, p);
if (runtime)
p->by_dlopen = 1;
......@@ -1191,7 +1374,7 @@ static struct dso *load_library(const char *name, struct dso *needed_by)
return p;
}
static void load_direct_deps(struct dso *p)
static void load_direct_deps(struct dso *p, ns_t *namespace)
{
size_t i, cnt=0;
......@@ -1215,7 +1398,7 @@ static void load_direct_deps(struct dso *p)
p->deps[cnt++] = q;
for (i=0; p->dynv[i]; i+=2) {
if (p->dynv[i] != DT_NEEDED) continue;
struct dso *dep = load_library(p->strings + p->dynv[i+1], p);
struct dso *dep = load_library(p->strings + p->dynv[i+1], p, namespace, true);
if (!dep) {
error("Error loading shared library %s: %m (needed by %s)",
p->strings + p->dynv[i+1], p->name);
......@@ -1228,11 +1411,11 @@ static void load_direct_deps(struct dso *p)
p->ndeps_direct = cnt;
}
static void load_deps(struct dso *p)
static void load_deps(struct dso *p, ns_t *ns)
{
if (p->deps) return;
for (; p; p=p->next)
load_direct_deps(p);
load_direct_deps(p, ns);
}
static void extend_bfs_deps(struct dso *p)
......@@ -1286,7 +1469,7 @@ static void extend_bfs_deps(struct dso *p)
p->mark = 0;
}
static void load_preload(char *s)
static void load_preload(char *s, ns_t *ns)
{
int tmp;
char *z;
......@@ -1295,7 +1478,7 @@ static void load_preload(char *s)
for (z=s; *z && !isspace(*z) && *z!=':'; z++);
tmp = *z;
*z = 0;
load_library(s, 0);
load_library(s, 0, ns, true);
*z = tmp;
}
}
......@@ -1867,8 +2050,10 @@ void __dls3(size_t *sp, size_t *auxv)
/* Load preload/needed libraries, add symbols to global namespace. */
ldso.deps = (struct dso **)no_deps;
if (env_preload) load_preload(env_preload);
load_deps(&app);
/* Init all namespaces by config file. there is a default namespace always*/
init_namespace(&app);
if (env_preload) load_preload(env_preload, get_default_ns());
load_deps(&app, get_default_ns());
for (struct dso *p=head; p; p=p->next)
add_syms(p);
......@@ -1893,6 +2078,8 @@ void __dls3(size_t *sp, size_t *auxv)
vdso.prev = tail;
tail->next = &vdso;
tail = &vdso;
vdso.namespace = get_default_ns();
ns_add_dso(vdso.namespace, &vdso);
}
for (i=0; app.dynv[i]; i+=2) {
......@@ -1999,7 +2186,8 @@ static void prepare_lazy(struct dso *p)
lazy_head = p;
}
void *dlopen(const char *file, int mode)
/* add namespace function */
static void *dlopen_impl(const char *file, int mode, const char *namespace, const void *caller_addr)
{
struct dso *volatile p, *orig_tail, *orig_syms_tail, *orig_lazy_head, *next;
struct tls_module *orig_tls_tail;
......@@ -2008,12 +2196,20 @@ void *dlopen(const char *file, int mode)
int cs;
jmp_buf jb;
struct dso **volatile ctor_queue = 0;
ns_t *ns;
struct dso *caller;
if (!file) return head;
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
pthread_rwlock_wrlock(&lock);
__inhibit_ptc();
/* When namespace does not exist, use caller's namespce
* and when caller does not exist, use default namespce. */
caller = (struct dso *)addr2dso((size_t)caller_addr);
ns = find_ns_by_name(namespace);
if (!ns) ns = ((caller && caller->namespace) ? caller->namespace : get_default_ns());
p = 0;
if (shutting_down) {
......@@ -2044,6 +2240,7 @@ void *dlopen(const char *file, int mode)
if (p->rpath != p->rpath_orig)
free(p->rpath);
free(p->deps);
dlclose_ns(p);
unmap_library(p);
free(p);
}
......@@ -2060,7 +2257,7 @@ void *dlopen(const char *file, int mode)
tail->next = 0;
p = 0;
goto end;
} else p = load_library(file, head);
} else p = load_library(file, head, ns, true);
if (!p) {
error(noload ?
......@@ -2071,7 +2268,7 @@ void *dlopen(const char *file, int mode)
}
/* First load handling */
load_deps(p);
load_deps(p, ns);
extend_bfs_deps(p);
pthread_mutex_lock(&init_fini_lock);
if (!p->constructed) ctor_queue = queue_ctors(p);
......@@ -2125,6 +2322,87 @@ end:
return p;
}
void *dlopen(const char *file, int mode)
{
const void *caller_addr = __builtin_return_address(0);
return dlopen_impl(file, mode, NULL, caller_addr);
}
void dlns_init(Dl_namespace *dlns, const char *name)
{
if (!dlns) return;
if (!name) {
dlns->name[0] = 0;
return;
}
snprintf(dlns->name, sizeof dlns->name, name);
}
void *dlopen_ns(Dl_namespace *dlns, const char *file, int mode)
{
const void *caller_addr = __builtin_return_address(0);
return dlopen_impl(file, mode, dlns->name, caller_addr);
}
int dlns_create(Dl_namespace *dlns, const char *lib_path)
{
if (!dlns) return EINVAL;
ns_t *ns;
pthread_rwlock_wrlock(&lock);
ns = find_ns_by_name(dlns->name);
if (ns) {
pthread_rwlock_unlock(&lock);
return EEXIST;
}
ns = ns_alloc();
if (!ns) {
pthread_rwlock_unlock(&lock);
return ENOMEM;
}
ns_set_name(ns, dlns->name);
ns_add_dso(ns, get_default_ns()->ns_dsos->dsos[0]); /* add main app to this namespace*/
nslist_add_ns(ns); /* add ns to list*/
ns_set_lib_paths(ns, lib_path);
ns_add_inherit(ns, get_default_ns(), NULL);
pthread_rwlock_unlock(&lock);
return 0;
}
int dlns_inherit(Dl_namespace *dlns, Dl_namespace *inherited, const char *shared_libs)
{
if (!dlns || !inherited) return EINVAL;
pthread_rwlock_wrlock(&lock);
ns_t* ns = find_ns_by_name(dlns->name);
ns_t* ns_inherited = find_ns_by_name(inherited->name);
if (!ns || !ns_inherited) {
pthread_rwlock_unlock(&lock);
return ENOKEY;
}
ns_add_inherit(ns, ns_inherited, shared_libs);
pthread_rwlock_unlock(&lock);
return 0;
}
static void dlclose_ns(struct dso *p)
{
if (!p) return;
ns_t * ns = p->namespace;
if (!ns||!ns->ns_dsos) return;
for (size_t i=0; i<ns->ns_dsos->num; i++) {
if (p == ns->ns_dsos->dsos[i]) {
for (size_t j=i+1; j<ns->ns_dsos->num; j++) {
ns->ns_dsos->dsos[j-1] = ns->ns_dsos->dsos[j];
}
ns->ns_dsos->num--;
return;
}
}
}
hidden int __dl_invalid_handle(void *h)
{
struct dso *p;
......@@ -2266,6 +2544,9 @@ static int do_dlclose(struct dso *p)
p->prev->next = p->next;
}
/* remove dso from namespace */
dlclose_ns(p);
if (p->lazy != NULL)
free(p->lazy);
if (p->deps != no_deps)
......@@ -2430,46 +2711,3 @@ static void error(const char *fmt, ...)
__dl_vseterr(fmt, ap);
va_end(ap);
}
void dlns_init(Dl_namespace *ns, const char *name)
{
*ns = name;
}
void *dlopen_ns(Dl_namespace *ns, const char *file, int mode)
{
if (!ns) return NULL;
return dlopen(file, mode);
}
int dlns_create(Dl_namespace *ns,const char *search_path)
{
int sys_length = 0;
int search_length = 0;
char * new_path = NULL;
if (!search_path || !ns) return EINVAL;
sys_length = strlen(sys_path);
search_length = strlen(search_path);
if (search_path[0] != ':'){
sys_length += search_length + 1;
} else {
sys_length += search_length;
}
new_path = (char *)malloc(sys_length + 1);
if (!new_path) return ENOMEM;
strcpy(new_path, sys_path);
if (search_path[0] != ':') {
strcat(new_path, ":");
}
strcat(new_path, search_path);
free(sys_path);
sys_path = new_path;
return 0;
}
[section.dir.map]
test = /data/tests/libc-test/src/functional
system = /usr/bin:/usr/sbin
[test]
added.nslist=ns1,ns2,ns3,ns4,no_inherit_A,inherit_B
namespace.ns1.separated = true
namespace.ns1.lib.paths = src/functional
namespace.ns1.permitted.paths = /usr/bin:/usr/sbin
#separated
#ns2 和 ns3 都是严格隔离
namespace.ns2.separated = true
namespace.ns2.lib.paths = src/functional
namespace.ns2.allowed.libs = libdlopen_ns_dso.so
namespace.ns2.permitted.paths = /data/tests/libc-test/src/functional/libdlopen_ns_dso.so
#ns3 在 allowed_libs 内,但是不在 env or lib or permitted Path 中
namespace.ns3.separated = true
namespace.ns3.lib.paths = src/common
namespace.ns3.allowed.libs = libdlopen_ns_dso.so
namespace.ns3.permitted.paths = src/common/libdlopenns_dso.so
#ns4 不在 allowed_libs 内
namespace.ns4.separated = true
namespace.ns4.lib.paths = src/functional
namespace.ns4.allowed.libs = libdlopen_dso.so
namespace.ns4.permitted.paths = /data/tests/libc-test/src/functional/libdlopen_ns_dso.so
#inherit
namespace.no_inherit_A.separated = true
namespace.no_inherit_A.lib.paths = .
namespace.no_inherit_A.permitted.paths = /data/tests/libc-test/src/functional/libdlopen_ns_dso.so
namespace.inherit_B.separated = true
namespace.inherit_B.lib.paths = .
namespace.inherit_B.inherit = ns2
namespace.inherit_B.inherit.ns2.shared.libs = libdlopen_ns_dso.so
namespace.inherit_B.permitted.paths = src/common/libdlopenns_dso.so
\ No newline at end of file
#include "strops.h"
#include "namespace.h"
static ns_t g_ns_default;
static nslist g_ns_list;
#define NSLIST_DEFAULT_SIZE 16
#define DSOLIST_DEFAULT_SIZE 16
#define INHERIT_DEFAULT_SIZE 16
static ns_inherit_list *nsinherits_alloc()
{
ns_inherit_list *nsinl;
nsinl = (ns_inherit_list *)calloc(1, sizeof *nsinl) ;
if (nsinl) {
nsinl->size = INHERIT_DEFAULT_SIZE;
nsinl->inherits = (ns_inherit **)calloc(INHERIT_DEFAULT_SIZE, sizeof *nsinl->inherits);
if (!nsinl->inherits) {
free(nsinl);
nsinl = NULL;
}
}
return nsinl;
}
static void nsinherits_free(ns_inherit_list *nsinl)
{
if (!nsinl) return;
for (size_t i=0; i<nsinl->num; i++) {
strlist_free(nsinl->inherits[i]->shared_libs);
free(nsinl->inherits[i]);
}
free(nsinl->inherits);
free(nsinl);
}
static void nsinherits_realloc(ns_inherit_list *nsinl)
{
if (!nsinl) return;
size_t size = 2*nsinl->size;
if (size) {
ns_inherit **inherits;
inherits = (ns_inherit **)realloc(nsinl->inherits, size * (sizeof *nsinl->inherits));
if (!inherits) return;
nsinl->size = size;
nsinl->inherits = inherits;
}
return;
}
static dsolist *dsolist_alloc()
{
dsolist *dsol;
dsol = (dsolist *)calloc(1, sizeof *dsol) ;
if (dsol) {
dsol->size = DSOLIST_DEFAULT_SIZE ;
dsol->dsos = (struct dso**)calloc(DSOLIST_DEFAULT_SIZE, sizeof *dsol->dsos);
if (!dsol->dsos) {
free(dsol);
dsol = NULL;
}
}
return dsol ;
}
static void dsolist_realloc(dsolist *dsol)
{
if (!dsol) return;
size_t size = 2*dsol->size;
if (size) {
struct dso **ds;
ds = (struct dso **)realloc(dsol->dsos, size * (sizeof *dsol->dsos));
if (!ds) return;
dsol->size = size;
dsol->dsos = ds;
}
return;
}
ns_t *ns_alloc()
{
ns_t *nst = (ns_t *)calloc(1, sizeof *nst);
nst->ns_dsos = dsolist_alloc();
if (!nst->ns_dsos) {
free(nst);
nst = NULL;
}
return nst;
}
void ns_free(ns_t *ns)
{
if (!ns) return;
free(ns->ns_name);
free(ns->env_paths);
free(ns->lib_paths);
strlist_free(ns->permitted_paths);
strlist_free(ns->allowed_libs);
nsinherits_free(ns->ns_inherits);
free(ns);
}
void ns_add_dso(ns_t *ns, struct dso *dso)
{
if (!ns||!dso) return;
if (!ns->ns_dsos) {
ns->ns_dsos = dsolist_alloc();
}
if (!ns->ns_dsos) return;
if (ns->ns_dsos->num == ns->ns_dsos->size) {
/* if list is full, realloc size to double*/
dsolist_realloc(ns->ns_dsos);
}
if (ns->ns_dsos->num < ns->ns_dsos->size) {
/* realloc succ */
ns->ns_dsos->dsos[ns->ns_dsos->num] = dso;
ns->ns_dsos->num++;
}
return;
}
nslist *nslist_init()
{
g_ns_list.size = NSLIST_DEFAULT_SIZE;
g_ns_list.num = 0;
g_ns_list.nss = (ns_t **)calloc(NSLIST_DEFAULT_SIZE, sizeof *g_ns_list.nss);
if (!g_ns_list.nss) {
return NULL;
}
return &g_ns_list;
}
static void nslist_realloc()
{
size_t size = 2*g_ns_list.size;
if (size) {
ns_t **nss;
nss = (ns_t **)realloc(g_ns_list.nss, size * (sizeof *g_ns_list.nss));
if (!nss) return;
g_ns_list.size = size;
g_ns_list.nss = nss;
}
return;
}
void nslist_add_ns(ns_t *ns)
{
if (!ns) return;
if (g_ns_list.num == g_ns_list.size) {
/* if list is full, realloc size to double*/
nslist_realloc();
}
if (g_ns_list.num < g_ns_list.size) {
/* realloc succ */
g_ns_list.nss[g_ns_list.num] = ns;
g_ns_list.num++;
}
return;
}
ns_t *get_default_ns()
{
return &g_ns_default;
}
/* set namespace attributes*/
void ns_set_name(ns_t *ns, const char *name)
{
if (!ns || !name) return;
if (ns->ns_name) free(ns->ns_name);
ns->ns_name = strdup(name);
strtrim(ns->ns_name);
}
void ns_set_env_paths(ns_t *ns, const char *env_paths)
{
if (!ns) return;
if (ns->env_paths) free(ns->env_paths);
if (env_paths) {
ns->env_paths = strdup(env_paths);
strtrim(ns->env_paths);
} else {
ns->env_paths = NULL;
}
}
void ns_set_lib_paths(ns_t *ns, const char *lib_paths)
{
if (!ns) return;
if (ns->lib_paths) free(ns->lib_paths);
if (lib_paths) {
ns->lib_paths = strdup(lib_paths);
strtrim(ns->lib_paths);
} else {
ns->lib_paths = NULL;
}
}
void ns_set_permitted_paths(ns_t *ns,const char *permitted_paths)
{
if (!ns) return;
if (ns->permitted_paths) strlist_free(ns->permitted_paths);
ns->permitted_paths = strsplit(permitted_paths,":");
}
void ns_set_separated(ns_t *ns,bool separated)
{
if (!ns) return;
ns->separated = separated;
}
void ns_set_allowed_libs(ns_t *ns, const char *allowed_libs)
{
if (!ns) return;
if (ns->allowed_libs) strlist_free(ns->allowed_libs);
ns->allowed_libs = NULL;
if (allowed_libs) {
/* if setted and not empty, split to list. */
char *a_libs = strdup(allowed_libs);
if (strtrim(a_libs) > 0) ns->allowed_libs = strsplit(a_libs,":");
free(a_libs);
}
}
ns_t *find_ns_by_name(const char *ns_name)
{
if (!ns_name) return NULL;
if (strcmp(NS_DEFAULT_NAME, ns_name)==0) return get_default_ns();
for (size_t i=0; i< g_ns_list.num; i++) {
if (strcmp(g_ns_list.nss[i]->ns_name, ns_name)==0) {
return g_ns_list.nss[i];
}
}
return NULL;
}
static ns_inherit *find_ns_inherit(ns_t *ns, ns_t *inherited)
{
if (!ns||!inherited) return NULL;
if (ns->ns_inherits) {
for (size_t i=0; i<ns->ns_inherits->num; i++) {
if (ns->ns_inherits->inherits[i]->inherited_ns == inherited) return ns->ns_inherits->inherits[i];
}
}
return NULL;
}
void ns_add_inherit(ns_t *ns, ns_t *ns_inherited, const char *shared_libs)
{
bool need_add = false;
if (!ns||!ns_inherited) return;
ns_inherit *inherit = find_ns_inherit(ns, ns_inherited);
if (!inherit) {
inherit = calloc(1, sizeof *inherit);
if (!inherit) return;
inherit->inherited_ns = ns_inherited;
need_add = true;
}
if (inherit->shared_libs) {
strlist_free(inherit->shared_libs);
inherit->shared_libs = NULL;
}
/* if setted and not empty, split to list. */
if (shared_libs) {
char *s_libs = strdup(shared_libs);
if (strtrim(s_libs) > 0) inherit->shared_libs = strsplit(shared_libs,":");
free(s_libs);
}
if (!need_add) return;
if (!ns->ns_inherits) {
ns->ns_inherits = nsinherits_alloc();
}
if (!ns->ns_inherits) {
if (inherit->shared_libs) strlist_free(inherit->shared_libs);
free(inherit);
return;
}
if (ns->ns_inherits->num == ns->ns_inherits->size) {
/* if list is full, realloc size to double*/
nsinherits_realloc(ns->ns_inherits);
}
if (ns->ns_inherits->num < ns->ns_inherits->size) {
/* realloc succ */
ns->ns_inherits->inherits[ns->ns_inherits->num] = inherit;
ns->ns_inherits->num++;
} else {
/* realloc failed */
if (inherit->shared_libs) strlist_free(inherit->shared_libs);
free(inherit);
}
return;
}
/* check library's pathname if accessible in this namespace */
bool is_accessible(ns_t *ns,const char *lib_pathname)
{
if (!ns->separated) {
return true;
}
if (ns->allowed_libs) {
char *shortname = strrchr(lib_pathname, '/');
if (shortname) {
shortname += 1;
size_t i = 0;
for (; i<ns->allowed_libs->num; i++) {
if (strcmp(shortname, ns->allowed_libs->strs[i]) == 0) {
break;
}
}
if (i >= ns->allowed_libs->num) return false;
}
}
strlist *paths;
if (ns->env_paths && (paths = strsplit(ns->env_paths, ":"))) {
for (size_t i=0; i<paths->num; i++) {
size_t len = strlen(paths->strs[i]);
if (strncmp(lib_pathname, paths->strs[i], len) == 0 &&
lib_pathname[len] == '/' &&
!strchr(lib_pathname+len +1, '/')) {
strlist_free(paths);
return true;
}
}
strlist_free(paths);
}
if (ns->lib_paths && (paths = strsplit(ns->lib_paths, ":"))) {
for (size_t i=0; i<paths->num; i++) {
size_t len = strlen(paths->strs[i]);
if (strncmp(lib_pathname, paths->strs[i], len) == 0 &&
lib_pathname[len] == '/' &&
!strchr(lib_pathname+len +1, '/')) {
strlist_free(paths);
return true;
}
}
strlist_free(paths);
}
if (ns->permitted_paths) {
for (size_t i=0; i<ns->permitted_paths->num; i++) {
size_t len = strlen(ns->permitted_paths->strs[i]);
if (strncmp(lib_pathname, ns->permitted_paths->strs[i], len) == 0 &&
lib_pathname[len] == '/') {
return true;
}
}
}
return false;
}
bool is_sharable(ns_inherit *inherit, const char *lib_name)
{
if (inherit && lib_name && inherit->shared_libs) {
for (size_t i=0; i<inherit->shared_libs->num; i++) {
if (strcmp(inherit->shared_libs->strs[i], lib_name)==0) {
return true;
}
}
return false;
}
return true;
}
#ifndef _NAMESPACE_H
#define _NAMESPACE_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
#include "strops.h"
#define NS_DEFAULT_NAME "default"
struct dso;
/* define dso list */
typedef struct _dso_list_ {
size_t num;
size_t size;
struct dso **dsos;
} dsolist;
/* define namespace struct */
struct _ns_inherit_list_;
typedef struct _namespace_t_ {
char *ns_name; /* namespace name */
char *env_paths; /* value of LD_LIBRARY_PATH. splited by ':'. */
char *lib_paths; /* library search paths splited by ':'. */
strlist *permitted_paths; /* when separated, permitted search paths splited by ':', including sub dirs. */
bool separated; /* if separated */
strlist *allowed_libs; /* when separated, allowed library names splited by ':'. */
dsolist *ns_dsos; /* dso list in this namespace */
struct _ns_inherit_list_ *ns_inherits; /* inherit list in this namespace */
} ns_t;
/* define namespace list */
typedef struct _namespaces_list_ {
size_t num;
size_t size;
ns_t **nss;
} nslist;
/* define namespace inherit */
typedef struct _namespace_inherit_ {
ns_t *inherited_ns; /* inherited namespace */
strlist *shared_libs; /* when inherited, shared library names splited by ':'. */
} ns_inherit;
/* define namespace inherit list */
typedef struct _ns_inherit_list_ {
size_t num;
size_t size;
ns_inherit **inherits;
} ns_inherit_list;
/* init g_ns_list */
nslist *nslist_init();
/* namespace funcs */
ns_t *ns_alloc();
void ns_free(ns_t *ns);
void ns_set_name(ns_t *ns, const char *name);
void ns_set_env_paths(ns_t *ns, const char *env_paths);
void ns_set_lib_paths(ns_t *ns, const char *lib_paths);
void ns_set_permitted_paths(ns_t *ns, const char *permitted_paths);
void ns_set_separated(ns_t *ns, bool separated);
void ns_set_allowed_libs(ns_t *ns, const char *allowed_libs);
void ns_add_dso(ns_t *ns, struct dso *dso);
void nslist_add_ns(ns_t *ns);
void ns_add_inherit(ns_t *ns,ns_t *inherited, const char *shared_libs);
/* get default namespace */
ns_t *get_default_ns();
/* check if library pathname is accessible in the namespace */
bool is_accessible(ns_t *ns, const char *lib_pathname);
/* check if library is sharable in the inherited namespace */
bool is_sharable(ns_inherit *inherit, const char *lib_name);
/* find namespace by name */
ns_t *find_ns_by_name(const char *ns_name);
#ifdef __cplusplus
}
#endif
#endif
\ No newline at end of file
/*-------------------------------------------------------------------------*/
/**
@file ns_config.c
@author yangwenjun
@brief deal with ld-musl-namespace.ini file
*/
#include <ctype.h>
#include <stdarg.h>
#include "ns_config.h"
/*---------------------------- Defines -------------------------------------*/
#define MAX_LINE_SIZE (1024)
#define INI_INVALID_KEY ((char*)-1)
typedef enum _line_status_ {
LINE_UNPROCESSED,
LINE_ERROR,
LINE_EMPTY,
LINE_COMMENT,
LINE_SECTION,
LINE_VALUE
} line_status;
#define MAX_KEY_LEN 256
static char g_key[MAX_KEY_LEN+1] = {0};
static char *config_key_join(const char *join, bool start)
{
if (start) g_key[0] = 0;
size_t cnt = MAX_KEY_LEN - strlen(g_key);
return strncat(g_key, join, cnt);
}
static int default_error_callback(const char *format, ...)
{
int ret = 0;
va_list argptr;
va_start(argptr, format);
/* do not print
ret = vfprintf(stderr, format, argptr);
*/
va_end(argptr);
return ret;
}
static int (*config_error_callback)(const char *, ...) = default_error_callback;
static void config_set_error_callback(int (*errback)(const char *, ...))
{
if (errback) {
config_error_callback = errback;
} else {
config_error_callback = default_error_callback;
}
}
static line_status config_line(char *line, char *section, char *key, char *value)
{
size_t len;
char *split;
if ((len = strcspn(line, "#;")) == 0) {
/* comment line */
return LINE_COMMENT;
}
line[len] = 0;
if ((len = strtrim(line)) == 0) {
/* empty line */
return LINE_EMPTY;
}
if (line[0] == '[' && line[len-1] == ']') {
/* section name */
memcpy(section, line+1, len-2);
section[len-2] = 0;
strtrim(section);
return LINE_SECTION;
}
if (split = strchr(line, '=')) {
/* key and value */
size_t klen, vlen;
klen = split - line;
vlen = len - klen -1;
if (klen > 0) memcpy(key, line, klen);
if (vlen > 0) memcpy(value, split+1, vlen);
key[klen] = 0;
value[vlen] = 0;
strtrim(key);
strtrim(value);
return LINE_VALUE;
}
return LINE_ERROR;
}
#define SECTION_DEFAULT_SIZE 16
#define KV_DEFAULT_SIZE 64
static kvlist * kvlist_alloc(size_t size)
{
kvlist *kvs;
if (size < KV_DEFAULT_SIZE) size = KV_DEFAULT_SIZE;
kvs = (kvlist *)calloc(1, sizeof *kvs);
if (kvs) {
kvs->key = (char **)calloc(size, sizeof *kvs->key);
kvs->val = (char **)calloc(size, sizeof *kvs->val);
if (kvs->key && kvs->val) {
kvs->size = size;
} else {
free(kvs->key);
free(kvs->val);
free(kvs);
kvs = NULL;
}
}
return kvs;
}
static void kvlist_realloc(kvlist *kvs)
{
if (!kvs) return;
size_t size = 2*kvs->size;
if (size) {
char **keys, **vals;
keys = (char **)realloc(kvs->key, size * (sizeof *kvs->key));
if (!keys) return;
kvs->key = keys;
vals = (char **)realloc(kvs->val, size * (sizeof *kvs->val));
if (!vals) return;
kvs->val = vals;
kvs->size = size;
}
return;
}
static void kvlist_free(kvlist *kvs)
{
size_t i;
if (!kvs) return;
for (i=0; i<kvs->num; i++) {
free(kvs->key[i]);
free(kvs->val[i]);
}
free(kvs->key);
free(kvs->val);
free(kvs);
}
static section_list *sections_alloc(size_t size)
{
section_list *sections;
if (size < SECTION_DEFAULT_SIZE) size = SECTION_DEFAULT_SIZE;
sections = (section_list *)calloc(1, sizeof *sections);
if (sections) {
sections->names = (char**)calloc(size, sizeof *sections->names);
sections->kvs = (kvlist**)calloc(size, sizeof *sections->kvs);
if (sections->names && sections->kvs) {
sections->size = size;
} else {
free(sections->names);
free(sections->kvs);
free(sections);
sections = NULL;
}
}
return sections;
}
static void sections_realloc(section_list *sections)
{
if (!sections) return;
size_t size = 2*sections->size;
if (size) {
char **names;
kvlist **kvs;
names = (char **)realloc(sections->names, size * (sizeof *sections->names));
if (!names) return;
sections->names = names;
kvs = (kvlist **)realloc(sections->kvs, size * (sizeof *sections->kvs));
if (!kvs) return;
sections->kvs = kvs;
sections->size = size;
}
return;
}
static void sections_free(section_list *sections)
{
if (!sections) return;
for (size_t i=0; i < sections->num; i++) {
free(sections->names[i]);
kvlist_free(sections->kvs[i]);
}
free(sections->names);
free(sections->kvs);
free(sections);
}
static void kvlist_set(kvlist *kvs, const char *key, const char *val)
{
size_t i;
if (!kvs||!key||!val) return;
for (i=0; i < kvs->num; i++) {
if (!strcmp(kvs->key[i], key)) {
break;
}
}
if (i < kvs->num) {
char * v = strdup(val);
if (v) {
free(kvs->val[i]);
kvs->val[i] = v;
}
return;
}
if (kvs->num == kvs->size) {
kvlist_realloc(kvs);
}
if (kvs->num < kvs->size) {
kvs->key[kvs->num] = strdup(key);
kvs->val[kvs->num] = strdup(val);
if (kvs->key[kvs->num] && kvs->val[kvs->num]) {
kvs->num++;
} else {
free(kvs->key[kvs->num]);
free(kvs->val[kvs->num]);
}
}
return;
}
static void sections_set(section_list *sections, const char *name, const char *key, const char *val)
{
kvlist* kvs = NULL;
if (!sections||!name||!key||!val) return;
for(size_t i=0; i < sections->num; i++) {
if (!strcmp(sections->names[i], name)) {
kvs = sections->kvs[i];
break;
}
}
if (kvs) {
kvlist_set(kvs,key,val);
return;
}
if (sections->num == sections->size) {
sections_realloc(sections);
}
if (sections->num < sections->size) {
kvs = kvlist_alloc(0);
sections->names[sections->num] = strdup(name);
sections->kvs[sections->num] = kvs;
if (sections->names[sections->num] && kvs) {
sections->num++;
kvlist_set(kvs,key,val);
} else {
free(sections->names[sections->num]);
kvlist_free(kvs);
}
}
}
static section_list *config_load(const char *filepath)
{
FILE *file;
char line[MAX_LINE_SIZE+1];
char section[MAX_LINE_SIZE+1];
char key[MAX_LINE_SIZE+1];
char val[MAX_LINE_SIZE+1];
size_t len;
int lineno = 0;
section_list *sections;
if ((file = fopen(filepath, "r")) == NULL) {
config_error_callback("config: cannot open %s\n", filepath);
return NULL;
}
sections = sections_alloc(0);
if (!sections) {
fclose(file);
return NULL;
}
memset(line, 0, sizeof line);
memset(section, 0, sizeof section);
memset(key, 0, sizeof key);
memset(val, 0, sizeof val);
while (fgets(line, sizeof line, file)) {
lineno++;
len = strlen(line);
if (len == 0) continue;
if (line[len-1]!='\n' && !feof(file)) {
config_error_callback(
"config: input line too long in %s (%d)\n", filepath, lineno);
sections_free(sections);
fclose(file);
return NULL;
}
if (line[len-1] == '\n') {
line[len-1] = 0;
len--;
}
switch (config_line(line, section, key, val)) {
case LINE_EMPTY:
case LINE_COMMENT:
case LINE_SECTION:
break;
case LINE_VALUE:
sections_set(sections, section, key, val);
break;
case LINE_ERROR:
config_error_callback(
"config: syntax error in %s (%d):\n-> %s\n",
filepath,
lineno,
line);
break;
default:
break;
}
}
fclose(file);
return sections;
}
static ns_configor g_configor;
/* const define */
#define CONFIG_DEFAULT_FILE "/etc/ld-musl-namespace.ini" /* default config file pathname */
#define SECTION_DIR_MAP "section.dir.map" /* map of section and directory of app */
#define ATTR_NS_PREFIX "namespace" /* prefix of namespace attribute */
#define ATTR_NS_LIB_PATHS "lib.paths" /* library search paths */
#define ATTR_NS_PERMITTED_PATHS "permitted.paths" /* when separated, permitted dir paths of libs, including sub dirs */
#define ATTR_NS_INHERITS "inherits" /* inherited namespace */
#define ATTR_NS_SEPARATED "separated" /* if separated */
#define ATTR_ADDED_NSLIST "added.nslist" /* all namespace names except default */
#define ATTR_NS_DEFAULT "default" /* default namespace name */
#define ATTR_NS_ALLOWED_LIBS "allowed.libs" /* when separated, allowed library names */
#define ATTR_NS_INHERIT_SHARED_LIBS "shared.libs" /* when inherited, shared library names */
/* get key-value list of section */
static kvlist *config_get_kvs(const char *sname)
{
size_t i;
for (i=0; i<g_configor.sections->num; i++) {
if (!strcmp(g_configor.sections->names[i], sname)) {
return g_configor.sections->kvs[i];
}
}
return NULL;
}
/* parse config, success 0, failure <0 */
static int config_parse(const char *file_path, const char *exe_path)
{
kvlist* dirkvs;
if (!exe_path) return -1;
g_configor.exe_path = strdup(exe_path);
const char * fpath = CONFIG_DEFAULT_FILE;
if (file_path) fpath = file_path;
g_configor.file_path = strdup(fpath);
g_configor.sections = config_load(fpath);
if (!g_configor.sections) {
return -2;
}
dirkvs = config_get_kvs(SECTION_DIR_MAP);
if (!dirkvs) return -3; /* no section directory map found */
size_t i;
char * sname = NULL;
for (i=0; i<dirkvs->num; i++) {
strlist * paths = strsplit(dirkvs->val[i], ":");
if (paths) {
size_t j;
for (j=0; j<paths->num; j++) {
if (!strcmp(paths->strs[j], exe_path)) break;
}
if (j<paths->num) sname = dirkvs->key[i];
}
strlist_free(paths);
if (sname) break;
}
if (!sname) return -4;/* no section found */
if (!(g_configor.kvs = config_get_kvs(sname))) return -5;/* no section key-value list found */
return 0;
}
/* get value by key */
static char *config_get_value(const char *key)
{
if (!g_configor.kvs) return NULL;
size_t i;
for (i=0; i<g_configor.kvs->num; i++) {
if (!strcmp(g_configor.kvs->key[i], key)) return g_configor.kvs->val[i];
}
return NULL;
}
/* get namespace names except default */
static strlist *config_get_namespaces()
{
char *key = config_key_join(ATTR_ADDED_NSLIST, true);
char *val = config_get_value(key);
return strsplit(val, ",");
}
/* get library search paths */
static char *config_get_lib_paths(const char *ns_name)
{
config_key_join(ATTR_NS_PREFIX, true);
config_key_join(".", false);
config_key_join(ns_name, false);
config_key_join(".", false);
char *key = config_key_join(ATTR_NS_LIB_PATHS, false);
return config_get_value(key);
}
/* get permitted paths */
static char *config_get_permitted_paths(const char *ns_name)
{
config_key_join(ATTR_NS_PREFIX, true);
config_key_join(".", false);
config_key_join(ns_name, false);
config_key_join(".", false);
char *key = config_key_join(ATTR_NS_PERMITTED_PATHS, false);
return config_get_value(key);
}
/* get inherited namespace names */
static strlist *config_get_inherits(const char *ns_name)
{
config_key_join(ATTR_NS_PREFIX, true);
config_key_join(".", false);
config_key_join(ns_name, false);
config_key_join(".", false);
char *key = config_key_join(ATTR_NS_INHERITS, false);
char *val = config_get_value(key);
return strsplit(val, ",");
}
/* get separated */
static bool config_get_separated(const char *ns_name)
{
config_key_join(ATTR_NS_PREFIX, true);
config_key_join(".", false);
config_key_join(ns_name, false);
config_key_join(".", false);
char *key = config_key_join(ATTR_NS_SEPARATED, false);
char *val = config_get_value(key);
strlwc(val);
if (val && !strcmp("true", val)) return true;
return false; /* default false */
}
/* get allowed libs */
static char *config_get_allowed_libs(const char *ns_name)
{
config_key_join(ATTR_NS_PREFIX, true);
config_key_join(".", false);
config_key_join(ns_name, false);
config_key_join(".", false);
char *key = config_key_join(ATTR_NS_ALLOWED_LIBS, false);
return config_get_value(key);
}
/* get shared libs by inherited namespace */
static char *config_get_inherit_shared_libs(const char *ns_name, const char *inherited_ns_name)
{
config_key_join(ATTR_NS_PREFIX, true);
config_key_join(".", false);
config_key_join(ns_name, false);
config_key_join(".inherit.", false);
config_key_join(inherited_ns_name, false);
config_key_join(".", false);
char *key = config_key_join(ATTR_NS_INHERIT_SHARED_LIBS, false);
return config_get_value(key);
}
ns_configor *configor_init()
{
memset(&g_configor, 0, sizeof g_configor);
g_configor.set_error_callback = config_set_error_callback;
g_configor.parse = config_parse;
g_configor.get_namespaces = config_get_namespaces;
g_configor.get_lib_paths = config_get_lib_paths;
g_configor.get_permitted_paths = config_get_permitted_paths;
g_configor.get_separated = config_get_separated;
g_configor.get_inherits = config_get_inherits;
g_configor.get_allowed_libs = config_get_allowed_libs;
g_configor.get_inherit_shared_libs = config_get_inherit_shared_libs;
return &g_configor;
}
void configor_free()
{
if (g_configor.sections) {
sections_free(g_configor.sections);
g_configor.sections = NULL;
}
if (g_configor.file_path) {
free(g_configor.file_path);
g_configor.file_path = NULL;
}
if (g_configor.exe_path) {
free(g_configor.exe_path);
g_configor.exe_path = NULL;
}
}
\ No newline at end of file
#ifndef _NS_CONFIG_H
#define _NS_CONFIG_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include "strops.h"
/*
* The following #include is necessary on many Unixes but not Linux.
* It is not needed for Windows platforms.
* Uncomment it if needed.
*/
/* #include <unistd.h> */
typedef struct _kv_list_ {
size_t num; /** Number of entries in list */
size_t size; /** Storage size */
char **key; /** List of string keys */
char **val; /** List of string values */
} kvlist;
typedef struct _section_list_ {
size_t num;
size_t size;
char **names;
kvlist **kvs;
} section_list;
typedef struct _ns_configor_ {
char *file_path;
char *exe_path;
section_list *sections;
kvlist *kvs;
void (*set_error_callback)(int (*errback)(const char *, ...));
int (*parse)(const char *file_path, const char *exe_path);
strlist *(*get_namespaces)(void);
char *(*get_lib_paths)(const char *ns_name);
char *(*get_permitted_paths)(const char *ns_name);
bool (*get_separated)(const char *ns_name);
strlist *(*get_inherits)(const char *ns_name);
char *(*get_allowed_libs)(const char *ns_name);
char *(*get_inherit_shared_libs)(const char *ns_name, const char *inherited_ns_name);
} ns_configor;
ns_configor *configor_init();
void configor_free();
#ifdef __cplusplus
}
#endif
#endif
#include <ctype.h>
#include "strops.h"
/* string to lower */
void strlwc(char *str)
{
if (str == NULL) return;
while (*str != '\0') {
*str = (char)tolower(*str);
str++ ;
}
return;
}
/* trim head and tail spaces of string */
size_t strtrim(char *str)
{
char *last = NULL;
char *dest = str;
if (str == NULL) return 0;
last = str + strlen(str);
while (isspace((int)*str) && *str) str++;
while (last > str) {
if (!isspace((int)*(last-1))) break;
last--;
}
*last = (char)0;
memmove(dest, str, last-str+1);
return last-str;
}
/* split string to list by given string */
strlist *strsplit(const char *str, const char *split_s)
{
char *cur, *next;
if(!str) return NULL;
strlist *sl = strlist_alloc(0);
char *ss = strdup(str);
if (!sl || !ss) {
strlist_free(sl);
free(ss);
return NULL;
}
cur = ss;
while (next = strstr(cur, split_s)) {
*next = 0;
strtrim(cur);
strlist_set(sl, cur);
cur = next + strlen(split_s);
}
strtrim(cur);
strlist_set(sl, cur);
free(ss);
return sl;
}
#define STR_DEFAULT_SIZE 16
strlist *strlist_alloc(size_t size)
{
strlist *strs;
if (size < STR_DEFAULT_SIZE) size = STR_DEFAULT_SIZE ;
strs = (strlist *)calloc(1, sizeof *strs) ;
if (strs) {
strs->strs = (char **)calloc(size, sizeof *strs->strs);
if (strs->strs) {
strs->size = size;
} else {
free(strs);
strs = NULL;
}
}
return strs ;
}
static void strlist_realloc(strlist *strs)
{
if(!strs) return;
size_t size = 2*strs->size;
if (size) {
char **ss = (char **)realloc(strs->strs, size * (sizeof *strs->strs));
if (ss) {
strs->size = size;
strs->strs = ss;
}
}
return;
}
void strlist_free(strlist *strs)
{
if (!strs) return;
for (size_t i=0; i < strs->num; i++) {
free(strs->strs[i]);
}
free(strs->strs);
free(strs);
}
void strlist_set(strlist *strs,const char *str)
{
if (!strs || !str) return;
if (strs->num == strs->size) {
strlist_realloc(strs);
}
if (strs->num < strs->size) {
strs->strs[strs->num] = strdup(str);
if (strs->strs[strs->num]) strs->num++;
}
}
\ No newline at end of file
#ifndef _STR_OPS_H
#define _STR_OPS_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdlib.h>
#include <string.h>
typedef struct _str_list_ {
size_t num; /** Number of entries in list */
size_t size; /** Storage size */
char **strs; /** string list */
} strlist;
strlist *strlist_alloc(size_t size);
void strlist_free(strlist *strs);
void strlwc(char *str);
size_t strtrim(char *str);
strlist *strsplit(const char *str, const char *split_s);
void strlist_set(strlist *strs, const char *str);
#ifdef __cplusplus
}
#endif
#endif
......@@ -60,7 +60,11 @@ for /F %%i in ('dir %TESTDIR% /S /B') do (
)
)
@REM 动态库传输
hdc shell mount -o rw,remount /
hdc shell chmod 777 /etc
hdc file send %LOCAL%\third_party\musl\porting\linux\user\ldso\ld-musl-namespace.ini /etc/ld-musl-namespace.ini
hdc file send %DYNLIB%\libdlopen_dso.so %REMOTE%/functional/libdlopen_dso.so
hdc file send %DYNLIB%\libdlopen_ns_dso.so %REMOTE%/functional/libdlopen_ns_dso.so
hdc file send %DYNLIB%\libdlclose_reset_dso.so %REMOTE%/functional/libdlclose_reset_dso.so
hdc file send %DYNLIB%\libtls_align_dso.so %REMOTE%/functional/libtls_align_dso.so
hdc file send %DYNLIB%\libtls_init_dso.so %REMOTE%/functional/libtls_init_dso.so
......@@ -68,6 +72,7 @@ hdc file send %DYNLIB%\libtls_get_new-dtv_dso.so %REMOTE%/regression/libtls_get_
@REM 修改动态库权限
hdc shell chmod a+x %REMOTE%/functional/libdlopen_dso.so
hdc shell chmod a+x %REMOTE%/functional/libdlopen_ns_dso.so
hdc shell chmod a+x %REMOTE%/functional/libdlclose_reset_dso.so
hdc shell chmod a+x %REMOTE%/functional/libtls_align_dso.so
hdc shell chmod a+x %REMOTE%/functional/libtls_init_dso.so
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册