Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (C) 2022 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
0004  *
0005  * The "Virtual Machine Generation ID" is exposed via ACPI and changes when a
0006  * virtual machine forks or is cloned. This driver exists for shepherding that
0007  * information to random.c.
0008  */
0009 
0010 #include <linux/kernel.h>
0011 #include <linux/module.h>
0012 #include <linux/acpi.h>
0013 #include <linux/random.h>
0014 
0015 ACPI_MODULE_NAME("vmgenid");
0016 
0017 enum { VMGENID_SIZE = 16 };
0018 
0019 struct vmgenid_state {
0020     u8 *next_id;
0021     u8 this_id[VMGENID_SIZE];
0022 };
0023 
0024 static int vmgenid_add(struct acpi_device *device)
0025 {
0026     struct acpi_buffer parsed = { ACPI_ALLOCATE_BUFFER };
0027     struct vmgenid_state *state;
0028     union acpi_object *obj;
0029     phys_addr_t phys_addr;
0030     acpi_status status;
0031     int ret = 0;
0032 
0033     state = devm_kmalloc(&device->dev, sizeof(*state), GFP_KERNEL);
0034     if (!state)
0035         return -ENOMEM;
0036 
0037     status = acpi_evaluate_object(device->handle, "ADDR", NULL, &parsed);
0038     if (ACPI_FAILURE(status)) {
0039         ACPI_EXCEPTION((AE_INFO, status, "Evaluating ADDR"));
0040         return -ENODEV;
0041     }
0042     obj = parsed.pointer;
0043     if (!obj || obj->type != ACPI_TYPE_PACKAGE || obj->package.count != 2 ||
0044         obj->package.elements[0].type != ACPI_TYPE_INTEGER ||
0045         obj->package.elements[1].type != ACPI_TYPE_INTEGER) {
0046         ret = -EINVAL;
0047         goto out;
0048     }
0049 
0050     phys_addr = (obj->package.elements[0].integer.value << 0) |
0051             (obj->package.elements[1].integer.value << 32);
0052     state->next_id = devm_memremap(&device->dev, phys_addr, VMGENID_SIZE, MEMREMAP_WB);
0053     if (IS_ERR(state->next_id)) {
0054         ret = PTR_ERR(state->next_id);
0055         goto out;
0056     }
0057 
0058     memcpy(state->this_id, state->next_id, sizeof(state->this_id));
0059     add_device_randomness(state->this_id, sizeof(state->this_id));
0060 
0061     device->driver_data = state;
0062 
0063 out:
0064     ACPI_FREE(parsed.pointer);
0065     return ret;
0066 }
0067 
0068 static void vmgenid_notify(struct acpi_device *device, u32 event)
0069 {
0070     struct vmgenid_state *state = acpi_driver_data(device);
0071     u8 old_id[VMGENID_SIZE];
0072 
0073     memcpy(old_id, state->this_id, sizeof(old_id));
0074     memcpy(state->this_id, state->next_id, sizeof(state->this_id));
0075     if (!memcmp(old_id, state->this_id, sizeof(old_id)))
0076         return;
0077     add_vmfork_randomness(state->this_id, sizeof(state->this_id));
0078 }
0079 
0080 static const struct acpi_device_id vmgenid_ids[] = {
0081     { "VMGENCTR", 0 },
0082     { "VM_GEN_COUNTER", 0 },
0083     { }
0084 };
0085 
0086 static struct acpi_driver vmgenid_driver = {
0087     .name = "vmgenid",
0088     .ids = vmgenid_ids,
0089     .owner = THIS_MODULE,
0090     .ops = {
0091         .add = vmgenid_add,
0092         .notify = vmgenid_notify
0093     }
0094 };
0095 
0096 module_acpi_driver(vmgenid_driver);
0097 
0098 MODULE_DEVICE_TABLE(acpi, vmgenid_ids);
0099 MODULE_DESCRIPTION("Virtual Machine Generation ID");
0100 MODULE_LICENSE("GPL v2");
0101 MODULE_AUTHOR("Jason A. Donenfeld <Jason@zx2c4.com>");