efi_loadopt_optional_data_size(efi_load_option *opt, size_t size) { size_t sz; uint8_t *p; if (!opt) return -1; if (size < sizeof(*opt)) return -1; size -= sizeof(*opt); if (size < opt->file_path_list_length) return -1; sz = ucs2size(opt->description, size); if (sz >= size) // since there's no room for a file path... return -1; p = (uint8_t *)(opt->description) + sz; size -= sz; if (!efidp_is_valid((const_efidp)p, size)) return -1; sz = efidp_size((const_efidp)p); p += sz; size -= sz; return size; }
static int put_info(update_info *info) { efi_guid_t varguid = FWUPDATE_GUID; ssize_t dps, is; char *guidstr = NULL; char *varname; int error; int rc; rc = efi_guid_to_str(&info->guid, &guidstr); if (rc < 0) { err: return rc; } guidstr = onstack(guidstr, strlen(guidstr)+1); rc = asprintf(&varname, "fwupdate-%s-%"PRIx64, guidstr, info->hw_inst); if (rc < 0) goto err; varname = onstack(varname, strlen(varname)+1); dps = efidp_size((efidp)info->dp_ptr); /* make sure dps is at least big enough to have our structure */ if (dps < 0 || (size_t)dps < sizeof(*info)) { errno = EINVAL; return -1; } /* Make sure sizeof(*info) + dps won't integer overflow */ if ((size_t)dps > SSIZE_MAX - sizeof(*info)) { errno = EOVERFLOW; return -1; } is = sizeof(*info) + dps - sizeof(info->dp_ptr); update_info *info2; info2 = malloc(is); if (!info2) return -1; memcpy(info2, info, sizeof(*info)); memcpy(info2->dp, info->dp_ptr, dps); uint32_t attributes = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS; rc = efi_set_variable(varguid, varname, (uint8_t *)info2, is, attributes, 0600); error = errno; free(info2); errno = error; return rc; }
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; }