From 70efbbd5a5dd10855d597cb42c019d497dc4ef89 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Tue, 16 Sep 2025 16:57:19 +0200 Subject: [PATCH] core: support returning binary output from the daemon helper The full output of the daemon helper is added to a NMStrBuf, without interpreting it as a string (that is, without stopping at the first NUL character). However, when we retrieve the content from the NMStrBuf we assume it's a string. This is fine for certain commands that expect a string output, but it's not for other commands as the read-file-as-user one. Add a new argument to nm_utils_spawn_helper() to specify whether the output is binary or not. Also have different finish functions depending on the return type. (cherry picked from commit 1d90d50fc6e8c167581c6831c2511bc4148f234b) (cherry picked from commit 59df5fc93fc30c9b8c9ceca3c42b173f831f53f7) (cherry picked from commit 7acf70dfb912ca65e1daaf669ad5f4ed1faadbcb) --- src/core/devices/nm-device-utils.c | 3 ++- src/core/nm-core-utils.c | 39 ++++++++++++++++++++++++++---- src/core/nm-core-utils.h | 4 ++- 3 files changed, 39 insertions(+), 7 deletions(-) diff --git a/src/core/devices/nm-device-utils.c b/src/core/devices/nm-device-utils.c index 9fd7ac9dbf..dff4d24283 100644 --- a/src/core/devices/nm-device-utils.c +++ b/src/core/devices/nm-device-utils.c @@ -235,7 +235,7 @@ resolve_addr_helper_cb(GObject *source, GAsyncResult *result, gpointer user_data gs_free_error GError *error = NULL; gs_free char *output = NULL; - output = nm_utils_spawn_helper_finish(result, &error); + output = nm_utils_spawn_helper_finish_string(result, &error); if (nm_utils_error_is_cancelled(error)) return; @@ -274,6 +274,7 @@ resolve_addr_spawn_helper(ResolveAddrInfo *info, ResolveAddrService services) nm_inet_ntop(info->addr_family, &info->address, addr_str); _LOG2D(info, "start lookup via nm-daemon-helper using services: %s", str); nm_utils_spawn_helper(NM_MAKE_STRV("resolve-address", addr_str, str), + FALSE, g_task_get_cancellable(info->task), resolve_addr_helper_cb, info); diff --git a/src/core/nm-core-utils.c b/src/core/nm-core-utils.c index e6e1c7c885..77db209c71 100644 --- a/src/core/nm-core-utils.c +++ b/src/core/nm-core-utils.c @@ -5011,6 +5011,7 @@ typedef struct { int child_stdin; int child_stdout; int child_stderr; + gboolean binary_output; GSource *input_source; GSource *output_source; GSource *error_source; @@ -5090,9 +5091,17 @@ helper_complete(HelperInfo *info, GError *error) } nm_clear_g_cancellable_disconnect(g_task_get_cancellable(info->task), &info->cancellable_id); - g_task_return_pointer(info->task, - nm_str_buf_finalize(&info->in_buffer, NULL) ?: g_new0(char, 1), - g_free); + + if (info->binary_output) { + g_task_return_pointer( + info->task, + g_bytes_new(nm_str_buf_get_str_unsafe(&info->in_buffer), info->in_buffer.len), + (GDestroyNotify) (g_bytes_unref)); + } else { + g_task_return_pointer(info->task, + nm_str_buf_finalize(&info->in_buffer, NULL) ?: g_new0(char, 1), + g_free); + } helper_info_free(info); } @@ -5235,6 +5244,7 @@ helper_cancelled(GObject *object, gpointer user_data) void nm_utils_spawn_helper(const char *const *args, + gboolean binary_output, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer cb_data) @@ -5250,9 +5260,14 @@ nm_utils_spawn_helper(const char *const *args, info = g_new(HelperInfo, 1); *info = (HelperInfo) { - .task = nm_g_task_new(NULL, cancellable, nm_utils_spawn_helper, callback, cb_data), + .task = nm_g_task_new(NULL, cancellable, nm_utils_spawn_helper, callback, cb_data), + .binary_output = binary_output, }; + /* Store if the caller requested binary output so that we can check later + * that the right result function is called. */ + g_task_set_task_data(info->task, GINT_TO_POINTER(binary_output), NULL); + if (!g_spawn_async_with_pipes("/", (char **) NM_MAKE_STRV(LIBEXECDIR "/nm-daemon-helper"), (char **) NM_MAKE_STRV(), @@ -5363,11 +5378,25 @@ nm_utils_spawn_helper(const char *const *args, } char * -nm_utils_spawn_helper_finish(GAsyncResult *result, GError **error) +nm_utils_spawn_helper_finish_string(GAsyncResult *result, GError **error) { GTask *task = G_TASK(result); nm_assert(nm_g_task_is_valid(result, NULL, nm_utils_spawn_helper)); + /* Check binary_output */ + nm_assert(GPOINTER_TO_INT(g_task_get_task_data(task)) == FALSE); + + return g_task_propagate_pointer(task, error); +} + +GBytes * +nm_utils_spawn_helper_finish_binary(GAsyncResult *result, GError **error) +{ + GTask *task = G_TASK(result); + + nm_assert(nm_g_task_is_valid(result, NULL, nm_utils_spawn_helper)); + /* Check binary_output */ + nm_assert(GPOINTER_TO_INT(g_task_get_task_data(task)) == TRUE); return g_task_propagate_pointer(task, error); } diff --git a/src/core/nm-core-utils.h b/src/core/nm-core-utils.h index a647eab1b9..b6a7dd4e52 100644 --- a/src/core/nm-core-utils.h +++ b/src/core/nm-core-utils.h @@ -478,11 +478,13 @@ guint8 nm_wifi_utils_level_to_quality(int val); /*****************************************************************************/ void nm_utils_spawn_helper(const char *const *args, + gboolean binary_output, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer cb_data); -char *nm_utils_spawn_helper_finish(GAsyncResult *result, GError **error); +char *nm_utils_spawn_helper_finish_string(GAsyncResult *result, GError **error); +GBytes *nm_utils_spawn_helper_finish_binary(GAsyncResult *result, GError **error); /*****************************************************************************/