pod: Check that choices have enough values for their kind

Prevent out of bounds reads when a choice is too small for the type of
choice that it is.  Add a utility function to help catch this case.
This commit is contained in:
Demi Marie Obenour 2025-07-25 17:09:19 -04:00
parent 5853e1150b
commit fcfe01a0be
3 changed files with 26 additions and 2 deletions

View file

@ -116,6 +116,27 @@ SPA_API_POD_BODY uint32_t spa_pod_type_align(uint32_t type)
} }
} }
SPA_API_POD_BODY uint32_t spa_pod_choice_min_values(uint32_t choice_type)
{
switch (choice_type) {
case SPA_CHOICE_Enum:
return 2;
case SPA_CHOICE_Range:
return 3;
case SPA_CHOICE_Step:
return 4;
case SPA_CHOICE_None:
case SPA_CHOICE_Flags:
default:
/*
* This must always return at least 1, because callers
* assume that n_vals >= spa_pod_choice_min_values()
* mean that n_vals is at least 1.
*/
return 1;
}
}
SPA_API_POD_BODY int spa_pod_body_from_data(void *data, size_t maxsize, off_t offset, size_t size, SPA_API_POD_BODY int spa_pod_body_from_data(void *data, size_t maxsize, off_t offset, size_t size,
struct spa_pod *pod, const void **body) struct spa_pod *pod, const void **body)
{ {

View file

@ -226,6 +226,8 @@ SPA_API_POD_COMPARE int spa_pod_compare_is_in_range(uint32_t type, const void *v
SPA_API_POD_COMPARE int spa_pod_compare_is_valid_choice(uint32_t type, uint32_t size, SPA_API_POD_COMPARE int spa_pod_compare_is_valid_choice(uint32_t type, uint32_t size,
const void *val, const void *vals, uint32_t n_vals, uint32_t choice) const void *val, const void *vals, uint32_t n_vals, uint32_t choice)
{ {
if (n_vals < spa_pod_choice_min_values(choice))
return 0;
switch (choice) { switch (choice) {
case SPA_CHOICE_None: case SPA_CHOICE_None:
if (spa_pod_compare_value(type, val, vals, size) == 0) if (spa_pod_compare_value(type, val, vals, size) == 0)

View file

@ -83,7 +83,8 @@ spa_pod_filter_prop(struct spa_pod_builder *b,
v2 = spa_pod_get_values(&p2->value, &nalt2, &p2c); v2 = spa_pod_get_values(&p2->value, &nalt2, &p2c);
/* empty or bogus choices */ /* empty or bogus choices */
if (nalt1 < 1 || nalt2 < 1) if (nalt1 < spa_pod_choice_min_values(p1c) ||
nalt2 < spa_pod_choice_min_values(p2c))
return -EINVAL; return -EINVAL;
alt1 = SPA_POD_BODY(v1); alt1 = SPA_POD_BODY(v1);
@ -403,7 +404,7 @@ SPA_API_POD_FILTER int spa_pod_filter_object_make(struct spa_pod_object *pod)
struct spa_pod *v = spa_pod_get_values(&res->value, &nvals, &choice); struct spa_pod *v = spa_pod_get_values(&res->value, &nvals, &choice);
const void *vals = SPA_POD_BODY(v); const void *vals = SPA_POD_BODY(v);
if (nvals < 1) if (nvals < spa_pod_choice_min_values(choice))
continue; continue;
if (spa_pod_compare_is_valid_choice(v->type, v->size, if (spa_pod_compare_is_valid_choice(v->type, v->size,