From patchwork Fri Apr 22 22:04:09 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yury Norov X-Patchwork-Id: 12824100 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id A387BC433EF for ; Fri, 22 Apr 2022 22:04:14 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id DB7906B0073; Fri, 22 Apr 2022 18:04:13 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id D3F836B0074; Fri, 22 Apr 2022 18:04:13 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id BB9F86B0075; Fri, 22 Apr 2022 18:04:13 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (relay.hostedemail.com [64.99.140.25]) by kanga.kvack.org (Postfix) with ESMTP id A6C216B0073 for ; Fri, 22 Apr 2022 18:04:13 -0400 (EDT) Received: from smtpin27.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay10.hostedemail.com (Postfix) with ESMTP id 732DD10AD for ; Fri, 22 Apr 2022 22:04:13 +0000 (UTC) X-FDA: 79385893986.27.0800BE3 Received: from mail-qt1-f179.google.com (mail-qt1-f179.google.com [209.85.160.179]) by imf07.hostedemail.com (Postfix) with ESMTP id 3F1CF40029 for ; Fri, 22 Apr 2022 22:04:12 +0000 (UTC) Received: by mail-qt1-f179.google.com with SMTP id hh4so6472864qtb.10 for ; Fri, 22 Apr 2022 15:04:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=yCHSC34arsQtBqUXmCj99wEfbz8l2mnQAFiJJnf/+tY=; b=qmfdiGivhoyIkipKSQ76fwohGQ0nvXqS1+nsk1poehqsmrff2+K/16UChzb38m3hQj gs1WQKtzgyTq2mMctaVd0Jt2zzr2zG2IqKNCLcM+nEG1TMLoqPiXqLQnEv2Kw/ioeAJK ZmU7plVLbatnN/8IoNWr7J+l5Wy6Zii8lL9NIw45KNmoFUNSf8s9KsWY5DStfUeCGP+f CI/b9EW51ScAA7B8x06oMrq5b/tsAEYP7ITb4x+lGfSbrvnafuwL1l1jIL13rQqu2E5u 71ghj+41o4siscitqftFUUVKGxB5KIUTREv6uiiQuexYnJRdpeQnRZcVNkEvG+bQ+Y3D kSjw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=yCHSC34arsQtBqUXmCj99wEfbz8l2mnQAFiJJnf/+tY=; b=GY9e4U6tmj/kp0v3mxN0tWb0NE8IwgbfB/3mnBlp0FfLpf21Gv9pMVzGftOwmsB9R5 tyHTnR/SOwN4phXeTn6alIslKkm5aqESH5kQqocDS4b0a2ATrC6pbB+bCgS5KK9Aa0LE TsiqvsJsmriN3gdgJMPs2dFcH2WuSXxzN2fGAvlwHJb3YQ6m4HyPCV8NGvrbRWl3UjC8 ekiZbO3BkbY3bY/EXCgcWVca/6huQMlAZYNj2GH6nmldSWKnfzL/9DORM0W5P66pnv0g uM6NU6e65+oCZoyo/SINsdCd7nWxk1c3yb1+yI4OhAbtrgbluGhuT2XculkVFBxnO4aW X+dQ== X-Gm-Message-State: AOAM532J0Y5WBFbc/8VILA8vHWTw1fTZOzAr1CsxUoLWbhn84BFP2oRd 1nwEkqM4A4pVDkbPjOoT/HY= X-Google-Smtp-Source: ABdhPJyz1y2RUabYBwdobyv5hbJm72+B1Hxi8qwHEg8tyJQ5dCwv2+SJtFNrZtoMkdp7DOqnRqQujg== X-Received: by 2002:a05:622a:1a86:b0:2f3:4be4:42dd with SMTP id s6-20020a05622a1a8600b002f34be442ddmr4886306qtc.55.1650665052201; Fri, 22 Apr 2022 15:04:12 -0700 (PDT) Received: from localhost ([2601:c4:c432:7d0:efbc:f1b5:7b2c:5d4c]) by smtp.gmail.com with ESMTPSA id h75-20020a379e4e000000b0069db8210ffbsm1440267qke.12.2022.04.22.15.04.11 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 22 Apr 2022 15:04:11 -0700 (PDT) From: Yury Norov To: Andrew Morton , Alexey Klimov , Anshuman Khandual , Catalin Marinas , Ding Tianhong , Mark Rutland , Matthew Wilcox , Nicholas Piggin , Robin Murphy , Russell King , Will Deacon , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org Cc: Yury Norov Subject: [PATCH v3] vmap(): don't allow invalid pages Date: Fri, 22 Apr 2022 15:04:09 -0700 Message-Id: <20220422220410.1308706-1-yury.norov@gmail.com> X-Mailer: git-send-email 2.32.0 MIME-Version: 1.0 X-Rspamd-Queue-Id: 3F1CF40029 X-Stat-Signature: ttnf3489de9647s7ka77idqp8mozfd1a X-Rspam-User: Authentication-Results: imf07.hostedemail.com; dkim=pass header.d=gmail.com header.s=20210112 header.b=qmfdiGiv; spf=pass (imf07.hostedemail.com: domain of yury.norov@gmail.com designates 209.85.160.179 as permitted sender) smtp.mailfrom=yury.norov@gmail.com; dmarc=pass (policy=none) header.from=gmail.com X-Rspamd-Server: rspam09 X-HE-Tag: 1650665052-809609 X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: vmap() takes struct page *pages as one of arguments, and user may provide an invalid pointer which may lead to corrupted translation table. An example of such behaviour is erroneous usage of virt_to_page(): vaddr1 = dma_alloc_coherent() page = virt_to_page() // Wrong here ... vaddr2 = vmap(page) memset(vaddr2) // Faulting here virt_to_page() returns a wrong pointer if vaddr1 is not a linear kernel address. The problem is that vmap() populates pte with bad pfn successfully, and it's much harder to debug at memory access time. This case should be caught by DEBUG_VIRTUAL being that enabled, but it's not enabled in popular distros. Kernel already checks the pages against NULL. In the case mentioned above, however, the address is not NULL, and it's big enough so that the hardware generated Address Size Abort on arm64: [ 665.484101] Unhandled fault at 0xffff8000252cd000 [ 665.488807] Mem abort info: [ 665.491617] ESR = 0x96000043 [ 665.494675] EC = 0x25: DABT (current EL), IL = 32 bits [ 665.499985] SET = 0, FnV = 0 [ 665.503039] EA = 0, S1PTW = 0 [ 665.506167] Data abort info: [ 665.509047] ISV = 0, ISS = 0x00000043 [ 665.512882] CM = 0, WnR = 1 [ 665.515851] swapper pgtable: 4k pages, 48-bit VAs, pgdp=00000000818cb000 [ 665.522550] [ffff8000252cd000] pgd=000000affcfff003, pud=000000affcffe003, pmd=0000008fad8c3003, pte=00688000a5217713 [ 665.533160] Internal error: level 3 address size fault: 96000043 [#1] SMP [ 665.539936] Modules linked in: [...] [ 665.616212] CPU: 178 PID: 13199 Comm: test Tainted: P OE 5.4.0-84-generic #94~18.04.1-Ubuntu [ 665.626806] Hardware name: HPE Apollo 70 /C01_APACHE_MB , BIOS L50_5.13_1.0.6 07/10/2018 [ 665.636618] pstate: 80400009 (Nzcv daif +PAN -UAO) [ 665.641407] pc : __memset+0x38/0x188 [ 665.645146] lr : test+0xcc/0x3f8 [ 665.650184] sp : ffff8000359bb840 [ 665.653486] x29: ffff8000359bb840 x28: 0000000000000000 [ 665.658785] x27: 0000000000000000 x26: 0000000000231000 [ 665.664083] x25: ffff00ae660f6110 x24: ffff00ae668cb800 [ 665.669382] x23: 0000000000000001 x22: ffff00af533e5000 [ 665.674680] x21: 0000000000001000 x20: 0000000000000000 [ 665.679978] x19: ffff00ae66950000 x18: ffffffffffffffff [ 665.685276] x17: 00000000588636a5 x16: 0000000000000013 [ 665.690574] x15: ffffffffffffffff x14: 000000000007ffff [ 665.695872] x13: 0000000080000000 x12: 0140000000000000 [ 665.701170] x11: 0000000000000041 x10: ffff8000652cd000 [ 665.706468] x9 : ffff8000252cf000 x8 : ffff8000252cd000 [ 665.711767] x7 : 0303030303030303 x6 : 0000000000001000 [ 665.717065] x5 : ffff8000252cd000 x4 : 0000000000000000 [ 665.722363] x3 : ffff8000252cdfff x2 : 0000000000000001 [ 665.727661] x1 : 0000000000000003 x0 : ffff8000252cd000 [ 665.732960] Call trace: [ 665.735395] __memset+0x38/0x188 [...] Interestingly, this abort happens even if copy_from_kernel_nofault() is used, which is quite inconvenient for debugging purposes. This patch adds a pfn_valid() check into vmap() path, so that invalid mapping will not be created; WARN_ON() is used to let client code know that something goes wrong, and it's not a regular EINVAL situation. Suggested-by: Matthew Wilcox (Oracle) Signed-off-by: Yury Norov (NVIDIA) --- RFC: https://lkml.org/lkml/2022/1/18/815 v1: https://lkml.org/lkml/2022/1/18/1026 v2: https://lore.kernel.org/linux-mm/20220118235244.540103-1-yury.norov@gmail.com/ v3: Add more details and example in commit message. mm/vmalloc.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mm/vmalloc.c b/mm/vmalloc.c index e163372d3967..9b51a290d133 100644 --- a/mm/vmalloc.c +++ b/mm/vmalloc.c @@ -478,6 +478,9 @@ static int vmap_pages_pte_range(pmd_t *pmd, unsigned long addr, return -EBUSY; if (WARN_ON(!page)) return -ENOMEM; + if (WARN_ON(!pfn_valid(page_to_pfn(page)))) + return -EINVAL; + set_pte_at(&init_mm, addr, pte, mk_pte(page, prot)); (*nr)++; } while (pte++, addr += PAGE_SIZE, addr != end);