From patchwork Wed Mar 7 21:50:10 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Max Filippov X-Patchwork-Id: 10265377 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 5D0CA60211 for ; Wed, 7 Mar 2018 21:51:19 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 4EFF7295B8 for ; Wed, 7 Mar 2018 21:51:19 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 43755295D9; Wed, 7 Mar 2018 21:51:19 +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=-5.3 required=2.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, FROM_LOCAL_NOVOWEL, HK_RANDOM_FROM, 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 7173F295EC for ; Wed, 7 Mar 2018 21:51:18 +0000 (UTC) Received: from localhost ([::1]:35780 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1etgxw-0006cp-Ux for patchwork-qemu-devel@patchwork.kernel.org; Wed, 07 Mar 2018 16:51:17 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:37445) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1etgx3-0005uX-4I for qemu-devel@nongnu.org; Wed, 07 Mar 2018 16:50:22 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1etgx1-0003TP-HX for qemu-devel@nongnu.org; Wed, 07 Mar 2018 16:50:21 -0500 Received: from mail-lf0-x243.google.com ([2a00:1450:4010:c07::243]:34558) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1etgx0-0003SN-Vl; Wed, 07 Mar 2018 16:50:19 -0500 Received: by mail-lf0-x243.google.com with SMTP id l191-v6so5462077lfe.1; Wed, 07 Mar 2018 13:50:18 -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=HOkQVmRTq7d69RCPs4Wtc01cTjdX6ArTfxP24rFZzuk=; b=o2l217AKsV2HIB4qh9uEjpJTMuAJiEuQU57wNTq93/AZmQmrwgQCblKoING3mmA/MH MnKlATILpnTNz1ghnyQPGjo6ztdYtIuXV3uY5S28Budz9cAXbmrn088/TUK6PBFRnX7O Rnb9L5wG9CNNcn+PKBlzBDEWMDr+Fbgjwxb4ZNElOc8mD6T0lCw1RMM/7bGeVFAaTjMJ yUb8zWvtd9lYz7UnftAXMrrn1Rkl/zFLpsSRyZh+X/+2FySxNY7o/YecBbjyTrGbhj3Y o0EcM8dj/jk9TXGfkowEzyNkcZp+zcrFb/+gyG9oVH409Pk7nNj3WOO4EkVtvERLRG+f j4jg== 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=HOkQVmRTq7d69RCPs4Wtc01cTjdX6ArTfxP24rFZzuk=; b=FyghhrZCa+RKRu17NZnmuN0TfLjWsYUTLtE7DdWZ5FwOIWGco9tg9OjH0gUMMzvrCG M32t237MdKzKgEsp37YubjrrAmUMrgsVbnlkURROfcXX4VxoKLCvBR0k2HSI2SFNaPgl dYxX7Oe/+C4JmW64YFJRxcZsv6iTYtoAoav343yUTj/P2hWtPT0y0bPKCgEzZ5pjtGwH 8q3AU7jOa+IDYhcH1axd/SX58LEh0+yE3OcsH1Fw9tpC8yYYCWnYENXtbZVvSvd2VJQe sKmhMxT07x6cY4cRfEx4YxuwO0sLeM6ao51Ua+EBjxbTEPM1GdPhDfuLnZjXlpReYfqP AsJg== X-Gm-Message-State: AElRT7FwCkDe/UdKyW/Sn/xGbNRMjN1JKCdK1MdSmY8MYVzE9gDeXjxA Bik9TGNrZEWdHDGAqeTI2+2m/Q== X-Google-Smtp-Source: AG47ELtwxGLcTnwui4lMcKUiPp+u1W97zEuusHS5UmWPpTClst4d5phgWT4qmbrTpg9C211o5Fx0uQ== X-Received: by 10.25.79.78 with SMTP id a14mr16204934lfk.97.1520459417310; Wed, 07 Mar 2018 13:50:17 -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 s82sm3766164lja.7.2018.03.07.13.50.14 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 07 Mar 2018 13:50:16 -0800 (PST) From: Max Filippov To: qemu-devel@nongnu.org Date: Wed, 7 Mar 2018 13:50:10 -0800 Message-Id: <20180307215010.30706-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 v6 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. 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 --- Changes v5->v6: - drop 'if (len)' clause from guest_range_valid and explicitly compare len with GUEST_ADDR_MAX. Changes v4->v5: - change definition of GUEST_ADDR_MAX to always be the last valid guest address. Account for this change in guest_addr_valid and open_self_maps. - turn guest_range_valid into a function. Changes v3->v4: - change GUEST_ADDR_MAX and h2g_valid definitions as suggested by Laurent Vivier. 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. 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 0b141683f095..f4fa94e9669d 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 191f2e962a3c..5de8c8a5afeb 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 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..809644742aff 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(); @@ -7468,7 +7471,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; }