diff --git a/musl_src.gni b/musl_src.gni index 2655700647a8c1318f99296418fda31a864f4278..38a1916eeb883a0a8373448382491bcaca85b268 100644 --- a/musl_src.gni +++ b/musl_src.gni @@ -2072,6 +2072,7 @@ musl_src_porting_file = [ "src/malloc/malloc_random.c", "src/multibyte/wcsnrtombs.c", "src/network/inet_legacy.c", + "src/network/socket.c", "src/passwd/getspnam_r.c", "src/sched/sched_setparam.c", "src/sched/sched_getparam.c", diff --git a/musl_template.gni b/musl_template.gni index c7623273442dfb4056b721bbc80eb5b5dec5f0bc..be2ae2c8f3245e73ab716eaf37a11bda62fc7146 100644 --- a/musl_template.gni +++ b/musl_template.gni @@ -125,7 +125,10 @@ template("musl_libs") { ] if (!is_asan) { - cflags_auto += [ "-DHOOK_ENABLE" ] + cflags_auto += [ + "-DHOOK_ENABLE", + "-DOHOS_SOCKET_HOOK_ENABLE", + ] } cflags_auto += [ "-DRESERVE_SIGNAL_STACK" ] @@ -195,7 +198,10 @@ template("musl_libs") { ] if (!is_asan) { - defines += [ "HOOK_ENABLE" ] + defines += [ + "HOOK_ENABLE", + "OHOS_SOCKET_HOOK_ENABLE", + ] } ldflags = [ "-nostdlib" ] @@ -700,6 +706,9 @@ template("musl_libs") { "./porting/linux/user/src/hook/memory_tag.c", "./porting/linux/user/src/hook/musl_preinit.c", "./porting/linux/user/src/hook/musl_preinit_common.c", + "./porting/linux/user/src/hook/musl_socket_preinit.c", + "./porting/linux/user/src/hook/musl_socket_preinit_common.c", + "./porting/linux/user/src/hook/socket_common.c", ] deps = [ diff --git a/porting/linux/user/src/hook/musl_socket.h b/porting/linux/user/src/hook/musl_socket.h new file mode 100644 index 0000000000000000000000000000000000000000..5e5b838c08976e2bc65cf86aaf52c1db8b4938e9 --- /dev/null +++ b/porting/linux/user/src/hook/musl_socket.h @@ -0,0 +1,21 @@ +#ifndef _MUSL_SOCKET_H +#define _MUSL_SOCKET_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef OHOS_SOCKET_HOOK_ENABLE +#define MuslSocket(func) __libc_ ## func +int __libc_socket(int, int, int); +#else +#define MuslSocket(func) func +#endif + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/porting/linux/user/src/hook/musl_socket_dispatch.h b/porting/linux/user/src/hook/musl_socket_dispatch.h new file mode 100644 index 0000000000000000000000000000000000000000..5d17cc6c3c1ca6d5d9d310d3f957debca2ef10f1 --- /dev/null +++ b/porting/linux/user/src/hook/musl_socket_dispatch.h @@ -0,0 +1,26 @@ +#ifndef _MUSL_SOCKET_DISPATCH_H +#define _MUSL_SOCKET_DISPATCH_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef int (*SocketSocketType)(int, int, int); + +typedef bool (*SocketGetHookFlagType)(); +typedef bool (*SocketSetHookFlagType)(bool); + +struct SocketDispatchType +{ + SocketSocketType socket; + SocketGetHookFlagType get_hook_flag; + SocketSetHookFlagType set_hook_flag; +}; + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/porting/linux/user/src/hook/musl_socket_preinit.c b/porting/linux/user/src/hook/musl_socket_preinit.c new file mode 100644 index 0000000000000000000000000000000000000000..b0a7f1887ea31e0725a7108763e0075884f781b0 --- /dev/null +++ b/porting/linux/user/src/hook/musl_socket_preinit.c @@ -0,0 +1,137 @@ +#ifdef OHOS_SOCKET_HOOK_ENABLE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "musl_socket_preinit_common.h" + +static char *__socket_hook_shared_lib = "libfwmark_client.z.so"; +static char *__socket_hook_function_prefix = "ohos_socket_hook"; +void* shared_lib_func[LAST_FUNC]; +long long __ohos_socket_hook_shared_library; +typedef bool (*init_func_type)(const struct SocketDispatchType*, bool*, const char*); +typedef void (*finalize_func_type)(); +#define MAX_SYMBOL_SIZE 1000 + +static bool init_socket_function(void* shared_library_handler, SocketSocketType* func) +{ + char symbol[MAX_SYMBOL_SIZE]; + (void)snprintf(symbol, sizeof(symbol), "%s_%s", __socket_hook_function_prefix, "socket"); + *func = (SocketSocketType)(dlsym(shared_library_handler, symbol)); + if (*func == NULL) { + return false; + } + return true; +} + +static void clear_socket_function() +{ + memset(shared_lib_func, 0, sizeof(shared_lib_func)); +} + +static void socket_finalize() +{ + ((finalize_func_type)shared_lib_func[FINALIZE_FUNC])(); + __current_dispatch = NULL; + __socket_hook_begin_flag = false; + // Don't dlclose because hidumper crash +} + +static bool finish_install_ohos_socket_hooks(const char* options) +{ + init_func_type init_func = (init_func_type)(shared_lib_func[INITIALIZE_FUNC]); + if (!init_func(&__libc_socket_default_dispatch, NULL, options)) { + clear_socket_function(); + return false; + } + + int ret_value = atexit(socket_finalize); + return true; +} + +static bool init_socket_hook_shared_library(void* shared_library_handle) +{ + static const char* names[] = { + "initialize", + "finalize", + "get_hook_flag", + "set_hook_flag", + }; + + for (int i = 0; i < LAST_FUNC; i++) { + char symbol[MAX_SYMBOL_SIZE]; + (void)snprintf(symbol, sizeof(symbol), "%s_%s", __socket_hook_function_prefix, names[i]); + shared_lib_func[i] = dlsym(shared_library_handle, symbol); + if (shared_lib_func[i] == NULL) { + clear_socket_function(); + return false; + } + } + + if (!init_socket_function(shared_library_handle, &(__musl_libc_socket_dispatch.socket))) { + clear_socket_function(); + return false; + } + + return true; +} + +static void* load_socket_hook_shared_library() +{ + void* shared_library_handle = NULL; + + shared_library_handle = dlopen(__socket_hook_shared_lib, RTLD_NOW | RTLD_LOCAL); + + if (shared_library_handle == NULL) { + return NULL; + } + + if (!init_socket_hook_shared_library(shared_library_handle)) { + dlclose(shared_library_handle); + shared_library_handle = NULL; + } + return shared_library_handle; +} + +static void install_ohos_socket_hook() +{ + void* shared_library_handle = (void *)__ohos_socket_hook_shared_library; + if (shared_library_handle != NULL && shared_library_handle != (void*)-1) { + return; + } + + __current_dispatch = NULL; + shared_library_handle = load_socket_hook_shared_library(); + if (shared_library_handle == NULL) { + return; + } + + if (finish_install_ohos_socket_hooks(NULL)) { + __ohos_socket_hook_shared_library = (long long)shared_library_handle; + __current_dispatch = (long long)(&__musl_libc_socket_dispatch); + } else { + __ohos_socket_hook_shared_library = NULL; + dlclose((void *)shared_library_handle); + } +} + +static void init_ohos_socket_hook() +{ + install_ohos_socket_hook(); +} + +__attribute__((constructor())) static void __musl_socket_initialize() +{ + bool begin_flag = __get_socket_hook_begin_flag(); + if (!begin_flag) { + __socket_hook_begin_flag = true; + init_ohos_socket_hook(); + } +} +#endif \ No newline at end of file diff --git a/porting/linux/user/src/hook/musl_socket_preinit_common.c b/porting/linux/user/src/hook/musl_socket_preinit_common.c new file mode 100644 index 0000000000000000000000000000000000000000..a586cf8785dc7f98dd5086474e1f799061691a3b --- /dev/null +++ b/porting/linux/user/src/hook/musl_socket_preinit_common.c @@ -0,0 +1,16 @@ +#ifdef OHOS_SOCKET_HOOK_ENABLE +#include +#include "musl_socket.h" +#include "musl_socket_preinit_common.h" + +struct SocketDispatchType __musl_libc_socket_dispatch; + +long long __current_dispatch; + +struct SocketDispatchType __libc_socket_default_dispatch = { + .socket = MuslSocket(socket), +}; + +bool __socket_hook_begin_flag; + +#endif \ No newline at end of file diff --git a/porting/linux/user/src/hook/musl_socket_preinit_common.h b/porting/linux/user/src/hook/musl_socket_preinit_common.h new file mode 100644 index 0000000000000000000000000000000000000000..c13b632063ed693466e00f3b015aebb0ee69ca3a --- /dev/null +++ b/porting/linux/user/src/hook/musl_socket_preinit_common.h @@ -0,0 +1,83 @@ +#ifndef _MUSL_SOCKET_PREINIT_COMMON_H +#define _MUSL_SOCKET_PREINIT_COMMON_H + +#include +#include "musl_socket_dispatch.h" +#include "common_def.h" + +extern struct SocketDispatchType __musl_libc_socket_dispatch; +extern struct SocketDispatchType __libc_socket_default_dispatch; + +enum SocketFuncEnum { + INITIALIZE_FUNC, + FINALIZE_FUNC, + GET_HOOK_FLAG_FUNC, + SET_HOOK_FLAG_FUNC, + LAST_FUNC, +}; + +#ifdef OHOS_SOCKET_HOOK_ENABLE +extern long long __current_dispatch; +extern bool __socket_hook_begin_flag; +extern long long __ohos_socket_hook_shared_library; +extern void* shared_lib_func[LAST_FUNC]; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +__attribute__((always_inline)) +inline bool __get_socket_hook_begin_flag() +{ +#ifdef OHOS_SOCKET_HOOK_ENABLE + return __socket_hook_begin_flag; +#else + return false; +#endif +} + +__attribute__((always_inline)) +inline bool __get_socket_hook_flag() +{ +#ifdef OHOS_SOCKET_HOOK_ENABLE + void* handle = (void *)__ohos_socket_hook_shared_library; + if (handle == NULL) { + return false; + } else if (handle == (void *)-1) { + return true; + } else { + SocketGetHookFlagType get_hook_func_ptr = (SocketGetHookFlagType)(shared_lib_func[GET_HOOK_FLAG_FUNC]); + bool flag = get_hook_func_ptr(); + return flag; + } +#else + return false; +#endif +} + +__attribute__((always_inline)) +inline volatile const struct SocketDispatchType* get_socket_dispatch() +{ +#ifdef OHOS_SOCKET_HOOK_ENABLE + volatile const struct SocketDispatchType* ret = (struct SocketDispatchType *)__current_dispatch; + if (ret != NULL) { + if (!__get_socket_hook_begin_flag()) { + ret = NULL; + } else if (!__get_socket_hook_flag()) { + ret = NULL; + } else { + return ret; + } + } + return ret; +#else + return NULL; +#endif +} + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/porting/linux/user/src/hook/socket_common.c b/porting/linux/user/src/hook/socket_common.c new file mode 100644 index 0000000000000000000000000000000000000000..939b75c5a25ed713f09c5395739e1c7f97c2006a --- /dev/null +++ b/porting/linux/user/src/hook/socket_common.c @@ -0,0 +1,18 @@ +#ifdef OHOS_SOCKET_HOOK_ENABLE +#include "musl_socket.h" +#include +#include "common_def.h" +#include "musl_socket_preinit_common.h" + +int socket(int domain, int type, int protocol) +{ + volatile const struct SocketDispatchType* dispatch = get_socket_dispatch(); + if (__predict_false(dispatch != NULL)) { + int ret = dispatch->socket(domain, type, protocol); + return ret; + } + int result = MuslSocket(socket)(domain, type, protocol); + return result; +} + +#endif \ No newline at end of file diff --git a/porting/linux/user/src/network/socket.c b/porting/linux/user/src/network/socket.c new file mode 100644 index 0000000000000000000000000000000000000000..072bc1cba0597ad3d83eef48fb49ba7bd4e7ee5c --- /dev/null +++ b/porting/linux/user/src/network/socket.c @@ -0,0 +1,69 @@ +#include +#include +#include +#include +#include +#include +#include "syscall.h" + +#if OHOS_PERMISSION_INTERNET +typedef uint8_t (*AllowFunc)(void); +static const char *LIB_NETSYS_CLIENT_NAME = "libnetsys_client.z.so"; +static const char *ALLOW_SOCKET_FUNC_NAME = "IsAllowInternet"; + +/* + * Read a flag from netsys_client, there is only one place to set this flag, is the + * founction named DoStartup in startup_appspawn. + * */ +uint8_t is_allow_internet(void) +{ + static uint8_t first_time = 1; + static uint8_t allow = 1; + + if (!first_time) { + return allow; + } + + void *handler = dlopen(LIB_NETSYS_CLIENT_NAME, RTLD_LAZY); + if (handler != NULL) { + AllowFunc func = (AllowFunc)dlsym(handler, ALLOW_SOCKET_FUNC_NAME); + if (func != NULL && func() == 0) { + allow = 0; + } + dlclose(handler); + } + first_time = 0; + return allow; +} +#endif + +#ifdef OHOS_SOCKET_HOOK_ENABLE +int __libc_socket(int domain, int type, int protocol) +#else +int socket(int domain, int type, int protocol) +#endif +{ +#if OHOS_PERMISSION_INTERNET + if ((domain == AF_INET || domain == AF_INET6) && is_allow_internet() == 0) { + errno = EPERM; + return -1; + } +#endif + int s = socketcall(socket, domain, type, protocol, 0, 0, 0); + if (s < 0 && (errno == EINVAL || errno == EPROTONOSUPPORT) + && (type & (SOCK_CLOEXEC | SOCK_NONBLOCK))) { + s = socketcall(socket, domain, + type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK), + protocol, 0, 0, 0); + if (s < 0) { + return s; + } + if (type & SOCK_CLOEXEC) { + __syscall(SYS_fcntl, s, F_SETFD, FD_CLOEXEC); + } + if (type & SOCK_NONBLOCK) { + __syscall(SYS_fcntl, s, F_SETFL, O_NONBLOCK); + } + } + return s; +} \ No newline at end of file