nitro_enclave.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. /*
  2. * AWS nitro-enclave machine
  3. *
  4. * Copyright (c) 2024 Dorjoy Chowdhury <dorjoychy111@gmail.com>
  5. *
  6. * This work is licensed under the terms of the GNU GPL, version 2 or
  7. * (at your option) any later version. See the COPYING file in the
  8. * top-level directory.
  9. */
  10. #include "qemu/osdep.h"
  11. #include "qemu/error-report.h"
  12. #include "qapi/error.h"
  13. #include "qom/object_interfaces.h"
  14. #include "chardev/char.h"
  15. #include "hw/sysbus.h"
  16. #include "hw/core/eif.h"
  17. #include "hw/i386/x86.h"
  18. #include "hw/i386/microvm.h"
  19. #include "hw/i386/nitro_enclave.h"
  20. #include "hw/virtio/virtio-mmio.h"
  21. #include "hw/virtio/virtio-nsm.h"
  22. #include "hw/virtio/vhost-user-vsock.h"
  23. #include "system/hostmem.h"
  24. static BusState *find_free_virtio_mmio_bus(void)
  25. {
  26. BusChild *kid;
  27. BusState *bus = sysbus_get_default();
  28. QTAILQ_FOREACH(kid, &bus->children, sibling) {
  29. DeviceState *dev = kid->child;
  30. if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MMIO)) {
  31. VirtIOMMIOProxy *mmio = VIRTIO_MMIO(OBJECT(dev));
  32. VirtioBusState *mmio_virtio_bus = &mmio->bus;
  33. BusState *mmio_bus = &mmio_virtio_bus->parent_obj;
  34. if (QTAILQ_EMPTY(&mmio_bus->children)) {
  35. return mmio_bus;
  36. }
  37. }
  38. }
  39. return NULL;
  40. }
  41. static void vhost_user_vsock_init(NitroEnclaveMachineState *nems)
  42. {
  43. DeviceState *dev = qdev_new(TYPE_VHOST_USER_VSOCK);
  44. VHostUserVSock *vsock = VHOST_USER_VSOCK(dev);
  45. BusState *bus;
  46. if (!nems->vsock) {
  47. error_report("A valid chardev id for vhost-user-vsock device must be "
  48. "provided using the 'vsock' machine option");
  49. exit(1);
  50. }
  51. bus = find_free_virtio_mmio_bus();
  52. if (!bus) {
  53. error_report("Failed to find bus for vhost-user-vsock device");
  54. exit(1);
  55. }
  56. Chardev *chardev = qemu_chr_find(nems->vsock);
  57. if (!chardev) {
  58. error_report("Failed to find chardev with id %s", nems->vsock);
  59. exit(1);
  60. }
  61. vsock->conf.chardev.chr = chardev;
  62. qdev_realize_and_unref(dev, bus, &error_fatal);
  63. }
  64. static void virtio_nsm_init(NitroEnclaveMachineState *nems)
  65. {
  66. DeviceState *dev = qdev_new(TYPE_VIRTIO_NSM);
  67. VirtIONSM *vnsm = VIRTIO_NSM(dev);
  68. BusState *bus = find_free_virtio_mmio_bus();
  69. if (!bus) {
  70. error_report("Failed to find bus for virtio-nsm device.");
  71. exit(1);
  72. }
  73. qdev_prop_set_string(dev, "module-id", nems->id);
  74. qdev_realize_and_unref(dev, bus, &error_fatal);
  75. nems->vnsm = vnsm;
  76. }
  77. static void nitro_enclave_devices_init(NitroEnclaveMachineState *nems)
  78. {
  79. vhost_user_vsock_init(nems);
  80. virtio_nsm_init(nems);
  81. }
  82. static void nitro_enclave_machine_state_init(MachineState *machine)
  83. {
  84. NitroEnclaveMachineClass *ne_class =
  85. NITRO_ENCLAVE_MACHINE_GET_CLASS(machine);
  86. NitroEnclaveMachineState *ne_state = NITRO_ENCLAVE_MACHINE(machine);
  87. ne_class->parent_init(machine);
  88. nitro_enclave_devices_init(ne_state);
  89. }
  90. static void nitro_enclave_machine_reset(MachineState *machine, ResetType type)
  91. {
  92. NitroEnclaveMachineClass *ne_class =
  93. NITRO_ENCLAVE_MACHINE_GET_CLASS(machine);
  94. NitroEnclaveMachineState *ne_state = NITRO_ENCLAVE_MACHINE(machine);
  95. ne_class->parent_reset(machine, type);
  96. memset(ne_state->vnsm->pcrs, 0, sizeof(ne_state->vnsm->pcrs));
  97. /* PCR0 */
  98. ne_state->vnsm->extend_pcr(ne_state->vnsm, 0, ne_state->image_hash,
  99. QCRYPTO_HASH_DIGEST_LEN_SHA384);
  100. /* PCR1 */
  101. ne_state->vnsm->extend_pcr(ne_state->vnsm, 1, ne_state->bootstrap_hash,
  102. QCRYPTO_HASH_DIGEST_LEN_SHA384);
  103. /* PCR2 */
  104. ne_state->vnsm->extend_pcr(ne_state->vnsm, 2, ne_state->app_hash,
  105. QCRYPTO_HASH_DIGEST_LEN_SHA384);
  106. /* PCR3 */
  107. if (ne_state->parent_role) {
  108. ne_state->vnsm->extend_pcr(ne_state->vnsm, 3,
  109. (uint8_t *) ne_state->parent_role,
  110. strlen(ne_state->parent_role));
  111. }
  112. /* PCR4 */
  113. if (ne_state->parent_id) {
  114. ne_state->vnsm->extend_pcr(ne_state->vnsm, 4,
  115. (uint8_t *) ne_state->parent_id,
  116. strlen(ne_state->parent_id));
  117. }
  118. /* PCR8 */
  119. if (ne_state->signature_found) {
  120. ne_state->vnsm->extend_pcr(ne_state->vnsm, 8,
  121. ne_state->fingerprint_hash,
  122. QCRYPTO_HASH_DIGEST_LEN_SHA384);
  123. }
  124. /* First 16 PCRs are locked from boot and reserved for nitro enclave */
  125. for (int i = 0; i < 16; ++i) {
  126. ne_state->vnsm->lock_pcr(ne_state->vnsm, i);
  127. }
  128. }
  129. static void nitro_enclave_machine_initfn(Object *obj)
  130. {
  131. MicrovmMachineState *mms = MICROVM_MACHINE(obj);
  132. X86MachineState *x86ms = X86_MACHINE(obj);
  133. NitroEnclaveMachineState *nems = NITRO_ENCLAVE_MACHINE(obj);
  134. nems->id = g_strdup("i-234-enc5678");
  135. /* AWS nitro enclaves have PCIE and ACPI disabled */
  136. mms->pcie = ON_OFF_AUTO_OFF;
  137. x86ms->acpi = ON_OFF_AUTO_OFF;
  138. }
  139. static void x86_load_eif(X86MachineState *x86ms, FWCfgState *fw_cfg,
  140. int acpi_data_size, bool pvh_enabled)
  141. {
  142. Error *err = NULL;
  143. char *eif_kernel, *eif_initrd, *eif_cmdline;
  144. MachineState *machine = MACHINE(x86ms);
  145. NitroEnclaveMachineState *nems = NITRO_ENCLAVE_MACHINE(x86ms);
  146. if (!read_eif_file(machine->kernel_filename, machine->initrd_filename,
  147. &eif_kernel, &eif_initrd, &eif_cmdline,
  148. nems->image_hash, nems->bootstrap_hash,
  149. nems->app_hash, nems->fingerprint_hash,
  150. &(nems->signature_found), &err)) {
  151. error_report_err(err);
  152. exit(1);
  153. }
  154. g_free(machine->kernel_filename);
  155. machine->kernel_filename = eif_kernel;
  156. g_free(machine->initrd_filename);
  157. machine->initrd_filename = eif_initrd;
  158. /*
  159. * If kernel cmdline argument was provided, let's concatenate it to the
  160. * extracted EIF kernel cmdline.
  161. */
  162. if (machine->kernel_cmdline != NULL) {
  163. char *cmd = g_strdup_printf("%s %s", eif_cmdline,
  164. machine->kernel_cmdline);
  165. g_free(eif_cmdline);
  166. g_free(machine->kernel_cmdline);
  167. machine->kernel_cmdline = cmd;
  168. } else {
  169. machine->kernel_cmdline = eif_cmdline;
  170. }
  171. x86_load_linux(x86ms, fw_cfg, 0, true);
  172. unlink(machine->kernel_filename);
  173. unlink(machine->initrd_filename);
  174. return;
  175. }
  176. static bool create_memfd_backend(MachineState *ms, const char *path,
  177. Error **errp)
  178. {
  179. Object *obj;
  180. MachineClass *mc = MACHINE_GET_CLASS(ms);
  181. bool r = false;
  182. obj = object_new(TYPE_MEMORY_BACKEND_MEMFD);
  183. if (!object_property_set_int(obj, "size", ms->ram_size, errp)) {
  184. goto out;
  185. }
  186. object_property_add_child(object_get_objects_root(), mc->default_ram_id,
  187. obj);
  188. if (!user_creatable_complete(USER_CREATABLE(obj), errp)) {
  189. goto out;
  190. }
  191. r = object_property_set_link(OBJECT(ms), "memory-backend", obj, errp);
  192. out:
  193. object_unref(obj);
  194. return r;
  195. }
  196. static char *nitro_enclave_get_vsock_chardev_id(Object *obj, Error **errp)
  197. {
  198. NitroEnclaveMachineState *nems = NITRO_ENCLAVE_MACHINE(obj);
  199. return g_strdup(nems->vsock);
  200. }
  201. static void nitro_enclave_set_vsock_chardev_id(Object *obj, const char *value,
  202. Error **errp)
  203. {
  204. NitroEnclaveMachineState *nems = NITRO_ENCLAVE_MACHINE(obj);
  205. g_free(nems->vsock);
  206. nems->vsock = g_strdup(value);
  207. }
  208. static char *nitro_enclave_get_id(Object *obj, Error **errp)
  209. {
  210. NitroEnclaveMachineState *nems = NITRO_ENCLAVE_MACHINE(obj);
  211. return g_strdup(nems->id);
  212. }
  213. static void nitro_enclave_set_id(Object *obj, const char *value,
  214. Error **errp)
  215. {
  216. NitroEnclaveMachineState *nems = NITRO_ENCLAVE_MACHINE(obj);
  217. g_free(nems->id);
  218. nems->id = g_strdup(value);
  219. }
  220. static char *nitro_enclave_get_parent_role(Object *obj, Error **errp)
  221. {
  222. NitroEnclaveMachineState *nems = NITRO_ENCLAVE_MACHINE(obj);
  223. return g_strdup(nems->parent_role);
  224. }
  225. static void nitro_enclave_set_parent_role(Object *obj, const char *value,
  226. Error **errp)
  227. {
  228. NitroEnclaveMachineState *nems = NITRO_ENCLAVE_MACHINE(obj);
  229. g_free(nems->parent_role);
  230. nems->parent_role = g_strdup(value);
  231. }
  232. static char *nitro_enclave_get_parent_id(Object *obj, Error **errp)
  233. {
  234. NitroEnclaveMachineState *nems = NITRO_ENCLAVE_MACHINE(obj);
  235. return g_strdup(nems->parent_id);
  236. }
  237. static void nitro_enclave_set_parent_id(Object *obj, const char *value,
  238. Error **errp)
  239. {
  240. NitroEnclaveMachineState *nems = NITRO_ENCLAVE_MACHINE(obj);
  241. g_free(nems->parent_id);
  242. nems->parent_id = g_strdup(value);
  243. }
  244. static void nitro_enclave_class_init(ObjectClass *oc, void *data)
  245. {
  246. MachineClass *mc = MACHINE_CLASS(oc);
  247. MicrovmMachineClass *mmc = MICROVM_MACHINE_CLASS(oc);
  248. NitroEnclaveMachineClass *nemc = NITRO_ENCLAVE_MACHINE_CLASS(oc);
  249. mmc->x86_load_linux = x86_load_eif;
  250. mc->family = "nitro_enclave_i386";
  251. mc->desc = "AWS Nitro Enclave";
  252. nemc->parent_init = mc->init;
  253. mc->init = nitro_enclave_machine_state_init;
  254. nemc->parent_reset = mc->reset;
  255. mc->reset = nitro_enclave_machine_reset;
  256. mc->create_default_memdev = create_memfd_backend;
  257. object_class_property_add_str(oc, NITRO_ENCLAVE_VSOCK_CHARDEV_ID,
  258. nitro_enclave_get_vsock_chardev_id,
  259. nitro_enclave_set_vsock_chardev_id);
  260. object_class_property_set_description(oc, NITRO_ENCLAVE_VSOCK_CHARDEV_ID,
  261. "Set chardev id for vhost-user-vsock "
  262. "device");
  263. object_class_property_add_str(oc, NITRO_ENCLAVE_ID, nitro_enclave_get_id,
  264. nitro_enclave_set_id);
  265. object_class_property_set_description(oc, NITRO_ENCLAVE_ID,
  266. "Set enclave identifier");
  267. object_class_property_add_str(oc, NITRO_ENCLAVE_PARENT_ROLE,
  268. nitro_enclave_get_parent_role,
  269. nitro_enclave_set_parent_role);
  270. object_class_property_set_description(oc, NITRO_ENCLAVE_PARENT_ROLE,
  271. "Set parent instance IAM role ARN");
  272. object_class_property_add_str(oc, NITRO_ENCLAVE_PARENT_ID,
  273. nitro_enclave_get_parent_id,
  274. nitro_enclave_set_parent_id);
  275. object_class_property_set_description(oc, NITRO_ENCLAVE_PARENT_ID,
  276. "Set parent instance identifier");
  277. }
  278. static const TypeInfo nitro_enclave_machine_info = {
  279. .name = TYPE_NITRO_ENCLAVE_MACHINE,
  280. .parent = TYPE_MICROVM_MACHINE,
  281. .instance_size = sizeof(NitroEnclaveMachineState),
  282. .instance_init = nitro_enclave_machine_initfn,
  283. .class_size = sizeof(NitroEnclaveMachineClass),
  284. .class_init = nitro_enclave_class_init,
  285. };
  286. static void nitro_enclave_machine_init(void)
  287. {
  288. type_register_static(&nitro_enclave_machine_info);
  289. }
  290. type_init(nitro_enclave_machine_init);