Received: by 2002:ac0:a5b6:0:0:0:0:0 with SMTP id m51-v6csp428264imm; Tue, 5 Jun 2018 23:21:01 -0700 (PDT) X-Google-Smtp-Source: ADUXVKKceHvJxJLAfkYsVr4pZJFEMUbzkJmrMk0zp/qTZWko1pZ8dPeavRp3SqzYgCnD2WKKA2Kh X-Received: by 2002:a62:aa18:: with SMTP id e24-v6mr1194383pff.72.1528266061019; Tue, 05 Jun 2018 23:21:01 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1528266060; cv=none; d=google.com; s=arc-20160816; b=ulr9Rxj8il/nEfdtklt1wC89NUDtaaTJVhyObSTMAdZqdgspDdm3/HNWkkBCO6x2jx GFaNVUOCkpltzhkSAVmA0/CODi4LlFwduZSJpdmH0zzZ8Ahlu87sp19v0glQE4UiME18 6hspaquqT0dM4/Yop7qyqAw17GRWPakVNhz35W9KkSvZYRYSQqoh2GaM5Saf5d3VHe4A 3UIVnkIfF03MrWS65rZN3Qr+FwTkntJBH4fOKsoFQpYZF40cR2OkZDRkjFRK0+ZIjfqm TrUGl6ct52JKx0qCFJW/wWKykToSjB6neSt99VFI3KNIVVprSk8tQzccbdS8IKLgbcO0 4TRg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:cc:to:subject:message-id:date:from :references:in-reply-to:mime-version:dkim-signature :arc-authentication-results; bh=KiLkW89Cq+K0WBJOlE0yl+86RtbisWqdIkjCJYbA12g=; b=IwP4yKEVqwCmajqsUhQ4p2DK+RAYBsTxsw9c4XMiMXRsrKVgpWBdIlOTxqE124Isz5 wncvVXcKxy/nsOK01+9Lw2w26srtfToj+1O/FKK4sGSkVqyQ8TUAxB5u9zIcwUqiv6j4 8J3W3ULtQD/SbF5x38vMXHWQgpArYhZ/bPePW+XHBWD6j0dnwO+mVw9iAWL+hGKtwb57 Wxca6HJkLaTCvM/UGaR1IFw9Ix8XGFLVgODEy3CeZIzFdhTwhEPbGyaFdKSKEC+kehtW gLV7Jov+ZTFZCBlICBJuO3P3jaoirG4qmfAWZ47R6FfXyWLfGmIgDv4cXz7bT3uY5mY2 Z0Kw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=JhJCDqao; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id w22-v6si49690073plq.196.2018.06.05.23.20.46; Tue, 05 Jun 2018 23:21:00 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=JhJCDqao; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932120AbeFFGUU (ORCPT + 99 others); Wed, 6 Jun 2018 02:20:20 -0400 Received: from mail-it0-f68.google.com ([209.85.214.68]:37927 "EHLO mail-it0-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751008AbeFFGUS (ORCPT ); Wed, 6 Jun 2018 02:20:18 -0400 Received: by mail-it0-f68.google.com with SMTP id v83-v6so6549410itc.3 for ; Tue, 05 Jun 2018 23:20:18 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=mime-version:in-reply-to:references:from:date:message-id:subject:to :cc; bh=KiLkW89Cq+K0WBJOlE0yl+86RtbisWqdIkjCJYbA12g=; b=JhJCDqaoGcWY8vHywri6thhpaZUSroG4/2c+7GBECsngYHkR6RiOCgfDocUyfq9oKK +NWol1pvy2VtbnBGuPOFishgmU7dAPme953t8EMuHagWFvYOH6ZZc1Q/888MfpawRsa5 iP0bI8TWWXmQQ/lJCY6v7wtjT1Pw2SgeQ6ZQc= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:in-reply-to:references:from:date :message-id:subject:to:cc; bh=KiLkW89Cq+K0WBJOlE0yl+86RtbisWqdIkjCJYbA12g=; b=YFcLqA3Xt1Wm3Vqko58S/ZNMRPir3t8076aX10uKddscc/Ia81mnLAe7QP/th7cEqV XlJNQ35GjSUlq8PTRKVGa5RR94+sVF+sw1HN300UozsNDLLS9QFQ7KOqEIwTOTK6Ms64 sDm0ync8cuEk4RclfRnkb76MhyoQ0YGueB0bIGvy0EpK2M7NZNfoxcIcI/rT+9CWsi1h K8wkaUyPL+/TDWogNHcRIHumremAyOkth1nqfLxJOSYm5Oc7HXDqrDoNecY0R51fVJRQ sAnIZPHD4awfRvOksa8sjyG/zhetuaGEG1turiFv61isw6YEW+vFfU78whxH8J68bWVV 36HA== X-Gm-Message-State: APt69E02e41hv8pNm4t3VuTfpIzuVK8izsQCYUzc3BsEJdPuRR6fepGe 20Dcyxd2jxyibTCf3gbopHTmuwTXmuMOVQMQgVM0vw== X-Received: by 2002:a24:e105:: with SMTP id n5-v6mr1237442ith.68.1528266017703; Tue, 05 Jun 2018 23:20:17 -0700 (PDT) MIME-Version: 1.0 Received: by 2002:a6b:bb86:0:0:0:0:0 with HTTP; Tue, 5 Jun 2018 23:20:17 -0700 (PDT) In-Reply-To: References: <1527616920-5415-1-git-send-email-zohar@linux.vnet.ibm.com> <1527616920-5415-8-git-send-email-zohar@linux.vnet.ibm.com> <20180601191545.GP4511@wotan.suse.de> <20180601192545.GR4511@wotan.suse.de> From: Ard Biesheuvel Date: Wed, 6 Jun 2018 08:20:17 +0200 Message-ID: Subject: Re: [RFC PATCH v4 7/8] ima: based on policy prevent loading firmware (pre-allocated buffer) To: Kees Cook Cc: Mimi Zohar , "Luis R. Rodriguez" , Vlastimil Babka , Matthew Garrett , linux-integrity , linux-security-module , LKML , David Howells , Eric Biederman , Kexec Mailing List , Andres Rodriguez , Greg Kroah-Hartman , "Serge E . Hallyn" , Stephen Boyd , Laura Abbott , Rik van Riel Content-Type: text/plain; charset="UTF-8" Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On 6 June 2018 at 00:37, Kees Cook wrote: > On Fri, Jun 1, 2018 at 12:25 PM, Luis R. Rodriguez wrote: >> On Fri, Jun 01, 2018 at 09:15:45PM +0200, Luis R. Rodriguez wrote: >>> On Tue, May 29, 2018 at 02:01:59PM -0400, Mimi Zohar wrote: >>> > Some systems are memory constrained but they need to load very large >>> > firmwares. The firmware subsystem allows drivers to request this >>> > firmware be loaded from the filesystem, but this requires that the >>> > entire firmware be loaded into kernel memory first before it's provided >>> > to the driver. This can lead to a situation where we map the firmware >>> > twice, once to load the firmware into kernel memory and once to copy the >>> > firmware into the final resting place. >>> > >>> > To resolve this problem, commit a098ecd2fa7d ("firmware: support loading >>> > into a pre-allocated buffer") introduced request_firmware_into_buf() API >>> > that allows drivers to request firmware be loaded directly into a >>> > pre-allocated buffer. The QCOM_MDT_LOADER calls dma_alloc_coherent() to >>> > allocate this buffer. According to Documentation/DMA-API.txt, >>> > >>> > Consistent memory is memory for which a write by either the >>> > device or the processor can immediately be read by the processor >>> > or device without having to worry about caching effects. (You >>> > may however need to make sure to flush the processor's write >>> > buffers before telling devices to read that memory.) >>> > >>> > Devices using pre-allocated DMA memory run the risk of the firmware >>> > being accessible by the device prior to the kernel's firmware signature >>> > verification has completed. >>> >>> Indeed. And since its DMA memory we have *no idea* what can happen in >>> terms of consumption of this firmware from hardware, when it would start >>> consuming it in particular. >>> >>> If the device has its own hardware firmware verification mechanism this is >>> completely obscure to us, but it may however suffice certain security policies. >>> >>> The problem here lies in the conflicting security policies of the kernel wanting >>> to not give away firmware until its complete and the current inability to enable >>> us to have platforms suggest they trust hardware won't do something stupid. >>> This becomes an issue since the semantics of the firmware API preallocated >>> buffer do not require currently allow the kernel to inform LSMs of the fact >>> that a buffer is DMA memory or not, and a way for certain platforms then >>> to say that such use is fine for specific devices. >>> >>> Given a pointer can we determine if a piece of memory is DMA or not? >> >> FWIW >> >> Vlastimil suggests page_zone() or virt_to_page() may be able to. > > I don't see a PAGEFLAG for DMA, but I do see ZONE_DMA for > page_zone()... So maybe something like > > struct page *page; > > page = virt_to_page(address); > if (!page) > fail closed... > if (page_zone(page) == ZONE_DMA) > handle dma case... > else > non-dma > > But I've CCed Laura and Rik, who I always lean on when I have these > kinds of page questions... > That is not going to help. In general, DMA can access any memory in the system (unless a IOMMU is actively preventing that). The streaming DMA API allows you to map()/unmap() arbitrary pieces of memory for DMA, regardless of how they were allocated. (Some drivers were even doing DMA from the stack at some point, but this broke vmapped stacks so most of these cases have been fixed) Uploading firmware to a device does not require a coherent (as opposed to streaming) mapping for DMA, and so it is perfectly reasonable for a driver to use the streaming API to map the firmware image (wherever it is in memory) and map it. However, the DMA API does impose some ordering. Mapping memory for DMA gives you a DMA address (which may be different from the physical address [depending on the platform]), and this DMA address is what gets programmed into the device, not the virtual or physical address. That means you can be reasonably confident that the device will not be able to consume what is in this memory before it has been mapped for DMA. Also, the DMA api explicitly forbids touching memory mapped for streaming DMA: the device owns it at this point, and so the CPU should refrain from accessing it. So the question is, why is QCOM_MDT_LOADER using a coherent DMA mapping? That does not make any sense purely for moving firmware into the device, and it is indeed a security hazard if we are trying to perform a signature check before the device is cleared for reading it. Note that qcom_scm_pas_init_image() is documented as /* * During the scm call memory protection will be enabled for the meta * data blob, so make sure it's physically contiguous, 4K aligned and * non-cachable to avoid XPU violations. */ and dma_alloc_coherent() happens to give them that. Whether the DMA mapping is actually used is a different matter: the code is a bit complex, but it calls into the secure world to set up the region. If this is the only counterexample, I wouldn't worry about it too much (QCOM have elaborate SoC management layers in the secure world), and simply mandate that only streaming DMA be used for firmware loading, and that the firmware signature verification is performed before the memory is mapped for DMA.