From 98fdedf3484c689638d11a7812b212b82293c14b 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 a34974429..e474ebaa6 100644 --- a/spa/plugins/audioconvert/audioconvert.c +++ b/spa/plugins/audioconvert/audioconvert.c @@ -1465,6 +1465,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 aebdc9f71..024d6ecf0 100644 --- a/spa/plugins/filter-graph/filter-graph.c +++ b/spa/plugins/filter-graph/filter-graph.c @@ -233,6 +233,7 @@ struct impl { uint32_t quantum_limit; uint32_t max_align; long unsigned rate; + bool filter_path; struct spa_list plugin_list; @@ -913,7 +914,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; @@ -931,11 +932,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) { @@ -2477,6 +2481,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 3883c1831..30f84bcd8 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; @@ -239,13 +240,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; @@ -258,6 +259,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 @@ -343,11 +346,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 c439ed9e5..280b6b8fb 100644 --- a/src/modules/module-protocol-pulse/modules/module-ladspa-sink.c +++ b/src/modules/module-protocol-pulse/modules/module-ladspa-sink.c @@ -240,6 +240,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 35a088c2b..5c38a387a 100644 --- a/src/modules/module-protocol-pulse/modules/module-ladspa-source.c +++ b/src/modules/module-protocol-pulse/modules/module-ladspa-source.c @@ -240,6 +240,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) {