diff --git a/steam-runtime-tools/architecture.c b/steam-runtime-tools/architecture.c index b92d49122f0c85345974fa58d35c2973922c713c..ab8166163a3e305449a36224cb2fb3ea22085866 100644 --- a/steam-runtime-tools/architecture.c +++ b/steam-runtime-tools/architecture.c @@ -28,6 +28,8 @@ #include "steam-runtime-tools/utils-internal.h" +#include <glib-object.h> + /** * SECTION:architecture * @title: Architectures @@ -48,6 +50,9 @@ _srt_architecture_can_run (const char *helpers_path, int exit_status = -1; GError *error = NULL; gboolean ret = FALSE; + GStrv my_environ = NULL; + const gchar *ld_preload; + gchar *filtered_preload = NULL; if (helpers_path == NULL) helpers_path = _srt_get_helpers_path (); @@ -56,14 +61,22 @@ _srt_architecture_can_run (const char *helpers_path, argv[0] = helper; g_debug ("Testing architecture %s with %s", multiarch, helper); - if (!g_spawn_sync (NULL, /* working directory */ + my_environ = g_get_environ (); + ld_preload = g_environ_getenv (my_environ, "LD_PRELOAD"); + if (ld_preload != NULL) + { + filtered_preload = _srt_filter_gameoverlayrenderer (ld_preload); + my_environ = g_environ_setenv (my_environ, "LD_PRELOAD", filtered_preload, TRUE); + } + + if (!g_spawn_sync (NULL, /* working directory */ (gchar **) argv, - NULL, /* envp */ - 0, /* flags */ - NULL, /* child setup */ - NULL, /* user data */ - NULL, /* stdout */ - NULL, /* stderr */ + my_environ, /* envp */ + 0, /* flags */ + NULL, /* child setup */ + NULL, /* user data */ + NULL, /* stdout */ + NULL, /* stderr */ &exit_status, &error)) { @@ -80,7 +93,9 @@ _srt_architecture_can_run (const char *helpers_path, g_debug ("... it works"); ret = TRUE; out: + g_strfreev (my_environ); g_free (helper); + g_free (filtered_preload); g_clear_error (&error); return ret; } diff --git a/steam-runtime-tools/library.c b/steam-runtime-tools/library.c index 8cf77cdfcbbd05affcf3b7cd3497d6d17e388e36..13849287813fab0c0b721a8f57ac9623a7585ba9 100644 --- a/steam-runtime-tools/library.c +++ b/steam-runtime-tools/library.c @@ -460,6 +460,9 @@ _srt_check_library_presence (const char *helpers_path, GStrv misversioned_symbols = NULL; GStrv dependencies = NULL; SrtLibraryIssues issues = SRT_LIBRARY_ISSUES_NONE; + GStrv my_environ = NULL; + const gchar *ld_preload; + gchar *filtered_preload = NULL; g_return_val_if_fail (soname != NULL, SRT_LIBRARY_ISSUES_INTERNAL_ERROR); g_return_val_if_fail (multiarch != NULL, SRT_LIBRARY_ISSUES_INTERNAL_ERROR); @@ -492,14 +495,22 @@ _srt_check_library_presence (const char *helpers_path, argv[0] = helper; g_debug ("Checking library %s integrity with %s", soname, helper); - if (!g_spawn_sync (NULL, /* working directory */ + my_environ = g_get_environ (); + ld_preload = g_environ_getenv (my_environ, "LD_PRELOAD"); + if (ld_preload != NULL) + { + filtered_preload = _srt_filter_gameoverlayrenderer (ld_preload); + my_environ = g_environ_setenv (my_environ, "LD_PRELOAD", filtered_preload, TRUE); + } + + if (!g_spawn_sync (NULL, /* working directory */ (gchar **) argv, - NULL, /* envp */ - 0, /* flags */ - NULL, /* child setup */ - NULL, /* user data */ - &output, /* stdout */ - NULL, /* stderr */ + my_environ, /* envp */ + 0, /* flags */ + NULL, /* child setup */ + NULL, /* user data */ + &output, /* stdout */ + NULL, /* stderr */ &exit_status, &error)) { @@ -595,12 +606,14 @@ out: if (parser != NULL) g_object_unref (parser); + g_strfreev (my_environ); g_strfreev (missing_symbols); g_strfreev (misversioned_symbols); g_strfreev (dependencies); g_free (absolute_path); g_free (helper); g_free (output); + g_free (filtered_preload); g_clear_error (&error); return issues; } diff --git a/steam-runtime-tools/utils-internal.h b/steam-runtime-tools/utils-internal.h index cb07d723cdcd09519e8c6156da9a72c28bb1031e..8fc5b0ecaed50282164de870a22a29e1674ae463 100644 --- a/steam-runtime-tools/utils-internal.h +++ b/steam-runtime-tools/utils-internal.h @@ -29,3 +29,4 @@ #include <glib.h> G_GNUC_INTERNAL const char *_srt_get_helpers_path (void); +gchar *_srt_filter_gameoverlayrenderer (const gchar *input); diff --git a/steam-runtime-tools/utils.c b/steam-runtime-tools/utils.c index e17191294cf9a871c1d36aa736f6c4f4a4f6b22a..8d19a8c7b753a80e412f976fc2130abed6728242 100644 --- a/steam-runtime-tools/utils.c +++ b/steam-runtime-tools/utils.c @@ -98,6 +98,45 @@ out: return path; } +/** + * _srt_filter_gameoverlayrenderer: + * @input: The environment variable value that needs to be filtered. + * Usually retrieved with g_environ_getenv () + * + * Filter the @input paths list from every path containing `gameoverlayrenderer.so` + * + * Returns: A newly-allocated string containing all the paths from @input + * except for the ones with `gameoverlayrenderer.so`. + * Free with g_free (). + */ +gchar * +_srt_filter_gameoverlayrenderer (const gchar *input) +{ + gchar **entries; + gchar **entry; + gchar *ret = NULL; + GPtrArray *filtered; + + g_return_val_if_fail (input != NULL, NULL); + + entries = g_strsplit (input, ":", 0); + filtered = g_ptr_array_new (); + + for (entry = entries; entry != NULL && *entry != NULL; entry++) + { + if (!g_str_has_suffix (*entry, "/gameoverlayrenderer.so")) + g_ptr_array_add (filtered, *entry); + } + + g_ptr_array_add (filtered, NULL); + ret = g_strjoinv (":", (gchar **) filtered->pdata); + + g_ptr_array_free (filtered, TRUE); + g_strfreev (entries); + + return ret; +} + #if !GLIB_CHECK_VERSION(2, 36, 0) static void _srt_constructor (void) __attribute__((__constructor__)); static void diff --git a/tests/meson.build b/tests/meson.build index 0de2a21f5aaa093301f63d67c5dce6b16c501c44..5e5f11f2e056c8baa2687c21b0adb043fce6f699 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -32,6 +32,7 @@ tests = [ 'library', 'system-info', 'system-info-cli', + 'utils', ] tests_utils = [ diff --git a/tests/utils.c b/tests/utils.c new file mode 100644 index 0000000000000000000000000000000000000000..2fc3c60c0ed215ad2a0ed16e3baba4746779c35d --- /dev/null +++ b/tests/utils.c @@ -0,0 +1,103 @@ +/* + * Copyright © 2019 Collabora Ltd. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include <steam-runtime-tools/steam-runtime-tools.h> + +#include <glib.h> +#include <glib/gstdio.h> +#include <glib-object.h> + +#include "steam-runtime-tools/utils-internal.h" +#include "test-utils.h" + +typedef struct +{ + int unused; +} Fixture; + +typedef struct +{ + int unused; +} Config; + +static void +setup (Fixture *f, + gconstpointer context) +{ + G_GNUC_UNUSED const Config *config = context; +} + +static void +teardown (Fixture *f, + gconstpointer context) +{ + G_GNUC_UNUSED const Config *config = context; +} + +/* + * Test _srt_filter_gameoverlayrenderer function. + */ +static void +filter_gameoverlayrenderer (Fixture *f, + gconstpointer context) +{ + const char *ld_preload1 = "/home/me/.local/share/Steam/ubuntu12_32/gameoverlayrenderer.so:" + "/home/me/.local/share/Steam/ubuntu12_64/gameoverlayrenderer.so"; + + const char *ld_preload2 = ":/home/me/my/lib.so:" + "/home/me/.local/share/Steam/ubuntu12_32/gameoverlayrenderer.so:" + "/home/me/.local/share/Steam/ubuntu12_64/gameoverlayrenderer.so:" + "/home/me/my/second.lib.so:"; + + const char *ld_preload3 = "/home/me/my/lib.so:" + "/home/me/my/second.lib.so"; + + gchar *filtered_preload = NULL; + + filtered_preload = _srt_filter_gameoverlayrenderer (ld_preload1); + g_assert_cmpstr (filtered_preload, ==, ""); + g_free (filtered_preload); + + filtered_preload = _srt_filter_gameoverlayrenderer (ld_preload2); + g_assert_cmpstr (filtered_preload, ==, + ":/home/me/my/lib.so:/home/me/my/second.lib.so:"); + g_free (filtered_preload); + + filtered_preload = _srt_filter_gameoverlayrenderer (ld_preload3); + g_assert_cmpstr (filtered_preload, ==, + "/home/me/my/lib.so:/home/me/my/second.lib.so"); + g_free (filtered_preload); +} + +int +main (int argc, + char **argv) +{ + g_test_init (&argc, &argv, NULL); + g_test_add ("/utils/filter_gameoverlayrenderer", Fixture, NULL, setup, + filter_gameoverlayrenderer, teardown); + + return g_test_run (); +}