gdesktopappinfo: Validate XDG_CURRENT_DESKTOP before using it

Its components are used to build filenames, so if the value of
`XDG_CURRENT_DESKTOP` comes from an untrusted caller (as can happen in
setuid programs), using it unvalidated may be unsafe.

Signed-off-by: Philip Withnall <pwithnall@endlessos.org>

Helps: #2168
This commit is contained in:
Philip Withnall 2020-12-04 23:38:18 +00:00
parent dba585d020
commit 45d01e5aa9

View File

@ -305,6 +305,27 @@ desktop_file_dir_app_name_is_masked (DesktopFileDir *dir,
return FALSE; return FALSE;
} }
/* Not much to go on from https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html
* so validate it as a non-empty alphanumeric ASCII string with `-` and `_` allowed.
*
* Validation is important as the desktop IDs are used to construct filenames,
* and may be set by an unprivileged caller if running in a setuid program. */
static gboolean
validate_xdg_desktop (const gchar *desktop)
{
gsize i;
for (i = 0; desktop[i] != '\0'; i++)
if (desktop[i] != '-' && desktop[i] != '_' &&
!g_ascii_isalnum (desktop[i]))
return FALSE;
if (i == 0)
return FALSE;
return TRUE;
}
static const gchar * const * static const gchar * const *
get_lowercase_current_desktops (void) get_lowercase_current_desktops (void)
{ {
@ -320,12 +341,22 @@ get_lowercase_current_desktops (void)
if (envvar) if (envvar)
{ {
gint i, j; gint i, j;
gsize tmp_len;
tmp = g_strsplit (envvar, G_SEARCHPATH_SEPARATOR_S, 0); tmp = g_strsplit (envvar, G_SEARCHPATH_SEPARATOR_S, 0);
tmp_len = g_strv_length (tmp);
for (i = 0; tmp[i]; i++) for (i = 0; tmp[i]; i++)
for (j = 0; tmp[i][j]; j++) {
tmp[i][j] = g_ascii_tolower (tmp[i][j]); /* If the desktop is invalid, drop it and shift the following
* ones (and trailing %NULL) up. */
if (!validate_xdg_desktop (tmp[i]))
memmove (tmp + i, tmp + i + 1, tmp_len - i);
/* Convert to lowercase. */
for (j = 0; tmp[i][j]; j++)
tmp[i][j] = g_ascii_tolower (tmp[i][j]);
}
} }
else else
tmp = g_new0 (gchar *, 0 + 1); tmp = g_new0 (gchar *, 0 + 1);
@ -344,6 +375,7 @@ get_current_desktops (const gchar *value)
if (g_once_init_enter (&result)) if (g_once_init_enter (&result))
{ {
gchar **tmp; gchar **tmp;
gsize tmp_len, i;
if (!value) if (!value)
value = g_getenv ("XDG_CURRENT_DESKTOP"); value = g_getenv ("XDG_CURRENT_DESKTOP");
@ -352,6 +384,15 @@ get_current_desktops (const gchar *value)
value = ""; value = "";
tmp = g_strsplit (value, ":", 0); tmp = g_strsplit (value, ":", 0);
tmp_len = g_strv_length (tmp);
for (i = 0; tmp[i]; i++)
{
/* If the desktop is invalid, drop it and shift the following
* ones (and trailing %NULL) up. */
if (!validate_xdg_desktop (tmp[i]))
memmove (tmp + i, tmp + i + 1, tmp_len - i);
}
g_once_init_leave (&result, tmp); g_once_init_leave (&result, tmp);
} }