Commit 7f4f0d9ea870 ("linux-user/arm: Implement __kernel_cmpxchg with host
atomics") switched to use qatomic_cmpxchg() to swap a word with the memory
content, but missed to endianess-swap the oldval and newval values when
emulating an armeb CPU, which expects words to be stored in big endian in
the guest memory.The bug can be verified with qemu >= v7.2 on any little-endian host, when starting the armeb binary of the upx program, which just hangs without this patch. Signed-off-by: Helge Deller <[email protected]> Cc: Richard Henderson <[email protected]> Cc: Peter Maydell <[email protected]> Cc: [email protected] Reported-by: "Markus F.X.J. Oberhumer" <[email protected]> Reported-by: John Reiser <[email protected]> Closes: https://github.com/upx/upx/issues/687 -- v2: - add tswap32() in arm_kernel_cmpxchg64_helper() diff --git a/linux-user/arm/cpu_loop.c b/linux-user/arm/cpu_loop.c index a992423257..0907cd8c15 100644 --- a/linux-user/arm/cpu_loop.c +++ b/linux-user/arm/cpu_loop.c @@ -117,8 +117,9 @@ static void arm_kernel_cmpxchg32_helper(CPUARMState *env) { uint32_t oldval, newval, val, addr, cpsr, *host_addr; - oldval = env->regs[0]; - newval = env->regs[1]; + /* endianess-swap if emulating armeb */ + oldval = tswap32(env->regs[0]); + newval = tswap32(env->regs[1]); addr = env->regs[2]; mmap_lock(); @@ -174,6 +175,10 @@ static void arm_kernel_cmpxchg64_helper(CPUARMState *env) return; } + /* endianess-swap if emulating armeb */ + oldval = tswap32(oldval); + newval = tswap32(newval); + #ifdef CONFIG_ATOMIC64 val = qatomic_cmpxchg__nocheck(host_addr, oldval, newval); cpsr = (val == oldval) * CPSR_C;
