efibootmgr: Simplify make_next_boot_var_name and fix cnt == 0 case

If cnt == 0 we access element 0 unconditionally, which is out of bounds,
and then if that doesn't crash and happens to be 0 we will access
element - 1, also out of bounds, and then if that doesn't crash will add
1 to whatever junk is there and use that for the variable. On CHERI,
though, this does crash. This code is also overly complicated, with
unnecessary special cases and tracking more state than needed.

Rewrite it in a more general manner that doesn't need those special
cases and naturally works for cnt == 0.

Found by:	CHERI
Reviewed by:	imp
Fixes:		1285bcc833 ("Import Netflix's efibootmgr to help manage UEFI boot variables")
MFC after:	1 week
Differential Revision:	https://reviews.freebsd.org/D44029
This commit is contained in:
Jessica Clarke 2024-02-23 02:36:21 +00:00
parent 04eca69323
commit 09cb8031b4

View file

@ -561,7 +561,7 @@ static char *
make_next_boot_var_name(void)
{
struct entry *v;
uint16_t *vals, next_free = 0;
uint16_t *vals;
char *name;
int cnt = 0;
int i;
@ -579,21 +579,14 @@ make_next_boot_var_name(void)
vals[i++] = v->idx;
}
qsort(vals, cnt, sizeof(uint16_t), compare);
/* if the hole is at the beginning, just return zero */
if (vals[0] > 0) {
next_free = 0;
} else {
/* now just run the list looking for the first hole */
for (i = 0; i < cnt - 1 && next_free == 0; i++)
if (vals[i] + 1 != vals[i + 1])
next_free = vals[i] + 1;
if (next_free == 0)
next_free = vals[cnt - 1] + 1;
/* In theory we could have used all 65k slots -- what to do? */
}
/* Find the first hole (could be at start or end) */
for (i = 0; i < cnt; ++i)
if (vals[i] != i)
break;
free(vals);
/* In theory we could have used all 65k slots -- what to do? */
asprintf(&name, "%s%04X", "Boot", next_free);
asprintf(&name, "%s%04X", "Boot", i);
if (name == NULL)
err(1, "asprintf");
return name;