vs.c
1 /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 3 #include "vs.h" 4 5 #include <limits.h> 6 #include <stdio.h> 7 #include <stdlib.h> 8 #include <string.h> 9 10 #include "udk2017.h" 11 #include "utils.h" 12 13 static size_t get_var_hdr_size(bool auth_vars) 14 { 15 if (auth_vars) 16 return sizeof(AUTHENTICATED_VARIABLE_HEADER); 17 return sizeof(VARIABLE_HEADER); 18 } 19 20 struct var_store_t vs_load(struct mem_range_t vs_data, bool auth_vars) 21 { 22 uint8_t *var_hdr = vs_data.start; 23 24 struct var_store_t vs = { 25 .auth_vars = auth_vars, 26 .vars = NULL, 27 }; 28 29 struct var_t *last_var = NULL; 30 31 const size_t var_hdr_size = get_var_hdr_size(auth_vars); 32 while (var_hdr + var_hdr_size < vs_data.start + vs_data.length) { 33 uint16_t start_id; 34 uint8_t state; 35 struct var_t var = {0}; 36 uint8_t *var_data = var_hdr; 37 38 if (auth_vars) { 39 const AUTHENTICATED_VARIABLE_HEADER *auth_hdr = 40 (void *)var_data; 41 42 start_id = auth_hdr->StartId; 43 state = auth_hdr->State; 44 45 var.reserved = auth_hdr->Reserved; 46 var.attrs = auth_hdr->Attributes; 47 var.name_size = auth_hdr->NameSize; 48 var.data_size = auth_hdr->DataSize; 49 var.guid = auth_hdr->VendorGuid; 50 } else { 51 const VARIABLE_HEADER *no_auth_hdr = (void *)var_data; 52 53 start_id = no_auth_hdr->StartId; 54 state = no_auth_hdr->State; 55 56 var.reserved = no_auth_hdr->Reserved; 57 var.attrs = no_auth_hdr->Attributes; 58 var.name_size = no_auth_hdr->NameSize; 59 var.data_size = no_auth_hdr->DataSize; 60 var.guid = no_auth_hdr->VendorGuid; 61 } 62 63 var_hdr += HEADER_ALIGN(var_hdr_size + 64 var.name_size + 65 var.data_size); 66 67 if (start_id != VARIABLE_DATA) 68 break; 69 70 if (state != VAR_ADDED) 71 continue; 72 73 if (var.data_size == UINT32_MAX || 74 var.name_size == UINT32_MAX || 75 var.attrs == UINT32_MAX) 76 continue; 77 78 CHAR16 *name = (void *)(var_data + var_hdr_size); 79 var.name = xmalloc(var.name_size); 80 memcpy(var.name, name, var.name_size); 81 82 uint8_t *data = 83 (void *)(var_data + var_hdr_size + var.name_size); 84 var.data = xmalloc(var.data_size); 85 memcpy(var.data, data, var.data_size); 86 87 struct var_t *var_node = xmalloc(sizeof(*var_node)); 88 *var_node = var; 89 if (last_var != NULL) 90 last_var->next = var_node; 91 else if (vs.vars == NULL) 92 vs.vars = var_node; 93 last_var = var_node; 94 } 95 96 return vs; 97 } 98 99 static void store_var(const struct var_t *var, bool auth_vars, uint8_t *data) 100 { 101 if (auth_vars) { 102 AUTHENTICATED_VARIABLE_HEADER hdr; 103 memset(&hdr, 0xff, sizeof(hdr)); 104 105 hdr.StartId = VARIABLE_DATA; 106 hdr.State = VAR_ADDED; 107 hdr.Reserved = var->reserved; 108 hdr.Attributes = var->attrs; 109 hdr.VendorGuid = var->guid; 110 hdr.NameSize = var->name_size; 111 hdr.DataSize = var->data_size; 112 113 memcpy(data, &hdr, sizeof(hdr)); 114 data += sizeof(hdr); 115 } else { 116 VARIABLE_HEADER hdr; 117 memset(&hdr, 0xff, sizeof(hdr)); 118 119 hdr.StartId = VARIABLE_DATA; 120 hdr.State = VAR_ADDED; 121 hdr.Reserved = var->reserved; 122 hdr.Attributes = var->attrs; 123 hdr.VendorGuid = var->guid; 124 hdr.NameSize = var->name_size; 125 hdr.DataSize = var->data_size; 126 127 memcpy(data, &hdr, sizeof(hdr)); 128 data += sizeof(hdr); 129 } 130 131 memcpy(data, var->name, var->name_size); 132 memcpy(data + var->name_size, var->data, var->data_size); 133 } 134 135 bool vs_store(struct var_store_t *vs, struct mem_range_t vs_data) 136 { 137 uint8_t *out_data = vs_data.start; 138 139 const size_t var_hdr_size = get_var_hdr_size(vs->auth_vars); 140 for (struct var_t *var = vs->vars; var != NULL; var = var->next) { 141 const size_t var_size = 142 var_hdr_size + var->name_size + var->data_size; 143 if (out_data + var_size > vs_data.start + vs_data.length) { 144 fprintf(stderr, 145 "Not enough space to serialize Variable Store.\n"); 146 return false; 147 } 148 149 store_var(var, vs->auth_vars, out_data); 150 out_data += HEADER_ALIGN(var_size); 151 } 152 153 // The rest is "uninitialized". 154 memset(out_data, 0xff, vs_data.length - (out_data - vs_data.start)); 155 156 return true; 157 } 158 159 struct var_t *vs_new_var(struct var_store_t *vs) 160 { 161 struct var_t *new_var = xmalloc(sizeof(*new_var)); 162 163 memset(new_var, 0, sizeof(*new_var)); 164 new_var->attrs = EFI_VARIABLE_NON_VOLATILE 165 | EFI_VARIABLE_BOOTSERVICE_ACCESS 166 | EFI_VARIABLE_RUNTIME_ACCESS; 167 168 struct var_t *var = vs->vars; 169 if (var == NULL) { 170 vs->vars = new_var; 171 } else { 172 while (var->next != NULL) 173 var = var->next; 174 var->next = new_var; 175 } 176 177 return new_var; 178 } 179 180 struct var_t *vs_find(struct var_store_t *vs, 181 const char name[], 182 const EFI_GUID *guid) 183 { 184 size_t name_size; 185 CHAR16 *uchar_name = to_uchars(name, &name_size); 186 187 struct var_t *var; 188 for (var = vs->vars; var != NULL; var = var->next) { 189 if (var->name_size != name_size) 190 continue; 191 if (memcmp(var->name, uchar_name, name_size) != 0) 192 continue; 193 if (memcmp(&var->guid, guid, sizeof(*guid)) != 0) 194 continue; 195 break; 196 } 197 198 free(uchar_name); 199 return var; 200 } 201 202 static void free_var(struct var_t *var) 203 { 204 free(var->name); 205 free(var->data); 206 free(var); 207 } 208 209 void vs_delete(struct var_store_t *vs, struct var_t *var) 210 { 211 if (vs->vars == var) { 212 vs->vars = var->next; 213 free_var(var); 214 return; 215 } 216 217 for (struct var_t *v = vs->vars; v != NULL; v = v->next) { 218 if (v->next == var) { 219 v->next = var->next; 220 free_var(var); 221 return; 222 } 223 } 224 } 225 226 void vs_free(struct var_store_t *vs) 227 { 228 for (struct var_t *next, *var = vs->vars; var != NULL; var = next) { 229 next = var->next; 230 free_var(var); 231 } 232 }