From patchwork Wed Oct 7 16:44:20 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Daniel Vetter X-Patchwork-Id: 11821191 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 7A9311592 for ; Wed, 7 Oct 2020 16:45:54 +0000 (UTC) Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 293CB206BE for ; Wed, 7 Oct 2020 16:45:54 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="G8/vk64Q"; dkim=fail reason="signature verification failed" (1024-bit key) header.d=ffwll.ch header.i=@ffwll.ch header.b="E4wIl1kh" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 293CB206BE Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=ffwll.ch Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=merlin.20170209; h=Sender:Content-Transfer-Encoding: Content-Type:Cc:List-Subscribe:List-Help:List-Post:List-Archive: List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To:Message-Id:Date: Subject:To:From:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=W/MrzZjXzesaeHiqIXIeKGuyea0fuhIdZfwBkity7uA=; b=G8/vk64Q/k3SUSV0isQMwabp7 w3wl7WbuiwMtxb7JUOlV8FV6tDnfJRRUDYucAhd0EckAsb6EwC+dMsbAAV9d3UU+RMdWv1CTEAsJv XoxkFQoK9oZ0HvPhkR12DmHU/UIAVz4r16KURYSiOGDLJaw+JMeKqH/VkJZhB4NNnA9ZIBvdOQLqb lB1Ctd5xYqNosIV04VnWKOcKx2+SklpchKotAcNPa08cxK8U0kjP35U2+ecC0+kcw2Pf4iI7scbfV tMe/C7vYNUnm8Hk0XoXBcPfF7gvoYcnHf9gl+N0LCVwwucBKwRNN1imeiFeeiTdHo1DuDfvA0aMq/ dLAnRZbJQ==; Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1kQCZQ-0001ai-K6; Wed, 07 Oct 2020 16:45:41 +0000 Received: from mail-wr1-x444.google.com ([2a00:1450:4864:20::444]) by merlin.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1kQCYW-0001Bo-9n for linux-arm-kernel@lists.infradead.org; Wed, 07 Oct 2020 16:45:00 +0000 Received: by mail-wr1-x444.google.com with SMTP id t10so3007067wrv.1 for ; Wed, 07 Oct 2020 09:44:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ffwll.ch; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=y0cYv7pt2ajdPKJ71Sud+gUJyoyQWkHY61omgO6gUCQ=; b=E4wIl1khATPAWsmoahDSq5XJ9XB3/O17Fju2KtWFpZcnpDunS6aB2uzf/IAoSlz+9+ 5VxZXcG5teVG2C1MloXLK4xiaqUArGcDx8l8ZuU+9gaO8lbpEVnn6vpAnmLx4qTlAd8x TdyxsIClr7xEEKfXI/m8EFXclIzKOCjXa7FyM= 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:in-reply-to :references:mime-version:content-transfer-encoding; bh=y0cYv7pt2ajdPKJ71Sud+gUJyoyQWkHY61omgO6gUCQ=; b=fMTzxeLMYXi8aGYD51TDRgYInq5Ye/w1MTvLNErSpH0uCTZnOuzZwzHg2BjeDzXY/W np73LcU5AtvYrY1Mn1Xh+hLn/cPHyZKg6w/PEOHZJIdIlibtV1aQ/xxRuYuoTSbOXH32 9n4vPx2G+1LHdopcF0FhcfDd8ZJwCA+xgxggy6Tn1JLzw40UQ6gucxalqjEM9ykaZ4UQ ZtYy8attWWl+BiUBmH3ScmScp6RkDxL7MgwIVUGBSnIdBXo0nm8jPTjpRonRv8OXIkVX tKy2T/O1Z6DffEaq8+T8xrFi1T49DOklMOKNaeElk6tty2SGjyI/ON/FALngF2UUKNbS Srog== X-Gm-Message-State: AOAM531LUOaMMhALbCMeO7NeWvnl7/DtUOfWWCmRWdQyuuGCKTBDswez 9l5vAgQ+/G2kDpE8Eva3NrMHsw== X-Google-Smtp-Source: ABdhPJyOhUNMEwwCQ+AEh8GM5Lra9AvYxZp9hFKsj4jVU6Oiy0Fq4b4Qf4lRUIggnlkhrBK3gQ/vuQ== X-Received: by 2002:a5d:51ca:: with SMTP id n10mr4539798wrv.222.1602089083290; Wed, 07 Oct 2020 09:44:43 -0700 (PDT) Received: from phenom.ffwll.local ([2a02:168:57f4:0:efd0:b9e5:5ae6:c2fa]) by smtp.gmail.com with ESMTPSA id z191sm3332280wme.40.2020.10.07.09.44.41 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 07 Oct 2020 09:44:42 -0700 (PDT) From: Daniel Vetter To: DRI Development , LKML Subject: [PATCH 07/13] mm: close race in generic_access_phys Date: Wed, 7 Oct 2020 18:44:20 +0200 Message-Id: <20201007164426.1812530-8-daniel.vetter@ffwll.ch> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20201007164426.1812530-1-daniel.vetter@ffwll.ch> References: <20201007164426.1812530-1-daniel.vetter@ffwll.ch> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20201007_124444_447367_51797824 X-CRM114-Status: GOOD ( 22.03 ) X-Spam-Score: -0.2 (/) X-Spam-Report: SpamAssassin version 3.4.4 on merlin.infradead.org summary: Content analysis details: (-0.2 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [2a00:1450:4864:20:0:0:0:444 listed in] [list.dnswl.org] 0.0 SPF_NONE SPF: sender does not publish an SPF Record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: linux-s390@vger.kernel.org, Rik van Riel , linux-samsung-soc@vger.kernel.org, Jan Kara , Kees Cook , kvm@vger.kernel.org, Jason Gunthorpe , Dave Airlie , Daniel Vetter , Daniel Vetter , linux-mm@kvack.org, =?utf-8?b?SsOp?= =?utf-8?b?csO0bWUgR2xpc3Nl?= , John Hubbard , Benjamin Herrensmidt , Hugh Dickins , Dan Williams , Andrew Morton , linux-arm-kernel@lists.infradead.org, linux-media@vger.kernel.org Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org Way back it was a reasonable assumptions that iomem mappings never change the pfn range they point at. But this has changed: - gpu drivers dynamically manage their memory nowadays, invalidating ptes with unmap_mapping_range when buffers get moved - contiguous dma allocations have moved from dedicated carvetouts to cma regions. This means if we miss the unmap the pfn might contain pagecache or anon memory (well anything allocated with GFP_MOVEABLE) - even /dev/mem now invalidates mappings when the kernel requests that iomem region when CONFIG_IO_STRICT_DEVMEM is set, see 3234ac664a87 ("/dev/mem: Revoke mappings when a driver claims the region") Accessing pfns obtained from ptes without holding all the locks is therefore no longer a good idea. Fix this. Since ioremap might need to manipulate pagetables too we need to drop the pt lock and have a retry loop if we raced. While at it, also add kerneldoc and improve the comment for the vma_ops->access function. It's for accessing, not for moving the memory from iomem to system memory, as the old comment seemed to suggest. References: 28b2ee20c7cb ("access_process_vm device memory infrastructure") Cc: Jason Gunthorpe Cc: Dan Williams Cc: Kees Cook Cc: Rik van Riel Cc: Benjamin Herrensmidt Cc: Dave Airlie Cc: Hugh Dickins Cc: Andrew Morton Cc: John Hubbard Cc: Jérôme Glisse Cc: Jan Kara Cc: Dan Williams Cc: linux-mm@kvack.org Cc: linux-arm-kernel@lists.infradead.org Cc: linux-samsung-soc@vger.kernel.org Cc: linux-media@vger.kernel.org Signed-off-by: Daniel Vetter --- include/linux/mm.h | 3 ++- mm/memory.c | 44 ++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/include/linux/mm.h b/include/linux/mm.h index acd60fbf1a5a..2a16631c1fda 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -566,7 +566,8 @@ struct vm_operations_struct { vm_fault_t (*pfn_mkwrite)(struct vm_fault *vmf); /* called by access_process_vm when get_user_pages() fails, typically - * for use by special VMAs that can switch between memory and hardware + * for use by special VMAs. See also generic_access_phys() for a generic + * implementation useful for any iomem mapping. */ int (*access)(struct vm_area_struct *vma, unsigned long addr, void *buf, int len, int write); diff --git a/mm/memory.c b/mm/memory.c index fcfc4ca36eba..8d467e23b44e 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -4873,28 +4873,68 @@ int follow_phys(struct vm_area_struct *vma, return ret; } +/** + * generic_access_phys - generic implementation for iomem mmap access + * @vma: the vma to access + * @addr: userspace addres, not relative offset within @vma + * @buf: buffer to read/write + * @len: length of transfer + * @write: set to FOLL_WRITE when writing, otherwise reading + * + * This is a generic implementation for &vm_operations_struct.access for an + * iomem mapping. This callback is used by access_process_vm() when the @vma is + * not page based. + */ int generic_access_phys(struct vm_area_struct *vma, unsigned long addr, void *buf, int len, int write) { resource_size_t phys_addr; unsigned long prot = 0; void __iomem *maddr; + pte_t *ptep, pte; + spinlock_t *ptl; int offset = addr & (PAGE_SIZE-1); + int ret = -EINVAL; + + if (!(vma->vm_flags & (VM_IO | VM_PFNMAP))) + return -EINVAL; + +retry: + if (follow_pte(vma->vm_mm, addr, &ptep, &ptl)) + return -EINVAL; + pte = *ptep; + pte_unmap_unlock(ptep, ptl); - if (follow_phys(vma, addr, write, &prot, &phys_addr)) + prot = pgprot_val(pte_pgprot(pte)); + phys_addr = (resource_size_t)pte_pfn(pte) << PAGE_SHIFT; + + if ((write & FOLL_WRITE) && !pte_write(pte)) return -EINVAL; maddr = ioremap_prot(phys_addr, PAGE_ALIGN(len + offset), prot); if (!maddr) return -ENOMEM; + if (follow_pte(vma->vm_mm, addr, &ptep, &ptl)) + goto out_unmap; + + if (pte_same(pte, *ptep)) { + pte_unmap_unlock(ptep, ptl); + iounmap(maddr); + + goto retry; + } + if (write) memcpy_toio(maddr + offset, buf, len); else memcpy_fromio(buf, maddr + offset, len); + ret = len; + pte_unmap_unlock(ptep, ptl); +out_unmap: iounmap(maddr); - return len; + return ret; } EXPORT_SYMBOL_GPL(generic_access_phys); #endif