1*12058948SGerd Hoffmann /* 2*12058948SGerd Hoffmann * SPDX-License-Identifier: GPL-2.0-or-later 3*12058948SGerd Hoffmann * 4*12058948SGerd Hoffmann * uefi vars device - serialize non-volatile varstore from/to json, 5*12058948SGerd Hoffmann * using qapi 6*12058948SGerd Hoffmann * 7*12058948SGerd Hoffmann * tools which can read/write these json files: 8*12058948SGerd Hoffmann * - https://gitlab.com/kraxel/virt-firmware 9*12058948SGerd Hoffmann * - https://github.com/awslabs/python-uefivars 10*12058948SGerd Hoffmann */ 11*12058948SGerd Hoffmann #include "qemu/osdep.h" 12*12058948SGerd Hoffmann #include "qemu/cutils.h" 13*12058948SGerd Hoffmann #include "qemu/error-report.h" 14*12058948SGerd Hoffmann #include "system/dma.h" 15*12058948SGerd Hoffmann 16*12058948SGerd Hoffmann #include "hw/uefi/var-service.h" 17*12058948SGerd Hoffmann 18*12058948SGerd Hoffmann #include "qobject/qobject.h" 19*12058948SGerd Hoffmann #include "qobject/qjson.h" 20*12058948SGerd Hoffmann 21*12058948SGerd Hoffmann #include "qapi/dealloc-visitor.h" 22*12058948SGerd Hoffmann #include "qapi/qobject-input-visitor.h" 23*12058948SGerd Hoffmann #include "qapi/qobject-output-visitor.h" 24*12058948SGerd Hoffmann #include "qapi/qapi-types-uefi.h" 25*12058948SGerd Hoffmann #include "qapi/qapi-visit-uefi.h" 26*12058948SGerd Hoffmann 27*12058948SGerd Hoffmann static char *generate_hexstr(void *data, size_t len) 28*12058948SGerd Hoffmann { 29*12058948SGerd Hoffmann static const char hex[] = { 30*12058948SGerd Hoffmann '0', '1', '2', '3', '4', '5', '6', '7', 31*12058948SGerd Hoffmann '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 32*12058948SGerd Hoffmann }; 33*12058948SGerd Hoffmann uint8_t *src = data; 34*12058948SGerd Hoffmann char *dest; 35*12058948SGerd Hoffmann size_t i; 36*12058948SGerd Hoffmann 37*12058948SGerd Hoffmann dest = g_malloc(len * 2 + 1); 38*12058948SGerd Hoffmann for (i = 0; i < len * 2;) { 39*12058948SGerd Hoffmann dest[i++] = hex[*src >> 4]; 40*12058948SGerd Hoffmann dest[i++] = hex[*src & 15]; 41*12058948SGerd Hoffmann src++; 42*12058948SGerd Hoffmann } 43*12058948SGerd Hoffmann dest[i++] = 0; 44*12058948SGerd Hoffmann 45*12058948SGerd Hoffmann return dest; 46*12058948SGerd Hoffmann } 47*12058948SGerd Hoffmann 48*12058948SGerd Hoffmann static UefiVarStore *uefi_vars_to_qapi(uefi_vars_state *uv) 49*12058948SGerd Hoffmann { 50*12058948SGerd Hoffmann UefiVarStore *vs; 51*12058948SGerd Hoffmann UefiVariableList **tail; 52*12058948SGerd Hoffmann UefiVariable *v; 53*12058948SGerd Hoffmann QemuUUID be; 54*12058948SGerd Hoffmann uefi_variable *var; 55*12058948SGerd Hoffmann 56*12058948SGerd Hoffmann vs = g_new0(UefiVarStore, 1); 57*12058948SGerd Hoffmann vs->version = 2; 58*12058948SGerd Hoffmann tail = &vs->variables; 59*12058948SGerd Hoffmann 60*12058948SGerd Hoffmann QTAILQ_FOREACH(var, &uv->variables, next) { 61*12058948SGerd Hoffmann if (!(var->attributes & EFI_VARIABLE_NON_VOLATILE)) { 62*12058948SGerd Hoffmann continue; 63*12058948SGerd Hoffmann } 64*12058948SGerd Hoffmann 65*12058948SGerd Hoffmann v = g_new0(UefiVariable, 1); 66*12058948SGerd Hoffmann be = qemu_uuid_bswap(var->guid); 67*12058948SGerd Hoffmann v->guid = qemu_uuid_unparse_strdup(&be); 68*12058948SGerd Hoffmann v->name = uefi_ucs2_to_ascii(var->name, var->name_size); 69*12058948SGerd Hoffmann v->attr = var->attributes; 70*12058948SGerd Hoffmann 71*12058948SGerd Hoffmann v->data = generate_hexstr(var->data, var->data_size); 72*12058948SGerd Hoffmann 73*12058948SGerd Hoffmann if (var->attributes & 74*12058948SGerd Hoffmann EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) { 75*12058948SGerd Hoffmann v->time = generate_hexstr(&var->time, sizeof(var->time)); 76*12058948SGerd Hoffmann if (var->digest && var->digest_size) { 77*12058948SGerd Hoffmann v->digest = generate_hexstr(var->digest, var->digest_size); 78*12058948SGerd Hoffmann } 79*12058948SGerd Hoffmann } 80*12058948SGerd Hoffmann 81*12058948SGerd Hoffmann QAPI_LIST_APPEND(tail, v); 82*12058948SGerd Hoffmann } 83*12058948SGerd Hoffmann return vs; 84*12058948SGerd Hoffmann } 85*12058948SGerd Hoffmann 86*12058948SGerd Hoffmann static unsigned parse_hexchar(char c) 87*12058948SGerd Hoffmann { 88*12058948SGerd Hoffmann switch (c) { 89*12058948SGerd Hoffmann case '0' ... '9': return c - '0'; 90*12058948SGerd Hoffmann case 'a' ... 'f': return c - 'a' + 0xa; 91*12058948SGerd Hoffmann case 'A' ... 'F': return c - 'A' + 0xA; 92*12058948SGerd Hoffmann default: return 0; 93*12058948SGerd Hoffmann } 94*12058948SGerd Hoffmann } 95*12058948SGerd Hoffmann 96*12058948SGerd Hoffmann static void parse_hexstr(void *dest, char *src, int len) 97*12058948SGerd Hoffmann { 98*12058948SGerd Hoffmann uint8_t *data = dest; 99*12058948SGerd Hoffmann size_t i; 100*12058948SGerd Hoffmann 101*12058948SGerd Hoffmann for (i = 0; i < len; i += 2) { 102*12058948SGerd Hoffmann *(data++) = 103*12058948SGerd Hoffmann parse_hexchar(src[i]) << 4 | 104*12058948SGerd Hoffmann parse_hexchar(src[i + 1]); 105*12058948SGerd Hoffmann } 106*12058948SGerd Hoffmann } 107*12058948SGerd Hoffmann 108*12058948SGerd Hoffmann static void uefi_vars_from_qapi(uefi_vars_state *uv, UefiVarStore *vs) 109*12058948SGerd Hoffmann { 110*12058948SGerd Hoffmann UefiVariableList *item; 111*12058948SGerd Hoffmann UefiVariable *v; 112*12058948SGerd Hoffmann QemuUUID be; 113*12058948SGerd Hoffmann uefi_variable *var; 114*12058948SGerd Hoffmann uint8_t *data; 115*12058948SGerd Hoffmann size_t i, len; 116*12058948SGerd Hoffmann 117*12058948SGerd Hoffmann for (item = vs->variables; item != NULL; item = item->next) { 118*12058948SGerd Hoffmann v = item->value; 119*12058948SGerd Hoffmann 120*12058948SGerd Hoffmann var = g_new0(uefi_variable, 1); 121*12058948SGerd Hoffmann var->attributes = v->attr; 122*12058948SGerd Hoffmann qemu_uuid_parse(v->guid, &be); 123*12058948SGerd Hoffmann var->guid = qemu_uuid_bswap(be); 124*12058948SGerd Hoffmann 125*12058948SGerd Hoffmann len = strlen(v->name); 126*12058948SGerd Hoffmann var->name_size = len * 2 + 2; 127*12058948SGerd Hoffmann var->name = g_malloc(var->name_size); 128*12058948SGerd Hoffmann for (i = 0; i <= len; i++) { 129*12058948SGerd Hoffmann var->name[i] = v->name[i]; 130*12058948SGerd Hoffmann } 131*12058948SGerd Hoffmann 132*12058948SGerd Hoffmann len = strlen(v->data); 133*12058948SGerd Hoffmann var->data_size = len / 2; 134*12058948SGerd Hoffmann var->data = data = g_malloc(var->data_size); 135*12058948SGerd Hoffmann parse_hexstr(var->data, v->data, len); 136*12058948SGerd Hoffmann 137*12058948SGerd Hoffmann if (v->time && strlen(v->time) == 32) { 138*12058948SGerd Hoffmann parse_hexstr(&var->time, v->time, 32); 139*12058948SGerd Hoffmann } 140*12058948SGerd Hoffmann 141*12058948SGerd Hoffmann if (v->digest) { 142*12058948SGerd Hoffmann len = strlen(v->digest); 143*12058948SGerd Hoffmann var->digest_size = len / 2; 144*12058948SGerd Hoffmann var->digest = g_malloc(var->digest_size); 145*12058948SGerd Hoffmann parse_hexstr(var->digest, v->digest, len); 146*12058948SGerd Hoffmann } 147*12058948SGerd Hoffmann 148*12058948SGerd Hoffmann QTAILQ_INSERT_TAIL(&uv->variables, var, next); 149*12058948SGerd Hoffmann } 150*12058948SGerd Hoffmann } 151*12058948SGerd Hoffmann 152*12058948SGerd Hoffmann static GString *uefi_vars_to_json(uefi_vars_state *uv) 153*12058948SGerd Hoffmann { 154*12058948SGerd Hoffmann UefiVarStore *vs = uefi_vars_to_qapi(uv); 155*12058948SGerd Hoffmann QObject *qobj = NULL; 156*12058948SGerd Hoffmann Visitor *v; 157*12058948SGerd Hoffmann GString *gstr; 158*12058948SGerd Hoffmann 159*12058948SGerd Hoffmann v = qobject_output_visitor_new(&qobj); 160*12058948SGerd Hoffmann if (visit_type_UefiVarStore(v, NULL, &vs, NULL)) { 161*12058948SGerd Hoffmann visit_complete(v, &qobj); 162*12058948SGerd Hoffmann } 163*12058948SGerd Hoffmann visit_free(v); 164*12058948SGerd Hoffmann qapi_free_UefiVarStore(vs); 165*12058948SGerd Hoffmann 166*12058948SGerd Hoffmann gstr = qobject_to_json_pretty(qobj, true); 167*12058948SGerd Hoffmann qobject_unref(qobj); 168*12058948SGerd Hoffmann 169*12058948SGerd Hoffmann return gstr; 170*12058948SGerd Hoffmann } 171*12058948SGerd Hoffmann 172*12058948SGerd Hoffmann void uefi_vars_json_init(uefi_vars_state *uv, Error **errp) 173*12058948SGerd Hoffmann { 174*12058948SGerd Hoffmann if (uv->jsonfile) { 175*12058948SGerd Hoffmann uv->jsonfd = qemu_create(uv->jsonfile, O_RDWR, 0666, errp); 176*12058948SGerd Hoffmann } 177*12058948SGerd Hoffmann } 178*12058948SGerd Hoffmann 179*12058948SGerd Hoffmann void uefi_vars_json_save(uefi_vars_state *uv) 180*12058948SGerd Hoffmann { 181*12058948SGerd Hoffmann GString *gstr; 182*12058948SGerd Hoffmann int rc; 183*12058948SGerd Hoffmann 184*12058948SGerd Hoffmann if (uv->jsonfd == -1) { 185*12058948SGerd Hoffmann return; 186*12058948SGerd Hoffmann } 187*12058948SGerd Hoffmann 188*12058948SGerd Hoffmann gstr = uefi_vars_to_json(uv); 189*12058948SGerd Hoffmann 190*12058948SGerd Hoffmann lseek(uv->jsonfd, 0, SEEK_SET); 191*12058948SGerd Hoffmann rc = ftruncate(uv->jsonfd, 0); 192*12058948SGerd Hoffmann if (rc != 0) { 193*12058948SGerd Hoffmann warn_report("%s: ftruncate error", __func__); 194*12058948SGerd Hoffmann } 195*12058948SGerd Hoffmann rc = write(uv->jsonfd, gstr->str, gstr->len); 196*12058948SGerd Hoffmann if (rc != gstr->len) { 197*12058948SGerd Hoffmann warn_report("%s: write error", __func__); 198*12058948SGerd Hoffmann } 199*12058948SGerd Hoffmann fsync(uv->jsonfd); 200*12058948SGerd Hoffmann 201*12058948SGerd Hoffmann g_string_free(gstr, true); 202*12058948SGerd Hoffmann } 203*12058948SGerd Hoffmann 204*12058948SGerd Hoffmann void uefi_vars_json_load(uefi_vars_state *uv, Error **errp) 205*12058948SGerd Hoffmann { 206*12058948SGerd Hoffmann UefiVarStore *vs; 207*12058948SGerd Hoffmann QObject *qobj; 208*12058948SGerd Hoffmann Visitor *v; 209*12058948SGerd Hoffmann char *str; 210*12058948SGerd Hoffmann size_t len; 211*12058948SGerd Hoffmann int rc; 212*12058948SGerd Hoffmann 213*12058948SGerd Hoffmann if (uv->jsonfd == -1) { 214*12058948SGerd Hoffmann return; 215*12058948SGerd Hoffmann } 216*12058948SGerd Hoffmann 217*12058948SGerd Hoffmann len = lseek(uv->jsonfd, 0, SEEK_END); 218*12058948SGerd Hoffmann if (len == 0) { 219*12058948SGerd Hoffmann return; 220*12058948SGerd Hoffmann } 221*12058948SGerd Hoffmann 222*12058948SGerd Hoffmann str = g_malloc(len + 1); 223*12058948SGerd Hoffmann lseek(uv->jsonfd, 0, SEEK_SET); 224*12058948SGerd Hoffmann rc = read(uv->jsonfd, str, len); 225*12058948SGerd Hoffmann if (rc != len) { 226*12058948SGerd Hoffmann warn_report("%s: read error", __func__); 227*12058948SGerd Hoffmann } 228*12058948SGerd Hoffmann str[len] = 0; 229*12058948SGerd Hoffmann 230*12058948SGerd Hoffmann qobj = qobject_from_json(str, errp); 231*12058948SGerd Hoffmann v = qobject_input_visitor_new(qobj); 232*12058948SGerd Hoffmann visit_type_UefiVarStore(v, NULL, &vs, errp); 233*12058948SGerd Hoffmann visit_free(v); 234*12058948SGerd Hoffmann 235*12058948SGerd Hoffmann if (!(*errp)) { 236*12058948SGerd Hoffmann uefi_vars_from_qapi(uv, vs); 237*12058948SGerd Hoffmann uefi_vars_update_storage(uv); 238*12058948SGerd Hoffmann } 239*12058948SGerd Hoffmann 240*12058948SGerd Hoffmann qapi_free_UefiVarStore(vs); 241*12058948SGerd Hoffmann qobject_unref(qobj); 242*12058948SGerd Hoffmann g_free(str); 243*12058948SGerd Hoffmann } 244