[pulseaudio-discuss] [PATCH] virtual sources and sinks: Fix possible segfault due to invalid master sink or source

Georg Chini georg at chini.tk
Tue May 2 05:36:51 UTC 2017


There are several places in the virtual sinks and sources code where a segfault is
possible when the master sink or source is invalid. The master may become invalid
during a profile switching situation when only one sound card is available or
when all real sinks or sources have been removed from the system.

This patch checks for the validity of master source or sink and lets the functions just
return if the master is invalid.

Bug link: https://bugs.freedesktop.org/show_bug.cgi?id=100277
---
 src/modules/echo-cancel/module-echo-cancel.c | 24 ++++++++++++++++--------
 src/modules/module-ladspa-sink.c             | 11 +++++++----
 src/modules/module-remap-sink.c              |  6 ++++--
 src/modules/module-remap-source.c            |  3 ++-
 src/modules/module-virtual-sink.c            | 12 ++++++++----
 src/modules/module-virtual-source.c          |  9 ++++++---
 src/modules/module-virtual-surround-sink.c   | 12 ++++++++----
 7 files changed, 51 insertions(+), 26 deletions(-)

diff --git a/src/modules/echo-cancel/module-echo-cancel.c b/src/modules/echo-cancel/module-echo-cancel.c
index 7e7290e6..75473a5a 100644
--- a/src/modules/echo-cancel/module-echo-cancel.c
+++ b/src/modules/echo-cancel/module-echo-cancel.c
@@ -525,7 +525,8 @@ static void source_update_requested_latency_cb(pa_source *s) {
     pa_assert_se(u = s->userdata);
 
     if (!PA_SOURCE_IS_LINKED(u->source->thread_info.state) ||
-        !PA_SOURCE_OUTPUT_IS_LINKED(u->source_output->thread_info.state))
+        !PA_SOURCE_OUTPUT_IS_LINKED(u->source_output->thread_info.state) ||
+        !u->source_output->source)
         return;
 
     pa_log_debug("Source update requested latency");
@@ -546,7 +547,8 @@ static void sink_update_requested_latency_cb(pa_sink *s) {
     pa_assert_se(u = s->userdata);
 
     if (!PA_SINK_IS_LINKED(u->sink->thread_info.state) ||
-        !PA_SINK_INPUT_IS_LINKED(u->sink_input->thread_info.state))
+        !PA_SINK_INPUT_IS_LINKED(u->sink_input->thread_info.state) ||
+        !u->sink_input->sink)
         return;
 
     pa_log_debug("Sink update requested latency");
@@ -566,7 +568,8 @@ static void sink_request_rewind_cb(pa_sink *s) {
     pa_assert_se(u = s->userdata);
 
     if (!PA_SINK_IS_LINKED(u->sink->thread_info.state) ||
-        !PA_SINK_INPUT_IS_LINKED(u->sink_input->thread_info.state))
+        !PA_SINK_INPUT_IS_LINKED(u->sink_input->thread_info.state) ||
+        !u->sink_input->sink)
         return;
 
     pa_log_debug("Sink request rewind %lld", (long long) s->thread_info.rewind_nbytes);
@@ -584,7 +587,8 @@ static void source_set_volume_cb(pa_source *s) {
     pa_assert_se(u = s->userdata);
 
     if (!PA_SOURCE_IS_LINKED(pa_source_get_state(s)) ||
-        !PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(u->source_output)))
+        !PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(u->source_output)) ||
+        !u->source_output->source)
         return;
 
     pa_source_output_set_volume(u->source_output, &s->real_volume, s->save_volume, true);
@@ -598,7 +602,8 @@ static void sink_set_volume_cb(pa_sink *s) {
     pa_assert_se(u = s->userdata);
 
     if (!PA_SINK_IS_LINKED(pa_sink_get_state(s)) ||
-        !PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(u->sink_input)))
+        !PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(u->sink_input)) ||
+        !u->sink_input->sink)
         return;
 
     pa_sink_input_set_volume(u->sink_input, &s->real_volume, s->save_volume, true);
@@ -613,7 +618,8 @@ static void source_get_volume_cb(pa_source *s) {
     pa_assert_se(u = s->userdata);
 
     if (!PA_SOURCE_IS_LINKED(pa_source_get_state(s)) ||
-        !PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(u->source_output)))
+        !PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(u->source_output)) ||
+        !u->source_output->source)
         return;
 
     pa_source_output_get_volume(u->source_output, &v, true);
@@ -634,7 +640,8 @@ static void source_set_mute_cb(pa_source *s) {
     pa_assert_se(u = s->userdata);
 
     if (!PA_SOURCE_IS_LINKED(pa_source_get_state(s)) ||
-        !PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(u->source_output)))
+        !PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(u->source_output)) ||
+        !u->source_output->source)
         return;
 
     pa_source_output_set_mute(u->source_output, s->muted, s->save_muted);
@@ -648,7 +655,8 @@ static void sink_set_mute_cb(pa_sink *s) {
     pa_assert_se(u = s->userdata);
 
     if (!PA_SINK_IS_LINKED(pa_sink_get_state(s)) ||
-        !PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(u->sink_input)))
+        !PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(u->sink_input)) ||
+        !u->sink_input->sink)
         return;
 
     pa_sink_input_set_mute(u->sink_input, s->muted, s->save_muted);
diff --git a/src/modules/module-ladspa-sink.c b/src/modules/module-ladspa-sink.c
index 86ab4a6f..cc2141b3 100644
--- a/src/modules/module-ladspa-sink.c
+++ b/src/modules/module-ladspa-sink.c
@@ -387,7 +387,7 @@ static int sink_set_state_cb(pa_sink *s, pa_sink_state_t state) {
     pa_assert_se(u = s->userdata);
 
     if (!PA_SINK_IS_LINKED(state) ||
-            !PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(u->sink_input)))
+        !PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(u->sink_input)))
         return 0;
 
     pa_sink_input_cork(u->sink_input, state == PA_SINK_SUSPENDED);
@@ -402,7 +402,8 @@ static void sink_request_rewind_cb(pa_sink *s) {
     pa_assert_se(u = s->userdata);
 
     if (!PA_SINK_IS_LINKED(u->sink->thread_info.state) ||
-            !PA_SINK_INPUT_IS_LINKED(u->sink_input->thread_info.state))
+        !PA_SINK_INPUT_IS_LINKED(u->sink_input->thread_info.state) ||
+        !u->sink_input->sink)
         return;
 
     /* Just hand this one over to the master sink */
@@ -419,7 +420,8 @@ static void sink_update_requested_latency_cb(pa_sink *s) {
     pa_assert_se(u = s->userdata);
 
     if (!PA_SINK_IS_LINKED(u->sink->thread_info.state) ||
-            !PA_SINK_INPUT_IS_LINKED(u->sink_input->thread_info.state))
+        !PA_SINK_INPUT_IS_LINKED(u->sink_input->thread_info.state) ||
+        !u->sink_input->sink)
         return;
 
     /* Just hand this one over to the master sink */
@@ -436,7 +438,8 @@ static void sink_set_mute_cb(pa_sink *s) {
     pa_assert_se(u = s->userdata);
 
     if (!PA_SINK_IS_LINKED(pa_sink_get_state(s)) ||
-            !PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(u->sink_input)))
+        !PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(u->sink_input)) ||
+        !u->sink_input->sink)
         return;
 
     pa_sink_input_set_mute(u->sink_input, s->muted, s->save_muted);
diff --git a/src/modules/module-remap-sink.c b/src/modules/module-remap-sink.c
index 534874d7..7bbd5429 100644
--- a/src/modules/module-remap-sink.c
+++ b/src/modules/module-remap-sink.c
@@ -125,7 +125,8 @@ static void sink_request_rewind(pa_sink *s) {
     pa_assert_se(u = s->userdata);
 
     if (!PA_SINK_IS_LINKED(u->sink->thread_info.state) ||
-        !PA_SINK_INPUT_IS_LINKED(u->sink_input->thread_info.state))
+        !PA_SINK_INPUT_IS_LINKED(u->sink_input->thread_info.state) ||
+        !u->sink_input->sink)
         return;
 
     pa_sink_input_request_rewind(u->sink_input, s->thread_info.rewind_nbytes, true, false, false);
@@ -139,7 +140,8 @@ static void sink_update_requested_latency(pa_sink *s) {
     pa_assert_se(u = s->userdata);
 
     if (!PA_SINK_IS_LINKED(u->sink->thread_info.state) ||
-        !PA_SINK_INPUT_IS_LINKED(u->sink_input->thread_info.state))
+        !PA_SINK_INPUT_IS_LINKED(u->sink_input->thread_info.state) ||
+        !u->sink_input->sink)
         return;
 
     /* Just hand this one over to the master sink */
diff --git a/src/modules/module-remap-source.c b/src/modules/module-remap-source.c
index 25772ecd..7221ce62 100644
--- a/src/modules/module-remap-source.c
+++ b/src/modules/module-remap-source.c
@@ -133,7 +133,8 @@ static void source_update_requested_latency_cb(pa_source *s) {
     pa_assert_se(u = s->userdata);
 
     if (!PA_SOURCE_IS_LINKED(u->source->thread_info.state) ||
-        !PA_SOURCE_OUTPUT_IS_LINKED(u->source_output->thread_info.state))
+        !PA_SOURCE_OUTPUT_IS_LINKED(u->source_output->thread_info.state) ||
+        !u->source_output->source)
         return;
 
     pa_log_debug("Source update requested latency.");
diff --git a/src/modules/module-virtual-sink.c b/src/modules/module-virtual-sink.c
index 6175ca8e..6695c4e9 100644
--- a/src/modules/module-virtual-sink.c
+++ b/src/modules/module-virtual-sink.c
@@ -137,7 +137,8 @@ static void sink_request_rewind_cb(pa_sink *s) {
     pa_assert_se(u = s->userdata);
 
     if (!PA_SINK_IS_LINKED(u->sink->thread_info.state) ||
-        !PA_SINK_INPUT_IS_LINKED(u->sink_input->thread_info.state))
+        !PA_SINK_INPUT_IS_LINKED(u->sink_input->thread_info.state) ||
+        !u->sink_input->sink)
         return;
 
     /* Just hand this one over to the master sink */
@@ -154,7 +155,8 @@ static void sink_update_requested_latency_cb(pa_sink *s) {
     pa_assert_se(u = s->userdata);
 
     if (!PA_SINK_IS_LINKED(u->sink->thread_info.state) ||
-        !PA_SINK_INPUT_IS_LINKED(u->sink_input->thread_info.state))
+        !PA_SINK_INPUT_IS_LINKED(u->sink_input->thread_info.state) ||
+        !u->sink_input->sink)
         return;
 
     /* Just hand this one over to the master sink */
@@ -171,7 +173,8 @@ static void sink_set_volume_cb(pa_sink *s) {
     pa_assert_se(u = s->userdata);
 
     if (!PA_SINK_IS_LINKED(pa_sink_get_state(s)) ||
-        !PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(u->sink_input)))
+        !PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(u->sink_input)) ||
+        !u->sink_input->sink)
         return;
 
     pa_sink_input_set_volume(u->sink_input, &s->real_volume, s->save_volume, true);
@@ -185,7 +188,8 @@ static void sink_set_mute_cb(pa_sink *s) {
     pa_assert_se(u = s->userdata);
 
     if (!PA_SINK_IS_LINKED(pa_sink_get_state(s)) ||
-        !PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(u->sink_input)))
+        !PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(u->sink_input)) ||
+        !u->sink_input->sink)
         return;
 
     pa_sink_input_set_mute(u->sink_input, s->muted, s->save_muted);
diff --git a/src/modules/module-virtual-source.c b/src/modules/module-virtual-source.c
index dd0b40e1..e9f2c266 100644
--- a/src/modules/module-virtual-source.c
+++ b/src/modules/module-virtual-source.c
@@ -219,7 +219,8 @@ static void source_update_requested_latency_cb(pa_source *s) {
     pa_assert_se(u = s->userdata);
 
     if (!PA_SOURCE_IS_LINKED(u->source->thread_info.state) ||
-        !PA_SOURCE_OUTPUT_IS_LINKED(u->source_output->thread_info.state))
+        !PA_SOURCE_OUTPUT_IS_LINKED(u->source_output->thread_info.state) ||
+        !u->source_output->source)
         return;
 
     /* Just hand this one over to the master source */
@@ -236,7 +237,8 @@ static void source_set_volume_cb(pa_source *s) {
     pa_assert_se(u = s->userdata);
 
     if (!PA_SOURCE_IS_LINKED(pa_source_get_state(s)) ||
-        !PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(u->source_output)))
+        !PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(u->source_output)) ||
+        !u->source_output->source)
         return;
 
     pa_source_output_set_volume(u->source_output, &s->real_volume, s->save_volume, true);
@@ -250,7 +252,8 @@ static void source_set_mute_cb(pa_source *s) {
     pa_assert_se(u = s->userdata);
 
     if (!PA_SOURCE_IS_LINKED(pa_source_get_state(s)) ||
-        !PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(u->source_output)))
+        !PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(u->source_output)) ||
+        !u->source_output->source)
         return;
 
     pa_source_output_set_mute(u->source_output, s->muted, s->save_muted);
diff --git a/src/modules/module-virtual-surround-sink.c b/src/modules/module-virtual-surround-sink.c
index 94ea9f4a..42b61a38 100644
--- a/src/modules/module-virtual-surround-sink.c
+++ b/src/modules/module-virtual-surround-sink.c
@@ -165,7 +165,8 @@ static void sink_request_rewind_cb(pa_sink *s) {
     pa_assert_se(u = s->userdata);
 
     if (!PA_SINK_IS_LINKED(u->sink->thread_info.state) ||
-        !PA_SINK_INPUT_IS_LINKED(u->sink_input->thread_info.state))
+        !PA_SINK_INPUT_IS_LINKED(u->sink_input->thread_info.state) ||
+        !u->sink_input->sink)
         return;
 
     /* Just hand this one over to the master sink */
@@ -182,7 +183,8 @@ static void sink_update_requested_latency_cb(pa_sink *s) {
     pa_assert_se(u = s->userdata);
 
     if (!PA_SINK_IS_LINKED(u->sink->thread_info.state) ||
-        !PA_SINK_INPUT_IS_LINKED(u->sink_input->thread_info.state))
+        !PA_SINK_INPUT_IS_LINKED(u->sink_input->thread_info.state) ||
+        !u->sink_input->sink)
         return;
 
     /* Just hand this one over to the master sink */
@@ -199,7 +201,8 @@ static void sink_set_volume_cb(pa_sink *s) {
     pa_assert_se(u = s->userdata);
 
     if (!PA_SINK_IS_LINKED(pa_sink_get_state(s)) ||
-        !PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(u->sink_input)))
+        !PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(u->sink_input)) ||
+        !u->sink_input->sink)
         return;
 
     pa_sink_input_set_volume(u->sink_input, &s->real_volume, s->save_volume, true);
@@ -213,7 +216,8 @@ static void sink_set_mute_cb(pa_sink *s) {
     pa_assert_se(u = s->userdata);
 
     if (!PA_SINK_IS_LINKED(pa_sink_get_state(s)) ||
-        !PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(u->sink_input)))
+        !PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(u->sink_input)) ||
+        !u->sink_input->sink)
         return;
 
     pa_sink_input_set_mute(u->sink_input, s->muted, s->save_muted);
-- 
2.11.0



More information about the pulseaudio-discuss mailing list