Minor fixes to edge cases in efi_get_next_variable_name
Fix allocating more memory for the names (unlikely to be needed, but still best to get right) to ask for the length the kernel told use we needed, not the old length of the variable. Mind the proper NUL that we add in the space we allocate. Free the old name string before we allcoate a new one to limit what we leak to the last one (free passed in name for the last one in the list), and detect the last one by rv != 0 and errno == ENOENT, rather then just the former to avoid false positives if errno happens to be ENOENT on entry. Sponsored by: Netflix
This commit is contained in:
parent
68467b1206
commit
0e5d767884
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=323519
@ -225,8 +225,13 @@ efi_get_next_variable_name(efi_guid_t **guid, char **name)
|
|||||||
if (efi_open_dev() == -1)
|
if (efi_open_dev() == -1)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Always allocate enough for an extra NUL on the end, but don't tell
|
||||||
|
* the IOCTL about it so we can NUL terminate the name before converting
|
||||||
|
* it to UTF8.
|
||||||
|
*/
|
||||||
if (buf == NULL)
|
if (buf == NULL)
|
||||||
buf = malloc(buflen);
|
buf = malloc(buflen + sizeof(efi_char));
|
||||||
|
|
||||||
again:
|
again:
|
||||||
efi_var_reset(&var);
|
efi_var_reset(&var);
|
||||||
@ -244,21 +249,23 @@ efi_get_next_variable_name(efi_guid_t **guid, char **name)
|
|||||||
rv = ioctl(efi_fd, EFIIOC_VAR_NEXT, &var);
|
rv = ioctl(efi_fd, EFIIOC_VAR_NEXT, &var);
|
||||||
if (rv == 0 && var.name == NULL) {
|
if (rv == 0 && var.name == NULL) {
|
||||||
/*
|
/*
|
||||||
* oops, too little space. Try again.
|
* Variable name not long enough, so allocate more space for the
|
||||||
|
* name and try again. As above, mind the NUL we add.
|
||||||
*/
|
*/
|
||||||
void *new = realloc(buf, buflen);
|
void *new = realloc(buf, var.namesize + sizeof(efi_char));
|
||||||
buflen = var.namesize;
|
|
||||||
if (new == NULL) {
|
if (new == NULL) {
|
||||||
rv = -1;
|
rv = -1;
|
||||||
errno = ENOMEM;
|
errno = ENOMEM;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
buflen = var.namesize;
|
||||||
buf = new;
|
buf = new;
|
||||||
goto again;
|
goto again;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rv == 0) {
|
if (rv == 0) {
|
||||||
*name = NULL; /* XXX */
|
free(*name); /* Free last name, to avoid leaking */
|
||||||
|
*name = NULL; /* Force ucs2_to_utf8 to malloc new space */
|
||||||
var.name[var.namesize / sizeof(efi_char)] = 0; /* EFI doesn't NUL terminate */
|
var.name[var.namesize / sizeof(efi_char)] = 0; /* EFI doesn't NUL terminate */
|
||||||
rv = ucs2_to_utf8(var.name, name);
|
rv = ucs2_to_utf8(var.name, name);
|
||||||
if (rv != 0)
|
if (rv != 0)
|
||||||
@ -269,9 +276,11 @@ efi_get_next_variable_name(efi_guid_t **guid, char **name)
|
|||||||
errout:
|
errout:
|
||||||
|
|
||||||
/* XXX The linux interface expects name to be a static buffer -- fix or leak memory? */
|
/* XXX The linux interface expects name to be a static buffer -- fix or leak memory? */
|
||||||
|
/* XXX for the moment, we free just before we'd leak, but still leak last one */
|
||||||
done:
|
done:
|
||||||
if (errno == ENOENT) {
|
if (rv != 0 && errno == ENOENT) {
|
||||||
errno = 0;
|
errno = 0;
|
||||||
|
free(*name); /* Free last name, to avoid leaking */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user