Example #1
0
static void
delete_variable(char *name)
{
	char *vname;
	efi_guid_t guid;

	breakdown_name(name, &guid, &vname);
	if (efi_del_variable(guid, vname) < 0)
		err(1, "efi_del_variable");
}
Example #2
0
static int
efivarfs_set_variable(efi_guid_t guid, const char *name, uint8_t *data,
		      size_t data_size, uint32_t attributes, mode_t mode)
{
	uint8_t buf[sizeof (attributes) + data_size];
	typeof(errno) errno_value;
	int ret = -1;

	if (strlen(name) > 1024) {
		errno = EINVAL;
		return -1;
	}

	char *path;
	int rc = make_efivarfs_path(&path, guid, name);
	if (rc < 0)
		return -1;

	int fd = -1;

	if (!access(path, F_OK) && !(attributes & EFI_VARIABLE_APPEND_WRITE)) {
		rc = efi_del_variable(guid, name);
		if (rc < 0)
			goto err;
	}

	fd = open(path, O_WRONLY|O_CREAT, mode);
	if (fd < 0)
		goto err;
	efivarfs_set_fd_immutable(fd, 0);

	memcpy(buf, &attributes, sizeof (attributes));
	memcpy(buf + sizeof (attributes), data, data_size);
	rc = write(fd, buf, sizeof (attributes) + data_size);
	if (rc >= 0) {
		ret = 0;
		efivarfs_set_fd_immutable(fd, 1);
	} else {
		efivarfs_set_fd_immutable(fd, 0);
		unlink(path);
	}
err:
	errno_value = errno;

	if (path)
		free(path);

	if (fd >= 0)
		close(fd);

	errno = errno_value;
	return ret;
}
static int
vars_set_variable(efi_guid_t guid, const char *name, uint8_t *data,
		 size_t data_size, uint32_t attributes)
{
	int errno_value;
	int ret = -1;
	int i = 0;
	if (strlen(name) > 1024) {
		errno = EINVAL;
		return -1;
	}
	if (data_size > 1024) {
		errno = ENOSPC;
		return -1;
	}

	char *path;
	int rc = asprintf(&path, VARS_PATH "%s-" GUID_FORMAT "/data",
			  name, guid.a, guid.b, guid.c, bswap_16(guid.d),
			  guid.e[0], guid.e[1], guid.e[2], guid.e[3],
			  guid.e[4], guid.e[5]);
	if (rc < 0)
		return -1;

	int fd = -1;

	if (!access(path, F_OK)) {
		rc = efi_del_variable(guid, name);
		if (rc < 0)
			goto err;
	}

	efi_variable_t var = {
		.VendorGuid = guid,
		.DataSize = data_size,
		.Status = 0,
		.Attributes = attributes
		};
	for (i = 0; name[i] != '\0'; i++)
		var.VariableName[i] = name[i];
	memcpy(var.Data, data, data_size);

	fd = open(VARS_PATH "new_var", O_WRONLY);
	if (fd < 0)
		goto err;

	rc = write(fd, &var, sizeof(var));
	if (rc >= 0)
		ret = 0;
err:
	errno_value = errno;
	
	if (path)
		free(path);

	if (fd >= 0)
		close(fd);

	errno = errno_value;
	return ret;
}

static int
vars_get_next_variable_name(efi_guid_t **guid, char **name)
{
	return generic_get_next_variable_name(VARS_PATH, guid, name);
}

struct efi_var_operations vars_ops = {
	.probe = vars_probe,
	.set_variable = vars_set_variable,
	.del_variable = vars_del_variable,
	.get_variable = vars_get_variable,
	.get_variable_attributes = vars_get_variable_attributes,
	.get_variable_size = vars_get_variable_size,
	.get_next_variable_name = vars_get_next_variable_name,
};
Example #4
0
static int
get_info(efi_guid_t *guid, uint64_t hw_inst, update_info **info)
{
	efi_guid_t varguid = FWUPDATE_GUID;
	char *varname = NULL;
	char *guidstr = NULL;
	int rc;
	update_info *local;
	int error;

	rc = efi_guid_to_str(guid, &guidstr);
	if (rc < 0)
		return -1;
	guidstr = onstack(guidstr, strlen(guidstr)+1);

	rc = asprintf(&varname, "fwupdate-%s-%"PRIx64, guidstr, hw_inst);
	if (rc < 0)
		return -1;
	varname = onstack(varname, strlen(varname)+1);

	uint8_t *data = NULL;
	size_t data_size = 0;
	uint32_t attributes;

	rc = efi_get_variable(varguid, varname, &data, &data_size, &attributes);
	if (rc < 0) {
		if (errno != ENOENT)
			return -1;
		local = calloc(1, sizeof (*local));
		if (!local)
			return -1;

		local->update_info_version = UPDATE_INFO_VERSION;
		local->guid = *guid;
		local->hw_inst = hw_inst;

		local->dp_ptr = calloc(1, 1024);
		if (!local->dp_ptr) {
alloc_err:
			error = errno;
			free_info(local);
			errno = error;
			return -1;
		}

		ssize_t sz;
		sz = efidp_make_end_entire((uint8_t *)local->dp_ptr, 1024);
		if (sz < 0) {
			rc = sz;
			goto alloc_err;
		}
		*info = local;
		return 0;
	}

	/* If our size is wrong, or our data is otherwise bad, try to delete
	 * the variable and create a new one. */
	if (data_size < sizeof (*local) || !data) {
		if (data)
			free(data);
get_err:
		rc = efi_del_variable(varguid, varname);
		if (rc < 0)
			return -1;
		return get_info(guid, hw_inst, info);
	}
	local = (update_info *)data;

	if (local->update_info_version != UPDATE_INFO_VERSION)
		goto get_err;

	ssize_t sz = efidp_size((efidp)local->dp);
	if (sz < 0) {
		free(data);
		errno = EINVAL;
		return -1;
	}

	efidp_header *dp = malloc((size_t)sz);
	if (!dp) {
		free(data);
		errno = ENOMEM;
		return -1;
	}

	memcpy(dp, local->dp, (size_t)sz);
	local->dp_ptr = dp;

	*info = local;
	return 0;
}