Ejemplo n.º 1
0
Archivo: mem.c Proyecto: matrach/PRoot
/**
 * Return the value of the word at the given @address in the @tracee's
 * memory space.  The caller must test errno to check if an error
 * occured.
 */
word_t peek_mem(const Tracee *tracee, word_t address)
{
	word_t result = 0;

#if defined(HAVE_PROCESS_VM)
	int status;
	struct iovec local;
	struct iovec remote;

	local.iov_base = &result;
	local.iov_len  = sizeof_word(tracee);

	remote.iov_base = (void *)address;
	remote.iov_len  = sizeof_word(tracee);

	errno = 0;
	status = process_vm_readv(tracee->pid, &local, 1, &remote, 1, 0);
	if (status > 0)
		return result;
	/* Fallback to ptrace if something went wrong.  */
#endif
	errno = 0;
	result = (word_t) ptrace(PTRACE_PEEKDATA, tracee->pid, address, NULL);

	/* Use only the 32 LSB when running a 32-bit process on a
	 * 64-bit kernel. */
	if (is_32on64_mode(tracee))
		result &= 0xFFFFFFFF;

	return result;
}
Ejemplo n.º 2
0
Archivo: mem.c Proyecto: BobbWu/PRoot
/**
 * Set the word at the given @address in the @tracee's memory space to
 * the given @value.  The caller must test errno to check if an error
 * occured.
 */
void poke_word(const Tracee *tracee, word_t address, word_t value)
{
	word_t tmp;

	if (belongs_to_heap_prealloc(tracee, address)) {
		errno = EFAULT;
		return;
	}

#if defined(HAVE_PROCESS_VM)
	int status;
	struct iovec local;
	struct iovec remote;

	/* Note: &value points to the 32 LSB on 64-bit little-endian
	 * architecture.  */
	local.iov_base = &value;
	local.iov_len  = sizeof_word(tracee);

	remote.iov_base = (void *)address;
	remote.iov_len  = sizeof_word(tracee);

	errno = 0;
	status = process_vm_writev(tracee->pid, &local, 1, &remote, 1, 0);
	if (status > 0)
		return;
	/* Fallback to ptrace if something went wrong.  */
#endif
	/* Don't overwrite the 32 MSB when running a 32-bit process on
	 * a 64-bit kernel. */
	if (is_32on64_mode(tracee)) {
		errno = 0;
		tmp = (word_t) ptrace(PTRACE_PEEKDATA, tracee->pid, address, NULL);
		if (errno != 0)
			return;

		value |= (tmp & 0xFFFFFFFF00000000ULL);
	}

	errno = 0;
	(void) ptrace(PTRACE_POKEDATA, tracee->pid, address, value);

	/* From ptrace(2) manual: "Unfortunately, under Linux,
	 * different variations of this fault will return EIO or
	 * EFAULT more or less arbitrarily."  */
	if (errno == EIO)
		errno = EFAULT;

	return;
}
Ejemplo n.º 3
0
/**
 * Fill @path with the content of @vectors, formatted according to
 * @ptracee's current ABI.
 */
static int fill_file_with_auxv(const Tracee *ptracee, const char *path,
			const ElfAuxVector *vectors)
{
	const ssize_t current_sizeof_word = sizeof_word(ptracee);
	ssize_t status;
	int fd = -1;
	int i;

	fd = open(path, O_WRONLY);
	if (fd < 0)
		return -1;

	i = 0;
	do {
		status = write(fd, &vectors[i].type, current_sizeof_word);
		if (status < current_sizeof_word) {
			status = -1;
			goto end;
		}

		status = write(fd, &vectors[i].value, current_sizeof_word);
		if (status < current_sizeof_word) {
			status = -1;
			goto end;
		}
	} while (vectors[i++].type != AT_NULL);

	status = 0;
end:
	if (fd >= 0)
		(void) close(fd);

	return status;
}
Ejemplo n.º 4
0
Archivo: mem.c Proyecto: BobbWu/PRoot
/**
 * Return the value of the word at the given @address in the @tracee's
 * memory space.  The caller must test errno to check if an error
 * occured.
 */
word_t peek_word(const Tracee *tracee, word_t address)
{
	word_t result = 0;

	if (belongs_to_heap_prealloc(tracee, address)) {
		errno = EFAULT;
		return 0;
	}

#if defined(HAVE_PROCESS_VM)
	int status;
	struct iovec local;
	struct iovec remote;

	local.iov_base = &result;
	local.iov_len  = sizeof_word(tracee);

	remote.iov_base = (void *)address;
	remote.iov_len  = sizeof_word(tracee);

	errno = 0;
	status = process_vm_readv(tracee->pid, &local, 1, &remote, 1, 0);
	if (status > 0)
		return result;
	/* Fallback to ptrace if something went wrong.  */
#endif
	errno = 0;
	result = (word_t) ptrace(PTRACE_PEEKDATA, tracee->pid, address, NULL);

	/* From ptrace(2) manual: "Unfortunately, under Linux,
	 * different variations of this fault will return EIO or
	 * EFAULT more or less arbitrarily."  */
	if (errno == EIO)
		errno = EFAULT;

	/* Use only the 32 LSB when running a 32-bit process on a
	 * 64-bit kernel. */
	if (is_32on64_mode(tracee))
		result &= 0xFFFFFFFF;

	return result;
}
Ejemplo n.º 5
0
Archivo: mem.c Proyecto: matrach/PRoot
/**
 * Set the word at the given @address in the @tracee's memory space to
 * the given @value.  The caller must test errno to check if an error
 * occured.
 */
void poke_mem(const Tracee *tracee, word_t address, word_t value)
{
	word_t tmp;

#if defined(HAVE_PROCESS_VM)
	int status;
	struct iovec local;
	struct iovec remote;

	/* Note: &value points to the 32 LSB on 64-bit little-endian
	 * architecture.  */
	local.iov_base = &value;
	local.iov_len  = sizeof_word(tracee);

	remote.iov_base = (void *)address;
	remote.iov_len  = sizeof_word(tracee);

	errno = 0;
	status = process_vm_writev(tracee->pid, &local, 1, &remote, 1, 0);
	if (status > 0)
		return;
	/* Fallback to ptrace if something went wrong.  */
#endif
	/* Don't overwrite the 32 MSB when running a 32-bit process on
	 * a 64-bit kernel. */
	if (is_32on64_mode(tracee)) {
		errno = 0;
		tmp = (word_t) ptrace(PTRACE_PEEKDATA, tracee->pid, address, NULL);
		if (errno != 0)
			return;

		value |= (tmp & 0xFFFFFFFF00000000ULL);
	}

	errno = 0;
	(void) ptrace(PTRACE_POKEDATA, tracee->pid, address, value);
	return;
}
Ejemplo n.º 6
0
int prepare_getsockname_chained_syscall(Tracee *tracee, Config *config, word_t sockfd, int is_socketcall) {
	int status = 0;
	word_t sock_addr, size_addr;
	struct sockaddr_un sockaddr;
	socklen_t size;

	size = sizeof(sockaddr);

	/* we check that it's the correct socket */
	if(sockfd != config->sockfd)
		return 0;

	/* we allocate a memory place to store the socket address.
	 * This is a buffer that will be filled by the getsockname() syscall.
	 */
	sock_addr = alloc_mem(tracee, sizeof(sockaddr));
	if (sock_addr == 0)
		return -EFAULT;
	size_addr = alloc_mem(tracee, sizeof(socklen_t));
	if(size_addr == 0)
		return -EFAULT;

	memset(&sockaddr, '\0', sizeof(sockaddr));

	/* we write the modified socket in this new address */
	status = write_data(tracee, sock_addr, &sockaddr, sizeof(sockaddr));
	if (status < 0)
		return status;
	status = write_data(tracee, size_addr, &size, sizeof(size));
	if (status < 0)
		return status;

	/* Only by using getsockname can we retrieve the port automatically
	 * assigned by the system to the socket.
	 */
	if (!is_socketcall) {
		status = register_chained_syscall(
				tracee, PR_getsockname,
				sockfd,  // SYS_ARG1, socket file descriptor.
				sock_addr,
				size_addr,
				0, 0, 0
		);
	} else {
		unsigned long args[6];
		
		args[0] = sockfd;
		args[1] = sock_addr;
		args[2] = size_addr;
		args[3] = 0;
		args[4] = 0;
		args[5] = 0;
		
		/* We allocate a little bloc of memory to store socketcall's arguments */
		word_t args_addr = alloc_mem(tracee, 6 * sizeof_word(tracee));
		
		status = write_data(tracee, args_addr, &args, 6 * sizeof_word(tracee));
	
		status = register_chained_syscall(
				tracee, PR_socketcall,
				SYS_GETSOCKNAME,
				args_addr,  // SYS_ARG1, socket file descriptor.
				0,
				0,
				0, 0
		);
	}
			
	if (status < 0)
		return status;
	//status = restart_original_syscall(tracee);
	//if (status < 0)
	//    return status;

	return 0;
}
Ejemplo n.º 7
0
/**
 * Convert @tracee->load_info into a load script, then transfer this
 * latter into @tracee's memory.
 */
static int transfer_load_script(Tracee *tracee)
{
	const word_t stack_pointer = peek_reg(tracee, CURRENT, STACK_POINTER);
	static word_t page_size = 0;
	static word_t page_mask = 0;

	word_t entry_point;

	size_t script_size;
	size_t strings_size;
	size_t string1_size;
	size_t string2_size;
	size_t string3_size;
	size_t padding_size;

	word_t string1_address;
	word_t string2_address;
	word_t string3_address;

	void *buffer;
	size_t buffer_size;

	bool needs_executable_stack;
	LoadStatement *statement;
	void *cursor;
	int status;

	if (page_size == 0) {
		page_size = sysconf(_SC_PAGE_SIZE);
		if ((int) page_size <= 0)
			page_size = 0x1000;
		page_mask = ~(page_size - 1);
	}

	needs_executable_stack = (tracee->load_info->needs_executable_stack
				|| (   tracee->load_info->interp != NULL
				    && tracee->load_info->interp->needs_executable_stack));

	/* Strings addresses are required to generate the load script,
	 * for "open" actions.  Since I want to generate it in one
	 * pass, these strings will be put right below the current
	 * stack pointer -- the only known adresses so far -- in the
	 * "strings area".  */
	string1_size = strlen(tracee->load_info->user_path) + 1;

	string2_size = (tracee->load_info->interp == NULL ? 0
			: strlen(tracee->load_info->interp->user_path) + 1);

	string3_size = (tracee->load_info->raw_path == tracee->load_info->user_path ? 0
			: strlen(tracee->load_info->raw_path) + 1);

	/* A padding will be appended at the end of the load script
	 * (a.k.a "strings area") to ensure this latter is aligned to
	 * a word boundary, for sake of performance.  */
	padding_size = (stack_pointer - string1_size - string2_size - string3_size)
			% sizeof_word(tracee);

	strings_size = string1_size + string2_size + string3_size + padding_size;
	string1_address = stack_pointer - strings_size;
	string2_address = stack_pointer - strings_size + string1_size;
	string3_address = (string3_size == 0
			? string1_address
			: stack_pointer - strings_size + string1_size + string2_size);

	/* Compute the size of the load script.  */
	script_size =
		LOAD_STATEMENT_SIZE(*statement, open)
		+ (LOAD_STATEMENT_SIZE(*statement, mmap)
			* talloc_array_length(tracee->load_info->mappings))
		+ (tracee->load_info->interp == NULL ? 0
			: LOAD_STATEMENT_SIZE(*statement, open)
			+ (LOAD_STATEMENT_SIZE(*statement, mmap)
				* talloc_array_length(tracee->load_info->interp->mappings)))
		+ (needs_executable_stack ? LOAD_STATEMENT_SIZE(*statement, make_stack_exec) : 0)
		+ LOAD_STATEMENT_SIZE(*statement, start);

	/* Allocate enough room for both the load script and the
	 * strings area.  */
	buffer_size = script_size + strings_size;
	buffer = talloc_zero_size(tracee->ctx, buffer_size);
	if (buffer == NULL)
		return -ENOMEM;

	cursor = buffer;

	/* Load script statement: open.  */
	statement = cursor;
	statement->action = LOAD_ACTION_OPEN;
	statement->open.string_address = string1_address;

	cursor += LOAD_STATEMENT_SIZE(*statement, open);

	/* Load script statements: mmap.  */
	cursor = transcript_mappings(cursor, tracee->load_info->mappings);

	if (tracee->load_info->interp != NULL) {
		/* Load script statement: open.  */
		statement = cursor;
		statement->action = LOAD_ACTION_OPEN_NEXT;
		statement->open.string_address = string2_address;

		cursor += LOAD_STATEMENT_SIZE(*statement, open);

		/* Load script statements: mmap.  */
		cursor = transcript_mappings(cursor, tracee->load_info->interp->mappings);

		entry_point = ELF_FIELD(tracee->load_info->interp->elf_header, entry);
	}
	else
		entry_point = ELF_FIELD(tracee->load_info->elf_header, entry);

	if (needs_executable_stack) {
		/* Load script statement: stack_exec.  */
		statement = cursor;

		statement->action = LOAD_ACTION_MAKE_STACK_EXEC;
		statement->make_stack_exec.start = stack_pointer & page_mask;

		cursor += LOAD_STATEMENT_SIZE(*statement, make_stack_exec);
	}

	/* Load script statement: start.  */
	statement = cursor;

	/* Start of the program slightly differs when ptraced.  */
	if (tracee->as_ptracee.ptracer != NULL)
		statement->action = LOAD_ACTION_START_TRACED;
	else
		statement->action = LOAD_ACTION_START;

	statement->start.stack_pointer = stack_pointer;
	statement->start.entry_point   = entry_point;
	statement->start.at_phent = ELF_FIELD(tracee->load_info->elf_header, phentsize);
	statement->start.at_phnum = ELF_FIELD(tracee->load_info->elf_header, phnum);
	statement->start.at_entry = ELF_FIELD(tracee->load_info->elf_header, entry);
	statement->start.at_phdr  = ELF_FIELD(tracee->load_info->elf_header, phoff)
				  + tracee->load_info->mappings[0].addr;
	statement->start.at_execfn = string3_address;

	cursor += LOAD_STATEMENT_SIZE(*statement, start);

	/* Sanity check.  */
	assert((uintptr_t) cursor - (uintptr_t) buffer == script_size);

	/* Convert the load script to the expected format.  */
	if (is_32on64_mode(tracee)) {
		int i;
		for (i = 0; buffer + i * sizeof(uint64_t) < cursor; i++)
			((uint32_t *) buffer)[i] = ((uint64_t *) buffer)[i];
	}

	/* Concatenate the load script and the strings.  */
	memcpy(cursor, tracee->load_info->user_path, string1_size);
	cursor += string1_size;

	if (string2_size != 0) {
		memcpy(cursor, tracee->load_info->interp->user_path, string2_size);
		cursor += string2_size;
	}

	if (string3_size != 0) {
		memcpy(cursor, tracee->load_info->raw_path, string3_size);
		cursor += string3_size;
	}

	/* Sanity check.  */
	cursor += padding_size;
	assert((uintptr_t) cursor - (uintptr_t) buffer == buffer_size);

	/* Allocate enough room in tracee's memory for the load
	 * script, and make the first user argument points to this
	 * location.  Note that it is safe to update the stack pointer
	 * manually since we are in execve sysexit.  However it should
	 * be done before transfering data since the kernel might not
	 * allow page faults below the stack pointer.  */
	poke_reg(tracee, STACK_POINTER, stack_pointer - buffer_size);
	poke_reg(tracee, USERARG_1, stack_pointer - buffer_size);

	/* Copy everything in the tracee's memory at once.  */
	status = write_data(tracee, stack_pointer - buffer_size, buffer, buffer_size);
	if (status < 0)
		return status;

	/* Tracee's stack content is now as follow:
	 *
	 *   +------------+ <- initial stack pointer (higher address)
	 *   |  padding   |
	 *   +------------+
	 *   |  string3   |
	 *   +------------+
	 *   |  string2   |
	 *   +------------+
	 *   |  string1   |
	 *   +------------+
	 *   |   start    |
	 *   +------------+
	 *   | mmap anon  |
	 *   +------------+
	 *   | mmap file  |
	 *   +------------+
	 *   | open next  |
	 *   +------------+
	 *   | mmap anon. |
	 *   +------------+
	 *   | mmap file  |
	 *   +------------+
	 *   |   open     |
	 *   +------------+ <- stack pointer, userarg1 (word aligned)
	 */

	/* Remember we are in the sysexit stage, so be sure the
	 * current register values will be used as-is at the end.  */
	save_current_regs(tracee, ORIGINAL);
	tracee->_regs_were_changed = true;

	return 0;
}