SDL: ibus: Handle error when getting the D-Bus machine ID (4ce5c)

From 4ce5c3a694eb397314c08aacdf1c06deaeef0fed Mon Sep 17 00:00:00 2001
From: Simon McVittie <[EMAIL REDACTED]>
Date: Tue, 20 Jun 2023 13:22:55 +0100
Subject: [PATCH] ibus: Handle error when getting the D-Bus machine ID

It is possible for retrieving the machine ID to fail, either because
dbus was installed incorrectly (machine ID absent or corrupt), or in
32-bit builds, because stat() on the machine ID fails with EOVERFLOW
if it has an out-of-range timestamp or inode number.

dbus has historically treated this as a faulty installation, raising
a warning which by default causes the process to crash. Unfortunately,
dbus_get_local_machine_id() never had a way to report errors, so it has
no alternative for that (bad) error handling.

In dbus >= 1.12.0, we can use dbus_try_get_local_machine_id() to get
the same information, but with the ability to cope gracefully with
errors. ibus won't work in this situation, but that's better than
crashing.

(cherry picked from commit 91198baed40d5709020c3001e9234f4580df696a)

Mitigates: https://github.com/ValveSoftware/steam-for-linux/issues/9605
Signed-off-by: Simon McVittie <smcv@collabora.com>
---
 src/core/linux/SDL_dbus.c | 41 +++++++++++++++++++++++++++++++++++++++
 src/core/linux/SDL_dbus.h |  3 +++
 src/core/linux/SDL_ibus.c |  7 ++++++-
 3 files changed, 50 insertions(+), 1 deletion(-)

diff --git a/src/core/linux/SDL_dbus.c b/src/core/linux/SDL_dbus.c
index 15720492d1d7..f2358343f2d3 100644
--- a/src/core/linux/SDL_dbus.c
+++ b/src/core/linux/SDL_dbus.c
@@ -36,6 +36,9 @@ static SDL_DBusContext dbus;
 
 static int LoadDBUSSyms(void)
 {
+#define SDL_DBUS_SYM2_OPTIONAL(x, y)                   \
+    dbus.x = SDL_LoadFunction(dbus_handle, #y)
+
 #define SDL_DBUS_SYM2(x, y)                            \
     if (!(dbus.x = SDL_LoadFunction(dbus_handle, #y))) \
     return -1
@@ -43,6 +46,9 @@ static int LoadDBUSSyms(void)
 #define SDL_DBUS_SYM(x) \
     SDL_DBUS_SYM2(x, dbus_##x)
 
+#define SDL_DBUS_SYM_OPTIONAL(x) \
+    SDL_DBUS_SYM2_OPTIONAL(x, dbus_##x)
+
     SDL_DBUS_SYM(bus_get_private);
     SDL_DBUS_SYM(bus_register);
     SDL_DBUS_SYM(bus_add_match);
@@ -80,6 +86,7 @@ static int LoadDBUSSyms(void)
     SDL_DBUS_SYM(error_is_set);
     SDL_DBUS_SYM(error_free);
     SDL_DBUS_SYM(get_local_machine_id);
+    SDL_DBUS_SYM_OPTIONAL(try_get_local_machine_id);
     SDL_DBUS_SYM(free);
     SDL_DBUS_SYM(free_string_array);
     SDL_DBUS_SYM(shutdown);
@@ -493,6 +500,40 @@ SDL_bool SDL_DBus_ScreensaverInhibit(SDL_bool inhibit)
 
     return SDL_TRUE;
 }
+
+/*
+ * Get the machine ID if possible. Result must be freed with dbus->free().
+ */
+char *SDL_DBus_GetLocalMachineId(void)
+{
+    DBusError err;
+    char *result;
+
+    dbus.error_init(&err);
+
+    if (dbus.try_get_local_machine_id) {
+        /* Available since dbus 1.12.0, has proper error-handling */
+        result = dbus.try_get_local_machine_id(&err);
+    } else {
+        /* Available since time immemorial, but has no error-handling:
+         * if the machine ID can't be read, many versions of libdbus will
+         * treat that as a fatal mis-installation and abort() */
+        result = dbus.get_local_machine_id();
+    }
+
+    if (result) {
+        return result;
+    }
+
+    if (dbus.error_is_set(&err)) {
+        SDL_SetError("%s: %s", err.name, err.message);
+        dbus.error_free(&err);
+    } else {
+        SDL_SetError("Error getting D-Bus machine ID");
+    }
+
+    return NULL;
+}
 #endif
 
 /* vi: set ts=4 sw=4 expandtab: */
diff --git a/src/core/linux/SDL_dbus.h b/src/core/linux/SDL_dbus.h
index 07e017cf498b..cda279eca49b 100644
--- a/src/core/linux/SDL_dbus.h
+++ b/src/core/linux/SDL_dbus.h
@@ -72,6 +72,7 @@ typedef struct SDL_DBusContext
     dbus_bool_t (*error_is_set)(const DBusError *);
     void (*error_free)(DBusError *);
     char *(*get_local_machine_id)(void);
+    char *(*try_get_local_machine_id)(DBusError *);
     void (*free)(void *);
     void (*free_string_array)(char **);
     void (*shutdown)(void);
@@ -95,6 +96,8 @@ extern SDL_bool SDL_DBus_QueryPropertyOnConnection(DBusConnection *conn, const c
 extern void SDL_DBus_ScreensaverTickle(void);
 extern SDL_bool SDL_DBus_ScreensaverInhibit(SDL_bool inhibit);
 
+extern char *SDL_DBus_GetLocalMachineId(void);
+
 #endif /* HAVE_DBUS_DBUS_H */
 
 #endif /* SDL_dbus_h_ */
diff --git a/src/core/linux/SDL_ibus.c b/src/core/linux/SDL_ibus.c
index 60b69b708ac3..4241cd4ad2c0 100644
--- a/src/core/linux/SDL_ibus.c
+++ b/src/core/linux/SDL_ibus.c
@@ -410,7 +410,12 @@ static char *IBus_GetDBusAddressFilename(void)
         (void)SDL_snprintf(config_dir, sizeof(config_dir), "%s/.config", home_env);
     }
 
-    key = dbus->get_local_machine_id();
+    key = SDL_DBus_GetLocalMachineId();
+
+    if (key == NULL) {
+        SDL_free(display);
+        return NULL;
+    }
 
     SDL_memset(file_path, 0, sizeof(file_path));
     (void)SDL_snprintf(file_path, sizeof(file_path), "%s/ibus/bus/%s-%s-%s",