Skip to content

Commit 854ac13

Browse files
standard apis
1 parent 3f9ded8 commit 854ac13

1 file changed

Lines changed: 70 additions & 79 deletions

File tree

echion/danger.cc

Lines changed: 70 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -1,96 +1,79 @@
11
#include <echion/danger.h>
2-
3-
#include <cstdio>
2+
#include <echion/state.h>
43

54
#include <algorithm>
5+
#include <cassert>
66
#include <cerrno>
7-
8-
#include <echion/state.h>
7+
#include <csetjmp>
8+
#include <cstdio>
9+
#include <sys/mman.h>
10+
#include <signal.h>
11+
#include <string.h>
12+
#include <unistd.h>
913

1014
struct sigaction g_old_segv;
1115
struct sigaction g_old_bus;
1216

1317
thread_local ThreadAltStack t_altstack;
1418

15-
thread_local volatile sig_atomic_t t_faulted;
16-
thread_local volatile void* t_landing_ip;
19+
thread_local volatile sig_atomic_t t_faulted = 0;
1720

18-
void arm_landing(void* p) {
19-
t_landing_ip = p;
21+
// We "arm" by publishing a valid jmp env for this thread.
22+
thread_local sigjmp_buf t_jmpenv;
23+
thread_local volatile sig_atomic_t t_jmpenv_armed = 0;
24+
25+
static inline void arm_landing() {
26+
t_jmpenv_armed = 1;
2027
__asm__ __volatile__("" ::: "memory");
2128
}
2229

23-
void disarm_landing() {
30+
static inline void disarm_landing() {
2431
__asm__ __volatile__("" ::: "memory");
25-
t_landing_ip = nullptr;
32+
t_jmpenv_armed = 0;
2633
}
2734

28-
void segv_handler(int signo, siginfo_t*, void* uctx) {
29-
if (!t_landing_ip) {
30-
struct sigaction *old = (signo == SIGSEGV) ? &g_old_segv : &g_old_bus;
31-
32-
// Restore the previous handler and re-raise
33-
sigaction(signo, old, NULL);
35+
static void segv_handler(int signo, siginfo_t*, void*) {
36+
if (!t_jmpenv_armed) {
37+
struct sigaction* old = (signo == SIGSEGV) ? &g_old_segv : &g_old_bus;
38+
// Restore the previous handler and re-raise so default/old handling occurs.
39+
sigaction(signo, old, nullptr);
3440
raise(signo);
41+
return;
3542
}
3643

3744
t_faulted = 1;
3845

39-
ucontext_t* uc = reinterpret_cast<ucontext_t*>(uctx);
40-
#if defined(__APPLE__)
41-
42-
// macOS
43-
# if defined(__x86_64__)
44-
// RIP is in the saved general-purpose register set
45-
((ucontext_t*)uc)->uc_mcontext->__ss.__rip = (uint64_t)(uintptr_t)t_landing_ip;
46-
# elif defined(__i386__)
47-
((ucontext_t*)uc)->uc_mcontext->__ss.__eip = (uint32_t)(uintptr_t)t_landing_ip;
48-
# elif defined(__aarch64__)
49-
((ucontext_t*)uc)->uc_mcontext->__ss.__pc = (uint64_t)(uintptr_t)t_landing_ip;
50-
# else
51-
# error "Unsupported macOS architecture"
52-
# endif
53-
54-
#else
55-
56-
// Linux / other libcs
57-
# if defined(__x86_64__) && defined(REG_RIP)
58-
((ucontext_t*)uc)->uc_mcontext.gregs[REG_RIP] = (greg_t)(uintptr_t)t_landing_ip;
59-
# elif defined(__i386__) && defined(REG_EIP)
60-
((ucontext_t*)uc)->uc_mcontext.gregs[REG_EIP] = (greg_t)(uintptr_t)t_landing_ip;
61-
# elif defined(__aarch64__)
62-
((ucontext_t*)uc)->uc_mcontext.pc = (uintptr_t)t_landing_ip; // or gregs[REG_PC] depending on libc
63-
# else
64-
# error "Set instruction pointer not implemented for this architecture/libc"
65-
# endif
66-
67-
#endif
46+
// Jump back to the armed site. Use 1 so sigsetjmp returns nonzero.
47+
siglongjmp(t_jmpenv, 1);
6848
}
6949

70-
void ensure_altstack_for_this_thread() {
50+
static inline void ensure_altstack_for_this_thread() {
7151
t_altstack.ensure_installed();
7252
}
7353

7454
int init_segv_catcher() {
7555
ensure_altstack_for_this_thread();
7656

77-
// 1) Alternate signal stack so handler runs even if the thread's normal stack is bad.
78-
const size_t sz = 1 << 20; // 1 MiB is plenty for a tiny handler
79-
80-
void* mem = mmap(NULL, sz, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
57+
// Reserve a page of memory just like before (not strictly necessary here,
58+
// but kept to preserve behavior/footprint).
59+
const size_t sz = 1 << 20;
60+
void* mem = mmap(nullptr, sz, PROT_READ | PROT_WRITE,
61+
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
8162
if (mem == MAP_FAILED) {
8263
return -1;
8364
}
8465

85-
// 2) Install handler (SA_SIGINFO for the ucontext if you ever need it; SA_ONSTACK to use altstack)
8666
struct sigaction sa{};
8767
sa.sa_sigaction = segv_handler;
8868
sigemptyset(&sa.sa_mask);
69+
// SA_SIGINFO for 3-arg handler; SA_ONSTACK to run on alt stack.
8970
sa.sa_flags = SA_SIGINFO | SA_ONSTACK;
9071
if (sigaction(SIGSEGV, &sa, &g_old_segv) != 0) {
9172
return -1;
9273
}
93-
if (sigaction(SIGBUS, &sa, &g_old_bus) != 0) {
74+
if (sigaction(SIGBUS, &sa, &g_old_bus) != 0) {
75+
// Try to roll back SIGSEGV install on failure.
76+
sigaction(SIGSEGV, &g_old_segv, nullptr);
9477
return -1;
9578
}
9679

@@ -108,26 +91,34 @@ safe_memcpy_return_t safe_memcpy(void* dst, const void* src, size_t n) {
10891

10992
t_faulted = 0;
11093

111-
uint8_t* d = static_cast<uint8_t*>(dst);
112-
const uint8_t* s = static_cast<const uint8_t*>(src);
113-
safe_memcpy_return_t rem = n;
94+
auto* d = static_cast<uint8_t*>(dst);
95+
auto* s = static_cast<const uint8_t*>(src);
96+
safe_memcpy_return_t rem = static_cast<safe_memcpy_return_t>(n);
11497

115-
// Publish landing target for the handler
116-
arm_landing(&&landing);
98+
// Arm and capture a landing site. Save/restore signal mask with savesigs=1.
99+
arm_landing();
100+
if (sigsetjmp(t_jmpenv, /*savesigs=*/1) != 0) {
101+
// We arrived here from siglongjmp after a fault.
102+
goto landing;
103+
}
117104

118-
// Copy in page-bounded chunks (at most one fault per bad page)
105+
// Copy in page-bounded chunks (at most one fault per bad page).
119106
while (rem && !t_faulted) {
120-
safe_memcpy_return_t to_src_pg = 4096 - (reinterpret_cast<uintptr_t>(s) & 4095);
121-
safe_memcpy_return_t to_dst_pg = 4096 - (reinterpret_cast<uintptr_t>(d) & 4095);
107+
safe_memcpy_return_t to_src_pg =
108+
4096 - (static_cast<uintptr_t>(reinterpret_cast<uintptr_t>(s)) & 4095);
109+
safe_memcpy_return_t to_dst_pg =
110+
4096 - (static_cast<uintptr_t>(reinterpret_cast<uintptr_t>(d)) & 4095);
122111
safe_memcpy_return_t chunk = std::min(rem, std::min(to_src_pg, to_dst_pg));
123112

124113
// Optional early probe to fault before entering large memcpy
125114
(void)*reinterpret_cast<volatile const uint8_t*>(s);
126115

127-
// If this faults, we'll resume at `landing` label
128-
(void)memcpy(d, s, chunk);
116+
// If this faults, we'll siglongjmp back to the sigsetjmp above.
117+
(void)memcpy(d, s, static_cast<size_t>(chunk));
129118

130-
d += chunk; s += chunk; rem -= chunk;
119+
d += chunk;
120+
s += chunk;
121+
rem -= chunk;
131122
}
132123

133124
landing:
@@ -138,38 +129,38 @@ safe_memcpy_return_t safe_memcpy(void* dst, const void* src, size_t n) {
138129
return -1;
139130
}
140131

141-
return n;
132+
return static_cast<safe_memcpy_return_t>(n);
142133
}
143134

144135
#if defined PL_LINUX
145136
ssize_t safe_memcpy_wrapper(
146137
pid_t,
147-
const struct iovec *__dstvec,
138+
const struct iovec* __dstvec,
148139
unsigned long int __dstiovcnt,
149-
const struct iovec *__srcvec,
140+
const struct iovec* __srcvec,
150141
unsigned long int __srciovcnt,
151-
unsigned long int)
152-
{
142+
unsigned long int) {
153143
(void)__dstiovcnt;
154144
(void)__srciovcnt;
155145
assert(__dstiovcnt == 1);
156146
assert(__srciovcnt == 1);
157147

158-
return safe_memcpy(__dstvec->iov_base, __srcvec->iov_base, std::min(__dstvec->iov_len, __srcvec->iov_len));
148+
size_t to_copy = std::min(__dstvec->iov_len, __srcvec->iov_len);
149+
return safe_memcpy(__dstvec->iov_base, __srcvec->iov_base, to_copy);
159150
}
160151
#elif defined PL_DARWIN
161-
kern_return_t safe_memcpy_wrapper
162-
(
163-
vm_map_read_t target_task,
164-
mach_vm_address_t address,
165-
mach_vm_size_t size,
166-
mach_vm_address_t data,
167-
mach_vm_size_t *outsize
168-
) {
152+
kern_return_t safe_memcpy_wrapper(
153+
vm_map_read_t target_task,
154+
mach_vm_address_t address,
155+
mach_vm_size_t size,
156+
mach_vm_address_t data,
157+
mach_vm_size_t* outsize) {
169158
(void)target_task;
170159

171-
auto copied = safe_memcpy(reinterpret_cast<void*>(address), reinterpret_cast<void*>(data), size);
160+
auto copied = safe_memcpy(reinterpret_cast<void*>(address),
161+
reinterpret_cast<void*>(data),
162+
static_cast<size_t>(size));
172163
*outsize = copied;
173164
return copied == size ? KERN_SUCCESS : KERN_FAILURE;
174165
}
175-
#endif
166+
#endif

0 commit comments

Comments
 (0)