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
generate_hexstr(void * data,size_t len)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
uefi_vars_to_qapi(uefi_vars_state * uv)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
parse_hexchar(char c)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
parse_hexstr(void * dest,char * src,int len)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
uefi_vars_from_qapi(uefi_vars_state * uv,UefiVarStore * vs)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
uefi_vars_to_json(uefi_vars_state * uv)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
uefi_vars_json_init(uefi_vars_state * uv,Error ** errp)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
uefi_vars_json_save(uefi_vars_state * uv)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
uefi_vars_json_load(uefi_vars_state * uv,Error ** errp)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