From 4ac5364004b3869f27747c2b14fa275909ffeec6 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 29 Apr 2026 13:10:46 +0200 Subject: [PATCH] security: add max followers limit to netjack2 manager Add a configurable netjack2.max-followers property (default 64) to limit the number of concurrent followers, preventing resource exhaustion from unbounded follower connections. Co-Authored-By: Claude Opus 4.7 --- src/modules/module-netjack2-manager.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/modules/module-netjack2-manager.c b/src/modules/module-netjack2-manager.c index ec9b6cf2f..ee918de92 100644 --- a/src/modules/module-netjack2-manager.c +++ b/src/modules/module-netjack2-manager.c @@ -80,6 +80,7 @@ * - `netjack2.period-size`: the buffer size to use, default 1024 * - `netjack2.encoding`: the encoding, float|opus|int, default float * - `netjack2.kbps`: the number of kilobits per second when encoding, default 64 + * - `netjack2.max-followers`: the maximum number of concurrent followers, default 64 * - `audio.ports`: the number of audio ports. Can also be added to the stream props. This * is the default suggestion for drivers that don't specify any number of audio channels. * - `midi.ports`: the number of midi ports. Can also be added to the stream props. This @@ -116,6 +117,7 @@ * #netjack2.period-size = 1024 * #netjack2.encoding = float # float|opus * #netjack2.kbps = 64 + * #netjack2.max-followers = 64 * #audio.ports = 0 * #midi.ports = 0 * #audio.channels = 2 @@ -157,6 +159,7 @@ PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME); #define DEFAULT_KBPS 64 #define DEFAULT_AUDIO_PORTS 2 #define DEFAULT_MIDI_PORTS 1 +#define DEFAULT_MAX_FOLLOWERS 64 #define MODULE_USAGE "( remote.name= ) " \ "( local.ifname= ) " \ @@ -168,6 +171,7 @@ PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME); "( netjack2.connect= ) " \ "( netjack2.sample-rate= ) "\ "( netjack2.period-size= ) " \ + "( netjack2.max-followers= ) " \ "( midi.ports= ) " \ "( audio.channels= ) " \ "( audio.position= ) " \ @@ -286,6 +290,8 @@ struct impl { struct spa_source *setup_socket; struct spa_list follower_list; uint32_t follower_id; + uint32_t n_followers; + uint32_t max_followers; unsigned int do_disconnect:1; }; @@ -421,6 +427,7 @@ static void follower_free(struct follower *follower) follower->freeing = true; + impl->n_followers--; spa_list_remove(&follower->link); if (follower->socket) { @@ -945,6 +952,11 @@ static int handle_follower_available(struct impl *impl, struct nj2_session_param pw_log_info("got follower available"); nj2_dump_session_params(params); + if (impl->n_followers >= impl->max_followers) { + pw_log_warn("max followers reached (%u), rejecting", impl->max_followers); + return -EBUSY; + } + if (ntohl(params->version) != NJ2_NETWORK_PROTOCOL) { pw_log_warn("invalid version"); return -EINVAL; @@ -957,6 +969,7 @@ static int handle_follower_available(struct impl *impl, struct nj2_session_param follower->impl = impl; follower->id = impl->follower_id; spa_list_append(&impl->follower_list, &follower->link); + impl->n_followers++; peer = &follower->peer; @@ -1388,6 +1401,8 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args) } impl->kbps = pw_properties_get_uint32(impl->props, "netjack2.kbps", DEFAULT_KBPS); + impl->max_followers = pw_properties_get_uint32(impl->props, "netjack2.max-followers", + DEFAULT_MAX_FOLLOWERS); pw_properties_set(props, PW_KEY_NODE_LOOP_NAME, impl->data_loop->name); if (pw_properties_get(props, PW_KEY_NODE_VIRTUAL) == NULL)