reassign 368297 libldap-2.4 2.4.31-1 thanks Hi!
I have been digging on this issue and I found the ultimate cause of this problem. When sudo/su/passwd/<insert-any-setuid-program-that-calls-getpwent()> on a system configured with PAM/LDAPs it chains into libldap, which uses GnuTLS/libgcrypt to manage the TLS channel. The problem is that when OpenLDAP calls gnutls_global_init(), this function does nothing because OpenLDAP had previously already initialized libgcrypt at some point on the stack (probably by mistake). So, gnutls_global_init() checks that some basic initialization of libgcrypt was already done and skips completely any action. The problem is that gnutls_global_init() is supposed to set the flag GCRYCTL_DISABLE_SECMEM which disables both the use of secure memory *and* the "feature" of dropping privileges that libgcrypt has. [1] So, what is happening is that the initialization of libgcrypt is not being done as expected. I cooked a very small patch that, just after calling gnutls_global_init() checks if the initialization was successful, and if was not, then it sets this flag (DISABLE_SECMEM) I understand that (perhaps) the right fix could be to patch GnuTLS to check for INITIALIZATION_FINISHED instead of ANY_INITIALIZATION. But there are two problems with this: * One is that this could introduce some regression or bug on some program that could be (wrongly) relying on this "feature" of GnuTLS. Keep in mind that this code has been there since the beginning of the project (I was blaming the git repository) * The second problem is that GnutTLS (upstream) completely dropped the support for libgcrypt (they even removed the code). So IMHO it don't makes sense to fix GnuTLS at this point. For Jessie, GnuTLS should switch to nettle. And OpenLDAP will have to switch to another crypto library other than libgcrypt, or will have to patch the file libraries/libldap/tls_g.c to stop using any GnuTLS code. So, for the moment (Wheezy) I think the best approach to solve this bug is to apply the small patch for OpenLDAP that I'm attaching. It is the less intrusive approach to fix this bug. It don't needs to touch anything on GnuTLS or libgcrypt. It is really fixing the problem where is: OpenLDAP is not setting DISABLE_SECMEM when initializing libgcrypt. The approach taken by Ubuntu, to patch libgcrypt (LP: #423252), already caused some regressions (LP: #1013798) If someone wants to try it, I have uploaded the debs (AMD64) and the sources to this URL: http://ftp.neutrino.es/debian/OpenLDAP/ I tested that with this small patch the problem goes completely away. Example of test: ---------------- 1) Install current libldap-2.4-2 from Wheezy and test sudo: root ~ # apt-get install --reinstall libldap-2.4-2=2.4.31-1 clopez ~ $ sudo whoami [sudo] password for clopez: sudo: PERM_ROOT: setresuid(0, -1, -1): Operation not permitted sudo: unable to open /var/lib/sudo/clopez/8: Operation not permitted sudo: unable to set supplementary group IDs: Operation not permitted sudo: unable to execute /usr/bin/whoami: Operation not permitted 2) Install fixed libldap-2.4-2 and test sudo: root ~ # wget http://ftp.neutrino.es/debian/OpenLDAP/libldap-2.4-2_2.4.31-1.1_amd64.deb root ~ # dpkg -i libldap-2.4-2_2.4.31-1.1_amd64.deb clopez ~ $ sudo whoami [sudo] password for clopez: root ------------- Therefore I'm reassigning this bug to libldap-2.4 (src:OpenLDAP) Attached is also a debdiff for src:OpenLDAP Read the comments inside the patch for further information. I'm CC'ing libgcrypt/OpenLDAP/GnuTLS maintainers and will be later reporting on Ubuntu's LP this. Regards! -------- [1] http://lists.debian.org/debian-devel/2010/03/msg00298.html https://bugs.g10code.com/gnupg/issue1181
diff -u openldap-2.4.31/debian/changelog openldap-2.4.31/debian/changelog --- openldap-2.4.31/debian/changelog +++ openldap-2.4.31/debian/changelog @@ -1,3 +1,14 @@ +openldap (2.4.31-1.1) unstable; urgency=low + + * Non-maintainer upload. + + [ Carlos Alberto Lopez Perez ] + * debian/patches/fix-dropping-privileges-by-libgcrypt-secmem.diff: + Ensure that we don't use secure memory when libgcrypt is initialized. + Avoids dropping privileges. Closes: #368297 + + -- Carlos Alberto Lopez Perez <clo...@igalia.com> Thu, 24 Jan 2013 22:53:57 +0100 + openldap (2.4.31-1) unstable; urgency=low * New upstream release. diff -u openldap-2.4.31/debian/patches/series openldap-2.4.31/debian/patches/series --- openldap-2.4.31/debian/patches/series +++ openldap-2.4.31/debian/patches/series @@ -21,0 +22 @@ +fix-dropping-privileges-by-libgcrypt-secmem.diff only in patch2: unchanged: --- openldap-2.4.31.orig/debian/patches/fix-dropping-privileges-by-libgcrypt-secmem.diff +++ openldap-2.4.31/debian/patches/fix-dropping-privileges-by-libgcrypt-secmem.diff @@ -0,0 +1,63 @@ +Author: Carlos Alberto Lopez Perez <clo...@igalia.com> +Date: Thu Jan 24 22:38:25 2013 +0100 +Subject: Check if the call gnutls_global_init() succeded to initalize + libgcrypt. If not succeded then disable the use of secure memory. + gnutls_global_init() is supposed to do this (disabling secure memory), + but if libgcrypt was initialized at some point before on the stack it + fails to do it. +Forwarded: not-needed. GnuTLS (upstream) not longer supports libgcrypt. + For Jessie, OpenLDAP should switch to another crypto library and drop + libgcrypt or patch libraries/libldap/tls_g.c to stop using GnuTLS code. +Bug-Debian: http://bugs.debian.org/368297 +--- +--- a/libraries/libldap/tls_g.c ++++ b/libraries/libldap/tls_g.c +@@ -180,6 +180,48 @@ + #endif + + gnutls_global_init(); ++ /* Most probably the above call will do nothing because ++ * gnutls_global_init() checks if the library has done _any_ ++ * initialization. ++ * ++ * gnutls_global_init() is defined on (src:gnutls26):lib/gcrypt/init.c ++ * It basically does: ++ * ++ * if (gcry_control(GCRYCTL_ANY_INITIALIZATION_P) == 0) { ++ * some_other_initializations(...); ++ * gcry_control(GCRYCTL_DISABLE_SECMEM, NULL, 0); ++ * gcry_control(GCRYCTL_INITIALIZATION_FINISHED, NULL, 0); ++ * gcry_control(GCRYCTL_ENABLE_QUICK_RANDOM, 0); ++ * } // else do_nothing ++ * ++ * So this means it will do nothing because gcrypt was _basically_ ++ * initialized before this call to gnutls_global_init() at some ++ * point in the stack. ++ * ++ * So we check if gnutls_global_init() did nothing by looking if the ++ * flag GCRYCTL_INITIALIZATION_FINISHED is set. ++ * ++ * If this flag is not set, we then do a basically initialization ++ * of gcrypt to disable secmem. (gnutls skipped to do it because of ++ * the above). ++ * ++ * This (disabling secmem) is completely necessary so setuid programs ++ * can run getpwent() or any other function that chains with libldap ++ * without being forced to drop privileges because of the libgcrypt ++ * nastiness. ++ * For example, sudo/passwd/su are know to *broke* without this patch ++ * if the system is configured with PAM/LDAP. ++ * ++ * We don't set the flag INITIALIZATION_FINISHED or any other flag. ++ * We *only* need to disable secmem to fix this bug. ++ * Setting any other flag than the strictly necessary one (disable_secmem) ++ * to fix this, could (who knows?) introduce some regression or bug ++ * on some program thas is relying on this broken thing. ++ * ++ * -- Carlos Alberto Lopez Perez <clo...@igalia.com> ++ */ ++ if (gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P) == 0) ++ gcry_control(GCRYCTL_DISABLE_SECMEM, 0); + + #ifndef HAVE_CIPHERSUITES + /* GNUtls cipher suite handling: The library ought to parse suite
Author: Carlos Alberto Lopez Perez <clo...@igalia.com> Date: Thu Jan 24 22:38:25 2013 +0100 Subject: Check if the call gnutls_global_init() succeded to initalize libgcrypt. If not succeded then disable the use of secure memory. gnutls_global_init() is supposed to do this (disabling secure memory), but if libgcrypt was initialized at some point before on the stack it fails to do it. Forwarded: not-needed. GnuTLS (upstream) not longer supports libgcrypt. For Jessie, OpenLDAP should switch to another crypto library and drop libgcrypt or patch libraries/libldap/tls_g.c to stop using GnuTLS code. Bug-Debian: http://bugs.debian.org/368297 --- --- a/libraries/libldap/tls_g.c +++ b/libraries/libldap/tls_g.c @@ -180,6 +180,48 @@ #endif gnutls_global_init(); + /* Most probably the above call will do nothing because + * gnutls_global_init() checks if the library has done _any_ + * initialization. + * + * gnutls_global_init() is defined on (src:gnutls26):lib/gcrypt/init.c + * It basically does: + * + * if (gcry_control(GCRYCTL_ANY_INITIALIZATION_P) == 0) { + * some_other_initializations(...); + * gcry_control(GCRYCTL_DISABLE_SECMEM, NULL, 0); + * gcry_control(GCRYCTL_INITIALIZATION_FINISHED, NULL, 0); + * gcry_control(GCRYCTL_ENABLE_QUICK_RANDOM, 0); + * } // else do_nothing + * + * So this means it will do nothing because gcrypt was _basically_ + * initialized before this call to gnutls_global_init() at some + * point in the stack. + * + * So we check if gnutls_global_init() did nothing by looking if the + * flag GCRYCTL_INITIALIZATION_FINISHED is set. + * + * If this flag is not set, we then do a basically initialization + * of gcrypt to disable secmem. (gnutls skipped to do it because of + * the above). + * + * This (disabling secmem) is completely necessary so setuid programs + * can run getpwent() or any other function that chains with libldap + * without being forced to drop privileges because of the libgcrypt + * nastiness. + * For example, sudo/passwd/su are know to *broke* without this patch + * if the system is configured with PAM/LDAP. + * + * We don't set the flag INITIALIZATION_FINISHED or any other flag. + * We *only* need to disable secmem to fix this bug. + * Setting any other flag than the strictly necessary one (disable_secmem) + * to fix this, could (who knows?) introduce some regression or bug + * on some program thas is relying on this broken thing. + * + * -- Carlos Alberto Lopez Perez <clo...@igalia.com> + */ + if (gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P) == 0) + gcry_control(GCRYCTL_DISABLE_SECMEM, 0); #ifndef HAVE_CIPHERSUITES /* GNUtls cipher suite handling: The library ought to parse suite
signature.asc
Description: OpenPGP digital signature