]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
selftests/bpf: Fix dangling stdout seen by traffic monitor thread
authorAmery Hung <ameryhung@gmail.com>
Wed, 5 Mar 2025 18:20:57 +0000 (10:20 -0800)
committerAlexei Starovoitov <ast@kernel.org>
Sat, 15 Mar 2025 18:48:57 +0000 (11:48 -0700)
Traffic monitor thread may see dangling stdout as the main thread closes
and reassigns stdout without protection. This happens when the main thread
finishes one subtest and moves to another one in the same netns_new()
scope.

The issue can be reproduced by running test_progs repeatedly with traffic
monitor enabled:

for ((i=1;i<=100;i++)); do
   ./test_progs -a flow_dissector_skb* -m '*'
done

For restoring stdout in crash_handler(), since it does not really care
about closing stdout, simlpy flush stdout and restore it to the original
one.

Then, Fix the issue by consolidating stdio_restore_cleanup() and
stdio_restore(), and protecting the use/close/assignment of stdout with
a lock. The locking in the main thread is always performed regradless of
whether traffic monitor is running or not for simplicity. It won't have
any side-effect.

Signed-off-by: Amery Hung <ameryhung@gmail.com>
Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://patch.msgid.link/20250305182057.2802606-3-ameryhung@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
tools/testing/selftests/bpf/test_progs.c

index ab0f2fed3c580d958a13c5c2b555c9ec331ab00a..d4ec9586b98caff33cba470691668386fbcd7981 100644 (file)
@@ -88,7 +88,9 @@ static void stdio_hijack(char **log_buf, size_t *log_cnt)
 #endif
 }
 
-static void stdio_restore_cleanup(void)
+static pthread_mutex_t stdout_lock = PTHREAD_MUTEX_INITIALIZER;
+
+static void stdio_restore(void)
 {
 #ifdef __GLIBC__
        if (verbose() && env.worker_id == -1) {
@@ -98,6 +100,8 @@ static void stdio_restore_cleanup(void)
 
        fflush(stdout);
 
+       pthread_mutex_lock(&stdout_lock);
+
        if (env.subtest_state) {
                fclose(env.subtest_state->stdout_saved);
                env.subtest_state->stdout_saved = NULL;
@@ -106,26 +110,21 @@ static void stdio_restore_cleanup(void)
        } else {
                fclose(env.test_state->stdout_saved);
                env.test_state->stdout_saved = NULL;
+               stdout = env.stdout_saved;
+               stderr = env.stderr_saved;
        }
+
+       pthread_mutex_unlock(&stdout_lock);
 #endif
 }
 
-static void stdio_restore(void)
+static int traffic_monitor_print_fn(const char *format, va_list args)
 {
-#ifdef __GLIBC__
-       if (verbose() && env.worker_id == -1) {
-               /* nothing to do, output to stdout by default */
-               return;
-       }
-
-       if (stdout == env.stdout_saved)
-               return;
-
-       stdio_restore_cleanup();
+       pthread_mutex_lock(&stdout_lock);
+       vfprintf(stdout, format, args);
+       pthread_mutex_unlock(&stdout_lock);
 
-       stdout = env.stdout_saved;
-       stderr = env.stderr_saved;
-#endif
+       return 0;
 }
 
 /* Adapted from perf/util/string.c */
@@ -536,7 +535,8 @@ void test__end_subtest(void)
                                   test_result(subtest_state->error_cnt,
                                               subtest_state->skipped));
 
-       stdio_restore_cleanup();
+       stdio_restore();
+
        env.subtest_state = NULL;
 }
 
@@ -1265,7 +1265,10 @@ void crash_handler(int signum)
 
        sz = backtrace(bt, ARRAY_SIZE(bt));
 
-       stdio_restore();
+       fflush(stdout);
+       stdout = env.stdout_saved;
+       stderr = env.stderr_saved;
+
        if (env.test) {
                env.test_state->error_cnt++;
                dump_test_log(env.test, env.test_state, true, false, NULL);
@@ -1957,6 +1960,8 @@ int main(int argc, char **argv)
        libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
        libbpf_set_print(libbpf_print_fn);
 
+       traffic_monitor_set_print(traffic_monitor_print_fn);
+
        srand(time(NULL));
 
        env.jit_enabled = is_jit_enabled();