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  }