testbench: check array size in component parsing

There may be a situation where size of all elements of the
snd_tplg_vendor_array is greater than the private data size.

If we take a look at array structure
struct snd_soc_tplg_vendor_array {
	__le32 size;	/* size in bytes of the array, including all elements */
	__le32 type;	/* SND_SOC_TPLG_TUPLE_TYPE_ */
	__le32 num_elems;	/* number of elements in array */
	union {
		struct snd_soc_tplg_vendor_uuid_elem uuid[0];
		struct snd_soc_tplg_vendor_value_elem value[0];
		struct snd_soc_tplg_vendor_string_elem string[0];
	};
} __attribute__((packed));

and assume of private data size is size.

If num_elems * sizeof(..._elem) > size occurs, this is bad
because, we first try to allocate _size_ bytes via malloc to array
pointer. Since the num_elems * sizeof(..._elem) is greater than
size, we get a segmentation fault when we try to memcpy the
remaining size in the subsequent functions (read tplg_read_array()).

We fix this problem by checking for whether array size falls
within the bounds of private data size.

Signed-off-by: Mohana Datta Yelugoti <ymdatta.work@gmail.com>
This commit is contained in:
Mohana Datta Yelugoti 2020-08-11 21:11:47 +00:00 committed by Liam Girdwood
parent 4b2edf8eed
commit 4758413fda
1 changed files with 42 additions and 0 deletions

View File

@ -10,6 +10,7 @@
#include <stdlib.h>
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
@ -60,6 +61,40 @@ static enum sof_comp_type find_process_comp_type(enum sof_ipc_process_type type)
return SOF_COMP_NONE;
}
static bool is_valid_priv_size(size_t size_read, size_t priv_size,
struct snd_soc_tplg_vendor_array *array)
{
size_t arr_size, elem_size, arr_elems_size;
arr_size = sizeof(struct snd_soc_tplg_vendor_array);
switch (array->type) {
case SND_SOC_TPLG_TUPLE_TYPE_UUID:
elem_size = sizeof(struct snd_soc_tplg_vendor_uuid_elem);
break;
case SND_SOC_TPLG_TUPLE_TYPE_STRING:
elem_size = sizeof(struct snd_soc_tplg_vendor_string_elem);
break;
case SND_SOC_TPLG_TUPLE_TYPE_BOOL:
case SND_SOC_TPLG_TUPLE_TYPE_BYTE:
case SND_SOC_TPLG_TUPLE_TYPE_WORD:
case SND_SOC_TPLG_TUPLE_TYPE_SHORT:
elem_size = sizeof(struct snd_soc_tplg_vendor_value_elem);
break;
default:
/* This is handled in the further calls */
return true;
}
arr_elems_size = array->num_elems * elem_size;
/*
* check if size of data to be read from widget's private data
* doesn't exceed private data's size.
*/
return size_read + arr_size + arr_elems_size <= priv_size;
}
/* read vendor tuples array from topology */
int tplg_read_array(struct snd_soc_tplg_vendor_array *array, FILE *file)
{
@ -339,6 +374,13 @@ int tplg_load_pga(int comp_id, int pipeline_id, int size,
return -EINVAL;
}
/* check for array size mismatch */
if (!is_valid_priv_size(total_array_size, size, array)) {
fprintf(stderr, "error: pga array size mismatch\n");
free(array);
return -EINVAL;
}
ret = tplg_read_array(array, file);
if (ret) {
fprintf(stderr, "error: read array fail\n");