[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Issues with modifying pc in a sigaction handler
From: |
Devin Hussey |
Subject: |
Issues with modifying pc in a sigaction handler |
Date: |
Tue, 13 Apr 2021 18:03:52 -0400 |
In a toy project I was doing
(https://github.com/easyaspi314/ThumbGolf), I found that qemu will
incorrectly handle modifying pc in a handler.
Specifically, on platforms with instruction alignment requirements
(most notably ARM), if you set the pc to an odd address, QEMU will
start reading unaligned instructions.
Naturally, this is frustrating when dealing with ARM Thumb functions
which have the lowest bit set when referenced, as you must manually
clear the Thumb bit instead of it being implicit on hardware.
The following code exhibits this bug for ARM:
---
#include <signal.h>
#include <ucontext.h>
#include <stdio.h>
static void hello(void)
{
printf("Hello,");
}
static void handler(int signo, siginfo_t *si, void *data)
{
ucontext_t *uc = (ucontext_t *)data;
// Effectively bl hello although we assume thumb state
uc->uc_mcontext.arm_lr = uc->uc_mcontext.arm_pc + 2 | 1;
uc->uc_mcontext.arm_pc = (unsigned long)&hello;
}
int main(void)
{
// Set up the signal handler
struct sigaction sa, osa;
sa.sa_flags = SA_ONSTACK | SA_RESTART | SA_NODEFER | SA_SIGINFO;
sa.sa_sigaction = handler;
sigaction(SIGILL, &sa, &osa);
sigaction(SIGTRAP, &sa, &osa);
// Throw a SIGILL, which we do a runtime patch to call hello().
// Make sure we mark the caller saved registers.
__asm__ ("udf #0" ::: "r0", "r1", "r2", "r3", "r12", "lr", "memory");
printf(" world!\n");
}
---
Compile with:
clang -O2 -march=armv7-a -mthumb file.c -static
(The same should happen with GCC).
On hardware (specifically, a Snapdragon 730g in Termux on Android 11),
the code prints "Hello, world!" and exits normally.
However, qemu-arm will get tripped up by the pc being odd, and execute this:
---
... snip
----------------
IN: main
0x00010288: 4c05 ldr r4, [pc, #0x14]
0x0001028a: de00 udf #0
----------------
IN: handler
0x000102a4: 4804 ldr r0, [pc, #0x10]
0x000102a6: 6dd1 ldr r1, [r2, #0x5c]
0x000102a8: 4478 add r0, pc
0x000102aa: 3102 adds r1, #2
0x000102ac: f041 0101 orr r1, r1, #1
0x000102b0: e9c2 1016 strd r1, r0, [r2, #0x58]
0x000102b4: 4770 bx lr
----------------
IN: __restore_rt
0x0004c36c: e3a070ad mov r7, #0xad
0x0004c370: ef000000 svc #0
----------------
IN: hello
0x000102bd: 7848 ldrb r0, [r1, #1]
0x000102bf: 0644 lsls r4, r0, #0x19
0x000102c1: 5cf0 ldrb r0, [r6, r3]
0x000102c3: 06bb lsls r3, r7, #0x1a
0x000102c5: 053e lsls r6, r7, #0x14
0x000102c7: f000 89b5 beq.w #0x90635
qemu: uncaught target signal 11 (Segmentation fault) - core dumped
---
Note the odd addresses in hello().
It should be interpreted as so, which happens when you manually clear
the Thumb bit:
---
0x000102b8: 4801 ldr r0, [pc, #4]
0x000102ba: 4478 add r0, pc
0x000102bc: f006
bb5c b.w #0x16978 (printf)
---
- Issues with modifying pc in a sigaction handler,
Devin Hussey <=