Skip to content

Commit 1aed440

Browse files
committed
fix(rootfs/qemu-static): use direct armhf exec probe instead of broken arch-test gate
`arch-test arm` probes ARMv5 EABI, divergent from kernel COMPAT (armhf EABI v5+), and returns failure on modern aarch64 hosts (Ubuntu Noble 6.8 / Ampere Altra) with a fully working CONFIG_COMPAT path — routing mmdebstrap through qemu-user emulation at ~10× slowdown. Replace with a 4-tier detection: prefer the packaged `/usr/share/binfmts/qemu-arm` descriptor if present, trust an already-enabled kernel registration, otherwise probe COMPAT directly by exec'ing `ld-linux-armhf.so.3`, falling back to the hand-rolled descriptor only when none applies. Assisted-by: Claude:claude-opus-4.7
1 parent 574b46a commit 1aed440

1 file changed

Lines changed: 80 additions & 26 deletions

File tree

lib/functions/rootfs/qemu-static.sh

Lines changed: 80 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -193,35 +193,89 @@ function prepare_host_binfmt_qemu_cross() {
193193
}
194194

195195
function prepare_host_binfmt_qemu_cross_arm64_host_armhf_target() {
196-
display_alert "Trying to update binfmts - aarch64 mostly does 32-bit sans emulation, but Apple said no" "update-binfmts --enable qemu-${wanted_arch}" "debug"
197-
run_host_command_logged update-binfmts --enable "qemu-${wanted_arch}" "&>" "/dev/null" "||" "true" # don't fail nor produce output, which can be misleading.
196+
declare armhf_probe="/usr/arm-linux-gnueabihf/lib/ld-linux-armhf.so.3"
197+
198+
# If qemu-arm is already enabled in the kernel, the native probe
199+
# below would route through qemu and lie about COMPAT. Trust the
200+
# existing setup — admin or packaged service intended it.
201+
if [[ -e /proc/sys/fs/binfmt_misc/qemu-arm ]] &&
202+
[[ "$(head -n1 /proc/sys/fs/binfmt_misc/qemu-arm 2> /dev/null)" == "enabled" ]]; then
203+
display_alert "qemu-arm already enabled in binfmt_misc" "trusting existing setup" "debug"
204+
return 0
205+
fi
206+
207+
# No active qemu-arm route. Probe CONFIG_COMPAT directly. `arch-test
208+
# arm` is unreliable here (probes ARMv5 EABI; COMPAT runs armhf —
209+
# EABI v5+; empirically broken on Ubuntu Noble / Ampere CAX). Direct
210+
# exec of ld-linux-armhf (from gcc-arm-linux-gnueabihf, an armbian
211+
# host build dep when target_arch=armhf|all) is authoritative.
212+
if [[ -x "${armhf_probe}" ]] && "${armhf_probe}" --help > /dev/null 2>&1; then
213+
display_alert "Host kernel can run armhf natively (CONFIG_COMPAT)" "no qemu-arm setup needed" "debug"
214+
return 0
215+
fi
216+
217+
# ld-linux-armhf may be absent on cross builds whose target isn't
218+
# armhf (gcc-arm-linux-gnueabihf isn't pulled in then). Fall back to
219+
# arch-test to avoid degraded host-capability detection on those
220+
# flows; on Ampere CAX it reports false-negative but the probe above
221+
# already covered the armhf-target case where it matters most.
222+
if [[ ! -x "${armhf_probe}" ]] && command -v arch-test > /dev/null 2>&1 && arch-test arm > /dev/null 2>&1; then
223+
display_alert "Host can run armhf (arch-test fallback)" "no qemu-arm setup needed" "debug"
224+
return 0
225+
fi
226+
227+
# No native COMPAT — need qemu-arm. Prefer a packaged descriptor
228+
# (qemu-user-binfmt on resolute installs `/usr/bin/qemu-arm`;
229+
# qemu-user-static elsewhere uses the -static suffix). Overwriting
230+
# it would break the resolute interpreter path.
231+
if [[ -f /usr/share/binfmts/qemu-arm ]]; then
232+
# Three-step recovery: re-import the descriptor into binfmt-support's
233+
# admin DB (handles stale/empty DB where --enable would fail with
234+
# "not in database"); --enable activates the format; force-sync via
235+
# /proc afterwards if the kernel entry was externally toggled to 0.
236+
run_host_command_logged update-binfmts --import qemu-arm 2> /dev/null || true
237+
run_host_command_logged update-binfmts --enable qemu-arm || true
238+
[[ -e /proc/sys/fs/binfmt_misc/qemu-arm ]] && echo 1 > /proc/sys/fs/binfmt_misc/qemu-arm 2> /dev/null || true
239+
if [[ -e /proc/sys/fs/binfmt_misc/qemu-arm ]] &&
240+
[[ "$(head -n1 /proc/sys/fs/binfmt_misc/qemu-arm 2> /dev/null)" == "enabled" ]]; then
241+
display_alert "qemu-arm enabled via packaged descriptor" "leaving package-provided setup intact" "debug"
242+
return 0
243+
fi
244+
exit_with_error "/usr/share/binfmts/qemu-arm exists but qemu-arm could not be enabled — packaged interpreter likely missing. Reinstall qemu-user-binfmt (resolute) / qemu-user-static, or remove the descriptor and retry."
245+
fi
246+
247+
# Kernel entry exists but disabled, no descriptor on host. The kernel
248+
# keeps the magic/mask in memory once registered; only the enabled
249+
# flag toggles. Try `echo 1 > /proc/...` before giving up — that
250+
# repairs the common "someone toggled it off" state without needing
251+
# the descriptor file back.
252+
if [[ -e /proc/sys/fs/binfmt_misc/qemu-arm ]]; then
253+
echo 1 > /proc/sys/fs/binfmt_misc/qemu-arm 2> /dev/null || true
254+
if [[ "$(head -n1 /proc/sys/fs/binfmt_misc/qemu-arm 2> /dev/null)" == "enabled" ]]; then
255+
display_alert "qemu-arm re-enabled via /proc" "kernel state restored without descriptor" "debug"
256+
return 0
257+
fi
258+
exit_with_error "qemu-arm kernel entry present but cannot be re-enabled and no descriptor to re-register from. Reinstall qemu-user-binfmt / qemu-user-static and retry."
259+
fi
260+
261+
# Apple-Silicon-like (no COMPAT, no qemu pkg): hand-roll the descriptor.
262+
display_alert "arm64 host can't run armhf natively (no CONFIG_COMPAT?)" "importing+enabling qemu-arm" "debug"
263+
cat <<- BINFMT_ARM_MAGIC > /usr/share/binfmts/qemu-arm
264+
package qemu-user-static
265+
interpreter /usr/bin/qemu-arm-static
266+
magic \x7f\x45\x4c\x46\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28\x00
267+
offset 0
268+
mask \xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff
269+
credentials yes
270+
fix_binary no
271+
preserve yes
272+
BINFMT_ARM_MAGIC
273+
run_host_command_logged update-binfmts --import qemu-arm
274+
run_host_command_logged update-binfmts --enable qemu-arm
198275

199276
if [[ "${SHOW_DEBUG}" == "yes" ]]; then
200277
display_alert "Debugging arch-test" "full output" "debug"
201278
run_host_command_logged arch-test "||" true
202279
fi
203-
204-
# to check, we use arch-test; if will return 0 if _either_ the host can natively run armhf, or if qemu-arm is correctly working.
205-
if arch-test arm; then
206-
display_alert "Host can run armhf natively or emulation is correctly setup already" "no need to enable qemu-arm" "debug"
207-
else
208-
display_alert "arm64 host can't run armhf natively" "importing enabling qemu-arm" "debug"
209-
cat <<-BINFMT_ARM_MAGIC >/usr/share/binfmts/qemu-arm
210-
package qemu-user-static
211-
interpreter /usr/bin/qemu-arm-static
212-
magic \x7f\x45\x4c\x46\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28\x00
213-
offset 0
214-
mask \xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff
215-
credentials yes
216-
fix_binary no
217-
preserve yes
218-
BINFMT_ARM_MAGIC
219-
run_host_command_logged update-binfmts --import "qemu-${wanted_arch}"
220-
run_host_command_logged update-binfmts --enable "qemu-${wanted_arch}"
221-
222-
# Test again using arch-test.
223-
display_alert "Checking if arm 32-bit emulation on arm64 works after enabling" "qemu-arm emulation" "info"
224-
run_host_command_logged arch-test arm
225-
display_alert "arm 32-bit emulation on arm64" "has been correctly setup" "cachehit"
226-
fi
280+
display_alert "arm 32-bit emulation on arm64" "has been set up via qemu-arm" "cachehit"
227281
}

0 commit comments

Comments
 (0)