From freebsd@grem.de  Wed May 22 01:38:12 2013
Return-Path: <freebsd@grem.de>
Received: from mx1.freebsd.org (mx1.FreeBSD.org [8.8.178.115])
	by hub.freebsd.org (Postfix) with ESMTP id 90D494D9
	for <FreeBSD-gnats-submit@freebsd.org>; Wed, 22 May 2013 01:38:12 +0000 (UTC)
	(envelope-from freebsd@grem.de)
Received: from mail.grem.de (outcast.grem.de [213.239.217.27])
	by mx1.freebsd.org (Postfix) with SMTP id E4516D56
	for <FreeBSD-gnats-submit@freebsd.org>; Wed, 22 May 2013 01:38:11 +0000 (UTC)
Received: (qmail 49299 invoked by uid 0); 22 May 2013 01:31:28 -0000
Message-Id: <20130522013128.49298.qmail@mail.grem.de>
Date: 22 May 2013 01:31:28 -0000
From: Michael Gmelin <freebsd@grem.de>
To: FreeBSD-gnats-submit@freebsd.org
Cc: delphij@FreeBSD.org
Subject: [PATCH] security/cryptopp: Bug in libc++ causes key generation to get stuck in endless loop
X-Send-Pr-Version: 3.113
X-GNATS-Notify:

>Number:         178827
>Category:       ports
>Synopsis:       [PATCH] security/cryptopp: Bug in libc++ causes key generation to get stuck in endless loop
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    delphij
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Wed May 22 01:40:00 UTC 2013
>Closed-Date:    Wed May 22 22:42:42 UTC 2013
>Last-Modified:  Wed May 22 22:50:00 UTC 2013
>Originator:     Michael Gmelin
>Release:        FreeBSD 9.1-RELEASE amd64
>Organization:
Grem Equity GmbH
>Environment:
System: FreeBSD bsd64.grem.de 9.1-RELEASE-p2 FreeBSD 9.1-RELEASE-p2 #4 r249052: Wed Apr  3 18:26:19 UTC
>Description:
Due to a bug in the version of libc++ shipping with FreeBSD 9.1-RELEASE,
RSA key generation - and most likely other operations depending on
class PrimeSieve - gets stuck in an endless loop when compiled using
libc++ (CXXFLAGS+= -std=c++11 -stdlib=libc++).

The problem has been reported last year:

http://sourceforge.net/apps/trac/cryptopp/ticket/17
http://old.nabble.com/keygeneration-on-ios-using-clang(libc%2B%2B)-never-terminates-td34614981.html

It is caused by libc++'s implementation of std::find returning invalid
results when operating on std::vector<bool> (read: bitsets). The
problem has already been fixed in libc++:

http://llvm.org/viewvc/llvm-project?view=revision&revision=156546

which is also part of release 3.2 of the library. Unfortunately this is
not available in any release version of FreeBSD yet.

The attached patch works around this problem by conditionally replacing
the call to std::find with a hand written loop in case clang and an
affected version libc++ are detected. For all other compilers as well
as versions of libc++ the code is not altered at all. The ABI stays
stable, so there won't be any unpleasant surprises when upgrading the
port at a later point in time using an updated version of libc++, e.g.
after upgrading to 9.2-RELEASE.

The maintainer might want to communicate this issue upstream as well,
it's not limited to FreeBSD.

Added file(s):
- files/patch-nbtheory.cpp

Port maintainer (delphij@FreeBSD.org) is cc'd.

Generated with FreeBSD Port Tools 0.99_6 (mode: change, diff: suffix)
>How-To-Repeat:

Requires a clang and libc++ enabled FreeBSD 9.1-RELEASE installation.

cd /usr/ports/security/cryptopp
CXX=clang++ CXXFLAGS="-std=c++11 -stdlib=libc++" \
make WITHOUT=STATIC install clean

cat >/tmp/test.cpp <<EOF
#include <cryptopp/rsa.h>
#include <cryptopp/osrng.h>
#include <cryptopp/base64.h>
#include <cryptopp/files.h>
using namespace CryptoPP;
int main()
{
  AutoSeededRandomPool rng;
  InvertibleRSAFunction privkey;
  privkey.Initialize(rng, 2048, 4);
}
EOF

clang++ -pthread -std=c++11 -stdlib=libc++ -I/usr/local/include \
-L/usr/local/lib -lcryptopp -o /tmp/test /tmp/test.cpp

/tmp/test

This is supposed to return immediately, but is hanging indefinitely
instead.

>Fix:
Apply the patch attached to this PR and update the package:

cd /usr/ports/security/cryptopp
patch -p1 </path/to/cryptopp-5.6.1_3.patch
portmaster cryptopp

--- cryptopp-5.6.1_3.patch begins here ---
diff -ruN --exclude=CVS ../cryptopp.orig/Makefile ./Makefile
--- ../cryptopp.orig/Makefile	2013-05-22 02:18:44.000000000 +0200
+++ ./Makefile	2013-05-22 02:19:32.000000000 +0200
@@ -3,7 +3,7 @@
 
 PORTNAME=		cryptopp
 PORTVERSION=		5.6.1
-PORTREVISION=		2
+PORTREVISION=		3
 CATEGORIES=		security
 MASTER_SITES=		SF \
 			http://www.cryptopp.com/
diff -ruN --exclude=CVS ../cryptopp.orig/files/patch-nbtheory.cpp ./files/patch-nbtheory.cpp
--- ../cryptopp.orig/files/patch-nbtheory.cpp	1970-01-01 01:00:00.000000000 +0100
+++ ./files/patch-nbtheory.cpp	2013-05-22 02:18:29.000000000 +0200
@@ -0,0 +1,21 @@
+--- nbtheory.cpp.orig	2013-05-22 00:16:26.761193859 +0000
++++ nbtheory.cpp	2013-05-22 00:15:29.401256454 +0000
+@@ -307,7 +307,18 @@
+ 
+ bool PrimeSieve::NextCandidate(Integer &c)
+ {
++#if defined(__clang__) && defined(_LIBCPP_VERSION) &&  _LIBCPP_VERSION < 1101
++	// Workaround for a bug in libc++ in std::find on std::vector<bool>
++	std::vector<bool>::iterator pos = m_sieve.begin()+m_next;
++	for (std::vector<bool>::iterator end = m_sieve.end(); pos != end; ++pos)
++	{
++		if (*pos == false)
++			break;
++	}
++	bool safe = SafeConvert(pos - m_sieve.begin(), m_next);
++#else
+ 	bool safe = SafeConvert(std::find(m_sieve.begin()+m_next, m_sieve.end(), false) - m_sieve.begin(), m_next);
++#endif
+ 	assert(safe);
+ 	if (m_next == m_sieve.size())
+ 	{
--- cryptopp-5.6.1_3.patch ends here ---

>Release-Note:
>Audit-Trail:
Responsible-Changed-From-To: freebsd-ports-bugs->delphij 
Responsible-Changed-By: edwin 
Responsible-Changed-When: Wed May 22 01:40:08 UTC 2013 
Responsible-Changed-Why:  
Over to maintainer (via the GNATS Auto Assign Tool) 

http://www.freebsd.org/cgi/query-pr.cgi?pr=178827 

From: Michael Gmelin <freebsd@grem.de>
To: bug-followup@FreeBSD.org, freebsd@grem.de
Cc:  
Subject: Re: ports/178827: [PATCH] security/cryptopp: Bug in libc++ causes
 key generation to get stuck in endless loop
Date: Wed, 22 May 2013 13:37:58 +0200

 --MP_/Qwt9YtjNQadscfTOseAEVzi
 Content-Type: text/plain; charset=US-ASCII
 Content-Transfer-Encoding: 7bit
 Content-Disposition: inline
 
 Please find attached an altered version of the patch. This has nothing
 to do with the original problem (the patch above addresses this just
 fine), but instead it fixes one of the most obnoxious warnings of the
 many cryptopp causes while building, e.g. clang emits the following
 (gcc warns about it as well, but in a different way).
 
 /usr/local/include/cryptopp/misc.h:414:8: warning: comparison of
 unsigned /  expression < 0 is
       always false [-Wtautological-compare]
         if (a < 0)
             ~ ^ ~
 /usr/local/include/cryptopp/simple.h:42:113: note: in instantiation of
 function template
       specialization 'CryptoPP::IntToString<unsigned int>' requested
 here ...rounds) : InvalidArgument(algorithm + ": " +
 IntToString(rounds) + " is not a valid...
                                                   ^
 2 warnings generated.
 
 This is caused by the template function IntToString checking for a < 0
 even if the template parameter is an unsigned type. There are literally
 dozens of these warnings. The patch fixes this in an easy to audit way
 - instead of modifying the code to use "abs" or change the semantics in
 any way it creates two template functions depending on if the template
 parameter is unsigned or not (thanks to Roland Bock for the patch).
 
 It would be cool if you could get that in while updating the port,
 since these warnings are all over the place not only while
 building the port itself, but also when using the library in your own
 code.
 
 Cheers,
 Michael
 
 -- 
 Michael Gmelin
 
 --MP_/Qwt9YtjNQadscfTOseAEVzi
 Content-Type: text/x-patch
 Content-Transfer-Encoding: 7bit
 Content-Disposition: attachment; filename=cryptopp-5.6.1_3.patch
 
 diff -ruN --exclude=CVS ../cryptopp.orig/Makefile ./Makefile
 --- ../cryptopp.orig/Makefile	2013-05-22 02:18:44.000000000 +0200
 +++ ./Makefile	2013-05-22 02:19:32.000000000 +0200
 @@ -3,7 +3,7 @@
  
  PORTNAME=		cryptopp
  PORTVERSION=		5.6.1
 -PORTREVISION=		2
 +PORTREVISION=		3
  CATEGORIES=		security
  MASTER_SITES=		SF \
  			http://www.cryptopp.com/
 diff -ruN --exclude=CVS ../cryptopp.orig/files/patch-misc.h ./files/patch-misc.h
 --- ../cryptopp.orig/files/patch-misc.h	1970-01-01 01:00:00.000000000 +0100
 +++ ./files/patch-misc.h	2013-05-22 13:22:25.245963334 +0200
 @@ -0,0 +1,54 @@
 +--- misc.h.orig	2010-08-06 18:46:18.000000000 +0000
 ++++ misc.h	2013-05-22 08:43:01.949194748 +0000
 +@@ -405,17 +405,13 @@
 + 	return order == GetNativeByteOrder();
 + }
 + 
 ++template<bool> struct IsUnsigned {};
 ++
 + template <class T>
 +-std::string IntToString(T a, unsigned int base = 10)
 ++std::string IntToStringImpl(T a, unsigned int base, IsUnsigned<true>)
 + {
 + 	if (a == 0)
 + 		return "0";
 +-	bool negate = false;
 +-	if (a < 0)
 +-	{
 +-		negate = true;
 +-		a = 0-a;	// VC .NET does not like -a
 +-	}
 + 	std::string result;
 + 	while (a > 0)
 + 	{
 +@@ -423,11 +419,30 @@
 + 		result = char((digit < 10 ? '0' : ('a' - 10)) + digit) + result;
 + 		a /= base;
 + 	}
 ++	return result;
 ++}
 ++
 ++template <class T>
 ++std::string IntToStringImpl(T a, unsigned int base, IsUnsigned<false>)
 ++{
 ++	bool negate = false;
 ++	if (a < 0)
 ++	{
 ++		negate = true;
 ++		a = 0-a;	// VC .NET does not like -a
 ++	}
 ++	std::string result = IntToStringImpl(a, base, IsUnsigned<true>());
 + 	if (negate)
 + 		result = "-" + result;
 + 	return result;
 + }
 + 
 ++template <class T>
 ++std::string IntToString(T a, unsigned int base = 10)
 ++{
 ++	return IntToStringImpl(a, base, IsUnsigned<(static_cast<T>(-1) > 0)>());
 ++}
 ++
 + template <class T1, class T2>
 + inline T1 SaturatingSubtract(const T1 &a, const T2 &b)
 + {
 diff -ruN --exclude=CVS ../cryptopp.orig/files/patch-nbtheory.cpp ./files/patch-nbtheory.cpp
 --- ../cryptopp.orig/files/patch-nbtheory.cpp	1970-01-01 01:00:00.000000000 +0100
 +++ ./files/patch-nbtheory.cpp	2013-05-22 02:18:29.000000000 +0200
 @@ -0,0 +1,21 @@
 +--- nbtheory.cpp.orig	2013-05-22 00:16:26.761193859 +0000
 ++++ nbtheory.cpp	2013-05-22 00:15:29.401256454 +0000
 +@@ -307,7 +307,18 @@
 + 
 + bool PrimeSieve::NextCandidate(Integer &c)
 + {
 ++#if defined(__clang__) && defined(_LIBCPP_VERSION) &&  _LIBCPP_VERSION < 1101
 ++	// Workaround for a bug in libc++ in std::find on std::vector<bool>
 ++	std::vector<bool>::iterator pos = m_sieve.begin()+m_next;
 ++	for (std::vector<bool>::iterator end = m_sieve.end(); pos != end; ++pos)
 ++	{
 ++		if (*pos == false)
 ++			break;
 ++	}
 ++	bool safe = SafeConvert(pos - m_sieve.begin(), m_next);
 ++#else
 + 	bool safe = SafeConvert(std::find(m_sieve.begin()+m_next, m_sieve.end(), false) - m_sieve.begin(), m_next);
 ++#endif
 + 	assert(safe);
 + 	if (m_next == m_sieve.size())
 + 	{
 
 --MP_/Qwt9YtjNQadscfTOseAEVzi--
State-Changed-From-To: open->closed 
State-Changed-By: delphij 
State-Changed-When: Wed May 22 22:42:32 UTC 2013 
State-Changed-Why:  
Committed, thanks! 

http://www.freebsd.org/cgi/query-pr.cgi?pr=178827 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: ports/178827: commit references a PR
Date: Wed, 22 May 2013 22:41:50 +0000 (UTC)

 Author: delphij
 Date: Wed May 22 22:41:42 2013
 New Revision: 318802
 URL: http://svnweb.freebsd.org/changeset/ports/318802
 
 Log:
   This changeset fixes two issues with crypto++ library:
   
    * patch-misc.h
   
      This fixes a warning triggered by testing an unsigned parameter against
      0.  The patch solves this by creating a different template for signed
      case.
   
    * patch-nbtheory.cpp
   
      This is a workaround for a bug with the current version of libc++ shipped
      with FreeBSD 9.x, which causes an infinite loop when generating RSA key,
      possibly also other operations.
   
   PR:		ports/178827
   Submitted by:	Michael Gmelin <freebsd grem de>
 
 Added:
   head/security/cryptopp/files/patch-misc.h   (contents, props changed)
   head/security/cryptopp/files/patch-nbtheory.cpp   (contents, props changed)
 Modified:
   head/security/cryptopp/Makefile
 
 Modified: head/security/cryptopp/Makefile
 ==============================================================================
 --- head/security/cryptopp/Makefile	Wed May 22 22:21:52 2013	(r318801)
 +++ head/security/cryptopp/Makefile	Wed May 22 22:41:42 2013	(r318802)
 @@ -3,7 +3,7 @@
  
  PORTNAME=		cryptopp
  PORTVERSION=		5.6.1
 -PORTREVISION=		2
 +PORTREVISION=		3
  CATEGORIES=		security
  MASTER_SITES=		SF \
  			http://www.cryptopp.com/
 
 Added: head/security/cryptopp/files/patch-misc.h
 ==============================================================================
 --- /dev/null	00:00:00 1970	(empty, because file is newly added)
 +++ head/security/cryptopp/files/patch-misc.h	Wed May 22 22:41:42 2013	(r318802)
 @@ -0,0 +1,54 @@
 +--- misc.h.orig	2010-08-06 18:46:18.000000000 +0000
 ++++ misc.h	2013-05-22 08:43:01.949194748 +0000
 +@@ -405,17 +405,13 @@
 + 	return order == GetNativeByteOrder();
 + }
 + 
 ++template<bool> struct IsUnsigned {};
 ++
 + template <class T>
 +-std::string IntToString(T a, unsigned int base = 10)
 ++std::string IntToStringImpl(T a, unsigned int base, IsUnsigned<true>)
 + {
 + 	if (a == 0)
 + 		return "0";
 +-	bool negate = false;
 +-	if (a < 0)
 +-	{
 +-		negate = true;
 +-		a = 0-a;	// VC .NET does not like -a
 +-	}
 + 	std::string result;
 + 	while (a > 0)
 + 	{
 +@@ -423,11 +419,30 @@
 + 		result = char((digit < 10 ? '0' : ('a' - 10)) + digit) + result;
 + 		a /= base;
 + 	}
 ++	return result;
 ++}
 ++
 ++template <class T>
 ++std::string IntToStringImpl(T a, unsigned int base, IsUnsigned<false>)
 ++{
 ++	bool negate = false;
 ++	if (a < 0)
 ++	{
 ++		negate = true;
 ++		a = 0-a;	// VC .NET does not like -a
 ++	}
 ++	std::string result = IntToStringImpl(a, base, IsUnsigned<true>());
 + 	if (negate)
 + 		result = "-" + result;
 + 	return result;
 + }
 + 
 ++template <class T>
 ++std::string IntToString(T a, unsigned int base = 10)
 ++{
 ++	return IntToStringImpl(a, base, IsUnsigned<(static_cast<T>(-1) > 0)>());
 ++}
 ++
 + template <class T1, class T2>
 + inline T1 SaturatingSubtract(const T1 &a, const T2 &b)
 + {
 
 Added: head/security/cryptopp/files/patch-nbtheory.cpp
 ==============================================================================
 --- /dev/null	00:00:00 1970	(empty, because file is newly added)
 +++ head/security/cryptopp/files/patch-nbtheory.cpp	Wed May 22 22:41:42 2013	(r318802)
 @@ -0,0 +1,21 @@
 +--- nbtheory.cpp.orig	2013-05-22 00:16:26.761193859 +0000
 ++++ nbtheory.cpp	2013-05-22 00:15:29.401256454 +0000
 +@@ -307,7 +307,18 @@
 + 
 + bool PrimeSieve::NextCandidate(Integer &c)
 + {
 ++#if defined(__clang__) && defined(_LIBCPP_VERSION) &&  _LIBCPP_VERSION < 1101
 ++	// Workaround for a bug in libc++ in std::find on std::vector<bool>
 ++	std::vector<bool>::iterator pos = m_sieve.begin()+m_next;
 ++	for (std::vector<bool>::iterator end = m_sieve.end(); pos != end; ++pos)
 ++	{
 ++		if (*pos == false)
 ++			break;
 ++	}
 ++	bool safe = SafeConvert(pos - m_sieve.begin(), m_next);
 ++#else
 + 	bool safe = SafeConvert(std::find(m_sieve.begin()+m_next, m_sieve.end(), false) - m_sieve.begin(), m_next);
 ++#endif
 + 	assert(safe);
 + 	if (m_next == m_sieve.size())
 + 	{
 _______________________________________________
 svn-ports-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-ports-all
 To unsubscribe, send any mail to "svn-ports-all-unsubscribe@freebsd.org"
 
>Unformatted:
