123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354 |
- /*
- * AWS nitro-enclave machine
- *
- * Copyright (c) 2024 Dorjoy Chowdhury <dorjoychy111@gmail.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or
- * (at your option) any later version. See the COPYING file in the
- * top-level directory.
- */
- #include "qemu/osdep.h"
- #include "qemu/error-report.h"
- #include "qapi/error.h"
- #include "qom/object_interfaces.h"
- #include "chardev/char.h"
- #include "hw/sysbus.h"
- #include "hw/core/eif.h"
- #include "hw/i386/x86.h"
- #include "hw/i386/microvm.h"
- #include "hw/i386/nitro_enclave.h"
- #include "hw/virtio/virtio-mmio.h"
- #include "hw/virtio/virtio-nsm.h"
- #include "hw/virtio/vhost-user-vsock.h"
- #include "system/hostmem.h"
- static BusState *find_free_virtio_mmio_bus(void)
- {
- BusChild *kid;
- BusState *bus = sysbus_get_default();
- QTAILQ_FOREACH(kid, &bus->children, sibling) {
- DeviceState *dev = kid->child;
- if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MMIO)) {
- VirtIOMMIOProxy *mmio = VIRTIO_MMIO(OBJECT(dev));
- VirtioBusState *mmio_virtio_bus = &mmio->bus;
- BusState *mmio_bus = &mmio_virtio_bus->parent_obj;
- if (QTAILQ_EMPTY(&mmio_bus->children)) {
- return mmio_bus;
- }
- }
- }
- return NULL;
- }
- static void vhost_user_vsock_init(NitroEnclaveMachineState *nems)
- {
- DeviceState *dev = qdev_new(TYPE_VHOST_USER_VSOCK);
- VHostUserVSock *vsock = VHOST_USER_VSOCK(dev);
- BusState *bus;
- if (!nems->vsock) {
- error_report("A valid chardev id for vhost-user-vsock device must be "
- "provided using the 'vsock' machine option");
- exit(1);
- }
- bus = find_free_virtio_mmio_bus();
- if (!bus) {
- error_report("Failed to find bus for vhost-user-vsock device");
- exit(1);
- }
- Chardev *chardev = qemu_chr_find(nems->vsock);
- if (!chardev) {
- error_report("Failed to find chardev with id %s", nems->vsock);
- exit(1);
- }
- vsock->conf.chardev.chr = chardev;
- qdev_realize_and_unref(dev, bus, &error_fatal);
- }
- static void virtio_nsm_init(NitroEnclaveMachineState *nems)
- {
- DeviceState *dev = qdev_new(TYPE_VIRTIO_NSM);
- VirtIONSM *vnsm = VIRTIO_NSM(dev);
- BusState *bus = find_free_virtio_mmio_bus();
- if (!bus) {
- error_report("Failed to find bus for virtio-nsm device.");
- exit(1);
- }
- qdev_prop_set_string(dev, "module-id", nems->id);
- qdev_realize_and_unref(dev, bus, &error_fatal);
- nems->vnsm = vnsm;
- }
- static void nitro_enclave_devices_init(NitroEnclaveMachineState *nems)
- {
- vhost_user_vsock_init(nems);
- virtio_nsm_init(nems);
- }
- static void nitro_enclave_machine_state_init(MachineState *machine)
- {
- NitroEnclaveMachineClass *ne_class =
- NITRO_ENCLAVE_MACHINE_GET_CLASS(machine);
- NitroEnclaveMachineState *ne_state = NITRO_ENCLAVE_MACHINE(machine);
- ne_class->parent_init(machine);
- nitro_enclave_devices_init(ne_state);
- }
- static void nitro_enclave_machine_reset(MachineState *machine, ResetType type)
- {
- NitroEnclaveMachineClass *ne_class =
- NITRO_ENCLAVE_MACHINE_GET_CLASS(machine);
- NitroEnclaveMachineState *ne_state = NITRO_ENCLAVE_MACHINE(machine);
- ne_class->parent_reset(machine, type);
- memset(ne_state->vnsm->pcrs, 0, sizeof(ne_state->vnsm->pcrs));
- /* PCR0 */
- ne_state->vnsm->extend_pcr(ne_state->vnsm, 0, ne_state->image_hash,
- QCRYPTO_HASH_DIGEST_LEN_SHA384);
- /* PCR1 */
- ne_state->vnsm->extend_pcr(ne_state->vnsm, 1, ne_state->bootstrap_hash,
- QCRYPTO_HASH_DIGEST_LEN_SHA384);
- /* PCR2 */
- ne_state->vnsm->extend_pcr(ne_state->vnsm, 2, ne_state->app_hash,
- QCRYPTO_HASH_DIGEST_LEN_SHA384);
- /* PCR3 */
- if (ne_state->parent_role) {
- ne_state->vnsm->extend_pcr(ne_state->vnsm, 3,
- (uint8_t *) ne_state->parent_role,
- strlen(ne_state->parent_role));
- }
- /* PCR4 */
- if (ne_state->parent_id) {
- ne_state->vnsm->extend_pcr(ne_state->vnsm, 4,
- (uint8_t *) ne_state->parent_id,
- strlen(ne_state->parent_id));
- }
- /* PCR8 */
- if (ne_state->signature_found) {
- ne_state->vnsm->extend_pcr(ne_state->vnsm, 8,
- ne_state->fingerprint_hash,
- QCRYPTO_HASH_DIGEST_LEN_SHA384);
- }
- /* First 16 PCRs are locked from boot and reserved for nitro enclave */
- for (int i = 0; i < 16; ++i) {
- ne_state->vnsm->lock_pcr(ne_state->vnsm, i);
- }
- }
- static void nitro_enclave_machine_initfn(Object *obj)
- {
- MicrovmMachineState *mms = MICROVM_MACHINE(obj);
- X86MachineState *x86ms = X86_MACHINE(obj);
- NitroEnclaveMachineState *nems = NITRO_ENCLAVE_MACHINE(obj);
- nems->id = g_strdup("i-234-enc5678");
- /* AWS nitro enclaves have PCIE and ACPI disabled */
- mms->pcie = ON_OFF_AUTO_OFF;
- x86ms->acpi = ON_OFF_AUTO_OFF;
- }
- static void x86_load_eif(X86MachineState *x86ms, FWCfgState *fw_cfg,
- int acpi_data_size, bool pvh_enabled)
- {
- Error *err = NULL;
- char *eif_kernel, *eif_initrd, *eif_cmdline;
- MachineState *machine = MACHINE(x86ms);
- NitroEnclaveMachineState *nems = NITRO_ENCLAVE_MACHINE(x86ms);
- if (!read_eif_file(machine->kernel_filename, machine->initrd_filename,
- &eif_kernel, &eif_initrd, &eif_cmdline,
- nems->image_hash, nems->bootstrap_hash,
- nems->app_hash, nems->fingerprint_hash,
- &(nems->signature_found), &err)) {
- error_report_err(err);
- exit(1);
- }
- g_free(machine->kernel_filename);
- machine->kernel_filename = eif_kernel;
- g_free(machine->initrd_filename);
- machine->initrd_filename = eif_initrd;
- /*
- * If kernel cmdline argument was provided, let's concatenate it to the
- * extracted EIF kernel cmdline.
- */
- if (machine->kernel_cmdline != NULL) {
- char *cmd = g_strdup_printf("%s %s", eif_cmdline,
- machine->kernel_cmdline);
- g_free(eif_cmdline);
- g_free(machine->kernel_cmdline);
- machine->kernel_cmdline = cmd;
- } else {
- machine->kernel_cmdline = eif_cmdline;
- }
- x86_load_linux(x86ms, fw_cfg, 0, true);
- unlink(machine->kernel_filename);
- unlink(machine->initrd_filename);
- return;
- }
- static bool create_memfd_backend(MachineState *ms, const char *path,
- Error **errp)
- {
- Object *obj;
- MachineClass *mc = MACHINE_GET_CLASS(ms);
- bool r = false;
- obj = object_new(TYPE_MEMORY_BACKEND_MEMFD);
- if (!object_property_set_int(obj, "size", ms->ram_size, errp)) {
- goto out;
- }
- object_property_add_child(object_get_objects_root(), mc->default_ram_id,
- obj);
- if (!user_creatable_complete(USER_CREATABLE(obj), errp)) {
- goto out;
- }
- r = object_property_set_link(OBJECT(ms), "memory-backend", obj, errp);
- out:
- object_unref(obj);
- return r;
- }
- static char *nitro_enclave_get_vsock_chardev_id(Object *obj, Error **errp)
- {
- NitroEnclaveMachineState *nems = NITRO_ENCLAVE_MACHINE(obj);
- return g_strdup(nems->vsock);
- }
- static void nitro_enclave_set_vsock_chardev_id(Object *obj, const char *value,
- Error **errp)
- {
- NitroEnclaveMachineState *nems = NITRO_ENCLAVE_MACHINE(obj);
- g_free(nems->vsock);
- nems->vsock = g_strdup(value);
- }
- static char *nitro_enclave_get_id(Object *obj, Error **errp)
- {
- NitroEnclaveMachineState *nems = NITRO_ENCLAVE_MACHINE(obj);
- return g_strdup(nems->id);
- }
- static void nitro_enclave_set_id(Object *obj, const char *value,
- Error **errp)
- {
- NitroEnclaveMachineState *nems = NITRO_ENCLAVE_MACHINE(obj);
- g_free(nems->id);
- nems->id = g_strdup(value);
- }
- static char *nitro_enclave_get_parent_role(Object *obj, Error **errp)
- {
- NitroEnclaveMachineState *nems = NITRO_ENCLAVE_MACHINE(obj);
- return g_strdup(nems->parent_role);
- }
- static void nitro_enclave_set_parent_role(Object *obj, const char *value,
- Error **errp)
- {
- NitroEnclaveMachineState *nems = NITRO_ENCLAVE_MACHINE(obj);
- g_free(nems->parent_role);
- nems->parent_role = g_strdup(value);
- }
- static char *nitro_enclave_get_parent_id(Object *obj, Error **errp)
- {
- NitroEnclaveMachineState *nems = NITRO_ENCLAVE_MACHINE(obj);
- return g_strdup(nems->parent_id);
- }
- static void nitro_enclave_set_parent_id(Object *obj, const char *value,
- Error **errp)
- {
- NitroEnclaveMachineState *nems = NITRO_ENCLAVE_MACHINE(obj);
- g_free(nems->parent_id);
- nems->parent_id = g_strdup(value);
- }
- static void nitro_enclave_class_init(ObjectClass *oc, void *data)
- {
- MachineClass *mc = MACHINE_CLASS(oc);
- MicrovmMachineClass *mmc = MICROVM_MACHINE_CLASS(oc);
- NitroEnclaveMachineClass *nemc = NITRO_ENCLAVE_MACHINE_CLASS(oc);
- mmc->x86_load_linux = x86_load_eif;
- mc->family = "nitro_enclave_i386";
- mc->desc = "AWS Nitro Enclave";
- nemc->parent_init = mc->init;
- mc->init = nitro_enclave_machine_state_init;
- nemc->parent_reset = mc->reset;
- mc->reset = nitro_enclave_machine_reset;
- mc->create_default_memdev = create_memfd_backend;
- object_class_property_add_str(oc, NITRO_ENCLAVE_VSOCK_CHARDEV_ID,
- nitro_enclave_get_vsock_chardev_id,
- nitro_enclave_set_vsock_chardev_id);
- object_class_property_set_description(oc, NITRO_ENCLAVE_VSOCK_CHARDEV_ID,
- "Set chardev id for vhost-user-vsock "
- "device");
- object_class_property_add_str(oc, NITRO_ENCLAVE_ID, nitro_enclave_get_id,
- nitro_enclave_set_id);
- object_class_property_set_description(oc, NITRO_ENCLAVE_ID,
- "Set enclave identifier");
- object_class_property_add_str(oc, NITRO_ENCLAVE_PARENT_ROLE,
- nitro_enclave_get_parent_role,
- nitro_enclave_set_parent_role);
- object_class_property_set_description(oc, NITRO_ENCLAVE_PARENT_ROLE,
- "Set parent instance IAM role ARN");
- object_class_property_add_str(oc, NITRO_ENCLAVE_PARENT_ID,
- nitro_enclave_get_parent_id,
- nitro_enclave_set_parent_id);
- object_class_property_set_description(oc, NITRO_ENCLAVE_PARENT_ID,
- "Set parent instance identifier");
- }
- static const TypeInfo nitro_enclave_machine_info = {
- .name = TYPE_NITRO_ENCLAVE_MACHINE,
- .parent = TYPE_MICROVM_MACHINE,
- .instance_size = sizeof(NitroEnclaveMachineState),
- .instance_init = nitro_enclave_machine_initfn,
- .class_size = sizeof(NitroEnclaveMachineClass),
- .class_init = nitro_enclave_class_init,
- };
- static void nitro_enclave_machine_init(void)
- {
- type_register_static(&nitro_enclave_machine_info);
- }
- type_init(nitro_enclave_machine_init);
|