summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorColin Walters <walters@verbum.org>2012-08-22 10:03:34 -0400
committerColin Walters <walters@verbum.org>2012-09-27 21:10:28 -0400
commit23fe78ceefb6cefcd58a49c77d1154b68478c8d2 (patch)
tree36d29e19d7a984f98dc1021c3ea3c8fac0e504f4
parent4d0a69027e6d089bab15ff7e844a0ab08256620c (diff)
CVE-2012-3524: Don't access environment variables or run dbus-launch when setuid
This matches a corresponding change in GLib. See glib/gutils.c:g_check_setuid(). Some programs attempt to use libdbus when setuid; notably the X.org server is shipped in such a configuration. libdbus never had an explicit policy about its use in setuid programs. I'm not sure whether we should advertise such support. However, given that there are real-world programs that do this currently, we can make them safer with not too much effort. Better to fix a problem caused by an interaction between two components in *both* places if possible. How to determine whether or not we're running in a privilege-escalated path is operating system specific. Note that GTK+'s code to check euid versus uid worked historically on Unix, more modern systems have filesystem capabilities and SELinux domain transitions, neither of which are captured by the uid comparison. On Linux/glibc, the way this works is that the kernel sets an AT_SECURE flag in the ELF auxiliary vector, and glibc looks for it on startup. If found, then glibc sets a public-but-undocumented __libc_enable_secure variable which we can use. Unfortunately, while it *previously* worked to check this variable, a combination of newer binutils and RPM break it: http://www.openwall.com/lists/owl-dev/2012/08/14/1 So for now on Linux/glibc, we fall back to the historical Unix version until we get glibc fixed. On some BSD variants, there is a issetugid() function. On other Unix variants, we fall back to what GTK+ has been doing. Reported-by: Sebastian Krahmer <krahmer@suse.de> Signed-off-by: Colin Walters <walters@verbum.org>
-rw-r--r--configure.ac2
-rw-r--r--dbus/dbus-keyring.c7
-rw-r--r--dbus/dbus-sysdeps-unix.c74
-rw-r--r--dbus/dbus-sysdeps-win.c6
-rw-r--r--dbus/dbus-sysdeps.c5
-rw-r--r--dbus/dbus-sysdeps.h1
6 files changed, 94 insertions, 1 deletions
diff --git a/configure.ac b/configure.ac
index e2c9bdf7..b0f2ec20 100644
--- a/configure.ac
+++ b/configure.ac
@@ -595,7 +595,7 @@ AC_DEFINE_UNQUOTED([DBUS_USE_SYNC], [$have_sync], [Use the gcc __sync extension]
595AC_SEARCH_LIBS(socket,[socket network]) 595AC_SEARCH_LIBS(socket,[socket network])
596AC_CHECK_FUNC(gethostbyname,,[AC_CHECK_LIB(nsl,gethostbyname)]) 596AC_CHECK_FUNC(gethostbyname,,[AC_CHECK_LIB(nsl,gethostbyname)])
597 597
598AC_CHECK_FUNCS(vsnprintf vasprintf nanosleep usleep setenv clearenv unsetenv socketpair getgrouplist fpathconf setrlimit poll setlocale localeconv strtoll strtoull) 598AC_CHECK_FUNCS(vsnprintf vasprintf nanosleep usleep setenv clearenv unsetenv socketpair getgrouplist fpathconf setrlimit poll setlocale localeconv strtoll strtoull issetugid getresuid)
599 599
600AC_CHECK_HEADERS([syslog.h]) 600AC_CHECK_HEADERS([syslog.h])
601if test "x$ac_cv_header_syslog_h" = "xyes"; then 601if test "x$ac_cv_header_syslog_h" = "xyes"; then
diff --git a/dbus/dbus-keyring.c b/dbus/dbus-keyring.c
index 23b9df5a..3b9ce315 100644
--- a/dbus/dbus-keyring.c
+++ b/dbus/dbus-keyring.c
@@ -717,6 +717,13 @@ _dbus_keyring_new_for_credentials (DBusCredentials *credentials,
717 DBusCredentials *our_credentials; 717 DBusCredentials *our_credentials;
718 718
719 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 719 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
720
721 if (_dbus_check_setuid ())
722 {
723 dbus_set_error_const (error, DBUS_ERROR_NOT_SUPPORTED,
724 "Unable to create DBus keyring when setuid");
725 return NULL;
726 }
720 727
721 keyring = NULL; 728 keyring = NULL;
722 error_set = FALSE; 729 error_set = FALSE;
diff --git a/dbus/dbus-sysdeps-unix.c b/dbus/dbus-sysdeps-unix.c
index cef8bd31..b4ecc96e 100644
--- a/dbus/dbus-sysdeps-unix.c
+++ b/dbus/dbus-sysdeps-unix.c
@@ -3434,6 +3434,13 @@ _dbus_get_autolaunch_address (const char *scope,
3434 DBusString uuid; 3434 DBusString uuid;
3435 dbus_bool_t retval; 3435 dbus_bool_t retval;
3436 3436
3437 if (_dbus_check_setuid ())
3438 {
3439 dbus_set_error_const (error, DBUS_ERROR_NOT_SUPPORTED,
3440 "Unable to autolaunch when setuid");
3441 return FALSE;
3442 }
3443
3437 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 3444 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
3438 retval = FALSE; 3445 retval = FALSE;
3439 3446
@@ -3551,6 +3558,13 @@ _dbus_lookup_launchd_socket (DBusString *socket_path,
3551 3558
3552 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 3559 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
3553 3560
3561 if (_dbus_check_setuid ())
3562 {
3563 dbus_set_error_const (error, DBUS_ERROR_NOT_SUPPORTED,
3564 "Unable to find launchd socket when setuid");
3565 return FALSE;
3566 }
3567
3554 i = 0; 3568 i = 0;
3555 argv[i] = "launchctl"; 3569 argv[i] = "launchctl";
3556 ++i; 3570 ++i;
@@ -3591,6 +3605,13 @@ _dbus_lookup_session_address_launchd (DBusString *address, DBusError *error)
3591 dbus_bool_t valid_socket; 3605 dbus_bool_t valid_socket;
3592 DBusString socket_path; 3606 DBusString socket_path;
3593 3607
3608 if (_dbus_check_setuid ())
3609 {
3610 dbus_set_error_const (error, DBUS_ERROR_NOT_SUPPORTED,
3611 "Unable to find launchd socket when setuid");
3612 return FALSE;
3613 }
3614
3594 if (!_dbus_string_init (&socket_path)) 3615 if (!_dbus_string_init (&socket_path))
3595 { 3616 {
3596 _DBUS_SET_OOM (error); 3617 _DBUS_SET_OOM (error);
@@ -4086,4 +4107,57 @@ _dbus_close_all (void)
4086 close (i); 4107 close (i);
4087} 4108}
4088 4109
4110/**
4111 * **NOTE**: If you modify this function, please also consider making
4112 * the corresponding change in GLib. See
4113 * glib/gutils.c:g_check_setuid().
4114 *
4115 * Returns TRUE if the current process was executed as setuid (or an
4116 * equivalent __libc_enable_secure is available). See:
4117 * http://osdir.com/ml/linux.lfs.hardened/2007-04/msg00032.html
4118 */
4119dbus_bool_t
4120_dbus_check_setuid (void)
4121{
4122 /* TODO: get __libc_enable_secure exported from glibc.
4123 * See http://www.openwall.com/lists/owl-dev/2012/08/14/1
4124 */
4125#if 0 && defined(HAVE_LIBC_ENABLE_SECURE)
4126 {
4127 /* See glibc/include/unistd.h */
4128 extern int __libc_enable_secure;
4129 return __libc_enable_secure;
4130 }
4131#elif defined(HAVE_ISSETUGID)
4132 /* BSD: http://www.freebsd.org/cgi/man.cgi?query=issetugid&sektion=2 */
4133 return issetugid ();
4134#else
4135 uid_t ruid, euid, suid; /* Real, effective and saved user ID's */
4136 gid_t rgid, egid, sgid; /* Real, effective and saved group ID's */
4137
4138 static dbus_bool_t check_setuid_initialised;
4139 static dbus_bool_t is_setuid;
4140
4141 if (_DBUS_UNLIKELY (!check_setuid_initialised))
4142 {
4143#ifdef HAVE_GETRESUID
4144 if (getresuid (&ruid, &euid, &suid) != 0 ||
4145 getresgid (&rgid, &egid, &sgid) != 0)
4146#endif /* HAVE_GETRESUID */
4147 {
4148 suid = ruid = getuid ();
4149 sgid = rgid = getgid ();
4150 euid = geteuid ();
4151 egid = getegid ();
4152 }
4153
4154 check_setuid_initialised = TRUE;
4155 is_setuid = (ruid != euid || ruid != suid ||
4156 rgid != egid || rgid != sgid);
4157
4158 }
4159 return is_setuid;
4160#endif
4161}
4162
4089/* tests in dbus-sysdeps-util.c */ 4163/* tests in dbus-sysdeps-util.c */
diff --git a/dbus/dbus-sysdeps-win.c b/dbus/dbus-sysdeps-win.c
index 397520af..bc4951b5 100644
--- a/dbus/dbus-sysdeps-win.c
+++ b/dbus/dbus-sysdeps-win.c
@@ -3632,6 +3632,12 @@ _dbus_path_is_absolute (const DBusString *filename)
3632 return FALSE; 3632 return FALSE;
3633} 3633}
3634 3634
3635dbus_bool_t
3636_dbus_check_setuid (void)
3637{
3638 return FALSE;
3639}
3640
3635/** @} end of sysdeps-win */ 3641/** @} end of sysdeps-win */
3636/* tests in dbus-sysdeps-util.c */ 3642/* tests in dbus-sysdeps-util.c */
3637 3643
diff --git a/dbus/dbus-sysdeps.c b/dbus/dbus-sysdeps.c
index 861bfec9..04fb8d76 100644
--- a/dbus/dbus-sysdeps.c
+++ b/dbus/dbus-sysdeps.c
@@ -182,6 +182,11 @@ _dbus_setenv (const char *varname,
182const char* 182const char*
183_dbus_getenv (const char *varname) 183_dbus_getenv (const char *varname)
184{ 184{
185 /* Don't respect any environment variables if the current process is
186 * setuid. This is the equivalent of glibc's __secure_getenv().
187 */
188 if (_dbus_check_setuid ())
189 return NULL;
185 return getenv (varname); 190 return getenv (varname);
186} 191}
187 192
diff --git a/dbus/dbus-sysdeps.h b/dbus/dbus-sysdeps.h
index 4052cda9..eee91608 100644
--- a/dbus/dbus-sysdeps.h
+++ b/dbus/dbus-sysdeps.h
@@ -87,6 +87,7 @@ typedef struct DBusPipe DBusPipe;
87 87
88void _dbus_abort (void) _DBUS_GNUC_NORETURN; 88void _dbus_abort (void) _DBUS_GNUC_NORETURN;
89 89
90dbus_bool_t _dbus_check_setuid (void);
90const char* _dbus_getenv (const char *varname); 91const char* _dbus_getenv (const char *varname);
91dbus_bool_t _dbus_setenv (const char *varname, 92dbus_bool_t _dbus_setenv (const char *varname,
92 const char *value); 93 const char *value);