diff --git a/configure.ac b/configure.ac index 0a3980a5f..ca1936081 100644 --- a/configure.ac +++ b/configure.ac @@ -586,9 +586,20 @@ AC_TRY_COMPILE([#include ], [DIR *dir;], # Checks for library functions. AC_FUNC_VPRINTF AC_FUNC_ALLOCA -AC_CHECK_FUNCS(mmap posix_memalign memalign valloc fsync pipe2) +AC_CHECK_FUNCS(mmap posix_memalign memalign valloc fsync pipe2 issetugid) AC_CHECK_FUNCS(atexit on_exit timegm gmtime_r) +AC_CACHE_CHECK([for __libc_enable_secure], glib_cv_have_libc_enable_secure, + [AC_TRY_LINK([#include + extern int __libc_enable_secure;], + [return __libc_enable_secure;], + glib_cv_have_libc_enable_secure=yes, + glib_cv_have_libc_enable_secure=no)]) +AS_IF([test x$glib_cv_have_libc_enable_secure = xyes], [ + AC_DEFINE(HAVE_LIBC_ENABLE_SECURE, 1, + [Define if you have the __libc_enable_secure variable (GNU libc, eglibc)]) +]) + AC_CHECK_SIZEOF(char) AC_CHECK_SIZEOF(short) AC_CHECK_SIZEOF(long) @@ -985,7 +996,7 @@ AC_MSG_RESULT(unsigned $glib_size_type) # Check for some functions AC_CHECK_FUNCS(lstat strerror strsignal memmove vsnprintf stpcpy strcasecmp strncasecmp poll getcwd vasprintf setenv unsetenv getc_unlocked readlink symlink fdwalk memmem) -AC_CHECK_FUNCS(chown lchmod lchown fchmod fchown link utimes getgrgid getpwuid) +AC_CHECK_FUNCS(chown lchmod lchown fchmod fchown link utimes getgrgid getpwuid getresuid) AC_CHECK_FUNCS(getmntent_r setmntent endmntent hasmntopt getfsstat getvfsstat) # Check for high-resolution sleep functions AC_CHECK_FUNCS(splice) diff --git a/gio/gdbusaddress.c b/gio/gdbusaddress.c index fac22b713..9ea1e75b6 100644 --- a/gio/gdbusaddress.c +++ b/gio/gdbusaddress.c @@ -37,6 +37,7 @@ #include "giostream.h" #include "gasyncresult.h" #include "gsimpleasyncresult.h" +#include "glib-private.h" #include "gdbusprivate.h" #include "giomodule-priv.h" #include "gdbusdaemon.h" @@ -1022,6 +1023,14 @@ get_session_address_dbus_launch (GError **error) restore_dbus_verbose = FALSE; old_dbus_verbose = NULL; + /* Don't run binaries as root if we're setuid. */ + if (GLIB_PRIVATE_CALL (g_check_setuid) ()) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + _("Cannot spawn a message bus when setuid")); + goto out; + } + machine_id = _g_dbus_get_machine_id (error); if (machine_id == NULL) { diff --git a/gio/gvfs.c b/gio/gvfs.c index b781b9ece..d08c49ef1 100644 --- a/gio/gvfs.c +++ b/gio/gvfs.c @@ -23,6 +23,7 @@ #include "config.h" #include #include "gvfs.h" +#include "glib-private.h" #include "glocalvfs.h" #include "gresourcefile.h" #include "giomodule-priv.h" @@ -193,6 +194,8 @@ g_vfs_parse_name (GVfs *vfs, GVfs * g_vfs_get_default (void) { + if (GLIB_PRIVATE_CALL (g_check_setuid) ()) + return g_vfs_get_local (); return _g_io_module_get_default (G_VFS_EXTENSION_POINT_NAME, "GIO_USE_VFS", (GIOModuleVerifyFunc)g_vfs_is_active); diff --git a/glib/genviron.c b/glib/genviron.c index aed4b6310..be2d6a5ac 100644 --- a/glib/genviron.c +++ b/glib/genviron.c @@ -40,6 +40,7 @@ #include #endif +#include "glib-private.h" #include "gmem.h" #include "gmessages.h" #include "gstrfuncs.h" diff --git a/glib/glib-private.c b/glib/glib-private.c index 3946e774b..350678291 100644 --- a/glib/glib-private.c +++ b/glib/glib-private.c @@ -38,7 +38,9 @@ glib__private__ (void) g_wakeup_signal, g_wakeup_acknowledge, - g_get_worker_context + g_get_worker_context, + + g_check_setuid }; return &table; diff --git a/glib/glib-private.h b/glib/glib-private.h index fde0be837..87da6f34c 100644 --- a/glib/glib-private.h +++ b/glib/glib-private.h @@ -25,6 +25,8 @@ G_GNUC_INTERNAL GMainContext * g_get_worker_context (void); +G_GNUC_INTERNAL +gboolean g_check_setuid (void); #define GLIB_PRIVATE_CALL(symbol) (glib__private__()->symbol) @@ -40,6 +42,8 @@ typedef struct { /* See gmain.c */ GMainContext * (* g_get_worker_context) (void); /* Add other private functions here, initialize them in glib-private.c */ + + gboolean (* g_check_setuid) (void); } GLibPrivateVTable; GLibPrivateVTable *glib__private__ (void); diff --git a/glib/gutils.c b/glib/gutils.c index 49862ac10..a34923d2f 100644 --- a/glib/gutils.c +++ b/glib/gutils.c @@ -2409,3 +2409,60 @@ g_get_tmp_dir (void) } #endif + +/* Private API: + * + * Returns %TRUE if the current process was executed as setuid (or an + * equivalent __libc_enable_secure is available). See: + * http://osdir.com/ml/linux.lfs.hardened/2007-04/msg00032.html + */ +gboolean +g_check_setuid (void) +{ + /* TODO: get __libc_enable_secure exported from glibc. + * See http://www.openwall.com/lists/owl-dev/2012/08/14/1 + */ +#if 0 && defined(HAVE_LIBC_ENABLE_SECURE) + { + /* See glibc/include/unistd.h */ + extern int __libc_enable_secure; + return __libc_enable_secure; + } +#elif defined(HAVE_ISSETUGID) + /* BSD: http://www.freebsd.org/cgi/man.cgi?query=issetugid&sektion=2 */ + return issetugid (); +#elif defined(G_OS_UNIX) + uid_t ruid, euid, suid; /* Real, effective and saved user ID's */ + gid_t rgid, egid, sgid; /* Real, effective and saved group ID's */ + + static gsize check_setuid_initialised; + static gboolean is_setuid; + + if (g_once_init_enter (&check_setuid_initialised)) + { +#ifdef HAVE_GETRESUID + /* These aren't in the header files, so we prototype them here. + */ + int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid); + int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid); + + if (getresuid (&ruid, &euid, &suid) != 0 || + getresgid (&rgid, &egid, &sgid) != 0) +#endif /* HAVE_GETRESUID */ + { + suid = ruid = getuid (); + sgid = rgid = getgid (); + euid = geteuid (); + egid = getegid (); + } + + is_setuid = (ruid != euid || ruid != suid || + rgid != egid || rgid != sgid); + + g_once_init_leave (&check_setuid_initialised, 1); + } + return is_setuid; +#else + return FALSE; +#endif +}