From patchwork Tue Nov 19 20:55:27 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Brian Johannesmeyer X-Patchwork-Id: 13880537 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 78ADBD6C299 for ; Tue, 19 Nov 2024 20:55:36 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id E7CD06B007B; Tue, 19 Nov 2024 15:55:35 -0500 (EST) Received: by kanga.kvack.org (Postfix, from userid 40) id E2C206B0082; Tue, 19 Nov 2024 15:55:35 -0500 (EST) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id CCCE46B0083; Tue, 19 Nov 2024 15:55:35 -0500 (EST) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0012.hostedemail.com [216.40.44.12]) by kanga.kvack.org (Postfix) with ESMTP id B05186B007B for ; Tue, 19 Nov 2024 15:55:35 -0500 (EST) Received: from smtpin23.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay02.hostedemail.com (Postfix) with ESMTP id 270F0120533 for ; Tue, 19 Nov 2024 20:55:35 +0000 (UTC) X-FDA: 82804049076.23.410E45D Received: from mail-ej1-f45.google.com (mail-ej1-f45.google.com [209.85.218.45]) by imf02.hostedemail.com (Postfix) with ESMTP id 6E65C80005 for ; Tue, 19 Nov 2024 20:53:57 +0000 (UTC) Authentication-Results: imf02.hostedemail.com; dkim=pass header.d=gmail.com header.s=20230601 header.b=UhDjYeCe; spf=pass (imf02.hostedemail.com: domain of bjohannesmeyer@gmail.com designates 209.85.218.45 as permitted sender) smtp.mailfrom=bjohannesmeyer@gmail.com; dmarc=pass (policy=none) header.from=gmail.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1732049489; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-transfer-encoding:content-transfer-encoding: in-reply-to:references:dkim-signature; bh=GAFNKtrBRUBVDKq3gLjDYKwvhPjyaMkGKIQ1dtJKNWg=; b=4h6lCugg+ZMOY5NmhhV2q8L2sEeV4ZktOGb3YAPMViDLYTiT9M+DiUCptjfU0BKR2S6gkM KpiZkcRRgnw3fvmNy8gACBxmadAG59X5dyjhCGtic+RkF195XQQOmJO7Nv/VT4ShGgpjlq 3BbvkoMYBQxGBqNs9caES9GuVSKYzlU= ARC-Authentication-Results: i=1; imf02.hostedemail.com; dkim=pass header.d=gmail.com header.s=20230601 header.b=UhDjYeCe; spf=pass (imf02.hostedemail.com: domain of bjohannesmeyer@gmail.com designates 209.85.218.45 as permitted sender) smtp.mailfrom=bjohannesmeyer@gmail.com; dmarc=pass (policy=none) header.from=gmail.com ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1732049489; a=rsa-sha256; cv=none; b=X+D3Kc5i4uGaiY/E/rYO+LZXNkyHYj/TMCnXYiSgrxT4BkVcz9kT1zJZNeZLx1neze7C8x w7uYP+BGbdnV1xWJdV7pMtT9Z1pqHjUMdrmKcSOH7tuhP6lyguspH4gVbSbL0SVhjbyg/d w6KhVmf6/HDiZzLpCOEln6zwl+xODHk= Received: by mail-ej1-f45.google.com with SMTP id a640c23a62f3a-a9e8522c10bso31016666b.1 for ; Tue, 19 Nov 2024 12:55:32 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1732049732; x=1732654532; darn=kvack.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=GAFNKtrBRUBVDKq3gLjDYKwvhPjyaMkGKIQ1dtJKNWg=; b=UhDjYeCebSNazRPVJ43uMadYrOSqHnGbSzmPp38GwqKxKAc8nO1yXOBEn4x7tWFnAE 8rkOKNz2U3lVzRBvZivKnB7j6/DEyF6fY0rPUx/KWaGIHffQEnrrsQb3vht+wiRJGTOc hPUcZrnGQy4KdtM4KjLzVfGKvTkHviK6kJKHFCV7KE1Jdec/F6qtj1Qoa0PtvAsoZdJm AEOC0j22Qbz5BpXX8VIEXm0nQQ6AMBExypw7lRPFFVkoR2J1PR1mhNnPjQfgrcVvAyB+ Heu9WzqoqxzsTD6CO4wUqIEy829UALscPeRYE+XgEzWDYOrUeTL0F1vSR+coJjHq0NxA Vv6Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1732049732; x=1732654532; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=GAFNKtrBRUBVDKq3gLjDYKwvhPjyaMkGKIQ1dtJKNWg=; b=eDZwLBaLNB3t7ztDUJY2UV/7puPzvW5aryoerlMew1arg4463OQ2f1/R7mYflhmgsq tQ/UiZup6vaqM4ZG1kvAafr5G2CYJBvJ/4uJBgoxR2uMEdsFmlyJJmysaBHYmWBEptzh Q/biwHwWDjn19cCdoWikZixJx47krCh4vq3B/3SWDjVolpmhInB64iiZ87EDeAdQguYs 6iBj7kpnmpoOBDO+EcZMKEXR2kg+dStBjHEI/K8VUCwDZFeFHC8yLNuq0dlurFw41MT1 Rf1MeVAQZJT2EWCZchTzrfdFEj4XF98HFYCJjtV6Jk0eRZnTN44EZeHUMPwblAKedGEJ cV4Q== X-Forwarded-Encrypted: i=1; AJvYcCUWQGkSjXuxBSilG2lXr4wcirZ60qD5G2c52Sv/PtldPgcNqLlpbkQyjUt9HKze4cQYB4Fw+mp6DQ==@kvack.org X-Gm-Message-State: AOJu0YxSWuKjPxVM/jOCTU3LPZWrKVngrGn1qxXeLLSTxsmglQ6ILV98 PXxHTBuFd0RTt0Q7doGPAiOSr/35w+X9RhBCG0gaVo1xsATxo8jH X-Google-Smtp-Source: AGHT+IHJsGLzylWE9CWQtOezfbuA1l2ST2+btHHw2oOH70Oser5nHJLzYFI62vUz8zOF50dmMCe9uA== X-Received: by 2002:a17:906:dac4:b0:a9a:597:8cc9 with SMTP id a640c23a62f3a-aa4dca6e28dmr43000966b.12.1732049731568; Tue, 19 Nov 2024 12:55:31 -0800 (PST) Received: from rex.hwlab.vusec.net (lab-4.lab.cs.vu.nl. [192.33.36.4]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-aa20dfffc00sm694709266b.101.2024.11.19.12.55.31 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 19 Nov 2024 12:55:31 -0800 (PST) From: Brian Johannesmeyer To: Andrew Morton , linux-mm@kvack.org, linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org Cc: Brian Johannesmeyer , Raphael Isemann , Cristiano Giuffrida , Herbert Bos , Greg KH Subject: [RFC v2 0/2] dmapool: Mitigate device-controllable mem. corruption Date: Tue, 19 Nov 2024 21:55:27 +0100 Message-Id: <20241119205529.3871048-1-bjohannesmeyer@gmail.com> X-Mailer: git-send-email 2.34.1 MIME-Version: 1.0 X-Rspamd-Server: rspam06 X-Rspamd-Queue-Id: 6E65C80005 X-Stat-Signature: jmzc7rgngcftzy3rn7733pcf654ihptb X-Rspam-User: X-HE-Tag: 1732049637-681136 X-HE-Meta: U2FsdGVkX1+r/0LPdhi3eECKrdVgK5Ioj1FGyULyHMs9niJrhRGzwM2t5pyyQ6j3al+t/n752js2BHzhsv30Gx8vn8eKmZ0Lg7xfcrPsNwPlwajfLdbI3SDZwsAjMfSqdr51hkQGpQ23eN8odKEE9s+1UqADkH8tC4DTbYsCpzp6XCCbU4UVa564zIBdwzjWgp25bFfbvgJ9KseAYwECafBzZlYYrOQBn0qJJyG79l0ncUphRimgs8CVC9jegjdCwsHBjA1DTBP9QBwOFeDKRuc6bP8+QyVsjeykN7qcrNtYhcXNjODs90n5tya58SQL1ucxmKjwsgtOjJdr+247kANKzkg2exeqQYe79qxMK5y0KLZpsn6jff6zm+k6G5jce9/l6LanbERS0E8W0JQIefGmVAh8AWoVzwppKTVrbsE8a4tLIkn4nskjYi5VMPMWrkSD9eEsXGI9MZBz7u09hE4grt+0q66ZNs5k+YkAlXVY8qTC4wwNcoz7cE+9mVaTvKwB3DBsZ9x5YGQDwpkpJFFtz4dCIwclgzWl0d7T5bYQ2jF1WPNGsPMgLKMPIlsr7QG0RE1FtKK947mgJFoHjC1GdTIRwt/2emPzRMKKDwPrX3kGYkkdbDiugXjVWDx9KXakW+hlJa7Uk1gCdHp4HTpvV7VMN6xtaHBuc/4/D5znKRBgaLejbEtLKXOk7QSJ+8nq77c4MqQBjPlbOhNUNhUY7FTdflc+YsoBuFJ7I5kVPdcwJBSWFNo3l9H8YahwbSA3MuS7AbzlWwHj+91UhOM3vpl9x1nJ+8k2qmrEq5F9whP4Ny6CeqLPg5i8Lf0/gPuFLczpAQor3ni6ecKvd8LQI4l9nSyO0NO6t/5POqBMxB4MJ15vOid2RcpmgUKf3P2n5gf4YNWPL1A9HbEIo97ozax2Fe01IPrez9MccNYKZEao9spYfqdv/ORPiDMgPbRBlSTkZFnRoGDny7V SlKM5XRa +WvT9f6CpjntCaCsJMpKk5Rl7BWcNUt8jucCR2QT+LeN4NxMSLtUJWxgTWI0JtX9V7hUvyP97crANfiaYMCWLLHGAPfqHDzFW1osT+TgQrJ47nw+sx5X5x9XMR/TdoNYIb3JPXJdb7gmjVrVUj0zeVKSIIRpzLntrB+zuGPQRJwDHqaCjRccepI+ghJ6VLfz7eARoLt+GtUuP+Ck7ghLXaUTZwFygvQ5NgzRoaBRk8UVfRS+M6e7EorqtMe7+TDnHr8AszUT2uS57jrcZUlo9Pocd9laC4gd81dN9UmKXvU8LD0Q/IPm7XZWp2jOJTFoTomy8aj9xcSyfHCXbz/I6iBQlr/dMjX76/qveTZk16Ab7guCZM069tSR1NP2c6BfW97pOx+Qan3FRVCGclVoJNf50zSv7yQXTaHYe 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: List-Subscribe: List-Unsubscribe: We discovered a security-related issue in the DMA pool allocator. V1 of our RFC was submitted to the Linux kernel security team. They recommended submitting it to the relevant subsystem maintainers and the hardening mailing list instead, as they did not consider this an explicit security issue. Their rationale was that Linux implicitly assumes hardware can be trusted. **Threat Model**: While Linux drivers typically trust their hardware, there may be specific drivers that do not operate under this assumption. Hence, this threat model assumes a malicious peripheral device capable of corrupting DMA data to exploit the kernel. In this scenario, the device manipulates kernel-initialized data (similar to the attack described in the Thunderclap paper [0]) to achieve arbitrary kernel memory corruption. **DMA pool background**. A DMA pool aims to reduce the overhead of DMA allocations by creating a large DMA buffer --- the "pool" --- from which smaller buffers are allocated as needed. Fundamentally, a DMA pool functions like a heap: it is a structure composed of linked memory "blocks", which, in this context, are DMA buffers. When a driver employs a DMA pool, it grants the device access not only to these blocks but also to the pointers linking them. **Vulnerability**. Similar to traditional heap corruption vulnerabilities --- where a malicious program corrupts heap metadata to e.g., hijack control flow --- a malicious device may corrupt DMA pool metadata. This corruption can trivially lead to arbitrary kernel memory corruption from any driver that uses it. Indeed, because the DMA pool API is extensively used, this vulnerability is not confined to a single instance. In fact, every usage of the DMA pool API is potentially vulnerable. An exploit proceeds with the following steps: 1. The DMA `pool` initializes its list of blocks, then points to the first block. 2. The malicious device overwrites the first 8 bytes of the first block --- which contain its `next_block` pointer --- to an arbitrary kernel address, `kernel_addr`. 3. The driver makes its first call to `dma_pool_alloc()`, after which, the pool should point to the second block. However, it instead points to `kernel_addr`. 4. The driver again calls `dma_pool_alloc()`, which incorrectly returns `kernel_addr`. Therefore, anytime the driver writes to this "block", it may corrupt sensitive kernel data. I have a PDF document that illustrates how these steps work. Please let me know if you would like me to share it with you. **Proposed mitigation**. To mitigate the corruption of DMA pool metadata (i.e., the pointers linking the blocks), the metadata should be moved into non-DMA memory, ensuring it cannot be altered by a device. I have included a patch series that implements this change. Since I am not deeply familiar with the DMA pool internals, I would appreciate any feedback on the patches. I have tested the patches with the `DMAPOOL_TEST` test and my own basic unit tests that ensure the DMA pool allocator is not vulnerable. **Performance**. I evaluated the patch set's performance by running the `DMAPOOL_TEST` test with `DMAPOOL_DEBUG` enabled and with/without the patches applied. Here is its output *without* the patches applied: ``` dmapool test: size:16 align:16 blocks:8192 time:3194110 dmapool test: size:64 align:64 blocks:8192 time:4730440 dmapool test: size:256 align:256 blocks:8192 time:5489630 dmapool test: size:1024 align:1024 blocks:2048 time:517150 dmapool test: size:4096 align:4096 blocks:1024 time:399616 dmapool test: size:68 align:32 blocks:8192 time:6156527 ``` And here is its output *with* the patches applied: ``` dmapool test: size:16 align:16 blocks:8192 time:3541031 dmapool test: size:64 align:64 blocks:8192 time:4227262 dmapool test: size:256 align:256 blocks:8192 time:4890273 dmapool test: size:1024 align:1024 blocks:2048 time:515775 dmapool test: size:4096 align:4096 blocks:1024 time:523096 dmapool test: size:68 align:32 blocks:8192 time:3450830 ``` Based on my interpretation of the output, the patch set does not appear to negatively impact performance. In fact, it shows slight performance improvements in some tests (i.e., for sizes 64, 256, 1024, and 68). I speculate that these performance gains may be due to improved spatial locality of the `next_block` pointers. With the patches applied, the `next_block` pointers are consistently spaced 24 bytes apart, matching the new size of `struct dma_block`. Previously, the spacing between `next_block` pointers depended on the block size, so for 1024-byte blocks, the pointers were spaced 1024 bytes apart. However, I am still unsure why the performance improvement for 68-byte blocks is so significant. [0] Link: https://www.csl.sri.com/~neumann/ndss-iommu.pdf Brian Johannesmeyer (2): dmapool: Move pool metadata into non-DMA memory dmapool: Use pool_find_block() in pool_block_err() mm/dmapool.c | 96 ++++++++++++++++++++++++++++++++++------------------ 1 file changed, 63 insertions(+), 33 deletions(-)