From 7f4fa6429113f8aa8a729e6f54148a1ba215b802 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 19 Jul 2021 09:53:23 +0200 Subject: [PATCH] loop: Fix crash because of overflow Also check if there is enough space to write the payload bytes. We check if there is enough space for the invoke_item structure first. Then we calculate how much bytes we need to use for the payload but we fail to check if we can actually write that much data, risking overwriting existing data from the ringbuffer and causing a crash later when we try to jump to invalid memory. Add some more comments. --- spa/plugins/support/loop.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/spa/plugins/support/loop.c b/spa/plugins/support/loop.c index e177c37fe..5a052e8d8 100644 --- a/spa/plugins/support/loop.c +++ b/spa/plugins/support/loop.c @@ -182,6 +182,8 @@ loop_invoke(void *object, } offset = idx & (DATAS_SIZE - 1); + /* l0 is remaining size in ringbuffer, this should always be larger than + * invoke_item, see below */ l0 = DATAS_SIZE - offset; item = SPA_PTROFF(impl->buffer_data, offset, struct invoke_item); @@ -194,14 +196,25 @@ loop_invoke(void *object, spa_log_trace(impl->log, NAME " %p: add item %p filled:%d", impl, item, filled); if (l0 > sizeof(struct invoke_item) + size) { + /* item + size fit in current ringbuffer idx */ item->data = SPA_PTROFF(item, sizeof(struct invoke_item), void); item->item_size = SPA_ROUND_UP_N(sizeof(struct invoke_item) + size, 8); - if (l0 < sizeof(struct invoke_item) + item->item_size) + if (l0 < sizeof(struct invoke_item) + item->item_size) { + /* not enough space for next invoke_item, fill up till the end + * so that the next item will be at the start */ item->item_size = l0; + } } else { + /* item does not fit, place the invoke_item at idx and start the + * data at the start of the ringbuffer */ item->data = impl->buffer_data; item->item_size = SPA_ROUND_UP_N(l0 + size, 8); } + if (avail < item->item_size) { + spa_log_warn(impl->log, NAME " %p: queue full %d, need %zd", impl, avail, + item->item_size); + return -EPIPE; + } if (data && size > 0) memcpy(item->data, data, size);