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
This commit is contained in:
Wim Taymans 2026-05-14 13:23:19 +02:00
parent 61431dcbc0
commit 98fdedf348
5 changed files with 22 additions and 8 deletions

View file

@ -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;

View file

@ -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;

View file

@ -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",

View file

@ -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) {

View file

@ -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) {