mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-29 05:40:27 -04:00
Merge branch 'fixsizes' into 'master'
spa: param: fix size passed in spa_format_audio_raw_ext_parse/build + add size checks See merge request pipewire/pipewire!2577
This commit is contained in:
commit
2b36b6c2cb
7 changed files with 201 additions and 5 deletions
|
|
@ -46,20 +46,61 @@ extern "C" {
|
|||
#endif
|
||||
#endif
|
||||
|
||||
SPA_API_AUDIO_FORMAT_UTILS bool
|
||||
spa_format_audio_ext_valid_size(uint32_t media_subtype, size_t size)
|
||||
{
|
||||
switch (media_subtype) {
|
||||
case SPA_MEDIA_SUBTYPE_raw:
|
||||
return size >= offsetof(struct spa_audio_info, info.raw) &&
|
||||
SPA_AUDIO_INFO_RAW_VALID_SIZE(size - offsetof(struct spa_audio_info, info.raw));
|
||||
|
||||
#define _SPA_FORMAT_AUDIO_EXT_VALID_SIZE_CASE(format) \
|
||||
case SPA_MEDIA_SUBTYPE_ ## format: \
|
||||
return size >= offsetof(struct spa_audio_info, info.format) + sizeof(struct spa_audio_info_ ## format);
|
||||
_SPA_FORMAT_AUDIO_EXT_VALID_SIZE_CASE(dsp)
|
||||
_SPA_FORMAT_AUDIO_EXT_VALID_SIZE_CASE(iec958)
|
||||
_SPA_FORMAT_AUDIO_EXT_VALID_SIZE_CASE(dsd)
|
||||
_SPA_FORMAT_AUDIO_EXT_VALID_SIZE_CASE(mp3)
|
||||
_SPA_FORMAT_AUDIO_EXT_VALID_SIZE_CASE(aac)
|
||||
_SPA_FORMAT_AUDIO_EXT_VALID_SIZE_CASE(vorbis)
|
||||
_SPA_FORMAT_AUDIO_EXT_VALID_SIZE_CASE(wma)
|
||||
_SPA_FORMAT_AUDIO_EXT_VALID_SIZE_CASE(ra)
|
||||
_SPA_FORMAT_AUDIO_EXT_VALID_SIZE_CASE(amr)
|
||||
_SPA_FORMAT_AUDIO_EXT_VALID_SIZE_CASE(alac)
|
||||
_SPA_FORMAT_AUDIO_EXT_VALID_SIZE_CASE(flac)
|
||||
_SPA_FORMAT_AUDIO_EXT_VALID_SIZE_CASE(ape)
|
||||
_SPA_FORMAT_AUDIO_EXT_VALID_SIZE_CASE(ac3)
|
||||
_SPA_FORMAT_AUDIO_EXT_VALID_SIZE_CASE(eac3)
|
||||
_SPA_FORMAT_AUDIO_EXT_VALID_SIZE_CASE(truehd)
|
||||
_SPA_FORMAT_AUDIO_EXT_VALID_SIZE_CASE(dts)
|
||||
_SPA_FORMAT_AUDIO_EXT_VALID_SIZE_CASE(mpegh)
|
||||
#undef _SPA_FORMAT_AUDIO_EXT_VALID_SIZE_CASE
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
SPA_API_AUDIO_FORMAT_UTILS int
|
||||
spa_format_audio_ext_parse(const struct spa_pod *format, struct spa_audio_info *info, size_t size)
|
||||
{
|
||||
int res;
|
||||
uint32_t media_type, media_subtype;
|
||||
|
||||
if ((res = spa_format_parse(format, &info->media_type, &info->media_subtype)) < 0)
|
||||
if ((res = spa_format_parse(format, &media_type, &media_subtype)) < 0)
|
||||
return res;
|
||||
|
||||
if (info->media_type != SPA_MEDIA_TYPE_audio)
|
||||
if (media_type != SPA_MEDIA_TYPE_audio)
|
||||
return -EINVAL;
|
||||
|
||||
switch (info->media_subtype) {
|
||||
if (!spa_format_audio_ext_valid_size(media_subtype, size))
|
||||
return -EINVAL;
|
||||
|
||||
info->media_type = media_type;
|
||||
info->media_subtype = media_subtype;
|
||||
|
||||
switch (media_subtype) {
|
||||
case SPA_MEDIA_SUBTYPE_raw:
|
||||
return spa_format_audio_raw_ext_parse(format, &info->info.raw, size);
|
||||
return spa_format_audio_raw_ext_parse(format, &info->info.raw,
|
||||
size - offsetof(struct spa_audio_info, info.raw));
|
||||
case SPA_MEDIA_SUBTYPE_dsp:
|
||||
return spa_format_audio_dsp_parse(format, &info->info.dsp);
|
||||
case SPA_MEDIA_SUBTYPE_iec958:
|
||||
|
|
@ -108,9 +149,15 @@ SPA_API_AUDIO_FORMAT_UTILS struct spa_pod *
|
|||
spa_format_audio_ext_build(struct spa_pod_builder *builder, uint32_t id,
|
||||
const struct spa_audio_info *info, size_t size)
|
||||
{
|
||||
if (!spa_format_audio_ext_valid_size(info->media_subtype, size)) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch (info->media_subtype) {
|
||||
case SPA_MEDIA_SUBTYPE_raw:
|
||||
return spa_format_audio_raw_ext_build(builder, id, &info->info.raw, size);
|
||||
return spa_format_audio_raw_ext_build(builder, id, &info->info.raw,
|
||||
size - offsetof(struct spa_audio_info, info.raw));
|
||||
case SPA_MEDIA_SUBTYPE_dsp:
|
||||
return spa_format_audio_dsp_build(builder, id, &info->info.dsp);
|
||||
case SPA_MEDIA_SUBTYPE_iec958:
|
||||
|
|
|
|||
|
|
@ -59,6 +59,8 @@ struct spa_audio_info {
|
|||
struct spa_audio_info_dts dts;
|
||||
struct spa_audio_info_mpegh mpegh;
|
||||
} info;
|
||||
|
||||
/* padding follows here when info has flexible size */
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -60,6 +60,10 @@ spa_audio_info_raw_ext_update(struct spa_audio_info_raw *info, size_t size,
|
|||
{
|
||||
uint32_t v;
|
||||
uint32_t max_position = SPA_AUDIO_INFO_RAW_MAX_POSITION(size);
|
||||
|
||||
if (!SPA_AUDIO_INFO_RAW_VALID_SIZE(size))
|
||||
return -EINVAL;
|
||||
|
||||
if (spa_streq(key, SPA_KEY_AUDIO_FORMAT)) {
|
||||
if (force || info->format == 0)
|
||||
info->format = (enum spa_audio_format)spa_type_audio_format_from_short_name(val);
|
||||
|
|
@ -100,6 +104,9 @@ spa_audio_info_raw_ext_init_dict_keys_va(struct spa_audio_info_raw *info, size_t
|
|||
{
|
||||
int res;
|
||||
|
||||
if (!SPA_AUDIO_INFO_RAW_VALID_SIZE(size))
|
||||
return -EINVAL;
|
||||
|
||||
memset(info, 0, size);
|
||||
SPA_FLAG_SET(info->flags, SPA_AUDIO_FLAG_UNPOSITIONED);
|
||||
if (dict) {
|
||||
|
|
|
|||
|
|
@ -35,6 +35,9 @@ spa_format_audio_raw_ext_parse(const struct spa_pod *format, struct spa_audio_in
|
|||
int res;
|
||||
uint32_t max_position = SPA_AUDIO_INFO_RAW_MAX_POSITION(size);
|
||||
|
||||
if (!SPA_AUDIO_INFO_RAW_VALID_SIZE(size))
|
||||
return -EINVAL;
|
||||
|
||||
info->flags = 0;
|
||||
res = spa_pod_parse_object(format,
|
||||
SPA_TYPE_OBJECT_Format, NULL,
|
||||
|
|
@ -64,6 +67,11 @@ spa_format_audio_raw_ext_build(struct spa_pod_builder *builder, uint32_t id,
|
|||
struct spa_pod_frame f;
|
||||
uint32_t max_position = SPA_AUDIO_INFO_RAW_MAX_POSITION(size);
|
||||
|
||||
if (!SPA_AUDIO_INFO_RAW_VALID_SIZE(size)) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
spa_pod_builder_push_object(builder, &f, SPA_TYPE_OBJECT_Format, id);
|
||||
spa_pod_builder_add(builder,
|
||||
SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_audio),
|
||||
|
|
|
|||
|
|
@ -293,6 +293,8 @@ struct spa_audio_info_raw {
|
|||
|
||||
#define SPA_AUDIO_INFO_RAW_MAX_POSITION(size) (((size)-offsetof(struct spa_audio_info_raw,position))/sizeof(uint32_t))
|
||||
|
||||
#define SPA_AUDIO_INFO_RAW_VALID_SIZE(size) ((size) >= offsetof(struct spa_audio_info_raw, position))
|
||||
|
||||
|
||||
#define SPA_KEY_AUDIO_FORMAT "audio.format" /**< an audio format as string,
|
||||
* Ex. "S16LE" */
|
||||
|
|
|
|||
|
|
@ -112,6 +112,7 @@ test('test-spa',
|
|||
executable('test-spa',
|
||||
'test-spa-buffer.c',
|
||||
'test-spa-control.c',
|
||||
'test-spa-format.c',
|
||||
'test-spa-json.c',
|
||||
'test-spa-utils.c',
|
||||
'test-spa-log.c',
|
||||
|
|
|
|||
129
test/test-spa-format.c
Normal file
129
test/test-spa-format.c
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2025 Pauli Virtanen */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#include <spa/param/audio/format-utils.h>
|
||||
#include <spa/param/audio/format.h>
|
||||
|
||||
#include "pwtest.h"
|
||||
|
||||
PWTEST(audio_format_sizes)
|
||||
{
|
||||
union {
|
||||
uint8_t buf[1024];
|
||||
struct spa_audio_info align;
|
||||
} data;
|
||||
struct spa_audio_info info;
|
||||
size_t i;
|
||||
|
||||
memset(&info, 0xf3, sizeof(info));
|
||||
info.media_type = SPA_MEDIA_TYPE_audio;
|
||||
info.media_subtype = SPA_MEDIA_SUBTYPE_raw;
|
||||
info.info.raw.channels = 5;
|
||||
info.info.raw.format = SPA_AUDIO_FORMAT_F32P;
|
||||
info.info.raw.rate = 12345;
|
||||
info.info.raw.flags = 0;
|
||||
info.info.raw.position[0] = 1;
|
||||
info.info.raw.position[1] = 2;
|
||||
info.info.raw.position[2] = 3;
|
||||
info.info.raw.position[3] = 4;
|
||||
info.info.raw.position[4] = 5;
|
||||
|
||||
for (i = 0; i < sizeof(data.buf); ++i) {
|
||||
struct spa_pod *pod;
|
||||
uint8_t buf[4096];
|
||||
struct spa_pod_builder b;
|
||||
|
||||
spa_pod_builder_init(&b, buf, sizeof(buf));
|
||||
memcpy(data.buf, &info, sizeof(info));
|
||||
|
||||
pod = spa_format_audio_ext_build(&b, 123, (void *)data.buf, i);
|
||||
if (i < offsetof(struct spa_audio_info, info.raw)
|
||||
+ offsetof(struct spa_audio_info_raw, position))
|
||||
pwtest_bool_true(!pod);
|
||||
else
|
||||
pwtest_bool_true(pod);
|
||||
}
|
||||
|
||||
for (i = 0; i < sizeof(data.buf); ++i) {
|
||||
struct spa_pod *pod;
|
||||
uint8_t buf[4096];
|
||||
struct spa_pod_builder b;
|
||||
int ret;
|
||||
|
||||
spa_pod_builder_init(&b, buf, sizeof(buf));
|
||||
pod = spa_format_audio_ext_build(&b, 123, &info, sizeof(info));
|
||||
pwtest_bool_true(pod);
|
||||
|
||||
memset(data.buf, 0xf3, sizeof(data.buf));
|
||||
|
||||
ret = spa_format_audio_ext_parse(pod, (void *)data.buf, i);
|
||||
if (i < offsetof(struct spa_audio_info, info.raw)
|
||||
+ offsetof(struct spa_audio_info_raw, position)
|
||||
+ info.info.raw.channels*sizeof(uint32_t)) {
|
||||
for (size_t j = i; j < sizeof(data.buf); ++j)
|
||||
pwtest_int_eq(data.buf[j], 0xf3);
|
||||
pwtest_int_lt(ret, 0);
|
||||
} else {
|
||||
pwtest_int_ge(ret, 0);
|
||||
pwtest_bool_true(memcmp(data.buf, &info, SPA_MIN(i, sizeof(info))) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
memset(&info, 0xf3, sizeof(info));
|
||||
info.media_type = SPA_MEDIA_TYPE_audio;
|
||||
info.media_subtype = SPA_MEDIA_SUBTYPE_aac;
|
||||
info.info.aac.rate = 12345;
|
||||
info.info.aac.channels = 6;
|
||||
info.info.aac.bitrate = 54321;
|
||||
info.info.aac.stream_format = SPA_AUDIO_AAC_STREAM_FORMAT_MP4LATM;
|
||||
|
||||
for (i = 0; i < sizeof(data.buf); ++i) {
|
||||
struct spa_pod *pod;
|
||||
uint8_t buf[4096];
|
||||
struct spa_pod_builder b;
|
||||
|
||||
spa_pod_builder_init(&b, buf, sizeof(buf));
|
||||
memcpy(data.buf, &info, sizeof(info));
|
||||
|
||||
pod = spa_format_audio_ext_build(&b, 123, (void *)data.buf, i);
|
||||
if (i < offsetof(struct spa_audio_info, info.raw)
|
||||
+ sizeof(struct spa_audio_info_aac))
|
||||
pwtest_bool_true(!pod);
|
||||
else
|
||||
pwtest_bool_true(pod);
|
||||
}
|
||||
|
||||
for (i = 0; i < sizeof(data.buf); ++i) {
|
||||
struct spa_pod *pod;
|
||||
uint8_t buf[4096];
|
||||
struct spa_pod_builder b;
|
||||
int ret;
|
||||
|
||||
spa_pod_builder_init(&b, buf, sizeof(buf));
|
||||
pod = spa_format_audio_ext_build(&b, 123, &info, sizeof(info));
|
||||
pwtest_bool_true(pod);
|
||||
|
||||
memset(data.buf, 0xf3, sizeof(data.buf));
|
||||
|
||||
ret = spa_format_audio_ext_parse(pod, (void *)data.buf, i);
|
||||
if (i < offsetof(struct spa_audio_info, info.raw)
|
||||
+ sizeof(struct spa_audio_info_aac)) {
|
||||
for (size_t j = i; j < sizeof(data.buf); ++j)
|
||||
pwtest_int_eq(data.buf[j], 0xf3);
|
||||
pwtest_int_lt(ret, 0);
|
||||
} else {
|
||||
pwtest_int_ge(ret, 0);
|
||||
pwtest_bool_true(memcmp(data.buf, &info, SPA_MIN(i, sizeof(info))) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
return PWTEST_PASS;
|
||||
}
|
||||
|
||||
PWTEST_SUITE(spa_format)
|
||||
{
|
||||
pwtest_add(audio_format_sizes, PWTEST_NOARG);
|
||||
|
||||
return PWTEST_PASS;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue