Skip to content

Commit 4383883

Browse files
author
Rich Welch
committed
memory_patcher: Add ability to detect patched memory
Adapt the memory patching code to add detection logic so we can detect when memory has already been patched. Look for this condition in patcher_open() and relay the return code OPAL_ERR_RESOURCE_BUSY when the memory has been previously patched. If we detect this, also unapply any patches that we've applied. Signed-off-by: Rich Welch <rlwelch@amazon.com>
1 parent 2f7a3d9 commit 4383883

File tree

4 files changed

+121
-12
lines changed

4 files changed

+121
-12
lines changed

opal/mca/memory/patcher/memory_patcher_component.c

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -607,31 +607,31 @@ static int patcher_open(void)
607607
rc = opal_patcher->patch_symbol("mmap", (uintptr_t) intercept_mmap,
608608
(uintptr_t *) &original_mmap);
609609
if (OPAL_SUCCESS != rc) {
610-
return rc;
610+
goto err_patching;
611611
}
612612
#endif
613613

614614
#if defined(SYS_munmap)
615615
rc = opal_patcher->patch_symbol("munmap", (uintptr_t) intercept_munmap,
616616
(uintptr_t *) &original_munmap);
617617
if (OPAL_SUCCESS != rc) {
618-
return rc;
618+
goto err_patching;
619619
}
620620
#endif
621621

622622
#if defined(SYS_mremap)
623623
rc = opal_patcher->patch_symbol("mremap", (uintptr_t) intercept_mremap,
624624
(uintptr_t *) &original_mremap);
625625
if (OPAL_SUCCESS != rc) {
626-
return rc;
626+
goto err_patching;
627627
}
628628
#endif
629629

630630
#if defined(SYS_madvise)
631631
rc = opal_patcher->patch_symbol("madvise", (uintptr_t) intercept_madvise,
632632
(uintptr_t *) &original_madvise);
633633
if (OPAL_SUCCESS != rc) {
634-
return rc;
634+
goto err_patching;
635635
}
636636
#endif
637637

@@ -640,7 +640,7 @@ static int patcher_open(void)
640640
rc = opal_patcher->patch_symbol("shmat", (uintptr_t) intercept_shmat,
641641
(uintptr_t *) &original_shmat);
642642
if (OPAL_SUCCESS != rc) {
643-
return rc;
643+
goto err_patching;
644644
}
645645
# endif
646646
#endif
@@ -650,7 +650,7 @@ static int patcher_open(void)
650650
rc = opal_patcher->patch_symbol("shmdt", (uintptr_t) intercept_shmdt,
651651
(uintptr_t *) &original_shmdt);
652652
if (OPAL_SUCCESS != rc) {
653-
return rc;
653+
goto err_patching;
654654
}
655655
# endif
656656
#endif
@@ -659,6 +659,18 @@ static int patcher_open(void)
659659
rc = opal_patcher->patch_symbol("brk", (uintptr_t) intercept_brk, (uintptr_t *) &original_brk);
660660
#endif
661661

662+
if (OPAL_SUCCESS != rc) {
663+
goto err_patching;
664+
}
665+
666+
return OPAL_SUCCESS;
667+
668+
err_patching:
669+
/* In the case we had a problem patching, set this flag to 0 so we do not
670+
directly return OPAL_SUCCESS if we call patcher_open() again. */
671+
was_executed_already = 0;
672+
opal_patcher_base_restore_all();
673+
662674
return rc;
663675
}
664676

opal/mca/patcher/base/base.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ OBJ_CLASS_DECLARATION(mca_patcher_base_patch_t);
6363
*/
6464
OPAL_DECLSPEC extern mca_base_framework_t opal_patcher_base_framework;
6565
OPAL_DECLSPEC int opal_patcher_base_select(void);
66+
OPAL_DECLSPEC int opal_patcher_base_restore_all(void);
6667
OPAL_DECLSPEC int mca_patcher_base_patch_hook(mca_patcher_base_module_t *module, uintptr_t hook);
6768
OPAL_DECLSPEC void mca_base_patcher_patch_apply_binary(mca_patcher_base_patch_t *patch);
6869

opal/mca/patcher/base/patcher_base_frame.c

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,17 +54,35 @@ int opal_patcher_base_select(void)
5454
return OPAL_SUCCESS;
5555
}
5656

57-
static int opal_patcher_base_close(void)
57+
int opal_patcher_base_restore_all(void)
5858
{
59+
mca_patcher_base_patch_t *patch, *patch_next;
60+
5961
if (opal_patcher == &empty_module) {
6062
return OPAL_SUCCESS;
6163
}
6264

63-
mca_patcher_base_patch_t *patch;
64-
OPAL_LIST_FOREACH_REV (patch, &opal_patcher->patch_list, mca_patcher_base_patch_t) {
65-
patch->patch_restore(patch);
65+
opal_mutex_lock(&opal_patcher->patch_list_mutex);
66+
67+
OPAL_LIST_FOREACH_SAFE_REV(patch, patch_next, &opal_patcher->patch_list, mca_patcher_base_patch_t) {
68+
patch->patch_restore (patch);
69+
opal_list_remove_item(&opal_patcher->patch_list, &patch->super);
70+
OBJ_RELEASE(patch);
71+
}
72+
73+
opal_mutex_unlock(&opal_patcher->patch_list_mutex);
74+
75+
return OPAL_SUCCESS;
76+
}
77+
78+
static int opal_patcher_base_close(void)
79+
{
80+
if (opal_patcher == &empty_module) {
81+
return OPAL_SUCCESS;
6682
}
6783

84+
opal_patcher_base_restore_all();
85+
6886
OPAL_LIST_DESTRUCT(&opal_patcher->patch_list);
6987
OBJ_DESTRUCT(&opal_patcher->patch_list_mutex);
7088

opal/mca/patcher/overwrite/patcher_overwrite_module.c

Lines changed: 80 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ static int mca_patcher_overwrite_apply_patch(mca_patcher_base_patch_t *patch)
5757
return OPAL_SUCCESS;
5858
}
5959

60-
/* end of #if defined(__i386__) || defined(__x86_64__) || defined(__ia64__) */
60+
/* end of #if defined(__i386__) || defined(__x86_64__) */
6161
// ------------------------------------------------- PPC equivalent:
6262
#elif (OPAL_ASSEMBLY_ARCH == OPAL_POWERPC32) || (OPAL_ASSEMBLY_ARCH == OPAL_POWERPC64)
6363

@@ -214,6 +214,78 @@ static int mca_patcher_overwrite_apply_patch(mca_patcher_base_patch_t *patch)
214214

215215
#endif
216216

217+
/*
218+
* The logic in this function for each platform is based on code from
219+
* mca_patcher_overwrite_apply_patch(). There are 2 general approaches:
220+
* 1: Directly check constant instructions (ignoring addresses as parameters)
221+
* 2: Generate a bit mask by passing min and max values to underlying helper
222+
* functions and negate the XOR'ed results. These results can be used to
223+
* mask off transient values (like addresess) and non-instruction values
224+
* (like register contents). Once the masks are applied, the results are
225+
* compared against the min values directly to check for equality. If equal,
226+
* we consider the memory to be previously patched.
227+
*/
228+
static bool mca_patcher_is_function_patched(unsigned char *target)
229+
{
230+
231+
#if (OPAL_ASSEMBLY_ARCH == OPAL_IA32)
232+
return (*(unsigned char *)target == 0xe9);
233+
#elif (OPAL_ASSEMBLY_ARCH == OPAL_X86_64)
234+
return (
235+
(*(unsigned short*)(target + 0) == 0xbb49) &&
236+
(*(unsigned char* )(target +10) == 0x41 ) &&
237+
(*(unsigned char* )(target +11) == 0xff ) &&
238+
(*(unsigned char* )(target +12) == 0xe3 )
239+
);
240+
#elif (OPAL_ASSEMBLY_ARCH == OPAL_POWERPC32 ) || (OPAL_ASSEMBLY_ARCH == OPAL_POWERPC64)
241+
const unsigned int gr_max = 0xF; //11 is used in our patching code, but is the max 4 or 5 bits?
242+
const unsigned int addr_max = 0xFFFF;
243+
unsigned int addis_base = addis( 0, 0, 0);
244+
unsigned int addis_mask = ~(addis_base ^ addis( gr_max, 0, addr_max));
245+
unsigned int ori_base = ori( 0, 0, 0);
246+
unsigned int ori_mask = ~( ori_base ^ ori( gr_max, gr_max, addr_max));
247+
unsigned int mtspr_base = mtspr( 9, 0); // 9 = CTR
248+
unsigned int mtspr_mask = ~(mtspr_base ^ mtspr( 9, gr_max));
249+
unsigned int bcctr_base = bcctr(20, 0, 0); // 20 = always
250+
unsigned int bcctr_mask = ~(bcctr_base ^ bcctr(20, 0, 0));
251+
#if (OPAL_ASSEMBLY_ARCH == OPAL_POWERPC32)
252+
253+
return (
254+
((*(unsigned int *) (target + 0 )) & addis_mask) == addis_base &&
255+
((*(unsigned int *) (target + 4 )) & ori_mask) == ori_base &&
256+
((*(unsigned int *) (target + 8 )) & mtspr_mask) == mtspr_base &&
257+
((*(unsigned int *) (target + 12)) & bcctr_mask) == bcctr_base
258+
);
259+
#else
260+
unsigned int rldicr_base = rldicr( 0, 0, 32, 31);
261+
unsigned int rldicr_mask = ~(rldicr_base ^ rldicr( gr_max, gr_max, 32, 31));
262+
unsigned int oris_base = oris( 0, 0, 0);
263+
unsigned int oris_mask = ~(oris_base ^ oris( gr_max, gr_max, addr_max));
264+
265+
return (
266+
((*(unsigned int *) (target + 0 )) & addis_mask) == addis_base &&
267+
((*(unsigned int *) (target + 4 )) & ori_mask) == ori_base &&
268+
((*(unsigned int *) (target + 8 )) & rldicr_mask) == rldicr_base &&
269+
((*(unsigned int *) (target + 12)) & oris_mask) == oris_base &&
270+
((*(unsigned int *) (target + 16)) & ori_mask) == ori_base &&
271+
((*(unsigned int *) (target + 20)) & mtspr_mask) == mtspr_base &&
272+
((*(unsigned int *) (target + 24)) & bcctr_mask) == bcctr_base
273+
);
274+
#endif
275+
#elif defined(__aarch64__)
276+
uint32_t mov_mask=~((0xFFFF << 5) | 0x1F);
277+
uint32_t br_mask=~(0x1F << 5);
278+
279+
return (
280+
((*(uint32_t *) (target + 0)) & mov_mask) == mov(0, 3, 0) &&
281+
((*(uint32_t *) (target + 4)) & mov_mask) == movk(0, 2, 0) &&
282+
((*(uint32_t *) (target + 8)) & mov_mask) == movk(0, 1, 0) &&
283+
((*(uint32_t *) (target + 12)) & mov_mask) == movk(0, 0, 0) &&
284+
((*(uint32_t *) (target + 16)) & br_mask) == br(0)
285+
);
286+
#endif
287+
}
288+
217289
static int mca_patcher_overwrite_patch_address(uintptr_t sys_addr, uintptr_t hook_addr)
218290
{
219291
mca_patcher_base_patch_t *patch;
@@ -268,7 +340,13 @@ static int mca_patcher_overwrite_patch_symbol(const char *func_symbol_name, uint
268340
*func_old_addr = 0;
269341
}
270342

271-
return mca_patcher_overwrite_patch_address(old_addr, func_new_addr);
343+
if (mca_patcher_is_function_patched((unsigned char*)old_addr)) {
344+
opal_output_verbose(10, 0, "function %s is already patched; stopping further patching\n",
345+
func_symbol_name);
346+
return OPAL_ERR_RESOURCE_BUSY;
347+
} else {
348+
return mca_patcher_overwrite_patch_address(old_addr, func_new_addr);
349+
}
272350
}
273351

274352
mca_patcher_base_module_t mca_patcher_overwrite_module = {

0 commit comments

Comments
 (0)