/** * Modify the current syscall of @tracee as described by @modif * regarding the given @config. This function returns whether the * syscall was modified or not. */ static bool modify_syscall(Tracee *tracee, const Config *config, const Modif *modif) { size_t i, j; word_t syscall; assert(config != NULL); if (!needs_kompat(config, modif->expected_release)) return false; /* Check if this syscall is supported on this architecture. */ syscall = detranslate_sysnum(get_abi(tracee), modif->new_sysarg_num); if (syscall == SYSCALL_AVOIDER) return false; set_sysnum(tracee, modif->new_sysarg_num); /* Shift syscall arguments. */ for (i = 0; i < MAX_ARG_SHIFT; i++) { Reg sysarg = modif->shifts[i].sysarg; size_t nb_args = modif->shifts[i].nb_args; int offset = modif->shifts[i].offset; for (j = 0; j < nb_args; j++) { word_t arg = peek_reg(tracee, CURRENT, sysarg + j); poke_reg(tracee, sysarg + j + offset, arg); } } return true; }
/** * Overwrite the @tracee's current syscall number with @sysnum. Note: * this neutral value is automatically converted into the architecture * value. */ void set_sysnum(Tracee *tracee, Sysnum sysnum) { poke_reg(tracee, SYSARG_NUM, detranslate_sysnum(get_abi(tracee), sysnum)); }
word_t translate_brk_enter(Tracee *tracee) { word_t new_brk_address; size_t old_heap_size; size_t new_heap_size; if (heap_offset == 0) { heap_offset = sysconf(_SC_PAGE_SIZE); if ((int) heap_offset <= 0) heap_offset = 0x1000; } /* Non-fixed mmap pages might be placed right after the * emulated heap on some architectures. A solution is to * preallocate some space to ensure a minimal heap size. */ if (tracee->heap->prealloc_size == 0) tracee->heap->prealloc_size = MAX(PREALLOCATED_HEAP_SIZE, heap_offset); new_brk_address = peek_reg(tracee, CURRENT, SYSARG_1); DEBUG_BRK("brk(0x%lx)\n", new_brk_address); /* Allocate a new mapping for the emulated heap. */ if (tracee->heap->base == 0) { Sysnum sysnum; if (new_brk_address != 0) notice(tracee, WARNING, INTERNAL, "process %d is doing suspicious brk()", tracee->pid); /* I don't understand yet why mmap(2) fails (EFAULT) * on architectures that also have mmap2(2). Maybe * this former implies MAP_FIXED in such cases. */ sysnum = detranslate_sysnum(get_abi(tracee), PR_mmap2) != SYSCALL_AVOIDER ? PR_mmap2 : PR_mmap; set_sysnum(tracee, sysnum); poke_reg(tracee, SYSARG_1 /* address */, 0); poke_reg(tracee, SYSARG_2 /* length */, heap_offset + tracee->heap->prealloc_size); poke_reg(tracee, SYSARG_3 /* prot */, PROT_READ | PROT_WRITE); poke_reg(tracee, SYSARG_4 /* flags */, MAP_PRIVATE | MAP_ANONYMOUS); poke_reg(tracee, SYSARG_5 /* fd */, -1); poke_reg(tracee, SYSARG_6 /* offset */, 0); return 0; } /* The size of the heap can't be negative. */ if (new_brk_address < tracee->heap->base) { set_sysnum(tracee, PR_void); return 0; } new_heap_size = new_brk_address - tracee->heap->base; old_heap_size = tracee->heap->size; /* Clear the released memory in preallocated space, so it will be * in the expected state next time it will be reallocated. */ if (new_heap_size < old_heap_size && new_heap_size < tracee->heap->prealloc_size) { (void) clear_mem(tracee, tracee->heap->base + new_heap_size, MIN(old_heap_size, tracee->heap->prealloc_size) - new_heap_size); } /* No need to use mremap when both old size and new size are * in the preallocated space. */ if ( new_heap_size <= tracee->heap->prealloc_size && old_heap_size <= tracee->heap->prealloc_size) { tracee->heap->size = new_heap_size; set_sysnum(tracee, PR_void); return 0; } /* Ensure the preallocated space will never be released. */ new_heap_size = MAX(new_heap_size, tracee->heap->prealloc_size); old_heap_size = MAX(old_heap_size, tracee->heap->prealloc_size); /* Actually resizing. */ set_sysnum(tracee, PR_mremap); poke_reg(tracee, SYSARG_1 /* old_address */, tracee->heap->base - heap_offset); poke_reg(tracee, SYSARG_2 /* old_size */, old_heap_size + heap_offset); poke_reg(tracee, SYSARG_3 /* new_size */, new_heap_size + heap_offset); poke_reg(tracee, SYSARG_4 /* flags */, 0); poke_reg(tracee, SYSARG_5 /* new_address */, 0); return 0; }