diff --git a/spa/include/spa/debug/format.h b/spa/include/spa/debug/format.h index 31104c678..571b4df20 100644 --- a/spa/include/spa/debug/format.h +++ b/spa/include/spa/debug/format.h @@ -39,14 +39,10 @@ spa_debug_strbuf_format_value(struct spa_strbuf *buffer, const struct spa_type_i switch (type) { case SPA_TYPE_Bool: - if (size < sizeof(int32_t)) - goto bad_body; spa_strbuf_append(buffer, "%s", *(int32_t *) body ? "true" : "false"); break; case SPA_TYPE_Id: { - if (size < sizeof(uint32_t)) - goto bad_body; uint32_t value = *(uint32_t *) body; const char *str = spa_debug_type_find_short_name(info, value); char tmp[64]; @@ -58,42 +54,28 @@ spa_debug_strbuf_format_value(struct spa_strbuf *buffer, const struct spa_type_i break; } case SPA_TYPE_Int: - if (size < sizeof(int32_t)) - goto bad_body; spa_strbuf_append(buffer, "%d", *(int32_t *) body); break; case SPA_TYPE_Long: - if (size < sizeof(int64_t)) - goto bad_body; spa_strbuf_append(buffer, "%" PRIi64, *(int64_t *) body); break; case SPA_TYPE_Float: - if (size < sizeof(float)) - goto bad_body; spa_strbuf_append(buffer, "%f", *(float *) body); break; case SPA_TYPE_Double: - if (size < sizeof(double)) - goto bad_body; spa_strbuf_append(buffer, "%f", *(double *) body); break; case SPA_TYPE_String: - if (size < 1 || ((const char *)body)[size - 1] != '\0') - goto bad_body; - spa_strbuf_append(buffer, "%s", (char *) body); + spa_strbuf_append(buffer, "%-*s", size, (char *) body); break; case SPA_TYPE_Rectangle: { - if (size < sizeof(struct spa_rectangle)) - goto bad_body; struct spa_rectangle *r = (struct spa_rectangle *)body; spa_strbuf_append(buffer, "%" PRIu32 "x%" PRIu32, r->width, r->height); break; } case SPA_TYPE_Fraction: { - if (size < sizeof(struct spa_fraction)) - goto bad_body; struct spa_fraction *f = (struct spa_fraction *)body; spa_strbuf_append(buffer, "%" PRIu32 "/%" PRIu32, f->num, f->denom); break; @@ -109,14 +91,14 @@ spa_debug_strbuf_format_value(struct spa_strbuf *buffer, const struct spa_type_i void *p; struct spa_pod_array_body *b = (struct spa_pod_array_body *)body; int i = 0; - if (size < sizeof(*b)) - goto bad_body; info = info && info->values ? info->values : info; spa_strbuf_append(buffer, "< "); - SPA_POD_ARRAY_BODY_FOREACH(b, size, p) { - if (i++ > 0) - spa_strbuf_append(buffer, ", "); - spa_debug_strbuf_format_value(buffer, info, b->child.type, p, b->child.size); + if (b->child.size >= spa_pod_type_size(b->child.type)) { + SPA_POD_ARRAY_BODY_FOREACH(b, size, p) { + if (i++ > 0) + spa_strbuf_append(buffer, ", "); + spa_debug_strbuf_format_value(buffer, info, b->child.type, p, b->child.size); + } } spa_strbuf_append(buffer, " >"); break; @@ -126,9 +108,6 @@ spa_debug_strbuf_format_value(struct spa_strbuf *buffer, const struct spa_type_i break; } return 0; -bad_body: - spa_strbuf_append(buffer, "INVALID BODY type %d", type); - return 0; } SPA_API_DEBUG_FORMAT int @@ -184,11 +163,12 @@ SPA_API_DEBUG_FORMAT int spa_debugc_format(struct spa_debug_context *ctx, int in type = val->type; size = val->size; - vals = SPA_POD_BODY(val); - if (type < SPA_TYPE_None || type >= _SPA_TYPE_LAST || n_vals < 1) + if (type < SPA_TYPE_None || type >= _SPA_TYPE_LAST || n_vals < 1 || + size < spa_pod_type_size(type)) continue; + vals = SPA_POD_BODY(val); ti = spa_debug_type_find(info, prop->key); key = ti ? ti->name : NULL; diff --git a/spa/include/spa/debug/pod.h b/spa/include/spa/debug/pod.h index 4ff3f3e01..a6d3b91db 100644 --- a/spa/include/spa/debug/pod.h +++ b/spa/include/spa/debug/pod.h @@ -87,13 +87,18 @@ spa_debugc_pod_value(struct spa_debug_context *ctx, int indent, const struct spa struct spa_pod_array_body *b = (struct spa_pod_array_body *)body; void *p; const struct spa_type_info *ti = spa_debug_type_find(SPA_TYPE_ROOT, b->child.type); + uint32_t min_size = spa_pod_type_size(b->child.type); spa_debugc(ctx, "%*s" "Array: child.size %" PRIu32 ", child.type %s", indent, "", b->child.size, ti ? ti->name : "unknown"); - info = info && info->values ? info->values : info; - SPA_POD_ARRAY_BODY_FOREACH(b, size, p) - spa_debugc_pod_value(ctx, indent + 2, info, b->child.type, p, b->child.size); + if (b->child.size < min_size) { + spa_debugc(ctx, "%*s" " INVALID child.size < %" PRIu32, indent, "", min_size); + } else { + info = info && info->values ? info->values : info; + SPA_POD_ARRAY_BODY_FOREACH(b, size, p) + spa_debugc_pod_value(ctx, indent + 2, info, b->child.type, p, b->child.size); + } break; } case SPA_TYPE_Choice: @@ -101,20 +106,31 @@ spa_debugc_pod_value(struct spa_debug_context *ctx, int indent, const struct spa struct spa_pod_choice_body *b = (struct spa_pod_choice_body *)body; void *p; const struct spa_type_info *ti = spa_debug_type_find(spa_type_choice, b->type); + uint32_t min_size = spa_pod_type_size(b->child.type); spa_debugc(ctx, "%*s" "Choice: type %s, flags %08" PRIx32 " %" PRIu32 " %" PRIu32, indent, "", ti ? ti->name : "unknown", b->flags, size, b->child.size); - SPA_POD_CHOICE_BODY_FOREACH(b, size, p) - spa_debugc_pod_value(ctx, indent + 2, info, b->child.type, p, b->child.size); + if (b->child.size < min_size) { + spa_debugc(ctx, "%*s" "INVALID child.size < %" PRIu32, indent, "", min_size); + } else { + SPA_POD_CHOICE_BODY_FOREACH(b, size, p) + spa_debugc_pod_value(ctx, indent + 2, info, b->child.type, p, b->child.size); + } break; } case SPA_TYPE_Struct: { struct spa_pod *b = (struct spa_pod *)body, *p; spa_debugc(ctx, "%*s" "Struct: size %" PRIu32, indent, "", size); - SPA_POD_FOREACH(b, size, p) - spa_debugc_pod_value(ctx, indent + 2, info, p->type, SPA_POD_BODY(p), p->size); + SPA_POD_FOREACH(b, size, p) { + uint32_t min_size = spa_pod_type_size(p->type); + if (p->size < min_size) { + spa_debugc(ctx, "%*s" "INVALID child.size < %" PRIu32, indent, "", min_size); + } else { + spa_debugc_pod_value(ctx, indent + 2, info, p->type, SPA_POD_BODY(p), p->size); + } + } break; } case SPA_TYPE_Object: @@ -136,6 +152,7 @@ spa_debugc_pod_value(struct spa_debug_context *ctx, int indent, const struct spa static const char custom_prefix[] = SPA_TYPE_INFO_PROPS_BASE "Custom:"; char custom_name[sizeof(custom_prefix) + 16]; const char *name = "unknown"; + uint32_t min_size = spa_pod_type_size(p->value.type); ii = spa_debug_type_find(info, p->key); if (ii) { @@ -149,10 +166,14 @@ spa_debugc_pod_value(struct spa_debug_context *ctx, int indent, const struct spa spa_debugc(ctx, "%*s" "Prop: key %s (%" PRIu32 "), flags %08" PRIx32, indent+2, "", name, p->key, p->flags); - spa_debugc_pod_value(ctx, indent + 4, ii ? ii->values : NULL, - p->value.type, - SPA_POD_CONTENTS(struct spa_pod_prop, p), - p->value.size); + if (p->value.size < min_size) { + spa_debugc(ctx, "%*s" "INVALID value.size < %" PRIu32, indent, "", min_size); + } else { + spa_debugc_pod_value(ctx, indent + 4, ii ? ii->values : NULL, + p->value.type, + SPA_POD_CONTENTS(struct spa_pod_prop, p), + p->value.size); + } } break; } @@ -168,15 +189,21 @@ spa_debugc_pod_value(struct spa_debug_context *ctx, int indent, const struct spa ti ? ti->name : "unknown"); SPA_POD_SEQUENCE_BODY_FOREACH(b, size, c) { + uint32_t min_size = spa_pod_type_size(c->value.type); + ii = spa_debug_type_find(spa_type_control, c->type); spa_debugc(ctx, "%*s" "Control: offset %" PRIu32 ", type %s", indent+2, "", c->offset, ii ? ii->name : "unknown"); - spa_debugc_pod_value(ctx, indent + 4, ii ? ii->values : NULL, - c->value.type, - SPA_POD_CONTENTS(struct spa_pod_control, c), - c->value.size); + if (c->value.size < min_size) { + spa_debugc(ctx, "%*s" "INVALID value.size < %" PRIu32, indent, "", min_size); + } else { + spa_debugc_pod_value(ctx, indent + 4, ii ? ii->values : NULL, + c->value.type, + SPA_POD_CONTENTS(struct spa_pod_control, c), + c->value.size); + } } break; } @@ -198,6 +225,8 @@ spa_debugc_pod_value(struct spa_debug_context *ctx, int indent, const struct spa SPA_API_DEBUG_POD int spa_debugc_pod(struct spa_debug_context *ctx, int indent, const struct spa_type_info *info, const struct spa_pod *pod) { + if (pod->size < spa_pod_type_size(pod->type)) + return -EINVAL; return spa_debugc_pod_value(ctx, indent, info ? info : SPA_TYPE_ROOT, pod->type, SPA_POD_BODY(pod), pod->size); } diff --git a/spa/include/spa/pod/compare.h b/spa/include/spa/pod/compare.h index 67c18ad46..d5d4b3dcc 100644 --- a/spa/include/spa/pod/compare.h +++ b/spa/include/spa/pod/compare.h @@ -39,41 +39,23 @@ SPA_API_POD_COMPARE int spa_pod_compare_value(uint32_t type, const void *r1, con case SPA_TYPE_None: return 0; case SPA_TYPE_Bool: - if (size < sizeof(int32_t)) - return -EINVAL; return SPA_CMP(!!*(int32_t *)r1, !!*(int32_t *)r2); case SPA_TYPE_Id: - if (size < sizeof(uint32_t)) - return -EINVAL; return SPA_CMP(*(uint32_t *)r1, *(uint32_t *)r2); case SPA_TYPE_Int: - if (size < sizeof(int32_t)) - return -EINVAL; return SPA_CMP(*(int32_t *)r1, *(int32_t *)r2); case SPA_TYPE_Long: - if (size < sizeof(int64_t)) - return -EINVAL; return SPA_CMP(*(int64_t *)r1, *(int64_t *)r2); case SPA_TYPE_Float: - if (size < sizeof(float)) - return -EINVAL; return SPA_CMP(*(float *)r1, *(float *)r2); case SPA_TYPE_Double: - if (size < sizeof(double)) - return -EINVAL; return SPA_CMP(*(double *)r1, *(double *)r2); case SPA_TYPE_String: - if (size < sizeof(char) || - ((char *)r1)[size - 1] || - ((char *)r2)[size - 1]) - return -EINVAL; - return strcmp((char *)r1, (char *)r2); + return strncmp((char *)r1, (char *)r2, size); case SPA_TYPE_Rectangle: { const struct spa_rectangle *rec1 = (struct spa_rectangle *) r1, *rec2 = (struct spa_rectangle *) r2; - if (size < sizeof(struct spa_rectangle)) - return -EINVAL; if (rec1->width == rec2->width && rec1->height == rec2->height) return 0; else if (rec1->width < rec2->width || rec1->height < rec2->height) @@ -86,8 +68,6 @@ SPA_API_POD_COMPARE int spa_pod_compare_value(uint32_t type, const void *r1, con const struct spa_fraction *f1 = (struct spa_fraction *) r1, *f2 = (struct spa_fraction *) r2; uint64_t n1, n2; - if (size < sizeof(struct spa_fraction)) - return -EINVAL; n1 = ((uint64_t) f1->num) * f2->denom; n2 = ((uint64_t) f2->num) * f1->denom; return SPA_CMP(n1, n2); @@ -176,6 +156,8 @@ SPA_API_POD_COMPARE int spa_pod_compare(const struct spa_pod *pod1, default: if (pod1->size != pod2->size) return -EINVAL; + if (pod1->size < spa_pod_type_size(pod1->type)) + return -EINVAL; res = spa_pod_compare_value(pod1->type, SPA_POD_BODY(pod1), SPA_POD_BODY(pod2), pod1->size); diff --git a/spa/include/spa/pod/filter.h b/spa/include/spa/pod/filter.h index 6e1d7e17d..836095029 100644 --- a/spa/include/spa/pod/filter.h +++ b/spa/include/spa/pod/filter.h @@ -95,6 +95,8 @@ 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); @@ -402,6 +404,10 @@ SPA_API_POD_FILTER int spa_pod_filter_object_make(struct spa_pod_object *pod) uint32_t nvals, choice; 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)) + continue; + if (spa_pod_compare_is_valid_choice(v->type, v->size, vals, vals, nvals, choice)) { ((struct spa_pod_choice*)&res->value)->body.type = SPA_CHOICE_None;