c7c6805ed059b0e927127dd929741717cd553e5c
[platform/kernel/u-boot.git] / lib / efi_loader / efi_var_file.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * File interface for UEFI variables
4  *
5  * Copyright (c) 2020, Heinrich Schuchardt
6  */
7
8 #define LOG_CATEGORY LOGC_EFI
9
10 #include <common.h>
11 #include <charset.h>
12 #include <fs.h>
13 #include <log.h>
14 #include <malloc.h>
15 #include <mapmem.h>
16 #include <efi_loader.h>
17 #include <efi_variable.h>
18 #include <u-boot/crc.h>
19
20 #define PART_STR_LEN 10
21
22 /**
23  * efi_set_blk_dev_to_system_partition() - select EFI system partition
24  *
25  * Set the EFI system partition as current block device.
26  *
27  * Return:      status code
28  */
29 static efi_status_t __maybe_unused efi_set_blk_dev_to_system_partition(void)
30 {
31         char part_str[PART_STR_LEN];
32         int r;
33
34         if (!efi_system_partition.if_type) {
35                 log_err("No EFI system partition\n");
36                 return EFI_DEVICE_ERROR;
37         }
38         snprintf(part_str, PART_STR_LEN, "%x:%x",
39                  efi_system_partition.devnum, efi_system_partition.part);
40         r = fs_set_blk_dev(blk_get_if_type_name(efi_system_partition.if_type),
41                            part_str, FS_TYPE_ANY);
42         if (r) {
43                 log_err("Cannot read EFI system partition\n");
44                 return EFI_DEVICE_ERROR;
45         }
46         return EFI_SUCCESS;
47 }
48
49 efi_status_t __maybe_unused efi_var_collect(struct efi_var_file **bufp, loff_t *lenp,
50                                             u32 check_attr_mask)
51 {
52         size_t len = EFI_VAR_BUF_SIZE;
53         struct efi_var_file *buf;
54         struct efi_var_entry *var, *old_var;
55         size_t old_var_name_length = 2;
56
57         *bufp = NULL; /* Avoid double free() */
58         buf = calloc(1, len);
59         if (!buf)
60                 return EFI_OUT_OF_RESOURCES;
61         var = buf->var;
62         old_var = var;
63         for (;;) {
64                 efi_uintn_t data_length, var_name_length;
65                 u8 *data;
66                 efi_status_t ret;
67
68                 if ((uintptr_t)buf + len <=
69                     (uintptr_t)var->name + old_var_name_length)
70                         return EFI_BUFFER_TOO_SMALL;
71
72                 var_name_length = (uintptr_t)buf + len - (uintptr_t)var->name;
73                 memcpy(var->name, old_var->name, old_var_name_length);
74                 guidcpy(&var->guid, &old_var->guid);
75                 ret = efi_get_next_variable_name_int(
76                                 &var_name_length, var->name, &var->guid);
77                 if (ret == EFI_NOT_FOUND)
78                         break;
79                 if (ret != EFI_SUCCESS) {
80                         free(buf);
81                         return ret;
82                 }
83                 old_var_name_length = var_name_length;
84                 old_var = var;
85
86                 data = (u8 *)var->name + old_var_name_length;
87                 data_length = (uintptr_t)buf + len - (uintptr_t)data;
88                 ret = efi_get_variable_int(var->name, &var->guid,
89                                            &var->attr, &data_length, data,
90                                            &var->time);
91                 if (ret != EFI_SUCCESS) {
92                         free(buf);
93                         return ret;
94                 }
95                 if ((var->attr & check_attr_mask) == check_attr_mask) {
96                         var->length = data_length;
97                         var = (struct efi_var_entry *)ALIGN((uintptr_t)data + data_length, 8);
98                 }
99         }
100
101         buf->reserved = 0;
102         buf->magic = EFI_VAR_FILE_MAGIC;
103         len = (uintptr_t)var - (uintptr_t)buf;
104         buf->crc32 = crc32(0, (u8 *)buf->var,
105                            len - sizeof(struct efi_var_file));
106         buf->length = len;
107         *bufp = buf;
108         *lenp = len;
109
110         return EFI_SUCCESS;
111 }
112
113 /**
114  * efi_var_to_file() - save non-volatile variables as file
115  *
116  * File ubootefi.var is created on the EFI system partion.
117  *
118  * Return:      status code
119  */
120 efi_status_t efi_var_to_file(void)
121 {
122 #ifdef CONFIG_EFI_VARIABLE_FILE_STORE
123         efi_status_t ret;
124         struct efi_var_file *buf;
125         loff_t len;
126         loff_t actlen;
127         int r;
128
129         ret = efi_var_collect(&buf, &len, EFI_VARIABLE_NON_VOLATILE);
130         if (ret != EFI_SUCCESS)
131                 goto error;
132
133         ret = efi_set_blk_dev_to_system_partition();
134         if (ret != EFI_SUCCESS)
135                 goto error;
136
137         r = fs_write(EFI_VAR_FILE_NAME, map_to_sysmem(buf), 0, len, &actlen);
138         if (r || len != actlen)
139                 ret = EFI_DEVICE_ERROR;
140
141 error:
142         if (ret != EFI_SUCCESS)
143                 log_err("Failed to persist EFI variables\n");
144         free(buf);
145         return ret;
146 #else
147         return EFI_SUCCESS;
148 #endif
149 }
150
151 efi_status_t efi_var_restore(struct efi_var_file *buf, bool safe)
152 {
153         struct efi_var_entry *var, *last_var;
154         u16 *data;
155         efi_status_t ret;
156
157         if (buf->reserved || buf->magic != EFI_VAR_FILE_MAGIC ||
158             buf->crc32 != crc32(0, (u8 *)buf->var,
159                                 buf->length - sizeof(struct efi_var_file))) {
160                 log_err("Invalid EFI variables file\n");
161                 return EFI_INVALID_PARAMETER;
162         }
163
164         last_var = (struct efi_var_entry *)((u8 *)buf + buf->length);
165         for (var = buf->var; var < last_var;
166              var = (struct efi_var_entry *)
167                    ALIGN((uintptr_t)data + var->length, 8)) {
168
169                 data = var->name + u16_strlen(var->name) + 1;
170
171                 /*
172                  * Secure boot related and non-volatile variables shall only be
173                  * restored from U-Boot's preseed.
174                  */
175                 if (!safe &&
176                     (efi_auth_var_get_type(var->name, &var->guid) !=
177                      EFI_AUTH_VAR_NONE ||
178                      !(var->attr & EFI_VARIABLE_NON_VOLATILE)))
179                         continue;
180                 if (!var->length)
181                         continue;
182                 ret = efi_var_mem_ins(var->name, &var->guid, var->attr,
183                                       var->length, data, 0, NULL,
184                                       var->time);
185                 if (ret != EFI_SUCCESS)
186                         log_err("Failed to set EFI variable %ls\n", var->name);
187         }
188         return EFI_SUCCESS;
189 }
190
191 /**
192  * efi_var_from_file() - read variables from file
193  *
194  * File ubootefi.var is read from the EFI system partitions and the variables
195  * stored in the file are created.
196  *
197  * In case the file does not exist yet or a variable cannot be set EFI_SUCCESS
198  * is returned.
199  *
200  * Return:      status code
201  */
202 efi_status_t efi_var_from_file(void)
203 {
204 #ifdef CONFIG_EFI_VARIABLE_FILE_STORE
205         struct efi_var_file *buf;
206         loff_t len;
207         efi_status_t ret;
208         int r;
209
210         buf = calloc(1, EFI_VAR_BUF_SIZE);
211         if (!buf) {
212                 log_err("Out of memory\n");
213                 return EFI_OUT_OF_RESOURCES;
214         }
215
216         ret = efi_set_blk_dev_to_system_partition();
217         if (ret != EFI_SUCCESS)
218                 goto error;
219         r = fs_read(EFI_VAR_FILE_NAME, map_to_sysmem(buf), 0, EFI_VAR_BUF_SIZE,
220                     &len);
221         if (r || len < sizeof(struct efi_var_file)) {
222                 log_err("Failed to load EFI variables\n");
223                 goto error;
224         }
225         if (buf->length != len || efi_var_restore(buf, false) != EFI_SUCCESS)
226                 log_err("Invalid EFI variables file\n");
227 error:
228         free(buf);
229 #endif
230         return EFI_SUCCESS;
231 }