From fcfe01a0be38fb0faa3b6af96ce77bffbb0e0e7e Mon Sep 17 00:00:00 2001 From: Demi Marie Obenour Date: Fri, 25 Jul 2025 17:09:19 -0400 Subject: [PATCH] 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. --- spa/include/spa/pod/body.h | 21 +++++++++++++++++++++ spa/include/spa/pod/compare.h | 2 ++ spa/include/spa/pod/filter.h | 5 +++-- 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/spa/include/spa/pod/body.h b/spa/include/spa/pod/body.h index a32f7f6bc..901537f81 100644 --- a/spa/include/spa/pod/body.h +++ b/spa/include/spa/pod/body.h @@ -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, struct spa_pod *pod, const void **body) { diff --git a/spa/include/spa/pod/compare.h b/spa/include/spa/pod/compare.h index 144bd4a5a..708568e91 100644 --- a/spa/include/spa/pod/compare.h +++ b/spa/include/spa/pod/compare.h @@ -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, 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) { case SPA_CHOICE_None: if (spa_pod_compare_value(type, val, vals, size) == 0) diff --git a/spa/include/spa/pod/filter.h b/spa/include/spa/pod/filter.h index 8eff1da37..a9feec87b 100644 --- a/spa/include/spa/pod/filter.h +++ b/spa/include/spa/pod/filter.h @@ -83,7 +83,8 @@ spa_pod_filter_prop(struct spa_pod_builder *b, v2 = spa_pod_get_values(&p2->value, &nalt2, &p2c); /* 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; 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); const void *vals = SPA_POD_BODY(v); - if (nvals < 1) + if (nvals < spa_pod_choice_min_values(choice)) continue; if (spa_pod_compare_is_valid_choice(v->type, v->size,