Merge branch 'backport-1862-gio-envvars-glib-2-66' into 'glib-2-66'

Backport !1862 “gio: Ignore various environment variables when running as setuid” to glib-2-66

See merge request GNOME/glib!1864
This commit is contained in:
Sebastian Dröge 2021-01-08 09:10:15 +00:00
commit 13732f800c
6 changed files with 86 additions and 10 deletions

View File

@ -436,6 +436,9 @@ Gvfs is also heavily distributed and relies on a session bus to be present.
modules from this alternate directory instead of the directory modules from this alternate directory instead of the directory
built into GIO. This is useful when running tests, for example. built into GIO. This is useful when running tests, for example.
</para> </para>
<para>
This environment variable is ignored when running in a setuid program.
</para>
</formalpara> </formalpara>
<formalpara> <formalpara>
@ -446,6 +449,9 @@ Gvfs is also heavily distributed and relies on a session bus to be present.
paths separated by a colon, GIO will attempt to load paths separated by a colon, GIO will attempt to load
additional modules from within the path. additional modules from within the path.
</para> </para>
<para>
This environment variable is ignored when running in a setuid program.
</para>
</formalpara> </formalpara>
<formalpara> <formalpara>

View File

@ -30,6 +30,7 @@
#include "gdbusaddress.h" #include "gdbusaddress.h"
#include "gdbuserror.h" #include "gdbuserror.h"
#include "gioenumtypes.h" #include "gioenumtypes.h"
#include "glib-private.h"
#include "gnetworkaddress.h" #include "gnetworkaddress.h"
#include "gsocketclient.h" #include "gsocketclient.h"
#include "giostream.h" #include "giostream.h"
@ -1279,6 +1280,7 @@ g_dbus_address_get_for_bus_sync (GBusType bus_type,
GCancellable *cancellable, GCancellable *cancellable,
GError **error) GError **error)
{ {
gboolean is_setuid = GLIB_PRIVATE_CALL (g_check_setuid) ();
gchar *ret, *s = NULL; gchar *ret, *s = NULL;
const gchar *starter_bus; const gchar *starter_bus;
GError *local_error; GError *local_error;
@ -1317,10 +1319,12 @@ g_dbus_address_get_for_bus_sync (GBusType bus_type,
_g_dbus_debug_print_unlock (); _g_dbus_debug_print_unlock ();
} }
/* Dont load the addresses from the environment if running as setuid, as they
* come from an unprivileged caller. */
switch (bus_type) switch (bus_type)
{ {
case G_BUS_TYPE_SYSTEM: case G_BUS_TYPE_SYSTEM:
ret = g_strdup (g_getenv ("DBUS_SYSTEM_BUS_ADDRESS")); ret = !is_setuid ? g_strdup (g_getenv ("DBUS_SYSTEM_BUS_ADDRESS")) : NULL;
if (ret == NULL) if (ret == NULL)
{ {
ret = g_strdup ("unix:path=/var/run/dbus/system_bus_socket"); ret = g_strdup ("unix:path=/var/run/dbus/system_bus_socket");
@ -1328,7 +1332,7 @@ g_dbus_address_get_for_bus_sync (GBusType bus_type,
break; break;
case G_BUS_TYPE_SESSION: case G_BUS_TYPE_SESSION:
ret = g_strdup (g_getenv ("DBUS_SESSION_BUS_ADDRESS")); ret = !is_setuid ? g_strdup (g_getenv ("DBUS_SESSION_BUS_ADDRESS")) : NULL;
if (ret == NULL) if (ret == NULL)
{ {
ret = get_session_address_platform_specific (&local_error); ret = get_session_address_platform_specific (&local_error);

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);
} }

View File

@ -30,6 +30,7 @@
#include "giomodule.h" #include "giomodule.h"
#include "giomodule-priv.h" #include "giomodule-priv.h"
#include "glib-private.h"
#include "glocalfilemonitor.h" #include "glocalfilemonitor.h"
#include "gnativevolumemonitor.h" #include "gnativevolumemonitor.h"
#include "gproxyresolver.h" #include "gproxyresolver.h"
@ -806,6 +807,9 @@ _g_io_module_get_default_type (const gchar *extension_point,
return G_TYPE_INVALID; return G_TYPE_INVALID;
} }
/* Its OK to query the environment here, even when running as setuid, because
* it only allows a choice between existing already-loaded modules. No new
* code is loaded based on the environment variable value. */
use_this = envvar ? g_getenv (envvar) : NULL; use_this = envvar ? g_getenv (envvar) : NULL;
if (g_strcmp0 (use_this, "help") == 0) if (g_strcmp0 (use_this, "help") == 0)
{ {
@ -955,6 +959,9 @@ _g_io_module_get_default (const gchar *extension_point,
return NULL; return NULL;
} }
/* Its OK to query the environment here, even when running as setuid, because
* it only allows a choice between existing already-loaded modules. No new
* code is loaded based on the environment variable value. */
use_this = envvar ? g_getenv (envvar) : NULL; use_this = envvar ? g_getenv (envvar) : NULL;
if (g_strcmp0 (use_this, "help") == 0) if (g_strcmp0 (use_this, "help") == 0)
{ {
@ -1150,8 +1157,16 @@ static gchar *
get_gio_module_dir (void) get_gio_module_dir (void)
{ {
gchar *module_dir; gchar *module_dir;
gboolean is_setuid = GLIB_PRIVATE_CALL (g_check_setuid) ();
module_dir = g_strdup (g_getenv ("GIO_MODULE_DIR")); /* If running as setuid, loading modules from an arbitrary directory
* controlled by the unprivileged user who is running the program could allow
* for execution of arbitrary code (in constructors in modules).
* Dont allow it.
*
* If a setuid program somehow needs to load additional GIO modules, it should
* explicitly call g_io_modules_scan_all_in_directory(). */
module_dir = !is_setuid ? g_strdup (g_getenv ("GIO_MODULE_DIR")) : NULL;
if (module_dir == NULL) if (module_dir == NULL)
{ {
#ifdef G_OS_WIN32 #ifdef G_OS_WIN32
@ -1183,13 +1198,14 @@ _g_io_modules_ensure_loaded (void)
if (!loaded_dirs) if (!loaded_dirs)
{ {
gboolean is_setuid = GLIB_PRIVATE_CALL (g_check_setuid) ();
gchar *module_dir; gchar *module_dir;
loaded_dirs = TRUE; loaded_dirs = TRUE;
scope = g_io_module_scope_new (G_IO_MODULE_SCOPE_BLOCK_DUPLICATES); scope = g_io_module_scope_new (G_IO_MODULE_SCOPE_BLOCK_DUPLICATES);
/* First load any overrides, extras */ /* First load any overrides, extras (but not if running as setuid!) */
module_path = g_getenv ("GIO_EXTRA_MODULES"); module_path = !is_setuid ? g_getenv ("GIO_EXTRA_MODULES") : NULL;
if (module_path) if (module_path)
{ {
gchar **paths; gchar **paths;

View File

@ -32,6 +32,8 @@
#include <gio/gzlibdecompressor.h> #include <gio/gzlibdecompressor.h>
#include <gio/gconverterinputstream.h> #include <gio/gconverterinputstream.h>
#include "glib-private.h"
struct _GResource struct _GResource
{ {
int ref_count; int ref_count;
@ -159,7 +161,7 @@ G_DEFINE_BOXED_TYPE (GResource, g_resource, g_resource_ref, g_resource_unref)
* replace resources in the program or library, without recompiling, for debugging or quick hacking and testing * replace resources in the program or library, without recompiling, for debugging or quick hacking and testing
* purposes. Since GLib 2.50, it is possible to use the `G_RESOURCE_OVERLAYS` environment variable to selectively overlay * purposes. Since GLib 2.50, it is possible to use the `G_RESOURCE_OVERLAYS` environment variable to selectively overlay
* resources with replacements from the filesystem. It is a %G_SEARCHPATH_SEPARATOR-separated list of substitutions to perform * resources with replacements from the filesystem. It is a %G_SEARCHPATH_SEPARATOR-separated list of substitutions to perform
* during resource lookups. * during resource lookups. It is ignored when running in a setuid process.
* *
* A substitution has the form * A substitution has the form
* *
@ -330,10 +332,13 @@ g_resource_find_overlay (const gchar *path,
if (g_once_init_enter (&overlay_dirs)) if (g_once_init_enter (&overlay_dirs))
{ {
gboolean is_setuid = GLIB_PRIVATE_CALL (g_check_setuid) ();
const gchar * const *result; const gchar * const *result;
const gchar *envvar; const gchar *envvar;
envvar = g_getenv ("G_RESOURCE_OVERLAYS"); /* Dont load overlays if setuid, as they could allow reading privileged
* files. */
envvar = !is_setuid ? g_getenv ("G_RESOURCE_OVERLAYS") : NULL;
if (envvar != NULL) if (envvar != NULL)
{ {
gchar **parts; gchar **parts;

View File

@ -18,6 +18,7 @@
#include "config.h" #include "config.h"
#include "glib-private.h"
#include "gsettingsschema-internal.h" #include "gsettingsschema-internal.h"
#include "gsettings.h" #include "gsettings.h"
@ -343,6 +344,7 @@ initialise_schema_sources (void)
*/ */
if G_UNLIKELY (g_once_init_enter (&initialised)) if G_UNLIKELY (g_once_init_enter (&initialised))
{ {
gboolean is_setuid = GLIB_PRIVATE_CALL (g_check_setuid) ();
const gchar * const *dirs; const gchar * const *dirs;
const gchar *path; const gchar *path;
gchar **extra_schema_dirs; gchar **extra_schema_dirs;
@ -357,7 +359,9 @@ initialise_schema_sources (void)
try_prepend_data_dir (g_get_user_data_dir ()); try_prepend_data_dir (g_get_user_data_dir ());
if ((path = g_getenv ("GSETTINGS_SCHEMA_DIR")) != NULL) /* Disallow loading extra schemas if running as setuid, as that could
* allow reading privileged files. */
if (!is_setuid && (path = g_getenv ("GSETTINGS_SCHEMA_DIR")) != NULL)
{ {
extra_schema_dirs = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 0); extra_schema_dirs = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 0);
for (i = 0; extra_schema_dirs[i]; i++); for (i = 0; extra_schema_dirs[i]; i++);