From e44fcf1223e1b7fcab0affad57e7248a5eeb5a27 Mon Sep 17 00:00:00 2001 From: nicolas Date: Mon, 14 Sep 2026 00:15:20 +0200 Subject: [PATCH] fix(ci): extract QEMU interceptor to dedicated C file to fix YAML indentation --- .gitea/workflows/build-apk.yaml | 100 ++++--------------------------- .github/workflows/build-apk.yaml | 100 ++++--------------------------- scripts/ci/qemu_intercept.c | 91 ++++++++++++++++++++++++++++ 3 files changed, 111 insertions(+), 180 deletions(-) create mode 100644 scripts/ci/qemu_intercept.c diff --git a/.gitea/workflows/build-apk.yaml b/.gitea/workflows/build-apk.yaml index 0febd82..183fdad 100644 --- a/.gitea/workflows/build-apk.yaml +++ b/.gitea/workflows/build-apk.yaml @@ -47,96 +47,6 @@ jobs: export QEMU_LD_PREFIX=/usr/x86_64-linux-gnu echo "QEMU_LD_PREFIX=/usr/x86_64-linux-gnu" >> "$GITHUB_ENV" - # Create transparent execve/posix_spawn interceptor to route ALL x86_64 binaries to QEMU - cat << 'EOF' > /tmp/qemu_intercept.c -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include - -static int is_x86_64_elf(const char *path) { - if (!path) return 0; - int fd = open(path, O_RDONLY); - if (fd < 0) return 0; - unsigned char header[20]; - ssize_t n = read(fd, header, sizeof(header)); - close(fd); - if (n < 20) return 0; - if (header[0] != 0x7f || header[1] != 'E' || header[2] != 'L' || header[3] != 'F') return 0; - if (header[4] != 2 || header[5] != 1) return 0; - uint16_t machine = (uint16_t)(header[18] | (header[19] << 8)); - return machine == 62; -} - -static char **build_qemu_argv(const char *pathname, char *const argv[]) { - int argc = 0; - while (argv && argv[argc]) argc++; - char **new_argv = malloc((argc + 4) * sizeof(char *)); - new_argv[0] = "/usr/bin/qemu-x86_64-static"; - new_argv[1] = "-L"; - new_argv[2] = "/usr/x86_64-linux-gnu"; - new_argv[3] = (char *)pathname; - for (int i = 1; i < argc; i++) { - new_argv[i + 3] = argv[i]; - } - new_argv[argc + 3] = NULL; - return new_argv; -} - -int execve(const char *pathname, char *const argv[], char *const envp[]) { - static int (*real_execve)(const char *, char *const [], char *const []) = NULL; - if (!real_execve) real_execve = dlsym(RTLD_NEXT, "execve"); - if (pathname && is_x86_64_elf(pathname)) { - char **new_argv = build_qemu_argv(pathname, argv); - return real_execve("/usr/bin/qemu-x86_64-static", new_argv, envp); - } - return real_execve(pathname, argv, envp); -} - -int execv(const char *pathname, char *const argv[]) { - extern char **environ; - return execve(pathname, argv, environ); -} - -int execvp(const char *file, char *const argv[]) { - extern char **environ; - return execve(file, argv, environ); -} - -int execvpe(const char *file, char *const argv[], char *const envp[]) { - return execve(file, argv, envp); -} - -int posix_spawn(pid_t *pid, const char *path, - const posix_spawn_file_actions_t *file_actions, - const posix_spawnattr_t *attrp, - char *const argv[], char *const envp[]) { - static int (*real_posix_spawn)(pid_t *, const char *, const posix_spawn_file_actions_t *, - const posix_spawnattr_t *, char *const [], char *const []) = NULL; - if (!real_posix_spawn) real_posix_spawn = dlsym(RTLD_NEXT, "posix_spawn"); - if (path && is_x86_64_elf(path)) { - char **new_argv = build_qemu_argv(path, argv); - return real_posix_spawn(pid, "/usr/bin/qemu-x86_64-static", file_actions, attrp, new_argv, envp); - } - return real_posix_spawn(pid, path, file_actions, attrp, argv, envp); -} - -int posix_spawnp(pid_t *pid, const char *file, - const posix_spawn_file_actions_t *file_actions, - const posix_spawnattr_t *attrp, - char *const argv[], char *const envp[]) { - return posix_spawn(pid, file, file_actions, attrp, argv, envp); -} -EOF - gcc -O2 -shared -fPIC -o /usr/local/lib/libqemu_intercept.so /tmp/qemu_intercept.c -ldl - echo "/usr/local/lib/libqemu_intercept.so" > /etc/ld.so.preload - echo "Installed transparent QEMU execution interceptor into /etc/ld.so.preload" - QEMU_BIN=$(command -v qemu-x86_64-static || command -v qemu-x86_64) # Dummy fallbacks for FEX binaries/sockets @@ -159,6 +69,16 @@ EOF - name: Checkout Repository uses: actions/checkout@v4 + - name: Setup QEMU Interceptor + run: | + ARCH=$(uname -m) + if [ "$ARCH" = "aarch64" ] || [ "$ARCH" = "arm64" ]; then + echo "Compiling and installing transparent QEMU execution interceptor..." + gcc -O2 -shared -fPIC -o /usr/local/lib/libqemu_intercept.so scripts/ci/qemu_intercept.c -ldl + echo "/usr/local/lib/libqemu_intercept.so" > /etc/ld.so.preload + echo "Installed transparent QEMU execution interceptor into /etc/ld.so.preload" + fi + - name: Make Gradlew Executable run: | if [ -f android/gradlew ]; then diff --git a/.github/workflows/build-apk.yaml b/.github/workflows/build-apk.yaml index 0febd82..183fdad 100644 --- a/.github/workflows/build-apk.yaml +++ b/.github/workflows/build-apk.yaml @@ -47,96 +47,6 @@ jobs: export QEMU_LD_PREFIX=/usr/x86_64-linux-gnu echo "QEMU_LD_PREFIX=/usr/x86_64-linux-gnu" >> "$GITHUB_ENV" - # Create transparent execve/posix_spawn interceptor to route ALL x86_64 binaries to QEMU - cat << 'EOF' > /tmp/qemu_intercept.c -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include - -static int is_x86_64_elf(const char *path) { - if (!path) return 0; - int fd = open(path, O_RDONLY); - if (fd < 0) return 0; - unsigned char header[20]; - ssize_t n = read(fd, header, sizeof(header)); - close(fd); - if (n < 20) return 0; - if (header[0] != 0x7f || header[1] != 'E' || header[2] != 'L' || header[3] != 'F') return 0; - if (header[4] != 2 || header[5] != 1) return 0; - uint16_t machine = (uint16_t)(header[18] | (header[19] << 8)); - return machine == 62; -} - -static char **build_qemu_argv(const char *pathname, char *const argv[]) { - int argc = 0; - while (argv && argv[argc]) argc++; - char **new_argv = malloc((argc + 4) * sizeof(char *)); - new_argv[0] = "/usr/bin/qemu-x86_64-static"; - new_argv[1] = "-L"; - new_argv[2] = "/usr/x86_64-linux-gnu"; - new_argv[3] = (char *)pathname; - for (int i = 1; i < argc; i++) { - new_argv[i + 3] = argv[i]; - } - new_argv[argc + 3] = NULL; - return new_argv; -} - -int execve(const char *pathname, char *const argv[], char *const envp[]) { - static int (*real_execve)(const char *, char *const [], char *const []) = NULL; - if (!real_execve) real_execve = dlsym(RTLD_NEXT, "execve"); - if (pathname && is_x86_64_elf(pathname)) { - char **new_argv = build_qemu_argv(pathname, argv); - return real_execve("/usr/bin/qemu-x86_64-static", new_argv, envp); - } - return real_execve(pathname, argv, envp); -} - -int execv(const char *pathname, char *const argv[]) { - extern char **environ; - return execve(pathname, argv, environ); -} - -int execvp(const char *file, char *const argv[]) { - extern char **environ; - return execve(file, argv, environ); -} - -int execvpe(const char *file, char *const argv[], char *const envp[]) { - return execve(file, argv, envp); -} - -int posix_spawn(pid_t *pid, const char *path, - const posix_spawn_file_actions_t *file_actions, - const posix_spawnattr_t *attrp, - char *const argv[], char *const envp[]) { - static int (*real_posix_spawn)(pid_t *, const char *, const posix_spawn_file_actions_t *, - const posix_spawnattr_t *, char *const [], char *const []) = NULL; - if (!real_posix_spawn) real_posix_spawn = dlsym(RTLD_NEXT, "posix_spawn"); - if (path && is_x86_64_elf(path)) { - char **new_argv = build_qemu_argv(path, argv); - return real_posix_spawn(pid, "/usr/bin/qemu-x86_64-static", file_actions, attrp, new_argv, envp); - } - return real_posix_spawn(pid, path, file_actions, attrp, argv, envp); -} - -int posix_spawnp(pid_t *pid, const char *file, - const posix_spawn_file_actions_t *file_actions, - const posix_spawnattr_t *attrp, - char *const argv[], char *const envp[]) { - return posix_spawn(pid, file, file_actions, attrp, argv, envp); -} -EOF - gcc -O2 -shared -fPIC -o /usr/local/lib/libqemu_intercept.so /tmp/qemu_intercept.c -ldl - echo "/usr/local/lib/libqemu_intercept.so" > /etc/ld.so.preload - echo "Installed transparent QEMU execution interceptor into /etc/ld.so.preload" - QEMU_BIN=$(command -v qemu-x86_64-static || command -v qemu-x86_64) # Dummy fallbacks for FEX binaries/sockets @@ -159,6 +69,16 @@ EOF - name: Checkout Repository uses: actions/checkout@v4 + - name: Setup QEMU Interceptor + run: | + ARCH=$(uname -m) + if [ "$ARCH" = "aarch64" ] || [ "$ARCH" = "arm64" ]; then + echo "Compiling and installing transparent QEMU execution interceptor..." + gcc -O2 -shared -fPIC -o /usr/local/lib/libqemu_intercept.so scripts/ci/qemu_intercept.c -ldl + echo "/usr/local/lib/libqemu_intercept.so" > /etc/ld.so.preload + echo "Installed transparent QEMU execution interceptor into /etc/ld.so.preload" + fi + - name: Make Gradlew Executable run: | if [ -f android/gradlew ]; then diff --git a/scripts/ci/qemu_intercept.c b/scripts/ci/qemu_intercept.c new file mode 100644 index 0000000..633b82b --- /dev/null +++ b/scripts/ci/qemu_intercept.c @@ -0,0 +1,91 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include + +static int is_x86_64_elf(const char *path) { + if (!path) return 0; + int fd = open(path, O_RDONLY); + if (fd < 0) return 0; + unsigned char header[20]; + ssize_t n = read(fd, header, sizeof(header)); + close(fd); + if (n < 20) return 0; + if (header[0] != 0x7f || header[1] != 'E' || header[2] != 'L' || header[3] != 'F') return 0; + if (header[4] != 2 || header[5] != 1) return 0; + uint16_t machine = (uint16_t)(header[18] | (header[19] << 8)); + return machine == 62; +} + +static char **build_qemu_argv(const char *pathname, char *const argv[]) { + int argc = 0; + while (argv && argv[argc]) argc++; + char **new_argv = (char **)malloc((argc + 4) * sizeof(char *)); + if (!new_argv) return NULL; + new_argv[0] = /usr/bin/qemu-x86_64-static; + new_argv[1] = -L; + new_argv[2] = /usr/x86_64-linux-gnu; + new_argv[3] = (char *)pathname; + for (int i = 1; i < argc; i++) { + new_argv[i + 3] = argv[i]; + } + new_argv[argc + 3] = NULL; + return new_argv; +} + +int execve(const char *pathname, char *const argv[], char *const envp[]) { + static int (*real_execve)(const char *, char *const [], char *const []) = NULL; + if (!real_execve) real_execve = (int (*)(const char *, char *const [], char *const []))dlsym(RTLD_NEXT, execve); + if (pathname && is_x86_64_elf(pathname)) { + char **new_argv = build_qemu_argv(pathname, argv); + if (new_argv) { + return real_execve(/usr/bin/qemu-x86_64-static, new_argv, envp); + } + } + return real_execve(pathname, argv, envp); +} + +int execv(const char *pathname, char *const argv[]) { + extern char **environ; + return execve(pathname, argv, environ); +} + +int execvp(const char *file, char *const argv[]) { + extern char **environ; + return execve(file, argv, environ); +} + +int execvpe(const char *file, char *const argv[], char *const envp[]) { + return execve(file, argv, envp); +} + +int posix_spawn(pid_t *pid, const char *path, + const posix_spawn_file_actions_t *file_actions, + const posix_spawnattr_t *attrp, + char *const argv[], char *const envp[]) { + static int (*real_posix_spawn)(pid_t *, const char *, const posix_spawn_file_actions_t *, + const posix_spawnattr_t *, char *const [], char *const []) = NULL; + if (!real_posix_spawn) { + real_posix_spawn = (int (*)(pid_t *, const char *, const posix_spawn_file_actions_t *, + const posix_spawnattr_t *, char *const [], char *const []))dlsym(RTLD_NEXT, posix_spawn); + } + if (path && is_x86_64_elf(path)) { + char **new_argv = build_qemu_argv(path, argv); + if (new_argv) { + return real_posix_spawn(pid, /usr/bin/qemu-x86_64-static, file_actions, attrp, new_argv, envp); + } + } + return real_posix_spawn(pid, path, file_actions, attrp, argv, envp); +} + +int posix_spawnp(pid_t *pid, const char *file, + const posix_spawn_file_actions_t *file_actions, + const posix_spawnattr_t *attrp, + char *const argv[], char *const envp[]) { + return posix_spawn(pid, file, file_actions, attrp, argv, envp); +}