From ff2c970c15ba93f877b22ddde71418c68b09a6b3 Mon Sep 17 00:00:00 2001 From: Frank Praznik Date: Mon, 6 Apr 2026 19:22:13 -0400 Subject: [PATCH] dbus: Better handle local URI paths Decode file URIs before trying to open them, and properly handle non-URI local paths. (cherry picked from commit b8e8caf7c57df1d6b86eaa9c70c854a3caaa1603) --- src/SDL_utils.c | 33 +++++++++++++++++++++++++++++++++ src/SDL_utils_c.h | 3 +++ src/core/linux/SDL_dbus.c | 27 +++++++++++++++++++++++---- 3 files changed, 59 insertions(+), 4 deletions(-) diff --git a/src/SDL_utils.c b/src/SDL_utils.c index 66b043796e..2667390ac6 100644 --- a/src/SDL_utils.c +++ b/src/SDL_utils.c @@ -384,6 +384,39 @@ int SDL_URIToLocal(const char *src, char *dst) return -1; } +bool SDL_IsURI(const char *uri) +{ + /* A valid URI begins with a letter and is followed by any sequence of + * letters, digits, '+', '.', or '-'. + */ + if (!uri) { + return false; + } + + // The first character of the scheme must be a letter. + if (!((*uri >= 'a' && *uri <= 'z') || (*uri >= 'A' && *uri <= 'Z'))) { + return false; + } + + /* If the colon is found before encountering the end of the string or + * any invalid characters, the scheme can be considered valid. + */ + while (*uri) { + if (!((*uri >= 'a' && *uri <= 'z') || + (*uri >= 'A' && *uri <= 'Z') || + (*uri >= '0' && *uri <= '9') || + *uri == '+' || *uri == '-' || *uri == '.')) { + return false; + } + + if (*++uri == ':') { + return true; + } + } + + return false; +} + // This is a set of per-thread persistent strings that we can return from the SDL API. // This is used for short strings that might persist past the lifetime of the object // they are related to. diff --git a/src/SDL_utils_c.h b/src/SDL_utils_c.h index 266eb09249..a49eaa11b6 100644 --- a/src/SDL_utils_c.h +++ b/src/SDL_utils_c.h @@ -48,6 +48,9 @@ extern bool SDL_endswith(const char *string, const char *suffix); */ extern int SDL_URIToLocal(const char *src, char *dst); +/// Determine if a URI is valid by validating the scheme. +extern bool SDL_IsURI(const char *uri); + typedef enum { SDL_OBJECT_TYPE_UNKNOWN, diff --git a/src/core/linux/SDL_dbus.c b/src/core/linux/SDL_dbus.c index 3b1f095a23..9a2bef87e1 100644 --- a/src/core/linux/SDL_dbus.c +++ b/src/core/linux/SDL_dbus.c @@ -487,14 +487,31 @@ bool SDL_DBus_OpenURI(const char *uri, const char *window_id, const char *activa return false; } - // The OpenURI method can't open local 'file://' URIs, so OpenFile must be used instead. DBusMessageIter iterInit; DBusMessage *msg = NULL; int fd = -1; bool ret = false; + const bool has_file_scheme = SDL_strncasecmp(uri, "file:/", 6) == 0; - if (SDL_strncasecmp(uri, "file://", 7) == 0) { - fd = open(uri + 7, O_RDWR | O_CLOEXEC); + // The OpenURI method can't open 'file://' URIs or local paths, so OpenFile must be used instead. + if (has_file_scheme || !SDL_IsURI(uri)) { + char *decoded_path = NULL; + + // Decode the path if it is a URI. + if (has_file_scheme) { + const size_t len = SDL_strlen(uri) + 1; + decoded_path = SDL_malloc(len); + if (!decoded_path) { + goto done; + } + if (SDL_URIToLocal(uri, decoded_path) < 0) { + SDL_free(decoded_path); + goto done; + } + uri = decoded_path; + } + fd = open(uri, O_RDWR | O_CLOEXEC); + SDL_free(decoded_path); if (fd >= 0) { msg = dbus.message_new_method_call(bus_name, path, interface, "OpenFile"); } @@ -548,7 +565,9 @@ bool SDL_DBus_OpenURI(const char *uri, const char *window_id, const char *activa } done: - dbus.message_unref(msg); + if (msg) { + dbus.message_unref(msg); + } // The file descriptor is duplicated by D-Bus, so it can be closed on this end. if (fd >= 0) {