Skip to content
This repository was archived by the owner on Jan 6, 2025. It is now read-only.

Commit 2c897b6

Browse files
committed
Add specialized code to handle relocation of LEA
1 parent 02770fc commit 2c897b6

13 files changed

+475
-148
lines changed

src/disasm_wrapper.c

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ intercept_disasm_next_instruction(struct intercept_disasm_context *context,
209209
{
210210
static const unsigned char endbr64[] = {0xf3, 0x0f, 0x1e, 0xfa};
211211

212-
struct intercept_disasm_result result = {0, };
212+
struct intercept_disasm_result result = {.address = code, 0, };
213213
const unsigned char *start = code;
214214
size_t size = (size_t)(context->end - code + 1);
215215
uint64_t address = (uint64_t)code;
@@ -227,8 +227,6 @@ intercept_disasm_next_instruction(struct intercept_disasm_context *context,
227227

228228
if (!cs_disasm_iter(context->handle, &start, &size,
229229
&address, context->insn)) {
230-
result.is_set = false;
231-
result.length = 0;
232230
return result;
233231
}
234232

@@ -300,6 +298,22 @@ intercept_disasm_next_instruction(struct intercept_disasm_context *context,
300298
check_op(&result, context->insn->detail->x86.operands + op_i,
301299
code);
302300

301+
result.is_lea_rip = (context->insn->id == X86_INS_LEA &&
302+
result.has_ip_relative_opr);
303+
304+
if (result.is_lea_rip) {
305+
/*
306+
* Extract the four bits from the encoding, which
307+
* specify the destination register.
308+
*/
309+
310+
/* one bit from the REX prefix */
311+
result.arg_register_bits = ((code[0] & 4) << 1);
312+
313+
/* three bits from the ModRM byte */
314+
result.arg_register_bits |= ((code[2] >> 3) & 7);
315+
}
316+
303317
result.is_set = true;
304318

305319
return result;

src/disasm_wrapper.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
#include <stdint.h>
5050

5151
struct intercept_disasm_result {
52+
const unsigned char *address;
5253

5354
bool is_set;
5455

@@ -66,6 +67,18 @@ struct intercept_disasm_result {
6667
/* as of now this only refers to endbr64 */
6768
bool is_endbr;
6869

70+
/*
71+
* Flag marking lea instructions setting a 64 bit register to a
72+
* RIP relative address. They can be relocated -- but by simple memcpy.
73+
*/
74+
bool is_lea_rip;
75+
76+
/*
77+
* The X86 encoding of 64 bit register being set in an instruction
78+
* marked above as is_lea_rip.
79+
*/
80+
unsigned char arg_register_bits;
81+
6982
/* call instruction */
7083
bool is_call;
7184

src/intercept.c

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -427,14 +427,39 @@ analyze_object(struct dl_phdr_info *info, size_t size, void *data)
427427
patches->base_addr = (unsigned char *)info->dlpi_addr;
428428
patches->path = path;
429429
find_syscalls(patches);
430-
allocate_trampoline_table(patches);
431-
create_patch_wrappers(patches);
432430

433431
return 0;
434432
}
435433

436434
const char *cmdline;
437435

436+
static unsigned char asm_wrapper_space[0x100000];
437+
static unsigned char *next_asm_wrapper_space = asm_wrapper_space + PAGE_SIZE;
438+
439+
static bool
440+
is_asm_wrapper_space_full(void)
441+
{
442+
return next_asm_wrapper_space + asm_wrapper_tmpl_size + 256 >
443+
asm_wrapper_space + sizeof(asm_wrapper_space);
444+
}
445+
446+
/*
447+
* mprotect_asm_wrappers
448+
* The code generated into the data segment at the asm_wrapper_space
449+
* array is not executable by default. This routine sets that memory region
450+
* to be executable, must called before attempting to execute any patched
451+
* syscall.
452+
*/
453+
void
454+
mprotect_asm_wrappers(void)
455+
{
456+
mprotect_no_intercept(
457+
round_down_address(asm_wrapper_space + PAGE_SIZE),
458+
sizeof(asm_wrapper_space) - PAGE_SIZE,
459+
PROT_READ | PROT_EXEC,
460+
"mprotect_asm_wrappers PROT_READ | PROT_EXEC");
461+
}
462+
438463
/*
439464
* intercept - This is where the highest level logic of hotpatching
440465
* is described. Upon startup, this routine looks for libc, and libpthread.
@@ -467,6 +492,12 @@ intercept(int argc, char **argv)
467492
if (!libc_found)
468493
xabort("libc not found");
469494

495+
for (unsigned i = 0; i < objs_count; ++i) {
496+
if (objs[i].count > 0 && is_asm_wrapper_space_full())
497+
xabort("not enough space in asm_wrapper_space");
498+
allocate_trampoline_table(objs + i);
499+
create_patch_wrappers(objs + i, &next_asm_wrapper_space);
500+
}
470501
mprotect_asm_wrappers();
471502
for (unsigned i = 0; i < objs_count; ++i)
472503
activate_patches(objs + i);

src/intercept.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ void allocate_trampoline_table(struct intercept_desc *desc);
194194
void find_syscalls(struct intercept_desc *desc);
195195

196196
void init_patcher(void);
197-
void create_patch_wrappers(struct intercept_desc *desc);
197+
void create_patch_wrappers(struct intercept_desc *desc, unsigned char **dst);
198198
void mprotect_asm_wrappers(void);
199199

200200
/*
@@ -217,4 +217,15 @@ void create_jump(unsigned char opcode, unsigned char *from, void *to);
217217

218218
const char *cmdline;
219219

220+
#define PAGE_SIZE ((size_t)0x1000)
221+
222+
static inline unsigned char *
223+
round_down_address(unsigned char *address)
224+
{
225+
return (unsigned char *)(((uintptr_t)address) & ~(PAGE_SIZE - 1));
226+
}
227+
228+
/* The size of an asm wrapper instance */
229+
extern size_t asm_wrapper_tmpl_size;
230+
220231
#endif

src/intercept_util.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,15 @@
5050
#include <sched.h>
5151
#include <linux/limits.h>
5252

53+
void
54+
mprotect_no_intercept(void *addr, size_t len, int prot,
55+
const char *msg_on_error)
56+
{
57+
long result = syscall_no_intercept(SYS_mprotect, addr, len, prot);
58+
59+
xabort_on_syserror(result, msg_on_error);
60+
}
61+
5362
void *
5463
xmmap_anon(size_t size)
5564
{

src/intercept_util.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@
4747
*/
4848
long syscall_no_intercept(long syscall_number, ...);
4949

50+
void mprotect_no_intercept(void *addr, size_t len, int prot,
51+
const char *msg_on_error);
5052
/*
5153
* xmmap_anon - get new memory mapping
5254
*

0 commit comments

Comments
 (0)