xref: /qemu/hw/uefi/var-service-json.c (revision 12058948abdf7eed8364aee79add66b40002fd5b)
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