fix(ci): inject LD_PRELOAD interceptor to redirect all x86_64 ELF executions to QEMU
This commit is contained in:
@@ -34,36 +34,9 @@ jobs:
|
|||||||
# On Linux ARM64, Flutter engine and Android AAPT2 need x86_64 emulation via QEMU.
|
# On Linux ARM64, Flutter engine and Android AAPT2 need x86_64 emulation via QEMU.
|
||||||
if [ "$ARCH" = "aarch64" ] || [ "$ARCH" = "arm64" ]; then
|
if [ "$ARCH" = "aarch64" ] || [ "$ARCH" = "arm64" ]; then
|
||||||
echo "Setting up ARM64 Flutter environment & QEMU binfmt emulation..."
|
echo "Setting up ARM64 Flutter environment & QEMU binfmt emulation..."
|
||||||
apt-get update -qq && apt-get install -y -qq qemu-user-static binfmt-support libc6-amd64-cross libstdc++6-amd64-cross
|
apt-get update -qq && apt-get install -y -qq qemu-user-static binfmt-support libc6-amd64-cross libstdc++6-amd64-cross gcc
|
||||||
|
|
||||||
# Mount binfmt_misc pseudo-filesystem (supported under --privileged)
|
# Setup x86_64 dynamic libraries & prefix for QEMU emulation
|
||||||
mkdir -p /proc/sys/fs/binfmt_misc
|
|
||||||
if ! grep -qs '/proc/sys/fs/binfmt_misc' /proc/mounts; then
|
|
||||||
mount -t binfmt_misc binfmt_misc /proc/sys/fs/binfmt_misc 2>/dev/null || true
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Cleanly unregister any conflicting or broken host binfmt handlers (e.g. host FEX)
|
|
||||||
if [ -f /proc/sys/fs/binfmt_misc/register ]; then
|
|
||||||
echo "=== Active binfmt_misc handlers before cleanup ==="
|
|
||||||
ls -la /proc/sys/fs/binfmt_misc/ || true
|
|
||||||
for entry in /proc/sys/fs/binfmt_misc/*; do
|
|
||||||
[ -f "$entry" ] || continue
|
|
||||||
name="$(basename "$entry")"
|
|
||||||
[ "$name" = "register" ] && continue
|
|
||||||
[ "$name" = "status" ] && continue
|
|
||||||
if grep -qi "fex" "$entry" 2>/dev/null || [ "$name" = "FEX-x86_64" ] || [ "$name" = "fex-x86_64" ] || [ "$name" = "x86_64" ] || [ "$name" = "qemu-x86_64" ]; then
|
|
||||||
echo "Unregistering conflicting binfmt handler: $name"
|
|
||||||
echo -1 > "$entry" 2>/dev/null || true
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
# Register QEMU x86_64 emulator directly with OCF flags (Fix-binary)
|
|
||||||
echo ':qemu-x86_64:M::\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x3e\x00:\xff\xff\xff\xff\xff\xfe\xfe\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/bin/qemu-x86_64-static:OCF' > /proc/sys/fs/binfmt_misc/register 2>/dev/null || true
|
|
||||||
echo "=== Active binfmt_misc handlers after registration ==="
|
|
||||||
ls -la /proc/sys/fs/binfmt_misc/ || true
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Setup x86_64 dynamic libraries & prefix for QEMU emulation of AAPT2 and tools
|
|
||||||
mkdir -p /etc/qemu-binfmt
|
mkdir -p /etc/qemu-binfmt
|
||||||
ln -sf /usr/x86_64-linux-gnu /etc/qemu-binfmt/x86_64
|
ln -sf /usr/x86_64-linux-gnu /etc/qemu-binfmt/x86_64
|
||||||
mkdir -p /lib64 /usr/lib64
|
mkdir -p /lib64 /usr/lib64
|
||||||
@@ -74,9 +47,99 @@ jobs:
|
|||||||
export QEMU_LD_PREFIX=/usr/x86_64-linux-gnu
|
export QEMU_LD_PREFIX=/usr/x86_64-linux-gnu
|
||||||
echo "QEMU_LD_PREFIX=/usr/x86_64-linux-gnu" >> "$GITHUB_ENV"
|
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 <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <spawn.h>
|
||||||
|
|
||||||
|
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)
|
QEMU_BIN=$(command -v qemu-x86_64-static || command -v qemu-x86_64)
|
||||||
|
|
||||||
# Dummy fallbacks for FEX binaries/sockets to eliminate unexpected errors
|
# Dummy fallbacks for FEX binaries/sockets
|
||||||
for fex in /usr/bin/FEXInterpreter /usr/bin/FEX /usr/local/bin/FEXInterpreter /usr/bin/FEXServer /usr/local/bin/FEXServer; do
|
for fex in /usr/bin/FEXInterpreter /usr/bin/FEX /usr/local/bin/FEXInterpreter /usr/bin/FEXServer /usr/local/bin/FEXServer; do
|
||||||
printf '#!/bin/sh\nexit 0\n' > "$fex"
|
printf '#!/bin/sh\nexit 0\n' > "$fex"
|
||||||
chmod +x "$fex" 2>/dev/null || true
|
chmod +x "$fex" 2>/dev/null || true
|
||||||
|
|||||||
@@ -34,36 +34,9 @@ jobs:
|
|||||||
# On Linux ARM64, Flutter engine and Android AAPT2 need x86_64 emulation via QEMU.
|
# On Linux ARM64, Flutter engine and Android AAPT2 need x86_64 emulation via QEMU.
|
||||||
if [ "$ARCH" = "aarch64" ] || [ "$ARCH" = "arm64" ]; then
|
if [ "$ARCH" = "aarch64" ] || [ "$ARCH" = "arm64" ]; then
|
||||||
echo "Setting up ARM64 Flutter environment & QEMU binfmt emulation..."
|
echo "Setting up ARM64 Flutter environment & QEMU binfmt emulation..."
|
||||||
apt-get update -qq && apt-get install -y -qq qemu-user-static binfmt-support libc6-amd64-cross libstdc++6-amd64-cross
|
apt-get update -qq && apt-get install -y -qq qemu-user-static binfmt-support libc6-amd64-cross libstdc++6-amd64-cross gcc
|
||||||
|
|
||||||
# Mount binfmt_misc pseudo-filesystem (supported under --privileged)
|
# Setup x86_64 dynamic libraries & prefix for QEMU emulation
|
||||||
mkdir -p /proc/sys/fs/binfmt_misc
|
|
||||||
if ! grep -qs '/proc/sys/fs/binfmt_misc' /proc/mounts; then
|
|
||||||
mount -t binfmt_misc binfmt_misc /proc/sys/fs/binfmt_misc 2>/dev/null || true
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Cleanly unregister any conflicting or broken host binfmt handlers (e.g. host FEX)
|
|
||||||
if [ -f /proc/sys/fs/binfmt_misc/register ]; then
|
|
||||||
echo "=== Active binfmt_misc handlers before cleanup ==="
|
|
||||||
ls -la /proc/sys/fs/binfmt_misc/ || true
|
|
||||||
for entry in /proc/sys/fs/binfmt_misc/*; do
|
|
||||||
[ -f "$entry" ] || continue
|
|
||||||
name="$(basename "$entry")"
|
|
||||||
[ "$name" = "register" ] && continue
|
|
||||||
[ "$name" = "status" ] && continue
|
|
||||||
if grep -qi "fex" "$entry" 2>/dev/null || [ "$name" = "FEX-x86_64" ] || [ "$name" = "fex-x86_64" ] || [ "$name" = "x86_64" ] || [ "$name" = "qemu-x86_64" ]; then
|
|
||||||
echo "Unregistering conflicting binfmt handler: $name"
|
|
||||||
echo -1 > "$entry" 2>/dev/null || true
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
# Register QEMU x86_64 emulator directly with OCF flags (Fix-binary)
|
|
||||||
echo ':qemu-x86_64:M::\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x3e\x00:\xff\xff\xff\xff\xff\xfe\xfe\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/bin/qemu-x86_64-static:OCF' > /proc/sys/fs/binfmt_misc/register 2>/dev/null || true
|
|
||||||
echo "=== Active binfmt_misc handlers after registration ==="
|
|
||||||
ls -la /proc/sys/fs/binfmt_misc/ || true
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Setup x86_64 dynamic libraries & prefix for QEMU emulation of AAPT2 and tools
|
|
||||||
mkdir -p /etc/qemu-binfmt
|
mkdir -p /etc/qemu-binfmt
|
||||||
ln -sf /usr/x86_64-linux-gnu /etc/qemu-binfmt/x86_64
|
ln -sf /usr/x86_64-linux-gnu /etc/qemu-binfmt/x86_64
|
||||||
mkdir -p /lib64 /usr/lib64
|
mkdir -p /lib64 /usr/lib64
|
||||||
@@ -74,9 +47,99 @@ jobs:
|
|||||||
export QEMU_LD_PREFIX=/usr/x86_64-linux-gnu
|
export QEMU_LD_PREFIX=/usr/x86_64-linux-gnu
|
||||||
echo "QEMU_LD_PREFIX=/usr/x86_64-linux-gnu" >> "$GITHUB_ENV"
|
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 <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <spawn.h>
|
||||||
|
|
||||||
|
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)
|
QEMU_BIN=$(command -v qemu-x86_64-static || command -v qemu-x86_64)
|
||||||
|
|
||||||
# Dummy fallbacks for FEX binaries/sockets to eliminate unexpected errors
|
# Dummy fallbacks for FEX binaries/sockets
|
||||||
for fex in /usr/bin/FEXInterpreter /usr/bin/FEX /usr/local/bin/FEXInterpreter /usr/bin/FEXServer /usr/local/bin/FEXServer; do
|
for fex in /usr/bin/FEXInterpreter /usr/bin/FEX /usr/local/bin/FEXInterpreter /usr/bin/FEXServer /usr/local/bin/FEXServer; do
|
||||||
printf '#!/bin/sh\nexit 0\n' > "$fex"
|
printf '#!/bin/sh\nexit 0\n' > "$fex"
|
||||||
chmod +x "$fex" 2>/dev/null || true
|
chmod +x "$fex" 2>/dev/null || true
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
org.gradle.jvmargs=-Xmx1536M
|
org.gradle.jvmargs=-Xmx1536M -Djdk.lang.Process.launchMechanism=vfork
|
||||||
android.useAndroidX=true
|
android.useAndroidX=true
|
||||||
android.enableJetifier=true
|
android.enableJetifier=true
|
||||||
|
|||||||
Reference in New Issue
Block a user