From: Simon McVittie Date: Mon, 18 Jul 2022 10:14:08 +0000 (+0100) Subject: test: Skip tests that involve switching uid if unable to do so X-Git-Tag: dbus-1.15.0~23^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8b08dd32644cfdf6d6d054bfbcb836f3fefca723;p=thirdparty%2Fdbus.git test: Skip tests that involve switching uid if unable to do so In a Linux user namespace, it is possible that we are uid 0 but are unable to switch to some other uid like DBUS_USER or DBUS_TEST_USER, because the other uid is not "mapped" in the user namespace, resulting in setuid() or setresuid() failing with EINVAL "Invalid argument". For example, it's easy for this to happen when running under the bubblewrap tool. Try to drop privileges in a child process, and skip the test if we are unable to do so. Resolves: dbus#407 Signed-off-by: Simon McVittie --- diff --git a/test/test-utils-glib.c b/test/test-utils-glib.c index 30b9836c5..bcd83d111 100644 --- a/test/test-utils-glib.c +++ b/test/test-utils-glib.c @@ -40,6 +40,7 @@ # include # include # include +# include # include #endif @@ -66,6 +67,61 @@ _test_assert_no_error (const DBusError *e, } #ifdef DBUS_UNIX +static gboolean +can_become_user_or_skip (uid_t uid) +{ + gchar *message; + pid_t child_pid; + pid_t pid; + int wstatus; + + /* We can't switch to the uid without affecting the whole process, + * which we don't necessarily want to do, so try it in a child process. */ + child_pid = fork (); + + if (child_pid < 0) + g_error ("fork: %s", g_strerror (errno)); + + if (child_pid == 0) + { + /* Child process: try to become uid, exit 0 on success, exit with + * status = errno on failure */ + + if (setuid (uid) != 0) + { + /* make sure we report failure even if errno is wrong */ + if (errno == 0) + errno = ENODATA; + + _exit (errno); + } + + /* success */ + _exit (0); + } + + /* Parent process: wait for child and report result */ + + pid = waitpid (child_pid, &wstatus, 0); + g_assert_cmpuint (child_pid, ==, pid); + + if (WIFEXITED (wstatus) && WEXITSTATUS (wstatus) == 0) + return TRUE; + + if (WIFEXITED (wstatus)) + message = g_strdup_printf ("unable to become uid %lu: %s", + (unsigned long) uid, + g_strerror (WEXITSTATUS (wstatus))); + else + message = g_strdup_printf ("unable to become uid %lu: unknown wait status %d", + (unsigned long) uid, + wstatus); + + g_test_skip (message); + g_free (message); + return FALSE; +} + static void child_setup (gpointer user_data) { @@ -141,6 +197,9 @@ spawn_dbus_daemon (const gchar *binary, return NULL; } + if (!can_become_user_or_skip (pwd->pw_uid)) + return NULL; + if (user == TEST_USER_ROOT_DROP_TO_MESSAGEBUS) { /* Let the dbus-daemon start as root and drop privileges @@ -163,6 +222,9 @@ spawn_dbus_daemon (const gchar *binary, return NULL; } + if (!can_become_user_or_skip (pwd->pw_uid)) + return NULL; + break; case TEST_USER_ME: