mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-29 05:40:27 -04:00
spa: param: add size checks for spa_audio_info* structs
In the API that take struct size for spa_audio_info*, also check the struct size.
This commit is contained in:
parent
8a23b13798
commit
c6d0b364ab
7 changed files with 197 additions and 3 deletions
|
|
@ -46,18 +46,58 @@ extern "C" {
|
||||||
#endif
|
#endif
|
||||||
#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_API_AUDIO_FORMAT_UTILS int
|
||||||
spa_format_audio_ext_parse(const struct spa_pod *format, struct spa_audio_info *info, size_t size)
|
spa_format_audio_ext_parse(const struct spa_pod *format, struct spa_audio_info *info, size_t size)
|
||||||
{
|
{
|
||||||
int res;
|
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;
|
return res;
|
||||||
|
|
||||||
if (info->media_type != SPA_MEDIA_TYPE_audio)
|
if (media_type != SPA_MEDIA_TYPE_audio)
|
||||||
return -EINVAL;
|
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:
|
case SPA_MEDIA_SUBTYPE_raw:
|
||||||
return spa_format_audio_raw_ext_parse(format, &info->info.raw,
|
return spa_format_audio_raw_ext_parse(format, &info->info.raw,
|
||||||
size - offsetof(struct spa_audio_info, info.raw));
|
size - offsetof(struct spa_audio_info, info.raw));
|
||||||
|
|
@ -109,6 +149,11 @@ SPA_API_AUDIO_FORMAT_UTILS struct spa_pod *
|
||||||
spa_format_audio_ext_build(struct spa_pod_builder *builder, uint32_t id,
|
spa_format_audio_ext_build(struct spa_pod_builder *builder, uint32_t id,
|
||||||
const struct spa_audio_info *info, size_t size)
|
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) {
|
switch (info->media_subtype) {
|
||||||
case SPA_MEDIA_SUBTYPE_raw:
|
case SPA_MEDIA_SUBTYPE_raw:
|
||||||
return spa_format_audio_raw_ext_build(builder, id, &info->info.raw,
|
return spa_format_audio_raw_ext_build(builder, id, &info->info.raw,
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,8 @@ struct spa_audio_info {
|
||||||
struct spa_audio_info_dts dts;
|
struct spa_audio_info_dts dts;
|
||||||
struct spa_audio_info_mpegh mpegh;
|
struct spa_audio_info_mpegh mpegh;
|
||||||
} info;
|
} 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 v;
|
||||||
uint32_t max_position = SPA_AUDIO_INFO_RAW_MAX_POSITION(size);
|
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 (spa_streq(key, SPA_KEY_AUDIO_FORMAT)) {
|
||||||
if (force || info->format == 0)
|
if (force || info->format == 0)
|
||||||
info->format = (enum spa_audio_format)spa_type_audio_format_from_short_name(val);
|
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;
|
int res;
|
||||||
|
|
||||||
|
if (!SPA_AUDIO_INFO_RAW_VALID_SIZE(size))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
memset(info, 0, size);
|
memset(info, 0, size);
|
||||||
SPA_FLAG_SET(info->flags, SPA_AUDIO_FLAG_UNPOSITIONED);
|
SPA_FLAG_SET(info->flags, SPA_AUDIO_FLAG_UNPOSITIONED);
|
||||||
if (dict) {
|
if (dict) {
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,9 @@ spa_format_audio_raw_ext_parse(const struct spa_pod *format, struct spa_audio_in
|
||||||
int res;
|
int res;
|
||||||
uint32_t max_position = SPA_AUDIO_INFO_RAW_MAX_POSITION(size);
|
uint32_t max_position = SPA_AUDIO_INFO_RAW_MAX_POSITION(size);
|
||||||
|
|
||||||
|
if (!SPA_AUDIO_INFO_RAW_VALID_SIZE(size))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
info->flags = 0;
|
info->flags = 0;
|
||||||
res = spa_pod_parse_object(format,
|
res = spa_pod_parse_object(format,
|
||||||
SPA_TYPE_OBJECT_Format, NULL,
|
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;
|
struct spa_pod_frame f;
|
||||||
uint32_t max_position = SPA_AUDIO_INFO_RAW_MAX_POSITION(size);
|
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_push_object(builder, &f, SPA_TYPE_OBJECT_Format, id);
|
||||||
spa_pod_builder_add(builder,
|
spa_pod_builder_add(builder,
|
||||||
SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_audio),
|
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_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,
|
#define SPA_KEY_AUDIO_FORMAT "audio.format" /**< an audio format as string,
|
||||||
* Ex. "S16LE" */
|
* Ex. "S16LE" */
|
||||||
|
|
|
||||||
|
|
@ -112,6 +112,7 @@ test('test-spa',
|
||||||
executable('test-spa',
|
executable('test-spa',
|
||||||
'test-spa-buffer.c',
|
'test-spa-buffer.c',
|
||||||
'test-spa-control.c',
|
'test-spa-control.c',
|
||||||
|
'test-spa-format.c',
|
||||||
'test-spa-json.c',
|
'test-spa-json.c',
|
||||||
'test-spa-utils.c',
|
'test-spa-utils.c',
|
||||||
'test-spa-log.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