Skip to content

Commit f11a74b

Browse files
committed
efi: efivars: Fix variable writes with unsupported query_variable_store()
Commit 8a254d9 ("efi: efivars: Fix variable writes without query_variable_store()") addressed an issue that was introduced during the EFI variable store refactor, where alternative implementations of the efivars layer that lacked query_variable_store() would no longer work. Unfortunately, there is another case to consider here, which was missed: if the efivars layer is backed by the EFI runtime services as usual, but the EFI implementation predates the introduction of QueryVariableInfo(), we will return EFI_UNSUPPORTED, and this is no longer being dealt with correctly. So let's fix this, and while at it, clean up the code a bit, by merging the check_var_size() routines as well as their callers. Cc: <[email protected]> # v6.0 Fixes: bbc6d2c ("efi: vars: Switch to new wrapper layer") Signed-off-by: Ard Biesheuvel <[email protected]> Tested-by: Aditya Garg <[email protected]>
1 parent 7d866e3 commit f11a74b

File tree

1 file changed

+20
-48
lines changed

1 file changed

+20
-48
lines changed

drivers/firmware/efi/vars.c

Lines changed: 20 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -21,29 +21,22 @@ static struct efivars *__efivars;
2121

2222
static DEFINE_SEMAPHORE(efivars_lock);
2323

24-
static efi_status_t check_var_size(u32 attributes, unsigned long size)
25-
{
26-
const struct efivar_operations *fops;
27-
28-
fops = __efivars->ops;
29-
30-
if (!fops->query_variable_store)
31-
return (size <= SZ_64K) ? EFI_SUCCESS : EFI_OUT_OF_RESOURCES;
32-
33-
return fops->query_variable_store(attributes, size, false);
34-
}
35-
36-
static
37-
efi_status_t check_var_size_nonblocking(u32 attributes, unsigned long size)
24+
static efi_status_t check_var_size(bool nonblocking, u32 attributes,
25+
unsigned long size)
3826
{
3927
const struct efivar_operations *fops;
28+
efi_status_t status;
4029

4130
fops = __efivars->ops;
4231

4332
if (!fops->query_variable_store)
33+
status = EFI_UNSUPPORTED;
34+
else
35+
status = fops->query_variable_store(attributes, size,
36+
nonblocking);
37+
if (status == EFI_UNSUPPORTED)
4438
return (size <= SZ_64K) ? EFI_SUCCESS : EFI_OUT_OF_RESOURCES;
45-
46-
return fops->query_variable_store(attributes, size, true);
39+
return status;
4740
}
4841

4942
/**
@@ -195,26 +188,6 @@ efi_status_t efivar_get_next_variable(unsigned long *name_size,
195188
}
196189
EXPORT_SYMBOL_NS_GPL(efivar_get_next_variable, EFIVAR);
197190

198-
/*
199-
* efivar_set_variable_blocking() - local helper function for set_variable
200-
*
201-
* Must be called with efivars_lock held.
202-
*/
203-
static efi_status_t
204-
efivar_set_variable_blocking(efi_char16_t *name, efi_guid_t *vendor,
205-
u32 attr, unsigned long data_size, void *data)
206-
{
207-
efi_status_t status;
208-
209-
if (data_size > 0) {
210-
status = check_var_size(attr, data_size +
211-
ucs2_strsize(name, 1024));
212-
if (status != EFI_SUCCESS)
213-
return status;
214-
}
215-
return __efivars->ops->set_variable(name, vendor, attr, data_size, data);
216-
}
217-
218191
/*
219192
* efivar_set_variable_locked() - set a variable identified by name/vendor
220193
*
@@ -228,23 +201,21 @@ efi_status_t efivar_set_variable_locked(efi_char16_t *name, efi_guid_t *vendor,
228201
efi_set_variable_t *setvar;
229202
efi_status_t status;
230203

231-
if (!nonblocking)
232-
return efivar_set_variable_blocking(name, vendor, attr,
233-
data_size, data);
204+
if (data_size > 0) {
205+
status = check_var_size(nonblocking, attr,
206+
data_size + ucs2_strsize(name, 1024));
207+
if (status != EFI_SUCCESS)
208+
return status;
209+
}
234210

235211
/*
236212
* If no _nonblocking variant exists, the ordinary one
237213
* is assumed to be non-blocking.
238214
*/
239-
setvar = __efivars->ops->set_variable_nonblocking ?:
240-
__efivars->ops->set_variable;
215+
setvar = __efivars->ops->set_variable_nonblocking;
216+
if (!setvar || !nonblocking)
217+
setvar = __efivars->ops->set_variable;
241218

242-
if (data_size > 0) {
243-
status = check_var_size_nonblocking(attr, data_size +
244-
ucs2_strsize(name, 1024));
245-
if (status != EFI_SUCCESS)
246-
return status;
247-
}
248219
return setvar(name, vendor, attr, data_size, data);
249220
}
250221
EXPORT_SYMBOL_NS_GPL(efivar_set_variable_locked, EFIVAR);
@@ -264,7 +235,8 @@ efi_status_t efivar_set_variable(efi_char16_t *name, efi_guid_t *vendor,
264235
if (efivar_lock())
265236
return EFI_ABORTED;
266237

267-
status = efivar_set_variable_blocking(name, vendor, attr, data_size, data);
238+
status = efivar_set_variable_locked(name, vendor, attr, data_size,
239+
data, false);
268240
efivar_unlock();
269241
return status;
270242
}

0 commit comments

Comments
 (0)