From d21a8caacea49cec2a6085b6432aa908b3e27536 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Barnab=C3=A1s=20P=C5=91cze?= Date: Thu, 14 Oct 2021 21:27:22 +0200 Subject: [PATCH] pipewire-v4l2: only access `globals.file_maps` while holding `globals.lock` `file_map` structures are allocated in a `pw_array`. When inserting into a full `pw_array`, it is resized to accomodate the new elements. In that case, all `file_map` pointers may be invalidated. Hence it is only safe to access `file_map` structs while holding `globals.lock`, which prevents any modifications to the file map array, thus keeping the references valid. --- pipewire-v4l2/src/pipewire-v4l2.c | 43 +++++++++++++++++-------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/pipewire-v4l2/src/pipewire-v4l2.c b/pipewire-v4l2/src/pipewire-v4l2.c index c6cbb787e..42d31028b 100644 --- a/pipewire-v4l2/src/pipewire-v4l2.c +++ b/pipewire-v4l2/src/pipewire-v4l2.c @@ -362,24 +362,34 @@ static int add_file_map(void *addr, struct file *file) pthread_mutex_unlock(&globals.lock); return 0; } -static struct file_map *find_file_map(void *addr) + +/* must be called with `globals.lock` held */ +static struct file_map *find_file_map_unlocked(void *addr) { - struct file_map *map, *res = NULL; - pthread_mutex_lock(&globals.lock); + struct file_map *map; + pw_array_for_each(map, &globals.file_maps) { - if (map->addr == addr) { - res = map; - break; - } + if (map->addr == addr) + return map; } - pthread_mutex_unlock(&globals.lock); - return res; + + return NULL; } -static void remove_file_map(struct file_map *map) +static struct file *remove_file_map(void *addr) { pthread_mutex_lock(&globals.lock); - pw_array_remove(&globals.file_maps, map); + + struct file_map *map = find_file_map_unlocked(addr); + struct file *file = NULL; + + if (map != NULL) { + file = map->file; + pw_array_remove(&globals.file_maps, map); + } + pthread_mutex_unlock(&globals.lock); + + return file; } static int add_buffer_map(struct file *file, void *addr, uint32_t id) @@ -729,9 +739,9 @@ static int v4l2_dup(int oldfd) static int v4l2_close(int fd) { - struct file *file = remove_fd_map(fd); + struct file *file; - if (file == NULL) + if ((file = remove_fd_map(fd)) == NULL) return globals.old_fops.close(fd); unref_file(file); @@ -1852,15 +1862,12 @@ error_unlock: static int v4l2_munmap(void *addr, size_t length) { int res; - struct file_map *fmap; struct buffer_map *bmap; struct file *file; - if ((fmap = find_file_map(addr)) == NULL) + if ((file = remove_file_map(addr)) == NULL) return globals.old_fops.munmap(addr, length); - file = fmap->file; - pw_thread_loop_lock(file->loop); bmap = find_buffer_map(file, addr); @@ -1879,8 +1886,6 @@ static int v4l2_munmap(void *addr, size_t length) exit_unlock: pw_thread_loop_unlock(file->loop); - remove_file_map(fmap); - return res; }