From patchwork Sat Feb 26 22:06:37 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Jason A. Donenfeld" X-Patchwork-Id: 546219 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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0F62FC43217 for ; Sat, 26 Feb 2022 22:07:07 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229823AbiBZWHj (ORCPT ); Sat, 26 Feb 2022 17:07:39 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:50724 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229776AbiBZWHi (ORCPT ); Sat, 26 Feb 2022 17:07:38 -0500 Received: from dfw.source.kernel.org (dfw.source.kernel.org [139.178.84.217]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 4E4C02BA9D3; Sat, 26 Feb 2022 14:07:03 -0800 (PST) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id D25F261130; Sat, 26 Feb 2022 22:07:02 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 0F8CEC340E8; Sat, 26 Feb 2022 22:07:00 +0000 (UTC) Authentication-Results: smtp.kernel.org; dkim=pass (1024-bit key) header.d=zx2c4.com header.i=@zx2c4.com header.b="NfRlxloY" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=zx2c4.com; s=20210105; t=1645913219; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=2km2UejiYYCkSDyW1zmU0/eY60KQFiPXWL05S8j5Yis=; b=NfRlxloY0t849ZdtH07d3lwBq2E9tlDSZW2N3N/gcjIaKmP66ESbQQcyC9/T8FXk0aodAi lYxRFXw0J0cm+JTEjbVV/6xjTaRxwkZZrDWqdG9S8mLhd/0tqH20kdSugUAn0v//h5TDxG dAuKVtd/Qa6lYjrjZ1KC4ptdrMg13CE= Received: by mail.zx2c4.com (ZX2C4 Mail Server) with ESMTPSA id 56ab209f (TLSv1.3:AEAD-AES256-GCM-SHA384:256:NO); Sat, 26 Feb 2022 22:06:59 +0000 (UTC) From: "Jason A. Donenfeld" To: Len Brown , "Rafael J. Wysocki" Cc: "Jason A. Donenfeld" , linux-crypto@vger.kernel.org, linux-acpi@vger.kernel.org, linux-kernel@vger.kernel.org, Alexander Graf , Ard Biesheuvel , Greg Kroah-Hartman , Dominik Brodowski , Theodore Ts'o , Jann Horn , Eric Biggers Subject: [PATCH v5 1/3] random: add mechanism for VM forks to reinitialize crng Date: Sat, 26 Feb 2022 23:06:37 +0100 Message-Id: <20220226220639.1173594-2-Jason@zx2c4.com> In-Reply-To: <20220226220639.1173594-1-Jason@zx2c4.com> References: <20220226220639.1173594-1-Jason@zx2c4.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-crypto@vger.kernel.org When a VM forks, we must immediately mix in additional information to the stream of random output so that two forks or a rollback don't produce the same stream of random numbers, which could have catastrophic cryptographic consequences. This commit adds a simple API, add_vmfork_ randomness(), for that, by force reseeding the crng. This has the added benefit of also draining the entropy pool and setting its timer back, so that any old entropy that was there prior -- which could have already been used by a different fork, or generally gone stale -- does not contribute to the accounting of the next 256 bits. Cc: Dominik Brodowski Cc: Theodore Ts'o Cc: Jann Horn Cc: Eric Biggers Reviewed-by: Ard Biesheuvel Signed-off-by: Jason A. Donenfeld --- drivers/char/random.c | 50 +++++++++++++++++++++++++++++------------- include/linux/random.h | 1 + 2 files changed, 36 insertions(+), 15 deletions(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index 8171c3bbf460..d9321b9bd3e3 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -289,14 +289,14 @@ static DEFINE_PER_CPU(struct crng, crngs) = { }; /* Used by crng_reseed() to extract a new seed from the input pool. */ -static bool drain_entropy(void *buf, size_t nbytes); +static bool drain_entropy(void *buf, size_t nbytes, bool force); /* * This extracts a new crng key from the input pool, but only if there is a - * sufficient amount of entropy available, in order to mitigate bruteforcing - * of newly added bits. + * sufficient amount of entropy available or force is true, in order to + * mitigate bruteforcing of newly added bits. */ -static void crng_reseed(void) +static void crng_reseed(bool force) { unsigned long flags; unsigned long next_gen; @@ -304,7 +304,7 @@ static void crng_reseed(void) bool finalize_init = false; /* Only reseed if we can, to prevent brute forcing a small amount of new bits. */ - if (!drain_entropy(key, sizeof(key))) + if (!drain_entropy(key, sizeof(key), force)) return; /* @@ -406,7 +406,7 @@ static void crng_make_state(u32 chacha_state[CHACHA_STATE_WORDS], * in turn bumps the generation counter that we check below. */ if (unlikely(time_after(jiffies, READ_ONCE(base_crng.birth) + CRNG_RESEED_INTERVAL))) - crng_reseed(); + crng_reseed(false); local_lock_irqsave(&crngs.lock, flags); crng = raw_cpu_ptr(&crngs); @@ -771,10 +771,10 @@ EXPORT_SYMBOL(get_random_bytes_arch); * * Finally, extract entropy via these two, with the latter one * setting the entropy count to zero and extracting only if there - * is POOL_MIN_BITS entropy credited prior: + * is POOL_MIN_BITS entropy credited prior or force is true: * * static void extract_entropy(void *buf, size_t nbytes) - * static bool drain_entropy(void *buf, size_t nbytes) + * static bool drain_entropy(void *buf, size_t nbytes, bool force) * **********************************************************************/ @@ -832,7 +832,7 @@ static void credit_entropy_bits(size_t nbits) } while (cmpxchg(&input_pool.entropy_count, orig, entropy_count) != orig); if (crng_init < 2 && entropy_count >= POOL_MIN_BITS) - crng_reseed(); + crng_reseed(false); } /* @@ -882,16 +882,16 @@ static void extract_entropy(void *buf, size_t nbytes) } /* - * First we make sure we have POOL_MIN_BITS of entropy in the pool, and then we - * set the entropy count to zero (but don't actually touch any data). Only then - * can we extract a new key with extract_entropy(). + * First we make sure we have POOL_MIN_BITS of entropy in the pool unless force + * is true, and then we set the entropy count to zero (but don't actually touch + * any data). Only then can we extract a new key with extract_entropy(). */ -static bool drain_entropy(void *buf, size_t nbytes) +static bool drain_entropy(void *buf, size_t nbytes, bool force) { unsigned int entropy_count; do { entropy_count = READ_ONCE(input_pool.entropy_count); - if (entropy_count < POOL_MIN_BITS) + if (!force && entropy_count < POOL_MIN_BITS) return false; } while (cmpxchg(&input_pool.entropy_count, entropy_count, 0) != entropy_count); extract_entropy(buf, nbytes); @@ -915,6 +915,7 @@ static bool drain_entropy(void *buf, size_t nbytes) * void add_hwgenerator_randomness(const void *buffer, size_t count, * size_t entropy); * void add_bootloader_randomness(const void *buf, size_t size); + * void add_vmfork_randomness(const void *unique_vm_id, size_t size); * void add_interrupt_randomness(int irq); * * add_device_randomness() adds data to the input pool that @@ -946,6 +947,10 @@ static bool drain_entropy(void *buf, size_t nbytes) * add_device_randomness(), depending on whether or not the configuration * option CONFIG_RANDOM_TRUST_BOOTLOADER is set. * + * add_vmfork_randomness() adds a unique (but not necessarily secret) ID + * representing the current instance of a VM to the pool, without crediting, + * and then force-reseeds the crng so that it takes effect immediately. + * * add_interrupt_randomness() uses the interrupt timing as random * inputs to the entropy pool. Using the cycle counters and the irq source * as inputs, it feeds the input pool roughly once a second or after 64 @@ -1173,6 +1178,21 @@ void add_bootloader_randomness(const void *buf, size_t size) } EXPORT_SYMBOL_GPL(add_bootloader_randomness); +/* + * Handle a new unique VM ID, which is unique, not secret, so we + * don't credit it, but we do immediately force a reseed after so + * that it's used by the crng posthaste. + */ +void add_vmfork_randomness(const void *unique_vm_id, size_t size) +{ + add_device_randomness(unique_vm_id, size); + if (crng_ready()) { + crng_reseed(true); + pr_notice("crng reseeded due to virtual machine fork\n"); + } +} +EXPORT_SYMBOL_GPL(add_vmfork_randomness); + struct fast_pool { union { u32 pool32[4]; @@ -1563,7 +1583,7 @@ static long random_ioctl(struct file *f, unsigned int cmd, unsigned long arg) return -EPERM; if (crng_init < 2) return -ENODATA; - crng_reseed(); + crng_reseed(false); return 0; default: return -EINVAL; diff --git a/include/linux/random.h b/include/linux/random.h index 6148b8d1ccf3..51b8ed797732 100644 --- a/include/linux/random.h +++ b/include/linux/random.h @@ -34,6 +34,7 @@ extern void add_input_randomness(unsigned int type, unsigned int code, extern void add_interrupt_randomness(int irq) __latent_entropy; extern void add_hwgenerator_randomness(const void *buffer, size_t count, size_t entropy); +extern void add_vmfork_randomness(const void *unique_vm_id, size_t size); extern void get_random_bytes(void *buf, size_t nbytes); extern int wait_for_random_bytes(void); From patchwork Sat Feb 26 22:06:38 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Jason A. Donenfeld" X-Patchwork-Id: 546479 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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 48EE4C433FE for ; Sat, 26 Feb 2022 22:07:12 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229776AbiBZWHo (ORCPT ); Sat, 26 Feb 2022 17:07:44 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:50852 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229845AbiBZWHn (ORCPT ); Sat, 26 Feb 2022 17:07:43 -0500 Received: from ams.source.kernel.org (ams.source.kernel.org [IPv6:2604:1380:4601:e00::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3BA0A2BA9D9; Sat, 26 Feb 2022 14:07:07 -0800 (PST) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ams.source.kernel.org (Postfix) with ESMTPS id DA640B80B23; Sat, 26 Feb 2022 22:07:05 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 7F933C340F1; Sat, 26 Feb 2022 22:07:03 +0000 (UTC) Authentication-Results: smtp.kernel.org; dkim=pass (1024-bit key) header.d=zx2c4.com header.i=@zx2c4.com header.b="hVhDgdre" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=zx2c4.com; s=20210105; t=1645913222; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=rJ7OlRCsSS8WuKwouw4P6E2HpFGNT8cQ0NpTG5KRx9U=; b=hVhDgdre7bjlMbXXbSOSSAq6teSp7bYMMbtGrCAEtg11r6jGCLmYJoAdq3KtDb8QhRJar+ gkKIa77ExzrSJZX6eU1xV72g4pZ4sM86Bm04B+K6Fq6StIqvxgJsz0qDUHYdBbu1ODFRKj Tgtp68wJFRqJBnKCnc74Z/EBu0F0xd8= Received: by mail.zx2c4.com (ZX2C4 Mail Server) with ESMTPSA id af55e8a1 (TLSv1.3:AEAD-AES256-GCM-SHA384:256:NO); Sat, 26 Feb 2022 22:07:02 +0000 (UTC) From: "Jason A. Donenfeld" To: Len Brown , "Rafael J. Wysocki" Cc: "Jason A. Donenfeld" , linux-crypto@vger.kernel.org, linux-acpi@vger.kernel.org, linux-kernel@vger.kernel.org, Alexander Graf , Ard Biesheuvel , Greg Kroah-Hartman Subject: [PATCH v5 2/3] ACPI: allow longer device IDs Date: Sat, 26 Feb 2022 23:06:38 +0100 Message-Id: <20220226220639.1173594-3-Jason@zx2c4.com> In-Reply-To: <20220226220639.1173594-1-Jason@zx2c4.com> References: <20220226220639.1173594-1-Jason@zx2c4.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-crypto@vger.kernel.org From: Alexander Graf We create a list of ACPI "PNP" IDs which contains _HID, _CID, and CLS entries of the respective devices. However, we squeeze them into struct acpi_device_id, which only has 9 bytes space to store the identifier. It originally had 16 bytes, but was changed to only have 9 in 6543becf26ff ("mod/file2alias: make modalias generation safe for cross compiling"), presumably on the theory that it would match the ACPI spec so it didn't matter. Unfortunately, while most people adhere to the ACPI specs, Microsoft decided that its VM Generation Counter device [1] should only be identifiable by _CID with a value of "VM_Gen_Counter", which is longer than 9 characters. To allow device drivers to match identifiers that exceed the 9 byte limit, this simply ups the length to 16, just like it was before the aforementioned commit. Empirical testing indicates that this doesn't actually increase vmlinux size, because the ulong in the same struct caused there to be 7 bytes of padding anyway. This patch is a prerequisite to add support for VMGenID in Linux, the subsequent patch in this series. It has been confirmed to also work on the udev/modalias side in userspace. [1] https://download.microsoft.com/download/3/1/C/31CFC307-98CA-4CA5-914C-D9772691E214/VirtualMachineGenerationID.docx Cc: Ard Biesheuvel Cc: Len Brown Cc: Rafael J. Wysocki Cc: Greg Kroah-Hartman Co-authored-by: Jason A. Donenfeld Signed-off-by: Alexander Graf Signed-off-by: Jason A. Donenfeld --- Hi Rafael & Len, This patchset is directed toward you two specifically. Patches 1/3 and 3/3 have been through the ringer of review a bit already and do not specifically require your attention, but in v4 we wound up getting hung up on an ACPI API limitation. This v5 fixes that limitation with this 2/3 patch that you see here, with a trivial one line fix, which does require your attention. Patches 1/3 and 3/3 will go through my random.git tree. However, 3/3 actually depends on this one here, 2/3, in order to compile without warnings (and be functional at all). Therefore, it would be nice if you would provide an "Acked-by" on it and permit me to /also/ take it through my random.git tree (if it looks like a correct patch to you, of course). This would make the merge logistics a lot easier. Plus it's a small +1/-1 line change. Please have a look and let me know what you think. Thanks, Jason include/linux/mod_devicetable.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h index 4bb71979a8fd..5da5d990ff58 100644 --- a/include/linux/mod_devicetable.h +++ b/include/linux/mod_devicetable.h @@ -211,7 +211,7 @@ struct css_device_id { kernel_ulong_t driver_data; }; -#define ACPI_ID_LEN 9 +#define ACPI_ID_LEN 16 struct acpi_device_id { __u8 id[ACPI_ID_LEN]; From patchwork Sat Feb 26 22:06:39 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: "Jason A. Donenfeld" X-Patchwork-Id: 546218 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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 38A59C43217 for ; Sat, 26 Feb 2022 22:07:13 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229862AbiBZWHq (ORCPT ); Sat, 26 Feb 2022 17:07:46 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51006 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229851AbiBZWHp (ORCPT ); Sat, 26 Feb 2022 17:07:45 -0500 Received: from dfw.source.kernel.org (dfw.source.kernel.org [IPv6:2604:1380:4641:c500::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3AE9B2BAF34; Sat, 26 Feb 2022 14:07:10 -0800 (PST) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id B24406114E; Sat, 26 Feb 2022 22:07:09 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id D7CA6C340E8; Sat, 26 Feb 2022 22:07:07 +0000 (UTC) Authentication-Results: smtp.kernel.org; dkim=pass (1024-bit key) header.d=zx2c4.com header.i=@zx2c4.com header.b="KkCPu/C0" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=zx2c4.com; s=20210105; t=1645913226; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=lgC4CNygcKrJYO+YX+We7wSVjgGMrkq6KLkVPJJTxVM=; b=KkCPu/C0Oh0/Grg+LjMMqij2Zu7Vx453DBEiOSKp5p1+hvDiiG8jM3JUpCjk2Nk7K2faPv NX07ktgf7DlEqHOmjeQ4j1CP4EWZq+DAyFDakPztdY8iTVcTOHR5V3VPcaM/Ti8dxKrTPu VtvaPlmgIHNShUPBR4WxmdpfnXMiF7Y= Received: by mail.zx2c4.com (ZX2C4 Mail Server) with ESMTPSA id 80dde4d1 (TLSv1.3:AEAD-AES256-GCM-SHA384:256:NO); Sat, 26 Feb 2022 22:07:06 +0000 (UTC) From: "Jason A. Donenfeld" To: Len Brown , "Rafael J. Wysocki" Cc: "Jason A. Donenfeld" , linux-crypto@vger.kernel.org, linux-acpi@vger.kernel.org, linux-kernel@vger.kernel.org, Alexander Graf , Ard Biesheuvel , Greg Kroah-Hartman , Adrian Catangiu , =?utf-8?q?Daniel_P_=2E_Berrang=C3=A9?= , Dominik Brodowski , Wei Yongjun , Laszlo Ersek Subject: [PATCH v5 3/3] virt: vmgenid: introduce driver for reinitializing RNG on VM fork Date: Sat, 26 Feb 2022 23:06:39 +0100 Message-Id: <20220226220639.1173594-4-Jason@zx2c4.com> In-Reply-To: <20220226220639.1173594-1-Jason@zx2c4.com> References: <20220226220639.1173594-1-Jason@zx2c4.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-crypto@vger.kernel.org VM Generation ID is a feature from Microsoft, described at , and supported by Hyper-V and QEMU. Its usage is described in Microsoft's RNG whitepaper, , as: If the OS is running in a VM, there is a problem that most hypervisors can snapshot the state of the machine and later rewind the VM state to the saved state. This results in the machine running a second time with the exact same RNG state, which leads to serious security problems. To reduce the window of vulnerability, Windows 10 on a Hyper-V VM will detect when the VM state is reset, retrieve a unique (not random) value from the hypervisor, and reseed the root RNG with that unique value. This does not eliminate the vulnerability, but it greatly reduces the time during which the RNG system will produce the same outputs as it did during a previous instantiation of the same VM state. Linux has the same issue, and given that vmgenid is supported already by multiple hypervisors, we can implement more or less the same solution. So this commit wires up the vmgenid ACPI notification to the RNG's newly added add_vmfork_randomness() function. It can be used from qemu via the `-device vmgenid,guid=auto` parameter. After setting that, use `savevm` in the monitor to save the VM state, then quit QEMU, start it again, and use `loadvm`. That will trigger this driver's notify function, which hands the new UUID to the RNG. This is described in . And there are hooks for this in libvirt as well, described in . Note, however, that the treatment of this as a UUID is considered to be an accidental QEMU nuance, per , so this driver simply treats these bytes as an opaque 128-bit binary blob, as per the spec. This doesn't really make a difference anyway, considering that's how it ends up when handed to the RNG in the end. Cc: Alexander Graf Cc: Adrian Catangiu Cc: Daniel P. Berrangé Cc: Dominik Brodowski Cc: Wei Yongjun Reviewed-by: Ard Biesheuvel Reviewed-by: Greg Kroah-Hartman Reviewed-by: Laszlo Ersek Signed-off-by: Jason A. Donenfeld --- Changes v4->v5: - [Greg] Use module_acpi_driver instead of writing my own code. - [Alex] Match on _CID instead of _HID. - Prefer Y over M but still allow M, to handle initramfs reseeds. - [Wei] Use IS_ERR instead of NULL check with devm_memremap. MAINTAINERS | 1 + drivers/virt/Kconfig | 11 +++++ drivers/virt/Makefile | 1 + drivers/virt/vmgenid.c | 100 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 113 insertions(+) create mode 100644 drivers/virt/vmgenid.c diff --git a/MAINTAINERS b/MAINTAINERS index 777cd6fa2b3d..a10997e15146 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -16211,6 +16211,7 @@ M: Jason A. Donenfeld T: git https://git.kernel.org/pub/scm/linux/kernel/git/crng/random.git S: Maintained F: drivers/char/random.c +F: drivers/virt/vmgenid.c RAPIDIO SUBSYSTEM M: Matt Porter diff --git a/drivers/virt/Kconfig b/drivers/virt/Kconfig index 8061e8ef449f..121b9293c737 100644 --- a/drivers/virt/Kconfig +++ b/drivers/virt/Kconfig @@ -13,6 +13,17 @@ menuconfig VIRT_DRIVERS if VIRT_DRIVERS +config VMGENID + tristate "Virtual Machine Generation ID driver" + default y + depends on ACPI + help + Say Y here to use the hypervisor-provided Virtual Machine Generation ID + to reseed the RNG when the VM is cloned. This is highly recommended if + you intend to do any rollback / cloning / snapshotting of VMs. + + Prefer Y to M so that this protection is activated very early. + config FSL_HV_MANAGER tristate "Freescale hypervisor management driver" depends on FSL_SOC diff --git a/drivers/virt/Makefile b/drivers/virt/Makefile index 3e272ea60cd9..108d0ffcc9aa 100644 --- a/drivers/virt/Makefile +++ b/drivers/virt/Makefile @@ -4,6 +4,7 @@ # obj-$(CONFIG_FSL_HV_MANAGER) += fsl_hypervisor.o +obj-$(CONFIG_VMGENID) += vmgenid.o obj-y += vboxguest/ obj-$(CONFIG_NITRO_ENCLAVES) += nitro_enclaves/ diff --git a/drivers/virt/vmgenid.c b/drivers/virt/vmgenid.c new file mode 100644 index 000000000000..0ae1a39f2e28 --- /dev/null +++ b/drivers/virt/vmgenid.c @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2022 Jason A. Donenfeld . All Rights Reserved. + * + * The "Virtual Machine Generation ID" is exposed via ACPI and changes when a + * virtual machine forks or is cloned. This driver exists for shepherding that + * information to random.c. + */ + +#include +#include +#include +#include + +ACPI_MODULE_NAME("vmgenid"); + +enum { VMGENID_SIZE = 16 }; + +struct vmgenid_state { + u8 *next_id; + u8 this_id[VMGENID_SIZE]; +}; + +static int vmgenid_add(struct acpi_device *device) +{ + struct acpi_buffer parsed = { ACPI_ALLOCATE_BUFFER }; + struct vmgenid_state *state; + union acpi_object *obj; + phys_addr_t phys_addr; + acpi_status status; + int ret = 0; + + state = devm_kmalloc(&device->dev, sizeof(*state), GFP_KERNEL); + if (!state) + return -ENOMEM; + + status = acpi_evaluate_object(device->handle, "ADDR", NULL, &parsed); + if (ACPI_FAILURE(status)) { + ACPI_EXCEPTION((AE_INFO, status, "Evaluating ADDR")); + return -ENODEV; + } + obj = parsed.pointer; + if (!obj || obj->type != ACPI_TYPE_PACKAGE || obj->package.count != 2 || + obj->package.elements[0].type != ACPI_TYPE_INTEGER || + obj->package.elements[1].type != ACPI_TYPE_INTEGER) { + ret = -EINVAL; + goto out; + } + + phys_addr = (obj->package.elements[0].integer.value << 0) | + (obj->package.elements[1].integer.value << 32); + state->next_id = devm_memremap(&device->dev, phys_addr, VMGENID_SIZE, MEMREMAP_WB); + if (IS_ERR(state->next_id)) { + ret = PTR_ERR(state->next_id); + goto out; + } + + memcpy(state->this_id, state->next_id, sizeof(state->this_id)); + add_device_randomness(state->this_id, sizeof(state->this_id)); + + device->driver_data = state; + +out: + ACPI_FREE(parsed.pointer); + return ret; +} + +static void vmgenid_notify(struct acpi_device *device, u32 event) +{ + struct vmgenid_state *state = acpi_driver_data(device); + u8 old_id[VMGENID_SIZE]; + + memcpy(old_id, state->this_id, sizeof(old_id)); + memcpy(state->this_id, state->next_id, sizeof(state->this_id)); + if (!memcmp(old_id, state->this_id, sizeof(old_id))) + return; + add_vmfork_randomness(state->this_id, sizeof(state->this_id)); +} + +static const struct acpi_device_id vmgenid_ids[] = { + { "VM_GEN_COUNTER", 0 }, + { } +}; + +static struct acpi_driver vmgenid_driver = { + .name = "vmgenid", + .ids = vmgenid_ids, + .owner = THIS_MODULE, + .ops = { + .add = vmgenid_add, + .notify = vmgenid_notify + } +}; + +module_acpi_driver(vmgenid_driver); + +MODULE_DEVICE_TABLE(acpi, vmgenid_ids); +MODULE_DESCRIPTION("Virtual Machine Generation ID"); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Jason A. Donenfeld ");