summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon McVittie <smcv@collabora.com>2022-07-18 11:14:08 +0100
committerSimon McVittie <smcv@collabora.com>2022-07-18 10:31:40 +0000
commit8b08dd32644cfdf6d6d054bfbcb836f3fefca723 (patch)
tree12344902c6616bc603253c2268aaaa3d1a10ebf1
parenta615db944c685b4fdb61c55de71b402fcb801d81 (diff)
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 <smcv@collabora.com>
-rw-r--r--test/test-utils-glib.c62
1 files changed, 62 insertions, 0 deletions
diff --git a/test/test-utils-glib.c b/test/test-utils-glib.c
index 30b9836c..bcd83d11 100644
--- a/test/test-utils-glib.c
+++ b/test/test-utils-glib.c
@@ -40,6 +40,7 @@
# include <unistd.h>
# include <sys/socket.h>
# include <sys/types.h>
+# include <sys/wait.h>
# include <pwd.h>
#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: