From 8554c9d02a6b6c10d63d4054003a4030653e8084 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 3 Jul 2025 18:27:37 +0200 Subject: [PATCH] pod: enforce max pod size Set a max pod size and add some more over and underflow checks --- spa/include/spa/pod/builder.h | 16 ++++++++++----- spa/include/spa/pod/iter.h | 38 ++++++++++++++++++++++------------- spa/include/spa/pod/pod.h | 1 + 3 files changed, 36 insertions(+), 19 deletions(-) diff --git a/spa/include/spa/pod/builder.h b/spa/include/spa/pod/builder.h index f3277d40a..abfaa8aaa 100644 --- a/spa/include/spa/pod/builder.h +++ b/spa/include/spa/pod/builder.h @@ -65,6 +65,11 @@ spa_pod_builder_get_state(struct spa_pod_builder *builder, struct spa_pod_builde *state = builder->state; } +SPA_API_POD_BUILDER bool spa_pod_builder_corrupted(const struct spa_pod_builder *builder) +{ + return builder->state.offset > builder->size; +} + SPA_API_POD_BUILDER void spa_pod_builder_set_callbacks(struct spa_pod_builder *builder, const struct spa_pod_builder_callbacks *callbacks, void *data) @@ -79,7 +84,7 @@ spa_pod_builder_reset(struct spa_pod_builder *builder, struct spa_pod_builder_st uint32_t size = builder->state.offset - state->offset; builder->state = *state; for (f = builder->state.frame; f ; f = f->parent) - f->pod.size -= size; + f->pod.size -= SPA_MIN(size, f->pod.size); } SPA_API_POD_BUILDER void spa_pod_builder_init(struct spa_pod_builder *builder, void *data, uint32_t size) @@ -91,9 +96,10 @@ SPA_API_POD_BUILDER struct spa_pod * spa_pod_builder_deref(struct spa_pod_builder *builder, uint32_t offset) { uint32_t size = builder->size; - if (offset + 8 <= size) { + if (offset + UINT64_C(8) <= size) { struct spa_pod *pod = SPA_PTROFF(builder->data, offset, struct spa_pod); - if (offset + SPA_POD_SIZE(pod) <= size) + if (offset + (uint64_t)SPA_POD_SIZE(pod) <= size && + SPA_POD_IS_VALID(pod)) return pod; } return NULL; @@ -159,9 +165,9 @@ SPA_API_POD_BUILDER int spa_pod_builder_raw(struct spa_pod_builder *builder, con SPA_API_POD_BUILDER void spa_pod_builder_remove(struct spa_pod_builder *builder, uint32_t size) { struct spa_pod_frame *f; - builder->state.offset -= size; + builder->state.offset -= SPA_MIN(size, builder->state.offset); for (f = builder->state.frame; f ; f = f->parent) - f->pod.size -= size; + f->pod.size -= SPA_MIN(size, f->pod.size); } SPA_API_POD_BUILDER int spa_pod_builder_pad(struct spa_pod_builder *builder, uint32_t size) diff --git a/spa/include/spa/pod/iter.h b/spa/include/spa/pod/iter.h index 96145a9f7..872c5e593 100644 --- a/spa/include/spa/pod/iter.h +++ b/spa/include/spa/pod/iter.h @@ -34,12 +34,25 @@ struct spa_pod_frame { uint32_t flags; }; +#define SPA_POD_IS_VALID(pod) \ + (SPA_POD_BODY_SIZE(pod) < SPA_POD_MAX_SIZE && \ + SPA_IS_ALIGNED(pod, SPA_POD_ALIGN)) + +#define SPA_POD_CHECK_TYPE(pod,_type) \ + (SPA_POD_IS_VALID(pod) && \ + (pod)->type == (_type)) + +#define SPA_POD_CHECK(pod,_type,_size) \ + (SPA_POD_CHECK_TYPE(pod,_type) && (pod)->size >= (_size)) + + SPA_API_POD_ITER bool spa_pod_is_inside(const void *pod, uint32_t size, const void *iter) { size_t remaining; return spa_ptr_type_inside(pod, size, iter, struct spa_pod, &remaining) && - remaining >= SPA_POD_BODY_SIZE(iter); + SPA_POD_IS_VALID((struct spa_pod*)iter) && + remaining >= SPA_POD_BODY_SIZE(iter); } SPA_API_POD_ITER void *spa_pod_next(const void *iter) @@ -58,7 +71,7 @@ SPA_API_POD_ITER bool spa_pod_prop_is_inside(const struct spa_pod_object_body *b size_t remaining; return spa_ptr_type_inside(body, size, iter, struct spa_pod_prop, &remaining) && - remaining >= iter->value.size; + SPA_POD_IS_VALID(&iter->value) && remaining >= iter->value.size; } SPA_API_POD_ITER struct spa_pod_prop *spa_pod_prop_next(const struct spa_pod_prop *iter) @@ -77,7 +90,7 @@ SPA_API_POD_ITER bool spa_pod_control_is_inside(const struct spa_pod_sequence_bo size_t remaining; return spa_ptr_type_inside(body, size, iter, struct spa_pod_control, &remaining) && - remaining >= iter->value.size; + SPA_POD_IS_VALID(&iter->value) && remaining >= iter->value.size; } SPA_API_POD_ITER struct spa_pod_control *spa_pod_control_next(const struct spa_pod_control *iter) @@ -136,20 +149,15 @@ SPA_API_POD_ITER void *spa_pod_from_data(void *data, size_t maxsize, off_t offse maxsize - size < (uint32_t)offset) return NULL; pod = SPA_PTROFF(data, offset, void); - if (!SPA_IS_ALIGNED(pod, SPA_POD_ALIGN)) + if (!SPA_POD_IS_VALID(pod)) return NULL; if (SPA_POD_BODY_SIZE(pod) > size - sizeof(struct spa_pod)) return NULL; return pod; } - -#define SPA_POD_CHECK_0(pod,_type) ((pod)->type == (_type) && SPA_IS_ALIGNED(pod, SPA_POD_ALIGN)) -#define SPA_POD_CHECK(pod,_type,_size) \ - (SPA_POD_CHECK_0(pod,_type) && (pod)->size >= (_size)) - SPA_API_POD_ITER int spa_pod_is_none(const struct spa_pod *pod) { - return SPA_POD_CHECK_0(pod, SPA_TYPE_None); + return SPA_POD_CHECK_TYPE(pod, SPA_TYPE_None); } SPA_API_POD_ITER int spa_pod_is_bool(const struct spa_pod *pod) @@ -257,7 +265,7 @@ SPA_API_POD_ITER int spa_pod_copy_string(const struct spa_pod *pod, size_t maxle SPA_API_POD_ITER int spa_pod_is_bytes(const struct spa_pod *pod) { - return SPA_POD_CHECK_0(pod, SPA_TYPE_Bytes); + return SPA_POD_CHECK_TYPE(pod, SPA_TYPE_Bytes); } SPA_API_POD_ITER int spa_pod_get_bytes(const struct spa_pod *pod, const void **value, uint32_t *len) @@ -328,7 +336,8 @@ SPA_API_POD_ITER int spa_pod_is_bitmap(const struct spa_pod *pod) SPA_API_POD_ITER int spa_pod_is_array(const struct spa_pod *pod) { - return SPA_POD_CHECK(pod, SPA_TYPE_Array, sizeof(struct spa_pod_array_body)); + return SPA_POD_CHECK(pod, SPA_TYPE_Array, sizeof(struct spa_pod_array_body)) && + SPA_POD_IS_VALID(SPA_POD_ARRAY_CHILD(pod)); } SPA_API_POD_ITER void *spa_pod_get_array(const struct spa_pod *pod, uint32_t *n_values) @@ -352,7 +361,8 @@ SPA_API_POD_ITER uint32_t spa_pod_copy_array(const struct spa_pod *pod, uint32_t SPA_API_POD_ITER int spa_pod_is_choice(const struct spa_pod *pod) { - return SPA_POD_CHECK(pod, SPA_TYPE_Choice, sizeof(struct spa_pod_choice_body)); + return SPA_POD_CHECK(pod, SPA_TYPE_Choice, sizeof(struct spa_pod_choice_body)) && + SPA_POD_IS_VALID(SPA_POD_CHOICE_CHILD(pod)); } SPA_API_POD_ITER struct spa_pod *spa_pod_get_values(const struct spa_pod *pod, uint32_t *n_vals, uint32_t *choice) @@ -372,7 +382,7 @@ SPA_API_POD_ITER struct spa_pod *spa_pod_get_values(const struct spa_pod *pod, u SPA_API_POD_ITER int spa_pod_is_struct(const struct spa_pod *pod) { - return SPA_POD_CHECK_0(pod, SPA_TYPE_Struct); + return SPA_POD_CHECK_TYPE(pod, SPA_TYPE_Struct); } SPA_API_POD_ITER int spa_pod_is_object(const struct spa_pod *pod) diff --git a/spa/include/spa/pod/pod.h b/spa/include/spa/pod/pod.h index f2b5c766e..63c2d4ee6 100644 --- a/spa/include/spa/pod/pod.h +++ b/spa/include/spa/pod/pod.h @@ -18,6 +18,7 @@ extern "C" { */ #define SPA_POD_ALIGN 8 +#define SPA_POD_MAX_SIZE (1u<<20) #define SPA_POD_BODY_SIZE(pod) (((struct spa_pod*)(pod))->size) #define SPA_POD_TYPE(pod) (((struct spa_pod*)(pod))->type)