112058948SGerd Hoffmann /* 212058948SGerd Hoffmann * SPDX-License-Identifier: GPL-2.0-or-later 312058948SGerd Hoffmann * 412058948SGerd Hoffmann * uefi vars device - serialize non-volatile varstore from/to json, 512058948SGerd Hoffmann * using qapi 612058948SGerd Hoffmann * 712058948SGerd Hoffmann * tools which can read/write these json files: 812058948SGerd Hoffmann * - https://gitlab.com/kraxel/virt-firmware 912058948SGerd Hoffmann * - https://github.com/awslabs/python-uefivars 1012058948SGerd Hoffmann */ 1112058948SGerd Hoffmann #include "qemu/osdep.h" 1212058948SGerd Hoffmann #include "qemu/cutils.h" 1312058948SGerd Hoffmann #include "qemu/error-report.h" 1412058948SGerd Hoffmann #include "system/dma.h" 1512058948SGerd Hoffmann 1612058948SGerd Hoffmann #include "hw/uefi/var-service.h" 1712058948SGerd Hoffmann 1812058948SGerd Hoffmann #include "qobject/qobject.h" 1912058948SGerd Hoffmann #include "qobject/qjson.h" 2012058948SGerd Hoffmann 2112058948SGerd Hoffmann #include "qapi/dealloc-visitor.h" 2212058948SGerd Hoffmann #include "qapi/qobject-input-visitor.h" 2312058948SGerd Hoffmann #include "qapi/qobject-output-visitor.h" 2412058948SGerd Hoffmann #include "qapi/qapi-types-uefi.h" 2512058948SGerd Hoffmann #include "qapi/qapi-visit-uefi.h" 2612058948SGerd Hoffmann 2712058948SGerd Hoffmann static char *generate_hexstr(void *data, size_t len) 2812058948SGerd Hoffmann { 2912058948SGerd Hoffmann static const char hex[] = { 3012058948SGerd Hoffmann '0', '1', '2', '3', '4', '5', '6', '7', 3112058948SGerd Hoffmann '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 3212058948SGerd Hoffmann }; 3312058948SGerd Hoffmann uint8_t *src = data; 3412058948SGerd Hoffmann char *dest; 3512058948SGerd Hoffmann size_t i; 3612058948SGerd Hoffmann 3712058948SGerd Hoffmann dest = g_malloc(len * 2 + 1); 3812058948SGerd Hoffmann for (i = 0; i < len * 2;) { 3912058948SGerd Hoffmann dest[i++] = hex[*src >> 4]; 4012058948SGerd Hoffmann dest[i++] = hex[*src & 15]; 4112058948SGerd Hoffmann src++; 4212058948SGerd Hoffmann } 4312058948SGerd Hoffmann dest[i++] = 0; 4412058948SGerd Hoffmann 4512058948SGerd Hoffmann return dest; 4612058948SGerd Hoffmann } 4712058948SGerd Hoffmann 4812058948SGerd Hoffmann static UefiVarStore *uefi_vars_to_qapi(uefi_vars_state *uv) 4912058948SGerd Hoffmann { 5012058948SGerd Hoffmann UefiVarStore *vs; 5112058948SGerd Hoffmann UefiVariableList **tail; 5212058948SGerd Hoffmann UefiVariable *v; 5312058948SGerd Hoffmann QemuUUID be; 5412058948SGerd Hoffmann uefi_variable *var; 5512058948SGerd Hoffmann 5612058948SGerd Hoffmann vs = g_new0(UefiVarStore, 1); 5712058948SGerd Hoffmann vs->version = 2; 5812058948SGerd Hoffmann tail = &vs->variables; 5912058948SGerd Hoffmann 6012058948SGerd Hoffmann QTAILQ_FOREACH(var, &uv->variables, next) { 6112058948SGerd Hoffmann if (!(var->attributes & EFI_VARIABLE_NON_VOLATILE)) { 6212058948SGerd Hoffmann continue; 6312058948SGerd Hoffmann } 6412058948SGerd Hoffmann 6512058948SGerd Hoffmann v = g_new0(UefiVariable, 1); 6612058948SGerd Hoffmann be = qemu_uuid_bswap(var->guid); 6712058948SGerd Hoffmann v->guid = qemu_uuid_unparse_strdup(&be); 6812058948SGerd Hoffmann v->name = uefi_ucs2_to_ascii(var->name, var->name_size); 6912058948SGerd Hoffmann v->attr = var->attributes; 7012058948SGerd Hoffmann 7112058948SGerd Hoffmann v->data = generate_hexstr(var->data, var->data_size); 7212058948SGerd Hoffmann 7312058948SGerd Hoffmann if (var->attributes & 7412058948SGerd Hoffmann EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) { 7512058948SGerd Hoffmann v->time = generate_hexstr(&var->time, sizeof(var->time)); 7612058948SGerd Hoffmann if (var->digest && var->digest_size) { 7712058948SGerd Hoffmann v->digest = generate_hexstr(var->digest, var->digest_size); 7812058948SGerd Hoffmann } 7912058948SGerd Hoffmann } 8012058948SGerd Hoffmann 8112058948SGerd Hoffmann QAPI_LIST_APPEND(tail, v); 8212058948SGerd Hoffmann } 8312058948SGerd Hoffmann return vs; 8412058948SGerd Hoffmann } 8512058948SGerd Hoffmann 8612058948SGerd Hoffmann static unsigned parse_hexchar(char c) 8712058948SGerd Hoffmann { 8812058948SGerd Hoffmann switch (c) { 8912058948SGerd Hoffmann case '0' ... '9': return c - '0'; 9012058948SGerd Hoffmann case 'a' ... 'f': return c - 'a' + 0xa; 9112058948SGerd Hoffmann case 'A' ... 'F': return c - 'A' + 0xA; 9212058948SGerd Hoffmann default: return 0; 9312058948SGerd Hoffmann } 9412058948SGerd Hoffmann } 9512058948SGerd Hoffmann 9612058948SGerd Hoffmann static void parse_hexstr(void *dest, char *src, int len) 9712058948SGerd Hoffmann { 9812058948SGerd Hoffmann uint8_t *data = dest; 9912058948SGerd Hoffmann size_t i; 10012058948SGerd Hoffmann 10112058948SGerd Hoffmann for (i = 0; i < len; i += 2) { 10212058948SGerd Hoffmann *(data++) = 10312058948SGerd Hoffmann parse_hexchar(src[i]) << 4 | 10412058948SGerd Hoffmann parse_hexchar(src[i + 1]); 10512058948SGerd Hoffmann } 10612058948SGerd Hoffmann } 10712058948SGerd Hoffmann 10812058948SGerd Hoffmann static void uefi_vars_from_qapi(uefi_vars_state *uv, UefiVarStore *vs) 10912058948SGerd Hoffmann { 11012058948SGerd Hoffmann UefiVariableList *item; 11112058948SGerd Hoffmann UefiVariable *v; 11212058948SGerd Hoffmann QemuUUID be; 11312058948SGerd Hoffmann uefi_variable *var; 11412058948SGerd Hoffmann uint8_t *data; 11512058948SGerd Hoffmann size_t i, len; 11612058948SGerd Hoffmann 11712058948SGerd Hoffmann for (item = vs->variables; item != NULL; item = item->next) { 11812058948SGerd Hoffmann v = item->value; 11912058948SGerd Hoffmann 12012058948SGerd Hoffmann var = g_new0(uefi_variable, 1); 12112058948SGerd Hoffmann var->attributes = v->attr; 12212058948SGerd Hoffmann qemu_uuid_parse(v->guid, &be); 12312058948SGerd Hoffmann var->guid = qemu_uuid_bswap(be); 12412058948SGerd Hoffmann 12512058948SGerd Hoffmann len = strlen(v->name); 12612058948SGerd Hoffmann var->name_size = len * 2 + 2; 12712058948SGerd Hoffmann var->name = g_malloc(var->name_size); 12812058948SGerd Hoffmann for (i = 0; i <= len; i++) { 12912058948SGerd Hoffmann var->name[i] = v->name[i]; 13012058948SGerd Hoffmann } 13112058948SGerd Hoffmann 13212058948SGerd Hoffmann len = strlen(v->data); 13312058948SGerd Hoffmann var->data_size = len / 2; 13412058948SGerd Hoffmann var->data = data = g_malloc(var->data_size); 13512058948SGerd Hoffmann parse_hexstr(var->data, v->data, len); 13612058948SGerd Hoffmann 13712058948SGerd Hoffmann if (v->time && strlen(v->time) == 32) { 13812058948SGerd Hoffmann parse_hexstr(&var->time, v->time, 32); 13912058948SGerd Hoffmann } 14012058948SGerd Hoffmann 14112058948SGerd Hoffmann if (v->digest) { 14212058948SGerd Hoffmann len = strlen(v->digest); 14312058948SGerd Hoffmann var->digest_size = len / 2; 14412058948SGerd Hoffmann var->digest = g_malloc(var->digest_size); 14512058948SGerd Hoffmann parse_hexstr(var->digest, v->digest, len); 14612058948SGerd Hoffmann } 14712058948SGerd Hoffmann 14812058948SGerd Hoffmann QTAILQ_INSERT_TAIL(&uv->variables, var, next); 14912058948SGerd Hoffmann } 15012058948SGerd Hoffmann } 15112058948SGerd Hoffmann 15212058948SGerd Hoffmann static GString *uefi_vars_to_json(uefi_vars_state *uv) 15312058948SGerd Hoffmann { 15412058948SGerd Hoffmann UefiVarStore *vs = uefi_vars_to_qapi(uv); 15512058948SGerd Hoffmann QObject *qobj = NULL; 15612058948SGerd Hoffmann Visitor *v; 15712058948SGerd Hoffmann GString *gstr; 15812058948SGerd Hoffmann 15912058948SGerd Hoffmann v = qobject_output_visitor_new(&qobj); 16012058948SGerd Hoffmann if (visit_type_UefiVarStore(v, NULL, &vs, NULL)) { 16112058948SGerd Hoffmann visit_complete(v, &qobj); 16212058948SGerd Hoffmann } 16312058948SGerd Hoffmann visit_free(v); 16412058948SGerd Hoffmann qapi_free_UefiVarStore(vs); 16512058948SGerd Hoffmann 16612058948SGerd Hoffmann gstr = qobject_to_json_pretty(qobj, true); 16712058948SGerd Hoffmann qobject_unref(qobj); 16812058948SGerd Hoffmann 16912058948SGerd Hoffmann return gstr; 17012058948SGerd Hoffmann } 17112058948SGerd Hoffmann 17212058948SGerd Hoffmann void uefi_vars_json_init(uefi_vars_state *uv, Error **errp) 17312058948SGerd Hoffmann { 17412058948SGerd Hoffmann if (uv->jsonfile) { 17512058948SGerd Hoffmann uv->jsonfd = qemu_create(uv->jsonfile, O_RDWR, 0666, errp); 17612058948SGerd Hoffmann } 17712058948SGerd Hoffmann } 17812058948SGerd Hoffmann 17912058948SGerd Hoffmann void uefi_vars_json_save(uefi_vars_state *uv) 18012058948SGerd Hoffmann { 181ae24cf13SGerd Hoffmann g_autoptr(GString) gstr = NULL; 18212058948SGerd Hoffmann int rc; 18312058948SGerd Hoffmann 18412058948SGerd Hoffmann if (uv->jsonfd == -1) { 18512058948SGerd Hoffmann return; 18612058948SGerd Hoffmann } 18712058948SGerd Hoffmann 18812058948SGerd Hoffmann gstr = uefi_vars_to_json(uv); 18912058948SGerd Hoffmann 190ae24cf13SGerd Hoffmann rc = lseek(uv->jsonfd, 0, SEEK_SET); 191ae24cf13SGerd Hoffmann if (rc < 0) { 192ae24cf13SGerd Hoffmann warn_report("%s: lseek error", __func__); 193ae24cf13SGerd Hoffmann return; 194ae24cf13SGerd Hoffmann } 195ae24cf13SGerd Hoffmann 19612058948SGerd Hoffmann rc = ftruncate(uv->jsonfd, 0); 19712058948SGerd Hoffmann if (rc != 0) { 19812058948SGerd Hoffmann warn_report("%s: ftruncate error", __func__); 199ae24cf13SGerd Hoffmann return; 20012058948SGerd Hoffmann } 201ae24cf13SGerd Hoffmann 20212058948SGerd Hoffmann rc = write(uv->jsonfd, gstr->str, gstr->len); 20312058948SGerd Hoffmann if (rc != gstr->len) { 20412058948SGerd Hoffmann warn_report("%s: write error", __func__); 205ae24cf13SGerd Hoffmann return; 20612058948SGerd Hoffmann } 20712058948SGerd Hoffmann 208ae24cf13SGerd Hoffmann fsync(uv->jsonfd); 20912058948SGerd Hoffmann } 21012058948SGerd Hoffmann 21112058948SGerd Hoffmann void uefi_vars_json_load(uefi_vars_state *uv, Error **errp) 21212058948SGerd Hoffmann { 21312058948SGerd Hoffmann UefiVarStore *vs; 21412058948SGerd Hoffmann QObject *qobj; 21512058948SGerd Hoffmann Visitor *v; 21612058948SGerd Hoffmann char *str; 217*761d0b5fSGerd Hoffmann ssize_t len; 21812058948SGerd Hoffmann int rc; 21912058948SGerd Hoffmann 22012058948SGerd Hoffmann if (uv->jsonfd == -1) { 22112058948SGerd Hoffmann return; 22212058948SGerd Hoffmann } 22312058948SGerd Hoffmann 22412058948SGerd Hoffmann len = lseek(uv->jsonfd, 0, SEEK_END); 225*761d0b5fSGerd Hoffmann if (len < 0) { 226*761d0b5fSGerd Hoffmann warn_report("%s: lseek error", __func__); 227*761d0b5fSGerd Hoffmann return; 228*761d0b5fSGerd Hoffmann } 22912058948SGerd Hoffmann if (len == 0) { 230*761d0b5fSGerd Hoffmann /* empty file */ 23112058948SGerd Hoffmann return; 23212058948SGerd Hoffmann } 23312058948SGerd Hoffmann 23412058948SGerd Hoffmann str = g_malloc(len + 1); 23512058948SGerd Hoffmann lseek(uv->jsonfd, 0, SEEK_SET); 23612058948SGerd Hoffmann rc = read(uv->jsonfd, str, len); 23712058948SGerd Hoffmann if (rc != len) { 23812058948SGerd Hoffmann warn_report("%s: read error", __func__); 239*761d0b5fSGerd Hoffmann g_free(str); 240*761d0b5fSGerd Hoffmann return; 24112058948SGerd Hoffmann } 24212058948SGerd Hoffmann str[len] = 0; 24312058948SGerd Hoffmann 24412058948SGerd Hoffmann qobj = qobject_from_json(str, errp); 24512058948SGerd Hoffmann v = qobject_input_visitor_new(qobj); 24612058948SGerd Hoffmann visit_type_UefiVarStore(v, NULL, &vs, errp); 24712058948SGerd Hoffmann visit_free(v); 24812058948SGerd Hoffmann 24912058948SGerd Hoffmann if (!(*errp)) { 25012058948SGerd Hoffmann uefi_vars_from_qapi(uv, vs); 25112058948SGerd Hoffmann uefi_vars_update_storage(uv); 25212058948SGerd Hoffmann } 25312058948SGerd Hoffmann 25412058948SGerd Hoffmann qapi_free_UefiVarStore(vs); 25512058948SGerd Hoffmann qobject_unref(qobj); 25612058948SGerd Hoffmann g_free(str); 25712058948SGerd Hoffmann } 258