From aae60d8db3b0f1a1a52e2999e188ed9721b287f9 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 14 May 2026 13:23:19 +0200 Subject: [PATCH] filter-graph: relax LADSPA plugin loading Make a new library.filter-path for the filter-graph that will filter and restrict the dlopen filenames (used for the LADSPA plugin only). By default this is false and so filter-chain can load from absolute paths without extra checks. Enable the extra checks for the pulse LADSPA modules and the audioconvert filter graphs because these allow loading LADSPA plugins into other processes. Fixes #5222 --- spa/plugins/audioconvert/audioconvert.c | 1 + spa/plugins/filter-graph/filter-graph.c | 8 +++++++- spa/plugins/filter-graph/plugin_ladspa.c | 19 ++++++++++++------- .../modules/module-ladspa-sink.c | 1 + .../modules/module-ladspa-source.c | 1 + 5 files changed, 22 insertions(+), 8 deletions(-) diff --git a/spa/plugins/audioconvert/audioconvert.c b/spa/plugins/audioconvert/audioconvert.c index 449a1750f..303e1c495 100644 --- a/spa/plugins/audioconvert/audioconvert.c +++ b/spa/plugins/audioconvert/audioconvert.c @@ -1417,6 +1417,7 @@ static int load_filter_graph(struct impl *impl, const char *graph, int order) &SPA_DICT_ITEMS( SPA_DICT_ITEM(SPA_KEY_LIBRARY_NAME, "filter-graph/libspa-filter-graph"), SPA_DICT_ITEM("clock.quantum-limit", qlimit), + SPA_DICT_ITEM("library.filter-path", "true"), SPA_DICT_ITEM("filter.graph", graph))); if (new_handle == NULL) goto error; diff --git a/spa/plugins/filter-graph/filter-graph.c b/spa/plugins/filter-graph/filter-graph.c index 9aab79a05..cd1ec7841 100644 --- a/spa/plugins/filter-graph/filter-graph.c +++ b/spa/plugins/filter-graph/filter-graph.c @@ -230,6 +230,7 @@ struct impl { uint32_t quantum_limit; uint32_t max_align; long unsigned rate; + bool filter_path; struct spa_list plugin_list; @@ -884,7 +885,7 @@ static struct plugin *plugin_load(struct impl *impl, const char *type, const cha struct spa_handle *hndl = NULL; struct plugin *plugin; char module[PATH_MAX]; - char factory_name[256], dsp_ptr[256]; + char factory_name[256], dsp_ptr[256], filter[16]; void *iface; int res; @@ -902,11 +903,14 @@ static struct plugin *plugin_load(struct impl *impl, const char *type, const cha "filter.graph.plugin.%s", type); spa_scnprintf(dsp_ptr, sizeof(dsp_ptr), "pointer:%p", impl->dsp); + spa_scnprintf(filter, sizeof(filter), + "%s", impl->filter_path ? "true" : "false"); hndl = spa_plugin_loader_load(impl->loader, factory_name, &SPA_DICT_ITEMS( SPA_DICT_ITEM(SPA_KEY_LIBRARY_NAME, module), SPA_DICT_ITEM("filter.graph.path", path), + SPA_DICT_ITEM("library.filter-path", filter), SPA_DICT_ITEM("filter.graph.audio.dsp", dsp_ptr))); if (hndl == NULL) { @@ -2400,6 +2404,8 @@ impl_init(const struct spa_handle_factory *factory, spa_atou32(s, &impl->info.n_inputs, 0); if (spa_streq(k, "filter-graph.n_outputs")) spa_atou32(s, &impl->info.n_outputs, 0); + if (spa_streq(k, "library.filter-path")) + impl->filter_path = spa_atob(s); } if (impl->quantum_limit == 0) return -EINVAL; diff --git a/spa/plugins/filter-graph/plugin_ladspa.c b/spa/plugins/filter-graph/plugin_ladspa.c index 54315861b..a0e0809d0 100644 --- a/spa/plugins/filter-graph/plugin_ladspa.c +++ b/spa/plugins/filter-graph/plugin_ladspa.c @@ -21,6 +21,7 @@ struct plugin { struct spa_handle handle; struct spa_fga_plugin plugin; + bool filter_path; struct spa_log *log; @@ -233,13 +234,13 @@ static inline const char *split_walk(const char *str, const char *delimiter, siz return s; } -static void make_search_paths(const char **path, const char **search_dirs) +static void make_search_paths(const char **path, const char **search_dirs, bool filter) { - const char *p; - - while ((p = strstr(*path, "../")) != NULL) - *path = p + 3; - + if (filter) { + const char *p; + while ((p = strstr(*path, "../")) != NULL) + *path = p + 3; + } *search_dirs = getenv("LADSPA_PATH"); if (!*search_dirs) *search_dirs = "/usr/lib64/ladspa:/usr/lib/ladspa:" LIBDIR; @@ -252,6 +253,8 @@ static int load_ladspa_plugin(struct plugin *impl, const char *path, const char char filename[PATH_MAX]; size_t len; + if (!impl->filter_path && path[0] == '/') + return ladspa_handle_load_by_path(impl, path); /* * set the errno for the case when `ladspa_handle_load_by_path()` * is never called, which can only happen if the supplied @@ -337,11 +340,13 @@ impl_init(const struct spa_handle_factory *factory, const char *s = info->items[i].value; if (spa_streq(k, "filter.graph.path")) path = s; + else if (spa_streq(k, "library.filter-path")) + impl->filter_path = spa_atob(s); } if (path == NULL) return -EINVAL; - make_search_paths(&path, &search_dirs); + make_search_paths(&path, &search_dirs, impl->filter_path); if ((res = load_ladspa_plugin(impl, path, search_dirs)) < 0) { spa_log_error(impl->log, "failed to load plugin '%s' in '%s': %s", diff --git a/src/modules/module-protocol-pulse/modules/module-ladspa-sink.c b/src/modules/module-protocol-pulse/modules/module-ladspa-sink.c index 50c368398..d19239d36 100644 --- a/src/modules/module-protocol-pulse/modules/module-ladspa-sink.c +++ b/src/modules/module-protocol-pulse/modules/module-ladspa-sink.c @@ -200,6 +200,7 @@ static int module_ladspa_sink_prepare(struct module * const module) } else { pw_properties_set(props, PW_KEY_NODE_DESCRIPTION, str); } + pw_properties_set(props, "library.filter-path", "true"); if ((str = pw_properties_get(props, "master")) != NULL || (str = pw_properties_get(props, "sink_master")) != NULL) { diff --git a/src/modules/module-protocol-pulse/modules/module-ladspa-source.c b/src/modules/module-protocol-pulse/modules/module-ladspa-source.c index 09eb11ce4..2f3521d12 100644 --- a/src/modules/module-protocol-pulse/modules/module-ladspa-source.c +++ b/src/modules/module-protocol-pulse/modules/module-ladspa-source.c @@ -200,6 +200,7 @@ static int module_ladspa_source_prepare(struct module * const module) } else { pw_properties_set(props, PW_KEY_NODE_DESCRIPTION, str); } + pw_properties_set(props, "library.filter-path", "true"); if ((str = pw_properties_get(props, "master")) != NULL || (str = pw_properties_get(props, "source_master")) != NULL) {