[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[RFC v6 3/9] linux-user: Implement native-bypass option support
From: |
Yeqi Fu |
Subject: |
[RFC v6 3/9] linux-user: Implement native-bypass option support |
Date: |
Wed, 13 Sep 2023 05:28:36 +0800 |
This commit implements support for the native-bypass option
in linux-user. By utilizing this functionality, the specified
shared library can be loaded into the user program. This is
achieved by dynamically modifying the /etc/ld.so.preload file,
enabling the user program to load the shared library effortlessly.
Signed-off-by: Yeqi Fu <fufuyqqqqqq@gmail.com>
---
include/native/native.h | 7 ++++++
linux-user/main.c | 20 +++++++++++++++
linux-user/syscall.c | 55 +++++++++++++++++++++++++++++++++++++++++
3 files changed, 82 insertions(+)
create mode 100644 include/native/native.h
diff --git a/include/native/native.h b/include/native/native.h
new file mode 100644
index 0000000000..12462a261e
--- /dev/null
+++ b/include/native/native.h
@@ -0,0 +1,7 @@
+#if defined(CONFIG_USER_ONLY) && defined(CONFIG_NATIVE_CALL)
+extern char *native_lib_path;
+/* Check if the native-bypass option is enabled. */
+#define native_bypass_enabled() (native_lib_path != NULL)
+#else
+#define native_bypass_enabled() false
+#endif
diff --git a/linux-user/main.c b/linux-user/main.c
index dba67ffa36..4c1d515944 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -60,6 +60,11 @@
#include "semihosting/semihost.h"
#endif
+#if defined(CONFIG_NATIVE_CALL)
+#include "native/native.h"
+char *native_lib_path;
+#endif
+
#ifndef AT_FLAGS_PRESERVE_ARGV0
#define AT_FLAGS_PRESERVE_ARGV0_BIT 0
#define AT_FLAGS_PRESERVE_ARGV0 (1 << AT_FLAGS_PRESERVE_ARGV0_BIT)
@@ -293,6 +298,17 @@ static void handle_arg_set_env(const char *arg)
free(r);
}
+#if defined(CONFIG_NATIVE_CALL)
+static void handle_arg_native_bypass(const char *arg)
+{
+ if (!g_file_test(arg, G_FILE_TEST_IS_REGULAR)) {
+ fprintf(stderr, "native library %s does not exist\n", arg);
+ exit(EXIT_FAILURE);
+ }
+ native_lib_path = g_strdup(arg);
+}
+#endif
+
static void handle_arg_unset_env(const char *arg)
{
char *r, *p, *token;
@@ -522,6 +538,10 @@ static const struct qemu_argument arg_table[] = {
"", "Generate a /tmp/perf-${pid}.map file for perf"},
{"jitdump", "QEMU_JITDUMP", false, handle_arg_jitdump,
"", "Generate a jit-${pid}.dump file for perf"},
+#if defined(CONFIG_NATIVE_CALL)
+ {"native-bypass", "QEMU_NATIVE_BYPASS", true, handle_arg_native_bypass,
+ "", "native bypass for library calls"},
+#endif
{NULL, NULL, false, NULL, NULL, NULL}
};
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 08162cc966..7034f58373 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -143,6 +143,7 @@
#include "fd-trans.h"
#include "tcg/tcg.h"
#include "cpu_loop-common.h"
+#include "native/native.h"
#ifndef CLONE_IO
#define CLONE_IO 0x80000000 /* Clone io context */
@@ -8503,6 +8504,40 @@ static int open_hardware(CPUArchState *cpu_env, int fd)
}
#endif
+#if defined(CONFIG_NATIVE_CALL)
+static int is_ld_so_preload(const char *filename, const char *entry)
+{
+ if (native_bypass_enabled() && !strcmp(filename, entry)) {
+ return 1;
+ }
+ return 0;
+}
+
+/* This function is only called when the "native-bypass" option is provided. */
+static int open_ld_so_preload(CPUArchState *cpu_env, int fd)
+{
+ FILE *fp;
+ char *line = NULL;
+ size_t len = 0;
+ ssize_t read;
+
+ dprintf(fd, "%s\n", native_lib_path);
+ fp = fopen("/etc/ld.so.preload", "r");
+ if (fp == NULL) {
+ return 0;
+ }
+
+ while ((read = getline(&line, &len, fp)) != -1) {
+ dprintf(fd, "%s", line);
+ }
+
+ free(line);
+ fclose(fp);
+
+ return 0;
+}
+#endif
+
int do_guest_openat(CPUArchState *cpu_env, int dirfd, const char *pathname,
int flags, mode_t mode, bool safe)
{
@@ -8527,6 +8562,9 @@ int do_guest_openat(CPUArchState *cpu_env, int dirfd,
const char *pathname,
#endif
#if defined(TARGET_M68K)
{ "/proc/hardware", open_hardware, is_proc },
+#endif
+#if defined(CONFIG_NATIVE_CALL)
+ { "/etc/ld.so.preload", open_ld_so_preload, is_ld_so_preload },
#endif
{ NULL, NULL, NULL }
};
@@ -9523,6 +9561,11 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int
num, abi_long arg1,
return -TARGET_EFAULT;
}
ret = get_errno(access(path(p), arg2));
+ if (ret != 0 && native_bypass_enabled()) {
+ if (strcmp(p, "/etc/ld.so.preload") == 0 && arg2 == R_OK) {
+ return 0;
+ }
+ }
unlock_user(p, arg1, 0);
return ret;
#endif
@@ -9532,6 +9575,12 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int
num, abi_long arg1,
return -TARGET_EFAULT;
}
ret = get_errno(faccessat(arg1, p, arg3, 0));
+ if (ret != 0 && native_bypass_enabled()) {
+ if (strcmp(p, "/etc/ld.so.preload") == 0 && arg1 == AT_FDCWD &&
+ arg3 == R_OK) {
+ return 0;
+ }
+ }
unlock_user(p, arg2, 0);
return ret;
#endif
@@ -9541,6 +9590,12 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int
num, abi_long arg1,
return -TARGET_EFAULT;
}
ret = get_errno(faccessat(arg1, p, arg3, arg4));
+ if (ret != 0 && native_bypass_enabled()) {
+ if (strcmp(p, "/etc/ld.so.preload") == 0 && arg1 == AT_FDCWD &&
+ arg3 == R_OK) {
+ return 0;
+ }
+ }
unlock_user(p, arg2, 0);
return ret;
#endif
--
2.34.1
- [RFC v6 0/9] Native Library Calls, Yeqi Fu, 2023/09/12
- [RFC v6 1/9] build: Implement logic for sharing cross-building config files, Yeqi Fu, 2023/09/12
- [RFC v6 2/9] build: Implement libnative library and the build machinery for libnative, Yeqi Fu, 2023/09/12
- [RFC v6 3/9] linux-user: Implement native-bypass option support,
Yeqi Fu <=
- [RFC v6 4/9] tcg: Add tcg opcodes and helpers for native library calls, Yeqi Fu, 2023/09/12
- [RFC v6 7/9] target/arm: Add support for native library calls, Yeqi Fu, 2023/09/12
- [RFC v6 8/9] tests/tcg/multiarch: Add nativecall.c test, Yeqi Fu, 2023/09/12
- [RFC v6 5/9] target/i386: Add support for native library calls, Yeqi Fu, 2023/09/12
- [RFC v6 6/9] target/mips: Add support for native library calls, Yeqi Fu, 2023/09/12
- [RFC v6 9/9] docs/user: Add doc for native library calls, Yeqi Fu, 2023/09/12