Received: by 2002:a05:6a10:16a7:0:0:0:0 with SMTP id gp39csp500690pxb; Thu, 19 Nov 2020 06:46:43 -0800 (PST) X-Google-Smtp-Source: ABdhPJw+hJ7cxkRz3rF/fhryulkjInrakr3b51M0FzA31z5kDkWIsmZPw8CA0n6AKdnOd478PZI9 X-Received: by 2002:a17:906:2a46:: with SMTP id k6mr7265933eje.533.1605797203115; Thu, 19 Nov 2020 06:46:43 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1605797203; cv=none; d=google.com; s=arc-20160816; b=N4zbVufiiImtnFkUwpLEif3LuaFYbOTB9co0LXzzZpdcb0rO2ShhzBmB3Qb+n8ThMr dYcg/FAWVQSArF2T10/+UjzKiT1Exm1lxb7iycroY8WR7B6ocpk21xAU2VQOcIlq9BZe H2xJzPYtE5acLNQhH61V+SAdvmrY1zhGfVN2JWcTQPkaXf5kiWUhz3I4DMFiMD3jf+f2 Eu0kGIsKaijXA1a0Dlym5MnZ426Ci3DcOMVobUcjm0OLP3lU9WiinqaCX4hrsXNfCkxG 4eIxCcT3coB0EjBvh+HWF1y9MJ60bTIpaN8NGKCwa0PE8mPiw1qCum15L34DzDqAjkFy POJA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=cz4UxMzNPVXjZbnTyayh/NWh/vgndlicpyEK5kDfcUM=; b=uFkPu/z+K4RBmWWMebW4QgVSFXL/rtIqqasc/8oCl3fpfIV5fPnPOR8DGIlM//TLYv sSEWnqRMLwamXrt5q8k/pbcmKa8Bd7fGhSUQ+zJDdEdQ6PQWlpwyu9aMrMvu2uQIiA1S vn9iHZgaELbm0J3MWZ+7l84ML527FojJmAqmqizFaBLr3IB8/CyRq4sNlkWUHvoRSAPX FrOcwO6NLtEbwcBuabKSzxKy71vDBP2rvRZOV7EiZUBeuXKqJ3S+Cbn+1utihOJl24JV lstk4zoh0pSGUxNMbhqQgoiFVwBxIPQh2nvZAnmxStw1ZGcRW4EikEaU4rSKQVEQ6EmN hBnA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@ffwll.ch header.s=google header.b=kT5hHVz2; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id 13si19615840edv.433.2020.11.19.06.46.19; Thu, 19 Nov 2020 06:46:43 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@ffwll.ch header.s=google header.b=kT5hHVz2; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728256AbgKSOnv (ORCPT + 99 others); Thu, 19 Nov 2020 09:43:51 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37404 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728255AbgKSOmF (ORCPT ); Thu, 19 Nov 2020 09:42:05 -0500 Received: from mail-wr1-x441.google.com (mail-wr1-x441.google.com [IPv6:2a00:1450:4864:20::441]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id EB2FAC061A53 for ; Thu, 19 Nov 2020 06:42:03 -0800 (PST) Received: by mail-wr1-x441.google.com with SMTP id d12so6619742wrr.13 for ; Thu, 19 Nov 2020 06:42:03 -0800 (PST) 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=cz4UxMzNPVXjZbnTyayh/NWh/vgndlicpyEK5kDfcUM=; b=kT5hHVz20ZLA+wBbKO3AP8hJ8BchOZR37nQ+YhO2rKi/6Q/B4Gn4706qqA1K6mIwSI MFWvY5ZFFxn0TyGFSMyq3gKB0RpHwjt9N1XtWYNdrxgTqsw7d1hgXiNMXbWgkM4GTzuj KaKJWvNU1jsezPYMJ/bMmUiAXzfdYlmUL0ggI= 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=cz4UxMzNPVXjZbnTyayh/NWh/vgndlicpyEK5kDfcUM=; b=b6s85+44m3xdNEGBMm9U2dXTG85g9S2LC1Zs8weISPRSp5Ue5KTviCAu6BsQTLo6up l/pu3nsW0qsHu9X9TDfhqgWMfuqKGiL5iVw5rz/zBDfjCXOXTbGbWxxFUOl531JlnJ/d f0qLA6RRuJiTTZs0WOdPjw2aHZQE7SAkmVJVrEhxtRA3Vu3TSI1z3+RCg0qcxoh4QfaL zKXzvIxRmR0tiW11JS5C6GS82Qc8PzF+4Rm7I6MrpT3XjFRLKAcgPC+jdQleMZmTK+Fo sdURlgy76wvUuxcx/AxUW/5X/JI8On16xvIZTw0VQCpxSnFYj2vupEWuBBoigXM80jeb HqHw== X-Gm-Message-State: AOAM531I+S2SIoSS33KjBJ8q4WBskQaIfm4MYTs0NmVAsXbR1ezMqyTe t9N6w8kVkCJnVXrEwQFk2TgMYg== X-Received: by 2002:adf:a3c1:: with SMTP id m1mr10245147wrb.28.1605796922738; Thu, 19 Nov 2020 06:42:02 -0800 (PST) Received: from phenom.ffwll.local ([2a02:168:57f4:0:efd0:b9e5:5ae6:c2fa]) by smtp.gmail.com with ESMTPSA id x63sm51292wmb.48.2020.11.19.06.42.01 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 19 Nov 2020 06:42:02 -0800 (PST) From: Daniel Vetter To: DRI Development , LKML Cc: kvm@vger.kernel.org, linux-mm@kvack.org, linux-arm-kernel@lists.infradead.org, linux-samsung-soc@vger.kernel.org, linux-media@vger.kernel.org, Daniel Vetter , Daniel Vetter , Jason Gunthorpe , Dan Williams , Kees Cook , Benjamin Herrensmidt , Dave Airlie , Andrew Morton , John Hubbard , =?UTF-8?q?J=C3=A9r=C3=B4me=20Glisse?= , Jan Kara , Chris Wilson Subject: [PATCH v6 07/17] mm: Close race in generic_access_phys Date: Thu, 19 Nov 2020 15:41:36 +0100 Message-Id: <20201119144146.1045202-8-daniel.vetter@ffwll.ch> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20201119144146.1045202-1-daniel.vetter@ffwll.ch> References: <20201119144146.1045202-1-daniel.vetter@ffwll.ch> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.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") Signed-off-by: Daniel Vetter Cc: Jason Gunthorpe Cc: Dan Williams Cc: Kees Cook Cc: Benjamin Herrensmidt Cc: Dave Airlie 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 Cc: Chris Wilson Signed-off-by: Daniel Vetter -- v2: Fix inversion in the retry check (John). v4: While at it, use offset_in_page (Chris Wilson) --- include/linux/mm.h | 3 ++- mm/memory.c | 46 +++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/include/linux/mm.h b/include/linux/mm.h index b1a4a140863d..06cc6f30fc78 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -574,7 +574,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 c48f8df6e502..ac32039ce941 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -4847,28 +4847,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; - int offset = addr & (PAGE_SIZE-1); + pte_t *ptep, pte; + spinlock_t *ptl; + int offset = offset_in_page(addr); + 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 -- 2.29.2