Skip to content

Commit d266fbc

Browse files
committed
Post linker, delayed relocations, v1: Allows for transitive shared library resolution from patch objects
1 parent c15001e commit d266fbc

8 files changed

Lines changed: 467 additions & 72 deletions

File tree

Makefile

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
BUILD_DIR = './build'
22
INTERP_PATH = $(PWD)/build/shiva
33
PATCH_PATH = "modules/aarch64_patches"
4-
GCC_OPTS= -fPIC -ggdb -c
4+
GCC_OPTS= -fPIC -ggdb -c
55
OBJ_LIST=shiva.o shiva_util.o shiva_signal.o shiva_ulexec.o shiva_auxv.o \
66
shiva_module.o shiva_trace.o shiva_trace_thread.o shiva_error.o shiva_maps.o shiva_analyze.o \
7-
shiva_callsite.o shiva_target.o shiva_xref.o shiva_transform.o
7+
shiva_callsite.o shiva_target.o shiva_xref.o shiva_transform.o shiva_so.o shiva_post_linker.o
88
STATIC_LIBS=/opt/elfmaster/lib/libelfmaster.a libcapstone.a
99
CC=gcc
1010
MUSL=musl-gcc
@@ -27,6 +27,8 @@ interp:
2727
$(CC) $(GCC_OPTS) shiva_target.c -o shiva_target.o
2828
$(CC) $(GCC_OPTS) shiva_xref.c -o shiva_xref.o
2929
$(CC) $(GCC_OPTS) shiva_transform.c -o shiva_transform.o
30+
$(CC) $(GCC_OPTS) shiva_so.c -o shiva_so.o
31+
$(CC) $(GCC_OPTS) -fno-stack-protector shiva_post_linker.c -o shiva_post_linker.o
3032
$(MUSL) -static -Wl,-undefined=system -Wl,-undefined=prctl -Wl,-undefined=pause -Wl,-undefined=puts -Wl,-undefined=putchar $(OBJ_LIST) $(STATIC_LIBS) -o $(BUILD_DIR)/shiva
3133

3234
shiva-ld:

PERFORMANCE.txt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# A document to describe thoughts on performance enhancements
2+
3+
1. Currently Shiva has to analyze every instruction within the .text
4+
to determine where it needs to relocate/relink external instructions
5+
from the target into the patch code, etc. This is the most time consuming
6+
part of Shiva, and can be fixed by implementing this analysis into shiva-ld
7+
the prelinker, and let it generate a new ELF section containing all of the
8+
necessary meta-data for external relinking.
9+
10+
2. We create a PLT entry in the module for every call. If there are 3 separate
11+
calls to a function, then 3 separate PLT entries are created. This creates
12+
a performance hit on runtime linking, and in the runtime post linker too.
13+

shiva.c

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,21 @@ shiva_interp_mode(struct shiva_ctx *ctx)
157157
}
158158
}
159159

160+
/*
161+
* Get the entry point of the target executable. Stored in AT_ENTRY
162+
* of the auxiliary vector.
163+
*/
164+
if (shiva_auxv_iterator_init(ctx, &auxv_iter, NULL) == false) {
165+
fprintf(stderr, "shiva_auxv_iterator_init failed\n");
166+
return false;
167+
}
168+
while (shiva_auxv_iterator_next(&auxv_iter, &auxv_entry) == SHIVA_ITER_OK) {
169+
if (auxv_entry.type == AT_ENTRY) {
170+
ctx->ulexec.entry_point = auxv_entry.value;
171+
shiva_debug("[1] Entry point: %#lx\n", entry_point);
172+
break;
173+
}
174+
}
160175
if (shiva_module_loader(ctx, ctx->module_path,
161176
&ctx->module.runtime, SHIVA_MODULE_F_RUNTIME) == false) {
162177
fprintf(stderr, "shiva_module_loader failed\n");
@@ -194,7 +209,7 @@ shiva_interp_mode(struct shiva_ctx *ctx)
194209
while (shiva_auxv_iterator_next(&auxv_iter, &auxv_entry) == SHIVA_ITER_OK) {
195210
if (auxv_entry.type == AT_ENTRY) {
196211
entry_point = auxv_entry.value;
197-
shiva_debug("Entry point: %#lx\n", entry_point);
212+
shiva_debug("[2] Entry point: %#lx\n", entry_point);
198213
break;
199214
}
200215
}

shiva.h

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
#define SHIVA_MODULE_F_INIT (1UL << 1) /* deprecated, meaningless */
6666
#define SHIVA_MODULE_F_DUMMY_TEXT (1UL << 2) /* Module has empty text region */
6767
#define SHIVA_MODULE_F_TRANSFORM (1UL << 3) /* Module has transform records */
68+
#define SHIVA_MODULE_F_DELAYED_RELOCS (1UL << 4) /* Module has delayed relocs to process */
6869

6970
#define SHIVA_DT_NEEDED (DT_LOOS + 10)
7071
#define SHIVA_DT_SEARCH (DT_LOOS + 11)
@@ -99,6 +100,19 @@
99100
"mov x0, #0 \n" \
100101
"ret " \
101102
:: "r" (stack), "r" (addr));
103+
104+
#define SHIVA_ULEXEC_TARGET_TRANSFER2(entry) __asm__ __volatile__ ("mov x9, %0\n" \
105+
"br x9" \
106+
:: "r"(entry));
107+
108+
#define SHIVA_ULEXEC_TARGET_TRANSFER(entry) __asm__ __volatile__("mov x30, %0 \n" \
109+
"ret " \
110+
:: "r"(entry));
111+
#define SHIVA_ULEXEC_TARGET_TRANSFER3(entry, arg0) __asm__ __volatile__ ("mov x0, %0\n" \
112+
"mov x9, %1\n" \
113+
"blr x9" \
114+
:: "r"(arg0), "r"(entry));
115+
102116
#endif
103117

104118
/*
@@ -338,6 +352,22 @@ typedef struct shiva_transform {
338352
TAILQ_ENTRY(shiva_transform) _linkage;
339353
} shiva_transform_t;
340354

355+
/*
356+
* Delayed relocatoin entries are not handled until
357+
* after ld-linux.so is completely done and passes
358+
* control back to Shiva AT_ENTRY, if needed.
359+
*/
360+
struct shiva_module_delayed_reloc {
361+
uint8_t *rel_unit;
362+
uint64_t rel_addr;
363+
uint64_t symval; /* The symbols value */
364+
struct elf_relocation rel; /* Original relocation: (May be updated/modified by Transforms though) */
365+
uint64_t flags;
366+
char *symname;
367+
char so_path[PATH_MAX];
368+
TAILQ_ENTRY(shiva_module_delayed_reloc) _linkage;
369+
} shiva_module_delayed_reloc_t;
370+
341371
struct shiva_module {
342372
int fd;
343373
uint64_t flags;
@@ -369,12 +399,14 @@ struct shiva_module {
369399
TAILQ_HEAD(, shiva_module_section_mapping) section_maplist;
370400
TAILQ_HEAD(, shiva_module_plt_entry) plt_list;
371401
TAILQ_HEAD(, shiva_transform) transform_list;
402+
TAILQ_HEAD(, shiva_module_delayed_reloc) delayed_reloc_list;
372403
} tailq;
373404
struct {
374405
struct hsearch_data bss;
375406
struct hsearch_data got;
376407
} cache;
377408
shiva_linking_mode_t mode;
409+
struct shiva_ctx *ctx; /* this is a pointer back to the main context */
378410
};
379411

380412
typedef struct shiva_trace_regset_x86_64 {
@@ -535,6 +567,9 @@ bool shiva_maps_validate_addr(shiva_ctx_t *, uint64_t);
535567
void shiva_maps_iterator_init(shiva_ctx_t *, shiva_maps_iterator_t *);
536568
shiva_iterator_res_t shiva_maps_iterator_next(shiva_maps_iterator_t *, struct shiva_mmap_entry *);
537569
bool shiva_maps_get_base(shiva_ctx_t *, uint64_t *);
570+
bool shiva_maps_get_so_base(struct shiva_ctx *, char *,
571+
uint64_t *);
572+
538573
/*
539574
* shiva_callsite.c
540575
*/
@@ -772,4 +807,15 @@ shiva_iterator_res_t shiva_xref_iterator_next(struct shiva_xref_iterator *, stru
772807
*/
773808
bool shiva_tf_process_transforms(struct shiva_module *, uint8_t *,
774809
struct elf_section section, uint64_t *segment_offset);
810+
811+
/*
812+
* shiva_so.c
813+
*/
814+
bool shiva_so_resolve_symbol(struct shiva_module *, char *, struct elf_symbol *,
815+
char **);
816+
817+
/*
818+
* shiva_post_linker.c
819+
*/
820+
void shiva_post_linker(void);
775821
#endif

shiva_maps.c

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,33 @@ shiva_maps_get_base(struct shiva_ctx *ctx, uint64_t *out)
2727
return false;
2828
}
2929

30+
bool
31+
shiva_maps_get_so_base(struct shiva_ctx *ctx, char *so_path,
32+
uint64_t *out)
33+
{
34+
FILE *fp;
35+
char buf[PATH_MAX];
36+
char *p;
37+
38+
fp = fopen("/proc/self/maps", "r");
39+
if (fp == NULL) {
40+
perror("fopen");
41+
return false;
42+
}
43+
while (fgets(buf, sizeof(buf), fp) != NULL) {
44+
if (strstr(buf, so_path) == NULL)
45+
continue;
46+
if (strstr(buf, "r-xp") == NULL)
47+
continue;
48+
p = strchr(buf, '-');
49+
*p = '\0';
50+
*out = strtoul(buf, NULL, 16);
51+
fclose(fp);
52+
return true;
53+
}
54+
fclose(fp);
55+
return false;
56+
}
3057
/*
3158
* Checking if 'addr' is a valid address mapping.
3259
* It's valid if it exists in /proc/pid/maps, as long as it
@@ -95,10 +122,10 @@ shiva_maps_build_list(struct shiva_ctx *ctx)
95122
if (strstr(buf, "r----") != NULL) {
96123
if (ctx->shiva_path == NULL) {
97124
p = strchr(tmp, '/');
98-
ctx->shiva_path = shiva_malloc(PATH_MAX + 1);
99-
for (i = 0; *p != '\n' && *p != '\0'; p++, i++)
100-
ctx->shiva_path[i] = *p;
101-
ctx->shiva_path[i] = '\0';
125+
ctx->shiva_path = shiva_malloc(PATH_MAX + 1);
126+
for (i = 0; *p != '\n' && *p != '\0'; p++, i++)
127+
ctx->shiva_path[i] = *p;
128+
ctx->shiva_path[i] = '\0';
102129
}
103130
}
104131
entry->mmap_type = SHIVA_MMAP_TYPE_SHIVA;

0 commit comments

Comments
 (0)