Skip to content

Commit 813c377

Browse files
committed
https://github.com/advanced-microcode-patching/shiva/issues/19
1 parent b90a426 commit 813c377

7 files changed

Lines changed: 98 additions & 18 deletions

File tree

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
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 \
77
shiva_callsite.o shiva_target.o shiva_xref.o shiva_transform.o shiva_so.o shiva_post_linker.o

modules/aarch64_patches/fsplice/example6/fsplice_host.c

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,6 @@
11
#include <stdio.h>
22

3-
/*
4-
* .rodata string
5-
*/
63
const char *banner = "ElfMaster";
7-
8-
/*
9-
* .bss static buffer
10-
*/
114
char global_buf[255];
125

136
int foo(int num, char *str)

shiva.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -439,10 +439,20 @@ int main(int argc, char **argv, char **envp)
439439
if (mpath != NULL) {
440440
strcpy(ctx.module_path, mpath);
441441
} else {
442-
strcpy(ctx.module_path, SHIVA_DEFAULT_MODULE_PATH);
442+
/*
443+
* If the target binary has no shiva-prelinking
444+
* and we are executing it with /lib/shiva directly
445+
* then we can flip on ulexec mode. Shiva won't load
446+
* any modules. it will simply pass control to ld-linux.so
447+
* and effectively ulexec the target ELF binary.
448+
*/
449+
ctx.flags |= SHIVA_OPTS_F_ULEXEC_ONLY;
443450
}
444451
}
445452

453+
if (ctx.flags & SHIVA_OPTS_F_ULEXEC_ONLY)
454+
goto transfer_control;
455+
446456
if (shiva_module_loader(&ctx, ctx.module_path,
447457
&ctx.module.runtime, SHIVA_MODULE_F_RUNTIME) == false) {
448458
fprintf(stderr, "shiva_module_loader failed\n");

shiva.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@
7070

7171
#define SHIVA_DT_NEEDED (DT_LOOS + 10)
7272
#define SHIVA_DT_SEARCH (DT_LOOS + 11)
73+
#define SHIVA_DT_ORIG_INTERP (DT_LOOS + 12)
7374

7475
#define SHIVA_DEFAULT_MODULE_PATH "/opt/shiva/modules/shakti.o"
7576

@@ -468,6 +469,7 @@ typedef struct shiva_ctx {
468469
int duplicate_pid;
469470
uint64_t duplicate_base;
470471
char *shiva_path; // path to /bin/shiva
472+
char orig_interp_path[PATH_MAX];
471473
union {
472474
struct shiva_trace_regset_x86_64 regset_x86_64;
473475
} regs;

shiva_target.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,6 @@ shiva_target_get_module_path(struct shiva_ctx *ctx, char *buf)
8787
return true;
8888
}
8989

90-
9190
/*
9291
* This function modifies the "live" dynamic segment in memory. It will modify
9392
* the first dynamic tag found of type 'tag' and change it to 'value'.

shiva_ulexec.c

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,31 @@ shiva_ulexec_total_segment_len(elfobj_t *elfobj, size_t *len)
256256
shiva_debug("Total mapping size: %#zu\n", *len);
257257
return true;
258258
}
259+
260+
bool
261+
shiva_ulexec_get_orig_interp(struct shiva_ctx *ctx, char *outbuf)
262+
{
263+
struct elf_dynamic_entry dyn;
264+
elf_dynamic_iterator_t dyn_iter;
265+
size_t len;
266+
bool res;
267+
268+
elf_dynamic_iterator_init(&ctx->elfobj, &dyn_iter);
269+
while (elf_dynamic_iterator_next(&dyn_iter, &dyn) == ELF_ITER_OK) {
270+
if (dyn.tag != SHIVA_DT_ORIG_INTERP)
271+
continue;
272+
res = shiva_target_copy_string(ctx, outbuf,
273+
(const char *)dyn.value, &len);
274+
if (res == false) {
275+
fprintf(stderr, "shiva_target_copy_string() failed at %#lx\n",
276+
dyn.value);
277+
return false;
278+
}
279+
break;
280+
}
281+
return true;
282+
}
283+
259284
/*
260285
* XXX -- We currently only support PIE binaries. This is very temporary.
261286
*/
@@ -422,8 +447,28 @@ shiva_ulexec_prep(struct shiva_ctx *ctx)
422447
shiva_auxv_iterator_t a_iter;
423448
struct shiva_auxv_entry a_entry;
424449

425-
if (elf_type(&ctx->elfobj) == ET_DYN) {
426-
interp = elf_interpreter_path(&ctx->elfobj);
450+
if (elf_linking_type(&ctx->elfobj) == ELF_LINKING_DYNAMIC) {
451+
/*
452+
* If the target binary is has been shiva-prelinked already,
453+
* then it's PT_INTERP segment will contain /lib/shiva. We
454+
* need the path of it's original interpreter "ld-linux.so"
455+
* so that we can prepare to map it into memory.
456+
*/
457+
if (shiva_target_has_prelinking(ctx) == true) {
458+
char interp_path[PATH_MAX];
459+
460+
if (shiva_ulexec_get_orig_interp(ctx, interp_path) == false) {
461+
fprintf(stderr, "shiva_target_get_orig_interp() failed\n");
462+
return false;
463+
}
464+
interp = interp_path;
465+
} else {
466+
interp = elf_interpreter_path(&ctx->elfobj);
467+
if (interp == NULL) {
468+
fprintf(stderr, "elf_interpreter_path() failed\n");
469+
return false;
470+
}
471+
}
427472
if (interp != NULL) {
428473
shiva_debug("Interp path: %s\n", interp);
429474
ctx->ulexec.flags |= SHIVA_F_ULEXEC_LDSO_NEEDED;

tools/shiva-ld/shiva-ld.c

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141

4242
#define SHIVA_DT_NEEDED DT_LOOS + 10
4343
#define SHIVA_DT_SEARCH DT_LOOS + 11
44+
#define SHIVA_DT_ORIG_INTERP DT_LOOS + 12
4445

4546
#define SHIVA_SIGNATURE 0x31f64
4647

@@ -69,6 +70,7 @@ struct shiva_prelink_ctx {
6970
char *output_exec;
7071
char *search_path;
7172
char *interp_path;
73+
char *orig_interp_path;
7274
struct {
7375
elfobj_t elfobj;
7476
} bin;
@@ -123,6 +125,8 @@ elf_segment_copy(elfobj_t *elfobj, uint8_t *dst, struct elf_segment segment)
123125
return true;
124126
}
125127

128+
#define NEW_DYN_COUNT 3
129+
126130
bool
127131
shiva_prelink(struct shiva_prelink_ctx *ctx)
128132
{
@@ -142,6 +146,19 @@ shiva_prelink(struct shiva_prelink_ctx *ctx)
142146
uint8_t *old_dynamic_segment;
143147
size_t old_dynamic_size, dynamic_index;
144148

149+
ctx->orig_interp_path = elf_interpreter_path(&ctx->bin.elfobj);
150+
if (ctx->orig_interp_path == NULL) {
151+
fprintf(stderr, "elf_interpreter_path() failed\n");
152+
return false;
153+
}
154+
/*
155+
* We must do this or it will get overwritten later by an strcpy
156+
*/
157+
ctx->orig_interp_path = strdup(ctx->orig_interp_path);
158+
if (ctx->orig_interp_path == NULL) {
159+
perror("strdup");
160+
return false;
161+
}
145162
if (elf_flags(&ctx->bin.elfobj, ELF_DYNAMIC_F) == false) {
146163
fprintf(stderr, "Currently we do not support static ELF executable\n");
147164
return false;
@@ -162,7 +179,7 @@ shiva_prelink(struct shiva_prelink_ctx *ctx)
162179
} else if (segment.type == PT_DYNAMIC) {
163180
found_dynamic = true;
164181
ctx->new_segment.dyn_size = elf_dtag_count(&ctx->bin.elfobj) * sizeof(ElfW(Dyn));
165-
ctx->new_segment.dyn_size += (sizeof(ElfW(Dyn)) * 2);
182+
ctx->new_segment.dyn_size += (sizeof(ElfW(Dyn)) * NEW_DYN_COUNT);
166183
ctx->new_segment.dyn_offset = 0;
167184

168185
old_dynamic_size = elf_dtag_count(&ctx->bin.elfobj) * sizeof(ElfW(Dyn));
@@ -183,9 +200,10 @@ shiva_prelink(struct shiva_prelink_ctx *ctx)
183200
/*
184201
* Make room for the two new additional dynamic entries
185202
*/
186-
ctx->new_segment.filesz += sizeof(ElfW(Dyn)) * 2;
203+
ctx->new_segment.filesz += sizeof(ElfW(Dyn)) * NEW_DYN_COUNT;
187204
ctx->new_segment.filesz += strlen(ctx->input_patch) + 1;
188205
ctx->new_segment.filesz += strlen(ctx->search_path) + 1;
206+
ctx->new_segment.filesz += strlen(ctx->orig_interp_path) + 1;
189207
/*
190208
* Mark the index of this segment so that we can modify it
191209
* to match the new dynamic segment location once we know it.
@@ -319,7 +337,9 @@ shiva_prelink(struct shiva_prelink_ctx *ctx)
319337
return false;
320338
}
321339

322-
ElfW(Dyn) dyn[3];
340+
#define NEW_DYN_ENTRY_SZ 4
341+
342+
ElfW(Dyn) dyn[NEW_DYN_ENTRY_SZ];
323343

324344
/*
325345
* Write out new dynamic entry for SHIVA_DT_SEARCH and
@@ -328,9 +348,13 @@ shiva_prelink(struct shiva_prelink_ctx *ctx)
328348
dyn[0].d_tag = SHIVA_DT_SEARCH;
329349
dyn[0].d_un.d_ptr = ctx->new_segment.vaddr + ctx->new_segment.dyn_size;
330350
dyn[1].d_tag = SHIVA_DT_NEEDED;
331-
dyn[1].d_un.d_ptr = ctx->new_segment.vaddr + ctx->new_segment.dyn_size + strlen(ctx->search_path) + 1;
332-
dyn[2].d_tag = DT_NULL;
333-
dyn[2].d_un.d_ptr = 0x0;
351+
dyn[1].d_un.d_ptr = ctx->new_segment.vaddr +
352+
ctx->new_segment.dyn_size + strlen(ctx->search_path) + 1;
353+
dyn[2].d_tag = SHIVA_DT_ORIG_INTERP;
354+
dyn[2].d_un.d_ptr = ctx->new_segment.vaddr + ctx->new_segment.dyn_size +
355+
strlen(ctx->search_path) + 1 + strlen(ctx->input_patch) + 1;
356+
dyn[3].d_tag = DT_NULL;
357+
dyn[3].d_un.d_ptr = 0x0;
334358

335359
if (write(fd, &dyn[0], sizeof(dyn)) < 0) {
336360
perror("write 4.");
@@ -345,6 +369,13 @@ shiva_prelink(struct shiva_prelink_ctx *ctx)
345369
return false;
346370
}
347371

372+
printf("Writing out original interp path: %s\n", ctx->orig_interp_path);
373+
374+
if (write(fd, ctx->orig_interp_path,
375+
strlen(ctx->orig_interp_path) + 1) < 0) {
376+
perror("write 7.");
377+
return false;
378+
}
348379
if (fchown(fd, st.st_uid, st.st_gid) < 0) {
349380
perror("fchown");
350381
return false;

0 commit comments

Comments
 (0)