From patchwork Tue Jun 19 01:41:49 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michael Roth X-Patchwork-Id: 10472891 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 C336160353 for ; Tue, 19 Jun 2018 02:22:21 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id B6B5628C1E for ; Tue, 19 Jun 2018 02:22:21 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id A953028CB5; Tue, 19 Jun 2018 02:22:21 +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=-7.8 required=2.0 tests=BAYES_00,DKIM_SIGNED, MAILING_LIST_MULTI, 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 10FB428C1E for ; Tue, 19 Jun 2018 02:22:21 +0000 (UTC) Received: from localhost ([::1]:38589 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fV6Hk-0004j2-6Q for patchwork-qemu-devel@patchwork.kernel.org; Mon, 18 Jun 2018 22:22:20 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:45324) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fV5hX-00016j-DD for qemu-devel@nongnu.org; Mon, 18 Jun 2018 21:44:56 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fV5hW-00086e-2i for qemu-devel@nongnu.org; Mon, 18 Jun 2018 21:44:55 -0400 Received: from mail-oi0-x243.google.com ([2607:f8b0:4003:c06::243]:44557) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1fV5hV-00086N-Ru; Mon, 18 Jun 2018 21:44:54 -0400 Received: by mail-oi0-x243.google.com with SMTP id c128-v6so16677403oig.11; Mon, 18 Jun 2018 18:44:53 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references; bh=m0+B9s+mSGfTWiYQNXrdMqfA94XVvo6m6l6FcDOZVNo=; b=cfMNaMnTkh76T9Kznac8wTt0O7AN+Ayn5pTyny8SXvnkayCBIsb5wiHOzNgsf0YXmh dLv/qmj3sDb1OUxpNAn9AZsEZ7oicywteZumH+Y2tIhfD/4IYnUv4dYwzV8wvTKN/vg+ ggk/vlCtzJk+JsHCacLUpyuq9kbtSbLvW9ZsZ4dA+fVKjYIk36/KQ+RzYK4vReaVA+V9 IkMqVSLjiowT2nemsPwzKd/A8oeX5lKRI/EzCDxga+Udxm7hzhG84rQ6bTl3stN1bn4F momKqFR2ektrazZkH7nJkJcGTonKFVTBIwovboqexBXIh6z3PiRAQWbjx+gzaeV9sf4F UrRg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id :in-reply-to:references; bh=m0+B9s+mSGfTWiYQNXrdMqfA94XVvo6m6l6FcDOZVNo=; b=i8jOKGorTXb1kOpMrpPT36FJK6qSmOaJmPjJV84nIQ0J4s5P3wTlgEhG/S1Isi0FPs FWGPc3/clSeEnY/tbwz5uiaFdy61Z21joM9+v3llKC0D97nsKawRazR5og47ZUHaBVSu IKBOBbyLOcWiR2NdVdTczo/3feFetN3Fnbp2a0Eei+/99GivxMUQSl7QMbV1ko5bHVKZ xGVE0GVe1du0rJNsqnSIwwwlFbsBf9+BJMXX/osV17HbGGtcfnvB8xYmzDCqSodGN7Ar Q57o0v5ANuevKvfHmFGri6sapS9bjPWD+H/Kr+OHDZkZAZe21xbHBEBxryy76Wy5kjlp l1jg== X-Gm-Message-State: APt69E3+WxqAkNbllfAv+8DTQttNwU4IvGFq29UgHMFaG8tVm8VOfq/T zH219H0INPzgXtjR3vBMXCLzADUn X-Google-Smtp-Source: ADUXVKJCi+hPnx9SR4KlwchmA39y6P1W+O4uMecZnsCraa43F1CVUYgzFMHvcOeZlHnFHay1qq9suA== X-Received: by 2002:aca:5094:: with SMTP id e142-v6mr7897424oib.190.1529372692677; Mon, 18 Jun 2018 18:44:52 -0700 (PDT) Received: from localhost ([2600:1700:70:e488:b0ee:9bda:ee6f:91be]) by smtp.gmail.com with ESMTPSA id v50-v6sm9189917otd.7.2018.06.18.18.44.51 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Mon, 18 Jun 2018 18:44:51 -0700 (PDT) From: Michael Roth To: qemu-devel@nongnu.org Date: Mon, 18 Jun 2018 20:41:49 -0500 Message-Id: <20180619014319.28272-24-mdroth@linux.vnet.ibm.com> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20180619014319.28272-1-mdroth@linux.vnet.ibm.com> References: <20180619014319.28272-1-mdroth@linux.vnet.ibm.com> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2607:f8b0:4003:c06::243 Subject: [Qemu-devel] [PATCH 023/113] 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 From: Max Filippov 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. Change definition of GUEST_ADDR_MAX to always be the last valid guest address. Account for this change in open_self_maps. Add macro guest_addr_valid that verifies if the guest address is valid. Add function 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 Reviewed-by: Laurent Vivier Message-Id: <20180307215010.30706-1-jcmvbkbc@gmail.com> Signed-off-by: Laurent Vivier (cherry picked from commit ebf9a3630c911d0cfc9c20f7cafe9ba4f88cf583) Signed-off-by: Michael Roth --- include/exec/cpu-all.h | 6 +++++- include/exec/cpu_ldst.h | 16 +++++++--------- linux-user/mmap.c | 20 +++++++++++++++----- linux-user/syscall.c | 5 ++++- 4 files changed, 31 insertions(+), 16 deletions(-) diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index 0b141683f0..f4fa94e966 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -159,8 +159,12 @@ extern unsigned long guest_base; extern int have_guest_base; extern unsigned long reserved_va; -#define GUEST_ADDR_MAX (reserved_va ? reserved_va : \ +#if HOST_LONG_BITS <= TARGET_VIRT_ADDR_SPACE_BITS +#define GUEST_ADDR_MAX (~0ul) +#else +#define GUEST_ADDR_MAX (reserved_va ? reserved_va - 1 : \ (1ul << TARGET_VIRT_ADDR_SPACE_BITS) - 1) +#endif #else #include "exec/hwaddr.h" diff --git a/include/exec/cpu_ldst.h b/include/exec/cpu_ldst.h index 191f2e962a..5de8c8a5af 100644 --- a/include/exec/cpu_ldst.h +++ b/include/exec/cpu_ldst.h @@ -51,15 +51,13 @@ /* All direct uses of g2h and h2g need to go away for usermode softmmu. */ #define g2h(x) ((void *)((unsigned long)(target_ulong)(x) + guest_base)) -#if HOST_LONG_BITS <= TARGET_VIRT_ADDR_SPACE_BITS -#define h2g_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)); \ -}) -#endif +#define guest_addr_valid(x) ((x) <= GUEST_ADDR_MAX) +#define h2g_valid(x) guest_addr_valid((unsigned long)(x) - guest_base) + +static inline int guest_range_valid(unsigned long start, unsigned long len) +{ + return len - 1 <= GUEST_ADDR_MAX && start <= GUEST_ADDR_MAX - len + 1; +} #define h2g_nocheck(x) ({ \ unsigned long __ret = (unsigned long)(x) - guest_base; \ diff --git a/linux-user/mmap.c b/linux-user/mmap.c index 4888f53139..33a73cd29c 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 11c9116c4a..9872de7221 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -4871,6 +4871,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(); @@ -7430,7 +7433,7 @@ static int open_self_maps(void *cpu_env, int fd) } if (h2g_valid(min)) { int flags = page_get_flags(h2g(min)); - max = h2g_valid(max - 1) ? max : (uintptr_t)g2h(GUEST_ADDR_MAX); + max = h2g_valid(max - 1) ? max : (uintptr_t)g2h(GUEST_ADDR_MAX) + 1; if (page_check_range(h2g(min), max - min, flags) == -1) { continue; }