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>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
diff --git a/src/core/linux/SDL_dbus.c b/src/core/linux/SDL_dbus.c
index 1572049..f235834 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 07e017c..cda279e 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 60b69b7..4241cd4 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",