mirror of
https://github.com/libretro/Lakka-LibreELEC.git
synced 2025-01-31 10:41:48 +00:00
23942f808a
Signed-off-by: Christian Hewitt <christianshewitt@gmail.com>
110 lines
3.5 KiB
Diff
110 lines
3.5 KiB
Diff
From c1328b956e9856210b1f2bc20c20fd152c309123 Mon Sep 17 00:00:00 2001
|
|
From: John Cox <jc@kynesim.co.uk>
|
|
Date: Mon, 29 Jan 2024 15:12:34 +0000
|
|
Subject: [PATCH 04/14] v4l2_req: Fix media pool delete race
|
|
|
|
fds & polltasks associated with media fds that are still in flight are
|
|
not freed on delete but the main pool is leading to use after free when
|
|
they finally do complete. Stop scanning the free chain on delete and
|
|
simply delete everything, in-flight or not. This requires changing alloc
|
|
as the buffers weren't previously tracked in-flight.
|
|
---
|
|
libavcodec/v4l2_req_media.c | 38 ++++++++++++++++++++-----------------
|
|
1 file changed, 21 insertions(+), 17 deletions(-)
|
|
|
|
diff --git a/libavcodec/v4l2_req_media.c b/libavcodec/v4l2_req_media.c
|
|
index 0394bb2b23..c94cc5b0f6 100644
|
|
--- a/libavcodec/v4l2_req_media.c
|
|
+++ b/libavcodec/v4l2_req_media.c
|
|
@@ -86,6 +86,8 @@ struct media_pool {
|
|
int fd;
|
|
sem_t sem;
|
|
pthread_mutex_t lock;
|
|
+ unsigned int pool_n;
|
|
+ struct media_request * pool_reqs;
|
|
struct media_request * free_reqs;
|
|
struct pollqueue * pq;
|
|
};
|
|
@@ -251,18 +253,17 @@ int media_request_abort(struct media_request ** const preq)
|
|
return 0;
|
|
}
|
|
|
|
-static void delete_req_chain(struct media_request * const chain)
|
|
+static void free_req_pool(struct media_request * const pool, const unsigned int n)
|
|
{
|
|
- struct media_request * next = chain;
|
|
- while (next) {
|
|
- struct media_request * const req = next;
|
|
- next = req->next;
|
|
+ unsigned int i;
|
|
+ for (i = 0; i != n; ++i) {
|
|
+ struct media_request * const req = pool + i;
|
|
if (req->pt)
|
|
polltask_delete(&req->pt);
|
|
if (req->fd != -1)
|
|
close(req->fd);
|
|
- free(req);
|
|
}
|
|
+ free(pool);
|
|
}
|
|
|
|
struct media_pool * media_pool_new(const char * const media_path,
|
|
@@ -283,17 +284,16 @@ struct media_pool * media_pool_new(const char * const media_path,
|
|
goto fail1;
|
|
}
|
|
|
|
+ if ((mp->pool_reqs = calloc(n, sizeof(*mp->pool_reqs))) == NULL)
|
|
+ goto fail3;
|
|
+ mp->pool_n = n;
|
|
for (i = 0; i != n; ++i) {
|
|
- struct media_request * req = malloc(sizeof(*req));
|
|
- if (!req)
|
|
- goto fail4;
|
|
+ mp->pool_reqs[i].mp = mp;
|
|
+ mp->pool_reqs[i].fd = -1;
|
|
+ }
|
|
|
|
- *req = (struct media_request){
|
|
- .next = mp->free_reqs,
|
|
- .mp = mp,
|
|
- .fd = -1
|
|
- };
|
|
- mp->free_reqs = req;
|
|
+ for (i = 0; i != n; ++i) {
|
|
+ struct media_request * const req = mp->pool_reqs + i;
|
|
|
|
if (ioctl(mp->fd, MEDIA_IOC_REQUEST_ALLOC, &req->fd) == -1) {
|
|
request_log("Failed to alloc request %d: %s\n", i, strerror(errno));
|
|
@@ -303,6 +303,9 @@ struct media_pool * media_pool_new(const char * const media_path,
|
|
req->pt = polltask_new(pq, req->fd, POLLPRI, media_request_done, req);
|
|
if (!req->pt)
|
|
goto fail4;
|
|
+
|
|
+ req->next = mp->free_reqs,
|
|
+ mp->free_reqs = req;
|
|
}
|
|
|
|
sem_init(&mp->sem, 0, n);
|
|
@@ -310,7 +313,8 @@ struct media_pool * media_pool_new(const char * const media_path,
|
|
return mp;
|
|
|
|
fail4:
|
|
- delete_req_chain(mp->free_reqs);
|
|
+ free_req_pool(mp->pool_reqs, mp->pool_n);
|
|
+fail3:
|
|
close(mp->fd);
|
|
pthread_mutex_destroy(&mp->lock);
|
|
fail1:
|
|
@@ -327,7 +331,7 @@ void media_pool_delete(struct media_pool ** pMp)
|
|
return;
|
|
*pMp = NULL;
|
|
|
|
- delete_req_chain(mp->free_reqs);
|
|
+ free_req_pool(mp->pool_reqs, mp->pool_n);
|
|
close(mp->fd);
|
|
sem_destroy(&mp->sem);
|
|
pthread_mutex_destroy(&mp->lock);
|
|
--
|
|
2.34.1
|
|
|