From 95fb03c8e34171d603add43a1b33fdc50bcffe0d Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 31 Oct 2025 11:39:41 +0100 Subject: [PATCH] spa: add some more POD tests Check if the pod size is at least big enough to hold 1 item when getting array or choice items. Check that the number of choice values is at least enough to handle the given choice type. Remove some redundant checks. --- spa/include/spa/debug/format.h | 3 +-- spa/include/spa/pod/body.h | 28 ++++++++++++++++++++++++++-- spa/include/spa/pod/filter.h | 6 ++---- spa/include/spa/pod/iter.h | 2 +- 4 files changed, 30 insertions(+), 9 deletions(-) diff --git a/spa/include/spa/debug/format.h b/spa/include/spa/debug/format.h index 874dd094a..1448ae223 100644 --- a/spa/include/spa/debug/format.h +++ b/spa/include/spa/debug/format.h @@ -164,8 +164,7 @@ SPA_API_DEBUG_FORMAT int spa_debugc_format(struct spa_debug_context *ctx, int in type = val->type; size = val->size; - if (type < SPA_TYPE_None || type >= _SPA_TYPE_LAST || n_vals < 1 || - size < spa_pod_type_size(type)) + if (type < SPA_TYPE_None || type >= _SPA_TYPE_LAST || n_vals < 1) continue; vals = SPA_POD_BODY(val); diff --git a/spa/include/spa/pod/body.h b/spa/include/spa/pod/body.h index 07758c7e6..51f8e8f74 100644 --- a/spa/include/spa/pod/body.h +++ b/spa/include/spa/pod/body.h @@ -78,6 +78,27 @@ SPA_API_POD_BODY uint32_t spa_pod_type_size(uint32_t type) return 0; } +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) { @@ -333,6 +354,8 @@ SPA_API_POD_BODY const void *spa_pod_array_body_get_values(const struct spa_pod_ *n_values = child_size ? (arr->pod.size - sizeof(arr->body)) / child_size : 0; *val_size = child_size; *val_type = arr->body.child.type; + if (*val_size < spa_pod_type_size(*val_type)) + *n_values = 0; return body; } @@ -371,8 +394,9 @@ SPA_API_POD_BODY const void *spa_pod_choice_body_get_values(const struct spa_pod *val_type = pod->body.child.type; *n_values = child_size ? (pod->pod.size - sizeof(pod->body)) / child_size : 0; *choice = pod->body.type; - if (*choice == SPA_CHOICE_None) - *n_values = SPA_MIN(1u, *n_values); + if (*n_values < spa_pod_choice_min_values(*choice) || + *val_size < spa_pod_type_size(*val_type)) + *n_values = 0; return body; } diff --git a/spa/include/spa/pod/filter.h b/spa/include/spa/pod/filter.h index 6e238c2e6..93d9a51ea 100644 --- a/spa/include/spa/pod/filter.h +++ b/spa/include/spa/pod/filter.h @@ -82,7 +82,7 @@ spa_pod_filter_prop(struct spa_pod_builder *b, v1 = spa_pod_get_values(&p1->value, &nalt1, &p1c); v2 = spa_pod_get_values(&p2->value, &nalt2, &p2c); - /* empty choices */ + /* empty/invalid choices */ if (nalt1 < 1 || nalt2 < 1) return -EINVAL; @@ -95,8 +95,6 @@ spa_pod_filter_prop(struct spa_pod_builder *b, /* incompatible property types */ if (type != v2->type || size != v2->size || p1->key != p2->key) return -EINVAL; - if (size < spa_pod_type_size(type)) - return -EINVAL; /* start with copying the property */ spa_pod_builder_prop(b, p1->key, p1->flags & p2->flags); @@ -406,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 (v->size < spa_pod_type_size(v->type)) + if (nvals < 1) continue; if (spa_pod_compare_is_valid_choice(v->type, v->size, diff --git a/spa/include/spa/pod/iter.h b/spa/include/spa/pod/iter.h index a0da580ea..779286e0c 100644 --- a/spa/include/spa/pod/iter.h +++ b/spa/include/spa/pod/iter.h @@ -228,7 +228,7 @@ SPA_API_POD_ITER struct spa_pod *spa_pod_get_values(const struct spa_pod *pod, spa_pod_choice_body_get_values(p, SPA_POD_BODY_CONST(p), n_vals, choice, &size, &type); return (struct spa_pod*)&p->body.child; } else { - *n_vals = 1; + *n_vals = pod->size < spa_pod_type_size(pod->type) ? 0 : 1; *choice = SPA_CHOICE_None; return (struct spa_pod*)pod; }