From patchwork Thu Nov 8 17:53:38 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Harrington, Sean M" X-Patchwork-Id: 995104 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=battelle.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 42rWrJ4bwdz9s7W for ; Fri, 9 Nov 2018 05:23:44 +1100 (AEDT) Received: from localhost ([::1]:58457 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gKoxy-0006zy-9H for incoming@patchwork.ozlabs.org; Thu, 08 Nov 2018 13:23:42 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:38625) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gKoV5-0001ST-6W for qemu-devel@nongnu.org; Thu, 08 Nov 2018 12:53:52 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1gKoUz-000746-TW for qemu-devel@nongnu.org; Thu, 08 Nov 2018 12:53:51 -0500 Received: from mx0a-0013ba01.pphosted.com ([67.231.149.77]:50068 helo=mx0b-0013ba01.pphosted.com) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1gKoUz-0006vo-Iu for qemu-devel@nongnu.org; Thu, 08 Nov 2018 12:53:45 -0500 Received: from pps.filterd (m0084500.ppops.net [127.0.0.1]) by mx0a-0013ba01.pphosted.com (8.16.0.22/8.16.0.22) with SMTP id wA8HmM15013337 for ; Thu, 8 Nov 2018 12:53:40 -0500 Received: from lz-cismta01.battelle.org (lp-mail01.battelle.org [131.167.218.50]) by mx0a-0013ba01.pphosted.com with ESMTP id 2nkmh024qg-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT) for ; Thu, 08 Nov 2018 12:53:40 -0500 Received: from WP-EX03.milky-way.battelle.org (wp-ex03.milky-way.battelle.org [10.50.8.133]) by lz-cismta01.battelle.org (Postfix) with ESMTP id 6D00D700002 for ; Thu, 8 Nov 2018 12:53:39 -0500 (EST) Received: from WP-EX02.milky-way.battelle.org (10.50.8.132) by WP-EX03.milky-way.battelle.org (10.50.8.133) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.1531.3; Thu, 8 Nov 2018 12:53:38 -0500 Received: from WP-EX02.milky-way.battelle.org ([10.50.8.132]) by WP-EX02.milky-way.battelle.org ([10.50.8.132]) with mapi id 15.01.1531.003; Thu, 8 Nov 2018 12:53:38 -0500 From: "Harrington, Sean M" To: "qemu-devel@nongnu.org" Thread-Topic: [PATCH] Added support for ASLR and PIE for target user mode binaries Thread-Index: AQHUd4jmKvaHsrisWUOos+DtOUuueA== Date: Thu, 8 Nov 2018 17:53:38 +0000 Message-ID: <2ddafd9424ab4a30817b8c59e207781d@battelle.org> Accept-Language: en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-originating-ip: [10.50.8.6] MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:, , definitions=2018-11-08_08:, , signatures=0 X-Proofpoint-Spam-Details: rule=notspam policy=default score=1 classifier= adjust=0 reason=forced scancount=1 engine=8.0.1-1807170000 definitions=main-1811080151 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x [generic] [fuzzy] X-Received-From: 67.231.149.77 X-Mailman-Approved-At: Thu, 08 Nov 2018 13:23:26 -0500 Subject: [Qemu-devel] [PATCH] Added support for ASLR and PIE for target user mode binaries X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" Hello, I recently had to extend QEMU user mode to support PIE enabled binaries compiled for non-native architectures. It was also important to emulate ASLR for the target binary if ASLR was enabled on the host machine. I would like to introduce this as a feature into QEMU mainstream as it seems like a feature others could use as well. With the patch implementation, ASLR will be enabled if /proc/sys/kernel/randomize_va_space is non-zero on the host machine. An alternative implementation could be passing an argument during runtime to enable or disable ASLR. PIE is automatically enabled as well if the binary has been compiled with this flag. Best regards, Sean Harrington Signed-off-by: Sean Harrington --- linux-user/Makefile.objs | 3 +- linux-user/elfload.c | 3 +- linux-user/main.c | 7 +++ linux-user/randomize_va.c | 95 +++++++++++++++++++++++++++++++++++++++ linux-user/randomize_va.h | 23 ++++++++++ 5 files changed, 129 insertions(+), 2 deletions(-) create mode 100644 linux-user/randomize_va.c create mode 100644 linux-user/randomize_va.h -- 2.17.2 (Apple Git-113) diff --git a/linux-user/Makefile.objs b/linux-user/Makefile.objs index 769b8d8336..384944a76d 100644 --- a/linux-user/Makefile.objs +++ b/linux-user/Makefile.objs @@ -1,7 +1,8 @@ obj-y = main.o syscall.o strace.o mmap.o signal.o \ elfload.o linuxload.o uaccess.o uname.o \ safe-syscall.o $(TARGET_ABI_DIR)/signal.o \ - $(TARGET_ABI_DIR)/cpu_loop.o exit.o fd-trans.o + $(TARGET_ABI_DIR)/cpu_loop.o exit.o fd-trans.o \ + randomize_va.o obj-$(TARGET_HAS_BFLT) += flatload.o obj-$(TARGET_I386) += vm86.o diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 5bccd2e243..5add383815 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -7,6 +7,7 @@ #include "qemu.h" #include "disas/disas.h" #include "qemu/path.h" +#include "randomize_va.h" #ifdef _ARCH_PPC64 #undef ARCH_DLINFO @@ -2258,7 +2259,7 @@ static void load_elf_image(const char *image_name, int image_fd, image is pre-linked, LOADDR will be non-zero. Since we do not supply MAP_FIXED here we'll use that address if and only if it remains available. */ - load_addr = target_mmap(loaddr, hiaddr - loaddr, PROT_NONE, + load_addr = get_pie_addr(loaddr, hiaddr - loaddr, PROT_NONE, MAP_PRIVATE | MAP_ANON | MAP_NORESERVE, -1, 0); if (load_addr == -1) { diff --git a/linux-user/main.c b/linux-user/main.c index 923cbb753a..3b789001dd 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -37,6 +37,7 @@ #include "trace/control.h" #include "target_elf.h" #include "cpu_loop-common.h" +#include "randomize_va.h" char *exec_path; @@ -694,6 +695,12 @@ int main(int argc, char **argv, char **envp) target_environ = envlist_to_environ(envlist, NULL); envlist_free(envlist); + /* + * If host has randomized_va_space enabled, emulate the same for the + * target. + */ + reserved_va = handle_randomized_va(reserved_va, MAX_RESERVED_VA); + /* * Now that page sizes are configured in tcg_exec_init() we can do * proper page alignment for guest_base. diff --git a/linux-user/randomize_va.c b/linux-user/randomize_va.c new file mode 100644 index 0000000000..792212a2b8 --- /dev/null +++ b/linux-user/randomize_va.c @@ -0,0 +1,95 @@ +/* + * QEMU user ASLR + PIE emulation + * + * Copyright (c) 2018 Sean Harrington (harrington@battelle.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include "qemu/osdep.h" +#include "qemu/bitops.h" + +#include "qemu.h" +#include "qemu-common.h" +#include "randomize_va.h" + +#define PIE_MMAP_ATTEMPTS 10 +#define RANDOMIZATION_RANGE 0x00100000 + +unsigned long handle_randomized_va(unsigned long va, unsigned long max_va_space) { + + int randomize_va_fd = open("/proc/sys/kernel/randomize_va_space", O_RDONLY); + srand(time(NULL)); + + if (randomize_va_fd >= 0) { + int aslr; + if (read(randomize_va_fd, &aslr, sizeof(aslr)) < 0) { + return va; + } + + if (aslr) { + /* At start, mmap_next_state is equal to TASK_UNMAPPED_BASE in + * mmap.c. Randomly choose a new random value within range + * [mmap_next_start - (TASK_UNMAPPED_BASE / 2), + * mmap_next_start - (TASK_UNMAPPED_BASE / 2)] + * Also make sure we are page aligned + */ + + /* If it is possible new va could overflow, prevent it */ + if ((va + (RANDOMIZATION_RANGE / 2)) > max_va_space) + { + va = max_va_space - (RANDOMIZATION_RANGE / 2); + } + /* If it is possible new va could underflow, prevent it */ + else if ((va - (RANDOMIZATION_RANGE / 2)) > max_va_space) + va = RANDOMIZATION_RANGE / 2; + + /* Perform randomization */ + abi_ulong offset = va - (RANDOMIZATION_RANGE / 2); + + abi_ulong range = RANDOMIZATION_RANGE; + abi_ulong random_val = rand(); + va = (random_val % range) + offset; + + /* Page align result */ + va &= qemu_host_page_mask; + } + } + + return va; +} + +abi_ulong get_pie_addr(abi_ulong addr, abi_ulong size, int prot_opts, + int map_opts, int fd, off_t offset) { + abi_ulong orig_addr = addr; + abi_ulong newloaddr = 0; + + /* New seed for upcoming rand. */ + srand(time(NULL)); + + /* If addr is 0, kernel handles finding a valid address. If non-zero + * we should honor the request for the specified mmap address. + */ + if (orig_addr == 0) { + while (newloaddr < size) + newloaddr = rand() & TARGET_PAGE_MASK; + } + else + newloaddr = addr; + + addr = target_mmap(newloaddr, size, prot_opts, map_opts, fd, + offset); + + return addr; +} diff --git a/linux-user/randomize_va.h b/linux-user/randomize_va.h new file mode 100644 index 0000000000..43b1a1a1a3 --- /dev/null +++ b/linux-user/randomize_va.h @@ -0,0 +1,23 @@ +/* + * QEMU user ASLR + PIE emulation + * + * Copyright (c) 2018 Sean Harrington (harrington@battelle.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +unsigned long handle_randomized_va(unsigned long va, unsigned long max_va_space); + +abi_ulong get_pie_addr(abi_ulong addr, abi_ulong size, int prot_opts, + int map_opts, int fd, off_t offset);