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

Attachment: signature.asc
Description: OpenPGP digital signature

Reply via email to