From patchwork Thu Mar 1 17:36:36 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Max Filippov X-Patchwork-Id: 10252071 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id F0507602B5 for ; Thu, 1 Mar 2018 17:37:57 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id DE3AD26256 for ; Thu, 1 Mar 2018 17:37:57 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id D28E327F94; Thu, 1 Mar 2018 17:37:57 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.3 required=2.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, FROM_LOCAL_NOVOWEL, RCVD_IN_DNSWL_HI, T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 5107A26256 for ; Thu, 1 Mar 2018 17:37:56 +0000 (UTC) Received: from localhost ([::1]:58505 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1erS9T-0008Iy-DC for patchwork-qemu-devel@patchwork.kernel.org; Thu, 01 Mar 2018 12:37:55 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:41856) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1erS8Y-0007co-So for qemu-devel@nongnu.org; Thu, 01 Mar 2018 12:37:00 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1erS8X-0002ZJ-Ld for qemu-devel@nongnu.org; Thu, 01 Mar 2018 12:36:58 -0500 Received: from mail-lf0-x243.google.com ([2a00:1450:4010:c07::243]:38452) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1erS8X-0002Z2-8o; Thu, 01 Mar 2018 12:36:57 -0500 Received: by mail-lf0-x243.google.com with SMTP id i80so9538257lfg.5; Thu, 01 Mar 2018 09:36:57 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id; bh=x8BkWGl6gVwEgaYIzNHuqwiD2HuK65DXSCVZmdFf280=; b=DtDBVgGvBwznGh2sfqTgb0R0L40OpMT3Tcu5zA0aK7MK1tLHvqc8DsFWKit408evQm uv7FJTcs5PtClE0hYruQo+dxZjSIeO8aUIs/bKvWrpKdJ9f2FExNqIh+vxBJ6iVcqA7b Kt3Qvyh0kjXNtc2pDUi4HEgWGu5wKYLzkI6+VGDlSSFe9u/PIT42IC6Q81ebjZu6P66X ovr8Af/aVhblp+e9wE7cDfWO9oVXYLCRn+Ca617GVEUJM8B6S33FKt0rZ2cp2+G9VLYq FhmFmmQ/41Rqam6pm1BRh24mpNQgudBYoFWSGnvwaMvnFmnhTdoS5MfhFsO28ub3xce0 kKCA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=x8BkWGl6gVwEgaYIzNHuqwiD2HuK65DXSCVZmdFf280=; b=n53Q0+rNZltyWZykvGLO6UwCP7qbjsvOvNEI2JlMNsInQCQJJ29y/M4Oxw/NYrpcm9 BoXj1FvhOuBzG0qd6cLCsPXc0Kxaf2OQDVlgy3760nDI77a9M3yw4ALVxRKtkober8ws aqznVPCK9rscxcC/PJtvB4k6jV9QAVb0736h/F/RGZ4wPdS9MrWdVamNxcXzV/5cQnrK ljdDhJlHpO5dLO1fPllJxcvcpMmrypwPrWAgBMGdxv1B8rbKz5i+VrK85V//tVfx3nm/ /WYHSQQDzpRnCM0AUkaUzilfq5+f2qKJgLXRlq+d6m9X8UAlhxfIYSAiRl0RKWmf3G+8 olBA== X-Gm-Message-State: APf1xPADydBKWM++TEhOFAKaLjxRvkX8AB3XKsv3xC0huCCRmMAiJH7C K/N39pIFGINpe3mHBIDthVKceA== X-Google-Smtp-Source: AG47ELt95ihtTMtixX5TWbrjIRvozGlKXxFLOO0fJenyeh+PHr2PhHz/u1aKqhBIaKX+42P7vM93jQ== X-Received: by 10.46.21.21 with SMTP id s21mr1947167ljd.58.1519925815559; Thu, 01 Mar 2018 09:36:55 -0800 (PST) Received: from octofox.cadence.com (jcmvbkbc-1-pt.tunnel.tserv24.sto1.ipv6.he.net. [2001:470:27:1fa::2]) by smtp.gmail.com with ESMTPSA id s7sm972214lfg.13.2018.03.01.09.36.52 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 01 Mar 2018 09:36:54 -0800 (PST) From: Max Filippov To: qemu-devel@nongnu.org Date: Thu, 1 Mar 2018 09:36:36 -0800 Message-Id: <20180301173636.19082-1-jcmvbkbc@gmail.com> X-Mailer: git-send-email 2.11.0 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2a00:1450:4010:c07::243 Subject: [Qemu-devel] [PATCH v3 05/11] linux-user: fix mmap/munmap/mprotect/mremap/shmat 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: , Cc: Max Filippov , Riku Voipio , qemu-stable@nongnu.org, Laurent Vivier Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP In linux-user QEMU that runs for a target with TARGET_ABI_BITS bigger than L1_MAP_ADDR_SPACE_BITS an assertion in page_set_flags fires when mmap, munmap, mprotect, mremap or shmat is called for an address outside the guest address space. mmap and mprotect should return ENOMEM in such case. Introduce macro guest_range_valid that verifies if address range is within guest address space and does not wrap around. Use that macro in mmap/munmap/mprotect/mremap/shmat for error checking. Cc: qemu-stable@nongnu.org Cc: Riku Voipio Cc: Laurent Vivier Signed-off-by: Max Filippov --- Changes v2->v3: - fix comparison in guest_valid: it must be 'less' to preserve the existing functionality, not 'less or equal'. - fix guest_range_valid: it may not use guest_valid, because single range that occupies all of the guest address space is valid. These changes fix assertion in page_check_range called from open_self_maps. include/exec/cpu-all.h | 2 +- include/exec/cpu_ldst.h | 12 +++++++----- linux-user/mmap.c | 20 +++++++++++++++----- linux-user/syscall.c | 3 +++ 4 files changed, 26 insertions(+), 11 deletions(-) diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index 0b141683f095..12bd049997ac 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -160,7 +160,7 @@ extern int have_guest_base; extern unsigned long reserved_va; #define GUEST_ADDR_MAX (reserved_va ? reserved_va : \ - (1ul << TARGET_VIRT_ADDR_SPACE_BITS) - 1) + (2ul << (TARGET_VIRT_ADDR_SPACE_BITS - 1)) - 1) #else #include "exec/hwaddr.h" diff --git a/include/exec/cpu_ldst.h b/include/exec/cpu_ldst.h index 191f2e962a3c..6528fd829ffe 100644 --- a/include/exec/cpu_ldst.h +++ b/include/exec/cpu_ldst.h @@ -53,14 +53,16 @@ #if HOST_LONG_BITS <= TARGET_VIRT_ADDR_SPACE_BITS #define h2g_valid(x) 1 +#define guest_valid(x) 1 #else -#define h2g_valid(x) ({ \ - unsigned long __guest = (unsigned long)(x) - guest_base; \ - (__guest < (1ul << TARGET_VIRT_ADDR_SPACE_BITS)) && \ - (!reserved_va || (__guest < reserved_va)); \ -}) +#define h2g_valid(x) guest_valid((unsigned long)(x) - guest_base) +#define guest_valid(x) ((x) < GUEST_ADDR_MAX) #endif +#define guest_range_valid(start, len) \ + ({unsigned long l = (len); \ + l <= GUEST_ADDR_MAX && (start) <= GUEST_ADDR_MAX - l; }) + #define h2g_nocheck(x) ({ \ unsigned long __ret = (unsigned long)(x) - guest_base; \ (abi_ulong)__ret; \ diff --git a/linux-user/mmap.c b/linux-user/mmap.c index 0fbfd6dff20d..df81f9b803b6 100644 --- a/linux-user/mmap.c +++ b/linux-user/mmap.c @@ -80,8 +80,9 @@ int target_mprotect(abi_ulong start, abi_ulong len, int prot) return -EINVAL; len = TARGET_PAGE_ALIGN(len); end = start + len; - if (end < start) - return -EINVAL; + if (!guest_range_valid(start, len)) { + return -ENOMEM; + } prot &= PROT_READ | PROT_WRITE | PROT_EXEC; if (len == 0) return 0; @@ -481,8 +482,8 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot, * It can fail only on 64-bit host with 32-bit target. * On any other target/host host mmap() handles this error correctly. */ - if ((unsigned long)start + len - 1 > (abi_ulong) -1) { - errno = EINVAL; + if (!guest_range_valid(start, len)) { + errno = ENOMEM; goto fail; } @@ -622,8 +623,10 @@ int target_munmap(abi_ulong start, abi_ulong len) if (start & ~TARGET_PAGE_MASK) return -EINVAL; len = TARGET_PAGE_ALIGN(len); - if (len == 0) + if (len == 0 || !guest_range_valid(start, len)) { return -EINVAL; + } + mmap_lock(); end = start + len; real_start = start & qemu_host_page_mask; @@ -678,6 +681,13 @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size, int prot; void *host_addr; + if (!guest_range_valid(old_addr, old_size) || + ((flags & MREMAP_FIXED) && + !guest_range_valid(new_addr, new_size))) { + errno = ENOMEM; + return -1; + } + mmap_lock(); if (flags & MREMAP_FIXED) { diff --git a/linux-user/syscall.c b/linux-user/syscall.c index e24f43c4a259..79245e73784f 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -4900,6 +4900,9 @@ static inline abi_ulong do_shmat(CPUArchState *cpu_env, return -TARGET_EINVAL; } } + if (!guest_range_valid(shmaddr, shm_info.shm_segsz)) { + return -TARGET_EINVAL; + } mmap_lock();