Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

libcrypto safe for library use?

21 views
Skip to first unread message

Mark Phalan

unread,
Mar 25, 2010, 9:13:33 AM3/25/10
to

The threads(3) manpage states that to use OpenSSL in multi-threaded
applications then locking callback functions must be set otherwise
random crashes may occur.

This poses a challenge when using OpenSSL in a library which should be
MT safe. There is no safe way to set the locking callbacks from within
the library itself. The calling application may or may not be using
OpenSSL or may be linking against multiple libraries some of which may
be linked against OpenSSL. The application may not even be aware that it
will end up calling into OpenSSL code.

The only safe way to ensure that the OpenSSL code will be MT safe would
be for the OpenSSL library itself to set locking callbacks, however I
don't see any compile-time option to do that.

Is there a reason I'm missing as to why this option isn't available?

Without this, the library can do its best to set the locking callbacks
when loaded if they are not set and then remove them when unloaded,
however this will always be inherently racy if there are other parts of
the process using OpenSSL.

Thanks,

-M


______________________________________________________________________
OpenSSL Project http://www.openssl.org
Development Mailing List opens...@openssl.org
Automated List Manager majo...@openssl.org

David Schwartz

unread,
Mar 25, 2010, 11:44:24 PM3/25/10
to

Mark Phalan wrote:

> The threads(3) manpage states that to use OpenSSL in multi-threaded
> applications then locking callback functions must be set otherwise
> random crashes may occur.

That is correct.

> This poses a challenge when using OpenSSL in a library which should be
> MT safe. There is no safe way to set the locking callbacks from within
> the library itself. The calling application may or may not be using
> OpenSSL or may be linking against multiple libraries some of which may
> be linked against OpenSSL. The application may not even be aware that
> it
> will end up calling into OpenSSL code.

It's trivial -- adopt the same solution OpenSSL adopts. Have the application
set your library's locking callbacks and you pass them onto OpenSSL. It
won't matter then if you change the callbacks because you'd be changing them
to what they already were or would be anyway.

> The only safe way to ensure that the OpenSSL code will be MT safe would
> be for the OpenSSL library itself to set locking callbacks, however I
> don't see any compile-time option to do that.

It can't do that, it has no idea what threading model the application is
using. It would have no way to know whether the locks it provided were
suitable or sensible.

> Is there a reason I'm missing as to why this option isn't available?

The library has no way to know what threading model the application that
calls it is using. Only the application has this knowledge, so it's the
application's responsibility to pass this to the library.



> Without this, the library can do its best to set the locking callbacks
> when loaded if they are not set and then remove them when unloaded,
> however this will always be inherently racy if there are other parts of
> the process using OpenSSL.

I agree. Your library should impose a requirement on any application that
uses it that it inform you of the threading model it's using so that you can
use appropriate locking as well. Then you can set the OpenSSL locking
callbacks (just pass them through) and there's no chance of a race or
problem.

DS

Mark Phalan

unread,
Mar 26, 2010, 6:37:09 AM3/26/10
to
On 03/26/10 04:44 AM, David Schwartz wrote:
>
> Mark Phalan wrote:
>
>> The threads(3) manpage states that to use OpenSSL in multi-threaded
>> applications then locking callback functions must be set otherwise
>> random crashes may occur.
>
> That is correct.
>
>> This poses a challenge when using OpenSSL in a library which should be
>> MT safe. There is no safe way to set the locking callbacks from within
>> the library itself. The calling application may or may not be using
>> OpenSSL or may be linking against multiple libraries some of which may
>> be linked against OpenSSL. The application may not even be aware that
>> it
>> will end up calling into OpenSSL code.
>
> It's trivial -- adopt the same solution OpenSSL adopts. Have the application
> set your library's locking callbacks and you pass them onto OpenSSL. It
> won't matter then if you change the callbacks because you'd be changing them
> to what they already were or would be anyway.
>

Unfortunately that's not really practical. To take an example I'm
familiar with - libgss. libgss can end up calling into OpenSSL in the
following way:

libgss -> kerberos -> pkinit plugin -> openssl

It's simply not practical to change libkrb5 and libgss and all
applications using those libraries.

>> The only safe way to ensure that the OpenSSL code will be MT safe would
>> be for the OpenSSL library itself to set locking callbacks, however I
>> don't see any compile-time option to do that.
>
> It can't do that, it has no idea what threading model the application is
> using. It would have no way to know whether the locks it provided were
> suitable or sensible.
>

Well on Solaris it's most likely going to be using either POSIX threads
or Solaris threads which are interoperable and can be used in the same
application. If an application wants to do something unusual it can set
the callbacks. I'm not suggesting that applications should lose the
power to set locking callbacks.
Having default callbacks will simply mean that applications which don't
use OpenSSL or don't set callbacks will be more likely to work.

>> Is there a reason I'm missing as to why this option isn't available?
>
> The library has no way to know what threading model the application that
> calls it is using. Only the application has this knowledge, so it's the
> application's responsibility to pass this to the library.
>
>> Without this, the library can do its best to set the locking callbacks
>> when loaded if they are not set and then remove them when unloaded,
>> however this will always be inherently racy if there are other parts of
>> the process using OpenSSL.
>
> I agree. Your library should impose a requirement on any application that
> uses it that it inform you of the threading model it's using so that you can
> use appropriate locking as well. Then you can set the OpenSSL locking
> callbacks (just pass them through) and there's no chance of a race or
> problem.

See above. That's simply not practical (the horse has left the stable).

-M

Darryl Miles

unread,
Mar 26, 2010, 7:34:16 AM3/26/10
to
Mark Phalan wrote:
>
> The threads(3) manpage states that to use OpenSSL in multi-threaded
> applications then locking callback functions must be set otherwise
> random crashes may occur.
>
> This poses a challenge when using OpenSSL in a library which should be
> MT safe. There is no safe way to set the locking callbacks from within
> the library itself. The calling application may or may not be using
> OpenSSL or may be linking against multiple libraries some of which may
> be linked against OpenSSL. The application may not even be aware that it
> will end up calling into OpenSSL code.

I agree this is a genuine concern.


Thing 1) It is one thing for OpenSSL to have multi-platform support by
delegating the locking mechanism with callbacks via abstraction. This
allows the library to be used with all major large platforms as well as
any tiny embedded platform (for which OpenSSL has not way in advance to
know or understand the locking mechanism on that platform). No one is
saying this is not a good and correct thing to do and such a thing shall
remain.


Thing 2) It is another thing not to provide a default implementation for
setting up those callback with a usable locking mechanism specific for
each platform it can be compiled for where one is known. It is not like
the WIN32 version is going to be used on Linux and the Linux on
Nokia-Symbian. This mechanism can have a common API symbol across all
platforms which will attempt to setup the locking mechanism in a
re-entrant multi-thread safe manner, it should also reference count the
setup mechanism so multiple users can load OpenSSL DSO and initialize it
independently in safety.


These two things are not mutually exclusive. I think there is some
common misconception that they are on the openssl-dev list.


--- THOUGHTS ON IMPLEMENTATION, SKIP IF BORED ---
On every large platform there is a default locking implementation that
can be used, there really are not too many options any more, on every
platform OpenSSL compiles for but does not know of such a lock mechanism
the API would error. Documentation would need to be produced about how
the OpenSSL library startup/shutdown would be implemented that conforms
to the re-entrant multi-thread safe requirements.

Maybe we should petition the binutils and ELF maintainers of open-source
platform about providing hooks in DSO for "on first load" and "on load"
and "on unload" and "on last unload", maybe such things already exist ?
Maybe this could be implemented as a single section with a control
word indicating a bitmask of which callbacks it is for followed by a
function pointer. Both items are of the platform native bit-width for
function pointers. The dynamic linker would then use this section if it
exists to fire callbacks. The use of the hook would be tagged in GCC
using __attribute(()) around symbols. Plenty of other criteria to add
should it be taken forward.
--- THOUGHTS ON IMPLEMENTATION, SKIP IF BORED ---

In this modern day with dlopen/GetProcAddress that dynamically loads
modules/DSOs/DLLs into executable which themselves can have compile time
dependencies causing additional DSOs/DLLs to loaded with them. The top
level application is no longer in control of proceedings the dynamic
linker is.

You are correct the application that needed to use OpenSSL doesn't know
it is the "first user" of OpenSSL in the process address space since
there is nothing provided within OpenSSL library API to arbitrate this
matter. If it could know it was the first user it could setup the
multi-threading callbacks accordingly, but again this all needs to be
arbitrated in a re-entrant thread-safe manner.

Not so long ago (~7 years) it was conceivable that OpenSSL developers
could say the controlling application needs to perform the arbitration
but this just isn't how people use dlopen/GetProcAddress these days,
rightly or wrongly.

I think that developing the OpenSSL API in this area will not limit or
change any existing behavior it will just ratify how to deal with these
new situations consistently.


Is it this use case there the OpenSSL's historic (archaic) view of the
world is wrong. The world has evolved and OpenSSL should do so too.

> The only safe way to ensure that the OpenSSL code will be MT safe would
> be for the OpenSSL library itself to set locking callbacks, however I
> don't see any compile-time option to do that.

With the above two things implemented it would them be a step away from
a providing a compile time option. But the same thing can be achieved
on every platform is the API callback to set a default locking
implementation was consistent (since part of what I'm claiming here is
that new API call would be re-entrant multi-thread safe, i.e. bullet
proof and not requiring multiple threads to co-operate outside of OpenSSL).


> Is there a reason I'm missing as to why this option isn't available?

It just is so (at this time).


> Without this, the library can do its best to set the locking callbacks
> when loaded if they are not set and then remove them when unloaded,
> however this will always be inherently racy if there are other parts of
> the process using OpenSSL.

I have had previous discussions in the list over better startup and
shutdown APIs/documentation for the OpenSSL library, I do think this is
an area that needs improvement. Those improvements don't need to
radically change how things are currently done. The matters brought up
here were loosely thought about then; but as time has passed my thoughts
on "the problem" have become much clearer to me.

Unfortunately at this time I can only provide input/guidance into how
such a thing could/should be done, not the man power.

Darryl

Mark Phalan

unread,
Mar 26, 2010, 11:27:59 AM3/26/10
to
On 03/25/10 02:13 PM, Mark Phalan wrote:
>
> The threads(3) manpage states that to use OpenSSL in multi-threaded
> applications then locking callback functions must be set otherwise
> random crashes may occur.
>
> This poses a challenge when using OpenSSL in a library which should be
> MT safe. There is no safe way to set the locking callbacks from within
> the library itself.

I should also point out that libraries are setting the callbacks
already. libldap_r (openldap) for example. I haven't done an extensive
survey of common opensource libraries but I'm sure openldap isn't alone
out there.

-M

David Schwartz

unread,
Mar 26, 2010, 5:47:02 PM3/26/10
to

Mark Phalan wrote:

> Unfortunately that's not really practical. To take an example I'm
> familiar with - libgss. libgss can end up calling into OpenSSL in the
> following way:
>
> libgss -> kerberos -> pkinit plugin -> openssl
>
> It's simply not practical to change libkrb5 and libgss and all
> applications using those libraries.

In this case, I presume 'pkinit' only supports one threading model (or one
set of compatible threading models). So it can set the callbacks. Any
application that uses 'pkinit' must be okay with those callbacks.



> > It can't do that, it has no idea what threading model the application
> > is
> > using. It would have no way to know whether the locks it provided
> > were
> > suitable or sensible.


> Well on Solaris it's most likely going to be using either POSIX threads
> or Solaris threads which are interoperable and can be used in the same
> application. If an application wants to do something unusual it can set

> the callbacks. I'm not suggesting that applications should lose the


> power to set locking callbacks.
> Having default callbacks will simply mean that applications which don't
> use OpenSSL or don't set callbacks will be more likely to work.

Then set default callbacks in your code that calls OpenSSL. OpenSSL can't do
it, because it has no idea what threading models your code uses.

> > I agree. Your library should impose a requirement on any application
> > that
> > uses it that it inform you of the threading model it's using so that
> > you can
> > use appropriate locking as well. Then you can set the OpenSSL locking
> > callbacks (just pass them through) and there's no chance of a race or
> > problem.

> See above. That's simply not practical (the horse has left the stable).

If the horse has left the stable and the code supports more than one
threading model, then the problem is provable insolvable. There is simply no
way for OpenSSL to know what kind of locks are adequate. If your code
supports only one threading model, then you can tell OpenSSL this by setting
the callbacks.

Multi-threading issues, as a general rule, have to be resolved at
application level. It cannot be done by libraries because they don't have
sufficient knowledge. Things like signal handlers are process-level
resources. The same is true of what kind of mutexes are needed to protect
structures from concurrent accesses that come into a library from outside
it.

> I should also point out that libraries are setting the callbacks already.
> libldap_r (openldap) for example. I haven't done an extensive survey of
> common opensource libraries but I'm sure openldap isn't alone out there.

Since libldap_r knows what threading model the application is using, it can
do this. OpenSSL doesn't know, so it can't do this.

DS

Peter Waltenberg

unread,
Mar 28, 2010, 6:03:29 PM3/28/10
to
Historically I suspect the reason there were no default callbacks is that a
sizeable proportion of OpenSSL users didn't use threading at all, and the
baggage hauling in the thread libraries imposed was significant.

I don't think that's an issue anymore - threading is the common case now.

But - there's another issue you've all missed. You can have multiple
independently developed libraries in the same process all using OpenSSL -
who gets to set the thread callbacks ?. They have to be set to ensure
thread safe operation, but no individual library can assume that "someone
else" has done it now.

Even better - a library does set the callbacks - and gets unloaded while
other libs are still using OpenSSL. (Not just a "what if" - that one I've
seen in the wild).

So - yes, you probably do need to set the callbacks by default now, and you
probably need to make that API a no-op as well. By all means have a compile
time option to restore the old behaviour for the set of users who need the
legacy behaviour - but that's likely a very small set now.


Peter


From: "David Schwartz" <dav...@webmaster.com>

To: <Mark....@Sun.COM>, <opens...@openssl.org>

Date: 27/03/2010 07:57 AM

Subject: RE: libcrypto safe for library use?

Sent by: owner-op...@openssl.org

Thor Lancelot Simon

unread,
Mar 28, 2010, 6:54:25 PM3/28/10
to
On Mon, Mar 29, 2010 at 08:03:29AM +1000, Peter Waltenberg wrote:
> Historically I suspect the reason there were no default callbacks is that a
> sizeable proportion of OpenSSL users didn't use threading at all, and the
> baggage hauling in the thread libraries imposed was significant.
>
> I don't think that's an issue anymore - threading is the common case now.

Maybe for some people. For others, actually doing locked-bus instructions
by default would wreck OpenSSL's performance beyond compare.

Please don't make locking the default.

Thor

Ger Hobbelt

unread,
Mar 28, 2010, 7:24:54 PM3/28/10
to
On Mon, Mar 29, 2010 at 1:18 AM, Ger Hobbelt <g...@hobbelt.com> wrote:
a) have an extra API function which delivers the references to the currently installed callbacks (NULL if none are set up), or

b) a kinda signal() style API function set up where the function which is used to register those callbacks with OpenSSL returns a reference to the previously installed callback.


And incidentally, since we already have a subject-related
CRYPTO_THREADID_get_callback()
API I guess option (a) above would be the preferable one to keep the API layout consistent as a whole, though I kinda like (b) better, myself. :-)

--
Met vriendelijke groeten / Best regards,

Ger Hobbelt

--------------------------------------------------
web:    http://www.hobbelt.com/
       http://www.hebbut.net/
mail:   g...@hobbelt.com
mobile: +31-6-11 120 978
--------------------------------------------------

Ger Hobbelt

unread,
Mar 28, 2010, 7:18:25 PM3/28/10
to
On Mon, Mar 29, 2010 at 12:03 AM, Peter Waltenberg <pwa...@au1.ibm.com> wrote:
I don't think that's an issue anymore - threading is the common case now.

common case != everybody
 

But - there's another issue you've all missed. You can have multiple
independently developed libraries in the same process all using OpenSSL -
who gets to set the thread callbacks ?. They have to be set to ensure
thread safe operation, but no individual library can assume that "someone
else" has done it now.

Even better - a library does set the callbacks - and gets unloaded while
other libs are still using OpenSSL. (Not just a "what if" - that one I've
seen in the wild).

Even if OpenSSL would submit to your wish, then that would /not/ fix your failure scenario above. At least not for everybody who needs to replace that 'default implementation', whatever it will be.

The proper way to fix that kind of conundrum (at least one of the ways and IMO the most feasible for OpenSSL) is to allow callers (= other libs and app using OpenSSL) a way to replace-and-restore those callbacks. push and pop if you will, but I'd rather see that bit of management done by the outside world (from the perspective of OpenSSL as a highly portable lib).

So that would be an API where you either


a) have an extra API function which delivers the references to the currently installed callbacks (NULL if none are set up), or

b) a kinda signal() style API function set up where the function which is used to register those callbacks with OpenSSL returns a reference to the previously installed callback.

Both ways allow for multiple independent setup and termination implementations like this (for style (b)):

init:
  global f *old_callback_ref = CRYPTO_set_lock_callback(my_lock_func);

... // do thy thing, lib/app

exit:
  // restore original:
  CRYPTO_set_lock_callback(old_callback_ref);
 

and the only thing that needs to be changed for style (b) is the return type of CRYPTO_set_lock_callback and friends (i.e. the dynlocks):

void CRYPTO_set_locking_callback(void (*locking_function)(int mode,
int n, const char *file, int line));

--> e.g.

typedef void CRYPTO_userdef_locking_function(int mode,
int n, const char *file, int line);

CRYPTO_userdef_locking_function *
CRYPTO_set_locking_callback(CRYPTO_userdef_locking_function *new);


which is at least compile-time backwards 'compatible' as current code expects a 'void' return type for this API.


So - yes, you probably do need to set the callbacks by default now, and you

Nope. Doesn't solve anything. (Maybe 'solves' -- on /some/ platforms -- 'weird issues' happening to those, em, programmers who don't check sample code or read man pages and forget about those locks altogether, but that's a whole 'nother subject matter.)
 



My 2 cents, donated to the cause.

Ger Hobbelt

unread,
Mar 28, 2010, 7:27:16 PM3/28/10
to
On Mon, Mar 29, 2010 at 12:54 AM, Thor Lancelot Simon <t...@panix.com> wrote:
Maybe for some people.  For others, actually doing locked-bus instructions
by default would wreck OpenSSL's performance beyond compare.

Please don't make locking the default.

+1

Peter Waltenberg

unread,
Mar 28, 2010, 8:02:32 PM3/28/10
to
You can't "push and pop" the callbacks.

The software is running in multiple threads and being used by multiple
independently developed libraries at the same time.
Do you really plan to swap the thread locking mechanism - (which is
protecting you while you swap the locking mechanism around) while threads
are running ?.

I hit this with IBM's bastard son of OpenSSL a few years back - the only
viable fix I could come up with was to internalize the callbacks and set
them to the OS default.

I agree there will be some users who want to use their own threading model
and that should be catered for but I don't think it should be the default
now.
Making the old behaviour a compile time option still works for closed
ecosystem users - but for most end users - i.e. on the Linux's or BSD's
having OpenSSL defaulting to sane and safe system locking is the best
solution I can come up with.

The memory callbacks have the same issue in that only one "caller" in the
process can set them sanely - though those at least default to system
default malloc()/free() so everyone leaving them alone works.
We don't have that option with the thread callbacks - they must be set, but
there's no safe way for multiple "users" in the same process to do that at
present - all I'm suggesting is that you "fix" this in the same way the
memory callback use is made safe.

Peter

common case != everybody

--> e.g.

typedef void CRYPTO_userdef_locking_function(int mode,

CRYPTO_userdef_locking_function *
CRYPTO_set_locking_callback(CRYPTO_userdef_locking_function *new);

--


Met vriendelijke groeten / Best regards,

Ger Hobbelt

--------------------------------------------------
web:    http://www.hobbelt.com/
       http://www.hebbut.net/
mail:   g...@hobbelt.com
mobile: +31-6-11 120 978
--------------------------------------------------

Ger Hobbelt

unread,
Mar 28, 2010, 9:08:26 PM3/28/10
to
Hrgh. No, you don't init or terminate anything when you're already trying to execute it from several threads; such init and termination should be done before and after that.

When a lib (instead of the app itself) is using OpenSSL on its own and that lib requires a certain approach it is probably coded to set it up. With an OpenSSL API augmented a la style (a) it can do this safely, i.e.:

init:
if (get_callbacks() != NULL)
{
  // flag this situation for termination time and leave those callbacks the hell alone
}


When the app is using several such libraries and/or doing OpenSSL work of its own, it should call the OpenSSL init and shutdown/termination APIs itself to ensure it is set up during the entire lifetime of the app, no way around that.

What OpenSSL /could/ do  is provide a few bits and pieces so that libraries/modules who think they should be responsible for setting up and shutting down OpenSSL themselves can check whether someone has done so already beforehand and change their own actions accordingly; preferably by leaving the setup alone. Indeed, wrong words by me 'push and pop'; it ain't a stack.

The 'was OpenSSL set up already? And in a way we expect/require?' check has to be performed in such [third party?] modules/libraries, at least in modules/libs who would attempt to init/shutdown OpenSSL on their own.
What OpenSSL init/shutdown code /could/ do to help is maybe 'count' the number of init and shutdown invocations and only really act on the first one.
And setting up the callbacks counts as individual pieces of init code, so they might be 'counted' individually (lock, dynlock, threadid).

That would fix this scenario:

On Mon, Mar 29, 2010 at 2:02 AM, Peter Waltenberg <pwa...@au1.ibm.com> wrote:
You can't "push and pop" the callbacks.

The software is running in multiple threads and being used by multiple
independently developed libraries at the same time.
 
------


Do you really plan to swap the thread locking mechanism - (which is
protecting you while you swap the locking mechanism around) while threads
are running ?.

Definitely not.
 
We don't have that option with the thread callbacks - they must be set, but
there's no safe way for multiple "users" in the same process to do that at
present - all I'm suggesting is that you "fix" this in the same way the
memory callback use is made safe.

When the case is init from multiple threads simultaneously, then the memory callback setup isn't 'safe' for that kind of thing either (none would). It's just that that particular init is almost never invoked by any 'users' as malloc/free is a /very/ common answer there. pthreads or what have you aren't so common so the locking callbacks are a different matter IMO.

The right way to do it is have the app set it up at init time, either through calling the OpenSSL functions directly or through a module/lib's 'init/setup' API if that's the one 'responsible' for OpenSSL activity in your application.
Just in case some lib developer takes matters in his own hands a bit too much, a 'only first invocation matters' style of setup might be used for these and other bits of OpenSSL setup.



Aw shucks, what am I blathering...
I just checked: ./crypto/cryptlib.c already offers everything you need, style (a):

void (*CRYPTO_get_locking_callback(void))(int mode,int type,const char *file,
        int line)
    {
    return(locking_callback);
    }

int (*CRYPTO_get_add_lock_callback(void))(int *num,int mount,int type,
                      const char *file,int line)
...

Well, the 'only first come is served' idea isn't in there, but that's not needed as long as library (instead of application) developers make sure to check that CRYPTO_get_locking_callback() API before they get all active about it themselves :-)

It's just that it's not in the man pages on the web site yet, it seems. A documentation patch perhaps?



Peter Waltenberg

unread,
Mar 29, 2010, 1:15:44 AM3/29/10
to
"
The right way to do it is have the app set it up at init time, either
through calling the OpenSSL functions directly or through a module/lib's
'init/setup' API if that's the one 'responsible' for OpenSSL activity in
your application.
Just in case some lib developer takes matters in his own hands a bit too
much, a 'only first invocation matters' style of setup might be used for
these and other bits of OpenSSL setup.
"

Sure - it works if you have a simple application, main -> OpenSSL
even main ->lib doing SSL -> OpenSSL still works.

What's giving us grief (and I suspect the person who first raised this
grief) is:
main -> lib that needs SSL to do client server comms -> OpenSSL
-> Another lib that does client server comms. ->OpenSSL
-> Another lib that does crypto ->OpenSSL

All the libraries of the big fat composite application expect to be able to
access OpenSSL's function, all were created independently - the top level
app doesn't do SSL or crypto. at all - it just uses libraries that need to
do SSL or crypto to function.

Yes, it's ugly - alas it's also what happens as time goes by and functions
that were regarded as standalone applications are now library functions -
you only have to look at any of the Unix desktops to see the sort of chaos
that results.

So - even if you don't want to change the defaults - at least add an
option to allow OpenSSL to be built with the system thread model by default
so all those modern (but oh so ugly) apps can still run safely.


Pete



From: Ger Hobbelt <g...@hobbelt.com>

To: opens...@openssl.org

Date: 03/29/2010 11:47 AM

Subject: Re: libcrypto safe for library use?

Sent by: owner-op...@openssl.org

------

Ger Hobbelt

Patrick Patterson

unread,
Mar 29, 2010, 7:39:03 AM3/29/10
to
Peter:

On 29/03/10 1:15 AM, Peter Waltenberg wrote:
>
> Sure - it works if you have a simple application, main -> OpenSSL
> even main ->lib doing SSL -> OpenSSL still works.
>
> What's giving us grief (and I suspect the person who first raised this
> grief) is:
> main -> lib that needs SSL to do client server comms -> OpenSSL
> -> Another lib that does client server comms. ->OpenSSL
> -> Another lib that does crypto ->OpenSSL
>
> All the libraries of the big fat composite application expect to be able to
> access OpenSSL's function, all were created independently - the top level
> app doesn't do SSL or crypto. at all - it just uses libraries that need to
> do SSL or crypto to function.
>

This is a rather specious argument - if an application uses SSL at the
lower layers, there has to be some method for that application to at
least tell OpenSSL which CA Certificates to use - and yes, it COULD have
a wrapper/higher level lib that sets up those locations (like I think
OpenLDAP can), but I would consider that a HORRIBLE design flaw of that
higher library to not expose SOME method to set the trust store (and
revocation information, etc.) globally for the application - otherwise,
in the situation that you mention, the poor admin COULD end up with an
application where it is almost impossible to troubleshoot why certain
connections are failing i.e.: Why do my LDAPS connections work, but my
HTTPS don't? (assuming that LDAP is provided by one lib, and HTTP by
another). So I would argue that it is the higher level libs problem to:

1: Set threading correctly and consistently on all of it's SUB library
dependencies with the model the higher level app tells it to.

2: Expose enough controls that allow for a higher level app to set keys,
cert stores, and revocation information locations.

If those libraries DON'T do both of the above (and OpenSSL can certainly
accommodate both today), then the bugs/feature requests to enable both
of these functionalities should be filed there.

I'm not one of the "core" devels, but this is just my 0.02 worth.

Patrick.

Mark Phalan

unread,
Mar 29, 2010, 8:18:22 AM3/29/10
to
On 03/26/10 10:47 PM, David Schwartz wrote:
>
> Mark Phalan wrote:
>
>> Unfortunately that's not really practical. To take an example I'm
>> familiar with - libgss. libgss can end up calling into OpenSSL in the
>> following way:
>>
>> libgss -> kerberos -> pkinit plugin -> openssl
>>
>> It's simply not practical to change libkrb5 and libgss and all
>> applications using those libraries.
>
> In this case, I presume 'pkinit' only supports one threading model (or one
> set of compatible threading models). So it can set the callbacks.

It can set the callbacks but it can't set them in a way which is safe
from races.

>> Well on Solaris it's most likely going to be using either POSIX threads
>> or Solaris threads which are interoperable and can be used in the same
>> application. If an application wants to do something unusual it can set
>> the callbacks. I'm not suggesting that applications should lose the
>> power to set locking callbacks.
>> Having default callbacks will simply mean that applications which don't
>> use OpenSSL or don't set callbacks will be more likely to work.
>
> Then set default callbacks in your code that calls OpenSSL. OpenSSL can't do
> it, because it has no idea what threading models your code uses.

Perhaps I don't understand exactly what you mean by "threading model".
Are you referring to 1:1, n:1 etc?
I think it would be reasonable for OpenSSL as delivered with an OS to
use the native threading model of the OS. Is there something I'm missing?

>
>>> I agree. Your library should impose a requirement on any application
>>> that
>>> uses it that it inform you of the threading model it's using so that
>>> you can
>>> use appropriate locking as well. Then you can set the OpenSSL locking
>>> callbacks (just pass them through) and there's no chance of a race or
>>> problem.
>
>> See above. That's simply not practical (the horse has left the stable).
>
> If the horse has left the stable and the code supports more than one
> threading model, then the problem is provable insolvable. There is simply no
> way for OpenSSL to know what kind of locks are adequate. If your code
> supports only one threading model, then you can tell OpenSSL this by setting
> the callbacks.

What I could do is say that when delivered as part of OpenSolaris
OpenSSL assumes the OS's threading model. If an application wants to
change that they the application should set its own callbacks.

Just to be totally clear. All I'd like to see is a compile-time option
(it can be disabled by default) to set a default set of locking
callbacks native to the OS it's compiling on. I'm not suggesting that
the ability to set locking callbacks be removed.

>
> Multi-threading issues, as a general rule, have to be resolved at
> application level. It cannot be done by libraries because they don't have
> sufficient knowledge.

And this is precisely the problem. For the case where an application
isn't using

...


> Since libldap_r knows what threading model the application is using, it can
> do this. OpenSSL doesn't know, so it can't do this.

It can do this but only by potentially introducing a race.

Thanks,

-M

Mark Phalan

unread,
Mar 29, 2010, 8:21:53 AM3/29/10
to
On 03/29/10 12:54 AM, Thor Lancelot Simon wrote:
> On Mon, Mar 29, 2010 at 08:03:29AM +1000, Peter Waltenberg wrote:
>> Historically I suspect the reason there were no default callbacks is that a
>> sizeable proportion of OpenSSL users didn't use threading at all, and the
>> baggage hauling in the thread libraries imposed was significant.
>>
>> I don't think that's an issue anymore - threading is the common case now.
>
> Maybe for some people. For others, actually doing locked-bus instructions
> by default would wreck OpenSSL's performance beyond compare.
>

I'd be interested in seeing any benchmarks of locking vs non-locking.
Even if there is a performance impact correctness needs to come first.

> Please don't make locking the default.

I'm just suggesting a compile-time option. The application could always
set the locking callbacks back to NULL if it knew what it was doing.

Mark Phalan

unread,
Mar 29, 2010, 8:25:52 AM3/29/10
to
On 03/29/10 07:15 AM, Peter Waltenberg wrote:
> "
> The right way to do it is have the app set it up at init time, either
> through calling the OpenSSL functions directly or through a module/lib's
> 'init/setup' API if that's the one 'responsible' for OpenSSL activity in
> your application.
> Just in case some lib developer takes matters in his own hands a bit too
> much, a 'only first invocation matters' style of setup might be used for
> these and other bits of OpenSSL setup.
> "
>
> Sure - it works if you have a simple application, main -> OpenSSL
> even main ->lib doing SSL -> OpenSSL still works.
>
> What's giving us grief (and I suspect the person who first raised this
> grief) is:
> main -> lib that needs SSL to do client server comms -> OpenSSL
> -> Another lib that does client server comms. ->OpenSSL
> -> Another lib that does crypto ->OpenSSL
>
> All the libraries of the big fat composite application expect to be able to
> access OpenSSL's function, all were created independently - the top level
> app doesn't do SSL or crypto. at all - it just uses libraries that need to
> do SSL or crypto to function.

You've summarized my issue well :) This becomes a particular problem
when multiple threads are dlopen'ing plugins which link against OpenSSL
or libraries which do so. The initialization routines of the plugins now
have two choices: 1) Race to set the locking callbacks or 2) Don't set
the callbacks. Neither option is very desirable.

...


>
> So - even if you don't want to change the defaults - at least add an
> option to allow OpenSSL to be built with the system thread model by default
> so all those modern (but oh so ugly) apps can still run safely.

+1

Mark Phalan

unread,
Mar 29, 2010, 8:37:32 AM3/29/10
to
On 03/29/10 12:03 AM, Peter Waltenberg wrote:
> Historically I suspect the reason there were no default callbacks is that a
> sizeable proportion of OpenSSL users didn't use threading at all, and the
> baggage hauling in the thread libraries imposed was significant.
>
> I don't think that's an issue anymore - threading is the common case now.
>
> But - there's another issue you've all missed. You can have multiple
> independently developed libraries in the same process all using OpenSSL -
> who gets to set the thread callbacks ?. They have to be set to ensure
> thread safe operation, but no individual library can assume that "someone
> else" has done it now.
>
> Even better - a library does set the callbacks - and gets unloaded while
> other libs are still using OpenSSL. (Not just a "what if" - that one I've
> seen in the wild).
>
> So - yes, you probably do need to set the callbacks by default now, and you
> probably need to make that API a no-op as well.

I think making the API a no-op is probably not a good idea currently. I
recently saw an application (BIND) using the callbacks to gather
statistics. Breaking these sorts of applications is probably not
desirable. Also, if there are indeed performance issues as another
poster pointed out then it would be nice if applications had control to
re-set/disable the callbacks.

Tanguy Fautre

unread,
Mar 29, 2010, 9:24:24 AM3/29/10
to
Having read posts from this thread, I'd like to bring a few comments as a casual OpenSSL user.

My feeling is that OpenSSL approach to locking is quite different from other libraries and poorly documented. Combined, these two facts have caused most of our developers to completely miss the locking callbacks, even though they are working on a multithreaded application.

- The documentation about the lock callback is deeply buried and not clear. Such an important point as thread-safety should surely be one of the first documented points instead of being buried and scattered in the documentation.

- Even when aware of the lock callback mechanism, most of these developers assumed that the library was providing a default implementation. Only reading and testing the actual code proved otherwise. Again, the documentation should be made more explicit.

As some people have already mentioned, the fact that an application may use OpenSSL indirectly via one or several 3rd party libraries doesn't help (we've also experienced it, and I'll quote one member of our team in saying that it was "a total cluster fuck").


Considering all of the above, I think that the current OpenSSL design regarding locking is imperfect as it diverges too much from your typical library (and the developer's expectations). IMHO:

1/ Most developers expect a default implementation, and OpenSSL should provide it.

2/ The API should be simple for the majority of use cases, and be complex when things need to be complex.

3/ Documentation, documentation and documentation.

I don't buy too much into the performance argument. Most modern locking implementation are actually quite fast as long as there is no thread contention; therefore a single threaded application pays little performance for the locking. Plus, if you care about performance, you're likely going to go multithreaded (you wouldn't want all those cores on your CPU to go unused?).

Nowadays, most common platforms assume that an application is to be multithreaded by default (or even provide this as the only choice, for example there has not been a single-threaded runtime on Visual C++ for quite a while). In that regard, providing a default locking callback on most platforms seems like quite a sensible choice to me.

The default callback not always being the most suitable in all cases, yes you should be able to change it (cf. point 2).


Regards,

Tanguy


-----Original Message-----
From: owner-op...@openssl.org [mailto:owner-op...@openssl.org] On Behalf Of Mark Phalan
Sent: 25 March 2010 1:14 PM
To: opens...@openssl.org
Subject: libcrypto safe for library use?


The threads(3) manpage states that to use OpenSSL in multi-threaded
applications then locking callback functions must be set otherwise
random crashes may occur.

This poses a challenge when using OpenSSL in a library which should be
MT safe. There is no safe way to set the locking callbacks from within

the library itself. The calling application may or may not be using
OpenSSL or may be linking against multiple libraries some of which may
be linked against OpenSSL. The application may not even be aware that it

will end up calling into OpenSSL code.

The only safe way to ensure that the OpenSSL code will be MT safe would
be for the OpenSSL library itself to set locking callbacks, however I
don't see any compile-time option to do that.

Is there a reason I'm missing as to why this option isn't available?

Without this, the library can do its best to set the locking callbacks

when loaded if they are not set and then remove them when unloaded,
however this will always be inherently racy if there are other parts of
the process using OpenSSL.

Thanks,

Dr. Stephen Henson

unread,
Mar 29, 2010, 9:55:36 AM3/29/10
to
On Mon, Mar 29, 2010, Tanguy Fautre wrote:

>
> - The documentation about the lock callback is deeply buried and not clear.
> Such an important point as thread-safety should surely be one of the first
> documented points instead of being buried and scattered in the
> documentation.
>

Erm it is first referenced in the FAQ:

http://www.openssl.org/support/faq.html#PROG1

Steve.
--
Dr Stephen N. Henson. OpenSSL project core developer.
Commercial tech support now available see: http://www.openssl.org

Howard Chu

unread,
Mar 29, 2010, 10:11:10 AM3/29/10
to
Patrick Patterson wrote:
> Peter:

>
> On 29/03/10 1:15 AM, Peter Waltenberg wrote:
>>
>> Sure - it works if you have a simple application, main -> OpenSSL
>> even main ->lib doing SSL -> OpenSSL still works.
>>
>> What's giving us grief (and I suspect the person who first raised this
>> grief) is:
>> main -> lib that needs SSL to do client server comms -> OpenSSL
>> -> Another lib that does client server comms. ->OpenSSL
>> -> Another lib that does crypto ->OpenSSL
>>
>> All the libraries of the big fat composite application expect to be able to
>> access OpenSSL's function, all were created independently - the top level
>> app doesn't do SSL or crypto. at all - it just uses libraries that need to
>> do SSL or crypto to function.
>>
> This is a rather specious argument - if an application uses SSL at the
> lower layers, there has to be some method for that application to at
> least tell OpenSSL which CA Certificates to use - and yes, it COULD have
> a wrapper/higher level lib that sets up those locations (like I think
> OpenLDAP can), but I would consider that a HORRIBLE design flaw of that
> higher library to not expose SOME method to set the trust store (and
> revocation information, etc.) globally for the application - otherwise,
> in the situation that you mention, the poor admin COULD end up with an
> application where it is almost impossible to troubleshoot why certain
> connections are failing i.e.: Why do my LDAPS connections work, but my
> HTTPS don't? (assuming that LDAP is provided by one lib, and HTTP by
> another). So I would argue that it is the higher level libs problem to:
>
> 1: Set threading correctly and consistently on all of it's SUB library
> dependencies with the model the higher level app tells it to.
>
> 2: Expose enough controls that allow for a higher level app to set keys,
> cert stores, and revocation information locations.
>
> If those libraries DON'T do both of the above (and OpenSSL can certainly
> accommodate both today), then the bugs/feature requests to enable both
> of these functionalities should be filed there.
>
> I'm not one of the "core" devels, but this is just my 0.02 worth.

Since we're using OpenLDAP as an example, I'll note - libldap_r's original
raison'd'etre was to provide threading in slapd. It was never intended for use
by 3rd party code; there is no IETF specification for thread support in the
LDAP C API and we've never advertised or documented libldap_r as anything
other than an OpenLDAP-specific (i.e., non-standard) library. So yes, in this
case, libldap_r was written with certain assumptions (that the threading model
is known, that it won't be unloaded while running, etc...) and it's only known
to behave correctly within those assumptions.

To your point about providing APIs to set the trust store globally for the
application: in a word, No.

libldap provides APIs to set up all the required trust settings, for a
particular SSL_CONTEXT. It initializes a single context for itself, and
typically this single context was used implicitly by any application that used
libldap (including slapd). Nowadays slapd uses one context for its main
listener, and can use a separate context for each of several other cases -
proxy sessions, replication tasks, etc. The fact is that slapd is often used
as an LDAP gateway, between unsafe external networks and brain-damaged
internal LDAP servers that aren't robust enough to face a real network on
their own. In a situation where it must act as a server on one side and as a
client on the other side, you very often need separate and distinct trusts /
policies in each role.

So regarding your comment about ldaps sessions working, but https sessions not
- that may seem like a hassle, but it's as it should be. Each protocol and
each usage of the protocol has to be able to operate in its own distinct
context. They must be able to have their security policies configured
separately. The fact that OpenSSL supports this in its most common usage is
one of its real strengths. (It is still pretty much impossible to handle this
type of requirement using e.g. Mozilla NSS.)

* most basic example: when using certificate-based authentication, typically
a server only needs to trust a single CA - the one that issued its own cert
and all of the users' certs. On the flip side, clients tend to need to be able
to talk to multiple servers, in multiple authentication realms. As such they
tend to need to be configured with many trusted CAs. When you have a single
process that can take on both server and client roles simulataneously, OpenSSL
handles the situation easily. Other SSL libraries ... not so much...
--
-- Howard Chu
CTO, Symas Corp. http://www.symas.com
Director, Highland Sun http://highlandsun.com/hyc/
Chief Architect, OpenLDAP http://www.openldap.org/project/

David Schwartz

unread,
Mar 29, 2010, 2:20:55 PM3/29/10
to
Mark Phalan wrote:

> I'm just suggesting a compile-time option. The application could always
> set the locking callbacks back to NULL if it knew what it was doing.
>
> -M

I think this fix is actually a bad one. Will existing libraries continue to
not set the locking callbacks and fail horribly if the system OpenSSL isn't
compiled with this flag? Or will they set sane locking callbacks to be safe
-- making this fix a no-op?

The issue is that existing code may set the locking callbacks badly and the
horse has already left the stable (we can't redesign them). I don't see how
this helps in that case -- the existing code will continue to set the
locking callbacks badly, overriding the sane default.

DS

Mark Phalan

unread,
Mar 29, 2010, 3:38:27 PM3/29/10
to
On 29 Mar 2010, at 20:20, David Schwartz <dav...@webmaster.com> wrote:

> Mark Phalan wrote:
>
>> I'm just suggesting a compile-time option. The application could
>> always
>> set the locking callbacks back to NULL if it knew what it was doing.
>>
>> -M
>
> I think this fix is actually a bad one.

I'm still not clear why you think that.

> Will existing libraries continue to
> not set the locking callbacks and fail horribly if the system
> OpenSSL isn't
> compiled with this flag?
> Or will they set sane locking callbacks to be safe
> -- making this fix a no-op?

Even without the proposed change libraries should at least check
before clobbering the existing callbacks. Checking before setting will
be racy but still better than blindly replacing callbacks.

The proposal doesn't make anything worse it 1) removes the race if
libraries set the callbacks properly and 2) fixes MT issues if they
don't.
Of course there is always the problem of what happens on dlclose() of
the lib if the callbacks are set...


> The issue is that existing code may set the locking callbacks badly
> and the
> horse has already left the stable (we can't redesign them).

We can't easily get all the libraries which might end up eventually
loading OpenSSL to change their APIs so that locking callbacks can be
set but I think it wouldn't be too difficult to get them to do a check
for existing callbacks before doing the set.
Libraries which don't set the callbacks immediately become MT safe (as
far as OpenSSL calls are concerned).

> I don't see how
> this helps in that case -- the existing code will continue to set the
> locking callbacks badly, overriding the sane default.

Indeed. Until those are changed they will be broken both now and
after the proposed change. The proposal offers a sane way out.

-M

Darryl Miles

unread,
Mar 29, 2010, 6:45:03 PM3/29/10
to
Mark Phalan wrote:
> On 29 Mar 2010, at 20:20, David Schwartz <dav...@webmaster.com> wrote:
>
>> Will existing libraries continue to
>> not set the locking callbacks and fail horribly if the system OpenSSL
>> isn't
>> compiled with this flag?
>> Or will they set sane locking callbacks to be safe
>> -- making this fix a no-op?
>
> Even without the proposed change libraries should at least check before
> clobbering the existing callbacks. Checking before setting will be racy
> but still better than blindly replacing callbacks.
>
> The proposal doesn't make anything worse it 1) removes the race if
> libraries set the callbacks properly and 2) fixes MT issues if they don't.
> Of course there is always the problem of what happens on dlclose() of
> the lib if the callbacks are set...

Having thought about the problem a little more.

There is no reason for it to be racy if you make use of the locking
implementation either already set or being passed. One thing for sure
there is some kind of valid locking mechanism to use, so make use of the
first available lock id slot for the purpose of managing the getting and
setting of the locking mechanism in a re-entrant thread-safe manner.

There should also be a reference counting mechanism, so any users who
set the locking up should also unset the locking via reference counting.
I agree that the concept of stacking and restoring the locking
mechanism (that has been suggested) is bogus and can not work but the
concept of the "first users wins" can work.

The first user to setup should get an indication back that it is so.

The last user to unset should get an indication back that is it so.

There needs to be a test, test-and-set and set operations on the locking
that are individually atomic and re-entrant thread-safe. (by making use
of the locking mechanism setup). There is no need for the 'test' and
'set' operations to be separate from the 'test-and-set' since one API
call can achieve all purposes, just like Unix signal handler setup
sigaction(2) does inside the kernel.

There should be an OpenSSL provided API call that sets up the locking to
a default implementation for the platform, or else it returns an error
return indicating OpenSSL was not compiled with any default
implementation (for your platform) which would force the caller to
address this matter within their own platform. Addressing it can be
done via patching future versions of OpenSSL or to provide their own
from their application.


I disagree that it is a bad idea to think about it now. Yes the horse
has bolted in respect of the number of application out there which are
open to the risk of failure due to this. So with that in mind there is
no reason not to consider what the correct future proof solution is even
if that means API breakage to force all applications to reconsider this
problem and bully them into consensus that the OpenSSL provided solution
will be good enough for most.

This means symbol changes and clear documentation on how to transition
with example code to make the application maintainers job easier. Make
the solution an easy 15 minute exercise to understand and read up about
and then modify their code base and I'm sure you can win the hearts and
minds of those using OpenSSL that it was a matter that needed to be
address with a small amount of breakage.


Darryl

David Schwartz

unread,
Mar 30, 2010, 3:16:21 PM3/30/10
to

Mark Phalan wrote:

> > In this case, I presume 'pkinit' only supports one threading model
> > (or one
> > set of compatible threading models). So it can set the callbacks.

> It can set the callbacks but it can't set them in a way which is safe
> from races.

It can set them before it performs any OpenSSL operations. How is that not
safe from races?


> > Then set default callbacks in your code that calls OpenSSL. OpenSSL
> > can't do
> > it, because it has no idea what threading models your code uses.

> Perhaps I don't understand exactly what you mean by "threading model".
> Are you referring to 1:1, n:1 etc?

That's part of it. It's also what threading library you are using.

> I think it would be reasonable for OpenSSL as delivered with an OS to
> use the native threading model of the OS. Is there something I'm
> missing?

If you only support one threading model, there's no problem. Just set
callbacks that are safe for that threading model before you use OpenSSL.



> > If the horse has left the stable and the code supports more than one
> > threading model, then the problem is provable insolvable. There is
> > simply no
> > way for OpenSSL to know what kind of locks are adequate. If your code
> > supports only one threading model, then you can tell OpenSSL this by
> > setting
> > the callbacks.

> What I could do is say that when delivered as part of OpenSolaris
> OpenSSL assumes the OS's threading model. If an application wants to
> change that they the application should set its own callbacks.

If that's what you want, it's trivial to implement. Simply set callbacks
that are safe for the OS' threading model before you call any OpenSSL
functions.



> Just to be totally clear. All I'd like to see is a compile-time option
> (it can be disabled by default) to set a default set of locking
> callbacks native to the OS it's compiling on. I'm not suggesting that
> the ability to set locking callbacks be removed.

If you are able to craft a default set of locking callbacks that are safe
for your application, then do so and set them. I don't see what assistance
you need from OpenSSL. If that is your case, your solution is trivial -- set
those callbacks. If you know they're safe, set them.

> > Since libldap_r knows what threading model the application is using,
> > it can
> > do this. OpenSSL doesn't know, so it can't do this.

> It can do this but only by potentially introducing a race.

What is the race exactly? If they're already set, setting them again to
precisely the same callbacks is harmless. And if the problem is an
application setting them to different callbacks, OpenSSL can't help you --
if an application changes the callbacks from the default to unsafe
callbacks, you're still hosed.

Existing code that uses OpenSSL will still change those callbacks from the
defaults. New applications that don't use OpenSSL at all won't be affected
by the change. New libraries could just as easily be coded to always set
known safe callbacks.

There is only a race if some application either reverts to no callbacks or
sets unsafe callbacks. Both of those operations will still be fatal with the
suggested change.

DS

David Schwartz

unread,
Mar 30, 2010, 3:25:24 PM3/30/10
to

Mark Phalan wrote:

> On 29 Mar 2010, at 20:20, David Schwartz <dav...@webmaster.com> wrote:

> > Mark Phalan wrote:
> >
> > I think this fix is actually a bad one.

> I'm still not clear why you think that.

Because it doesn't solve the problem case -- where one library user sets
callbacks that another library user isn't happy with. It won't help existing
code, because it will already set callbacks (or it's hopelessly broken). It
might help new code, but if we're going to help new code, we should do it a
better way.

> Even without the proposed change libraries should at least check
> before clobbering the existing callbacks. Checking before setting will
> be racy but still better than blindly replacing callbacks.

I don't get what is this race you see. Are you talking about libraries that
unset the OpenSSL callbacks while another library running in the same
application might be using OpenSSL? That would still be fatal, and can never
be made to work anyway.



> The proposal doesn't make anything worse it 1) removes the race if
> libraries set the callbacks properly

How is that? I don't see how it removes the race. There are two cases for
existing code:

1) They all set callbacks that are 100% compatible -- in which case there
never was any race to fix.

2) Some of them set callbacks that are not 100% compatible with the
callbacks others set -- in this case, there's still a race.

> and 2) fixes MT issues if they
> don't.

If they don't set locking callbacks where such is clearly documented to be
required, they're so hopelessly broken there's no point in trying to fix
them in OpenSSL. What other requirements do they ignore?

> Of course there is always the problem of what happens on dlclose() of
> the lib if the callbacks are set...

You can't shutdown a library while another library in that same application
is or might be using it. It will never be possible to make that work. Again,
that would be such hopelessly broken behavior that there's no point in
trying to fix it for existing libraries/applications. A sensible way to fix
it for new applications/libraries might make sense.



> > The issue is that existing code may set the locking callbacks badly
> > and the
> > horse has already left the stable (we can't redesign them).

> We can't easily get all the libraries which might end up eventually
> loading OpenSSL to change their APIs so that locking callbacks can be
> set but I think it wouldn't be too difficult to get them to do a check
> for existing callbacks before doing the set.
> Libraries which don't set the callbacks immediately become MT safe (as
> far as OpenSSL calls are concerned).

For new implementations, then best solution is an OpenSSL wrapper that can
arbitrate when OpenSSL needs to be loaded and unloaded and who is using it.
This could certainly be built into OpenSSL. But I don't think it would help
existing applications unless they at least make some kind of 'add OpenSSL
user' and 'remove OpenSSL user' kind of call.



> > I don't see how
> > this helps in that case -- the existing code will continue to set the
> > locking callbacks badly, overriding the sane default.

> Indeed. Until those are changed they will be broken both now and
> after the proposed change. The proposal offers a sane way out.

If we're talking about fixing it for new code, I think either an OpenSSL
wrapper library, OpenSSL wrapper support in the application, or an 'add
OpenSSL user'/'remove OpenSSL user' function in OpenSSL is the right way to
go.

Darryl Miles

unread,
Mar 30, 2010, 5:00:41 PM3/30/10
to
David Schwartz wrote:
> Mark Phalan wrote:
>
>>> In this case, I presume 'pkinit' only supports one threading model
>>> (or one
>>> set of compatible threading models). So it can set the callbacks.
>
>> It can set the callbacks but it can't set them in a way which is safe
>> from races.
>
> It can set them before it performs any OpenSSL operations. How is that not
> safe from races?

Still don't get it. Lets use Linux as an example.

You have a top level executable whose only runtime linked libraries are
"libc", "libdl", "libpthread". This library from 3 independent threads
decides it needs to dynamically load via the libdl API call "dlopen()"
the following libraries:

"libldap_r" (this in turn has a runtime library dependency on
"libcrypto" "libssl" amongst other DSOs).

"libcurl" (this in turn has a runtime library dependency on "libcrypto"
"libssl" amongst other DSOs).

"libstunnel" (this in turn has a runtime library dependency on
"libcrypto" "libssl" amongst other DSOs).

There are less contrived cases; Perl and Python built into executables
that in turn link with OpenSSL as well.

The top level application doesn't even know OpenSSL exists. It doesn't
care that is exists, since the API contract is has relates to some other
functionality.


The dynamic linker will de-duplicate the DSO being loaded, so when
"libcrypto" is loaded for the 2nd time it will realize it is already
loaded and reference count it up one and hand the same DSO address to
each of the 3 callers to share. Since that is the point of DSOs.

How does each of the 3 threads arbitrate in a thread-safe manner the
initialization of the OpenSSL related libraries. How does any one of
them know it is the "first user" ?

Once each of the 3 users has finished using their copy of OpenSSL they
can request the dynamic linker unload it "dlclose()". So it is also
necessary for OpenSSL to know when the last user has closed the library
and it needs to perform memory freeing and cleanup because there are no
users left. How does any one of them know it is the "last user" ?

I think these cases should have equal merit, if you are going to fix the
load case you must also fix the unload case.


Now you can re look at the problem and simplify it on the basis what can
be do if we know its a single thread. Then from that vantage point work
out what small areas of the process need to be protected.

If you ask me the dynamic linker should provide support for this issue
itself, the ability to embed a control block in the executable that
provides callbacks with the dynamic linker providing serialization of
running those callback and exposing the most basic locking primitives
(mutex) for use only from inside those callbacks.

Windows provides this infrastructure already, _DllMain symbol and the
fact that all platform provide access to the Windows API and the mutex
system calls are available. Maybe open source systems do as well but we
are just not aware of the hooking mechanism in this list.

The issue is we don't want the thread-aware code to manage this in the
OpenSSL DSOs since that will mess up the single-thread (thread unaware)
users of OpenSSL. This also means we don't want a runtime linker
dependancy on libpthread just for this purpose (libcrypto currently
doesn't have one, libssl does).

Since the thread locking primitives needs to be provided by the platform
and this is a linker caused issue, it is the dynamic link that should
provide the mechanism to clean up this mess.

This effectively becomes imposed baggage by the dynamic linker due to
_SOME_ users being multi-threaded users (as well as allowing the linker
freedom to load dependancies on a whim).


>> Perhaps I don't understand exactly what you mean by "threading model".
>> Are you referring to 1:1, n:1 etc?
>
> That's part of it. It's also what threading library you are using.

You can still have a "default theading model" and still support all
"known threading models" via reconfiguration before first use. There is
no conflict here please stop implying there is one.


>> What I could do is say that when delivered as part of OpenSolaris
>> OpenSSL assumes the OS's threading model. If an application wants to
>> change that they the application should set its own callbacks.
>
> If that's what you want, it's trivial to implement. Simply set callbacks
> that are safe for the OS' threading model before you call any OpenSSL
> functions.

This is exactly where the issue lies. We know we need to do this
(please stop repeating back to us that this is what we need to do).

The issue is we can not do this in a thread-safe manner since:
* The dynamic linker provides no arbitration (this is who I really blame)
* OpenSSL the library provides no arbitration (due to it having a
single thread / thread unaware use case).


>> Just to be totally clear. All I'd like to see is a compile-time option
>> (it can be disabled by default) to set a default set of locking
>> callbacks native to the OS it's compiling on. I'm not suggesting that
>> the ability to set locking callbacks be removed.

The real resistance to this Mark, is the fact you are now forcing a
dependency on libpthread for libcrypto which didn't exist before.

Yes I know the single threaded users (thread unaware users) can
recompile a special version for their own use but this still poses a
problem relating to the DSO name of the library and that fact you are
impacting their support issues in the future (for your gain).

Maybe what would be better is a libcrypto_r and a libssl_r de-facto
standard where multi-threaded support is a requirement and override-able
default implementation was already setup to go ?

This does not mean we should not fix the real issue, it is just a naming
work around until that point in time. This is more a packaging issue
than a OpenSSL developer issue.

>> It can do this but only by potentially introducing a race.
>
> What is the race exactly? If they're already set, setting them again to
> precisely the same callbacks is harmless.

Just because you have the "same threading model" doesn't mean you are
using the same threading primitive symbols.

Managing to publish and agree across many projects the exist symbols and
use of OpenSSL is a problem that is completely avoided by better
engineering. Trying to push out the solution to a "social" issue will
not guarantee a solution.

> And if the problem is an
> application setting them to different callbacks, OpenSSL can't help you --
> if an application changes the callbacks from the default to unsafe
> callbacks, you're still hosed.

This appears to be the point where we disagree. Many including mysely
are claiming that OpenSSL (or rather I am claiming the "dynamic linker")
_SHOULD_ be helping us.

You are correct in that currently OpenSSL can't help us, but this is why
we have a discussion here to resolve that.


> Existing code that uses OpenSSL will still change those callbacks from the
> defaults. New applications that don't use OpenSSL at all won't be affected
> by the change. New libraries could just as easily be coded to always set
> known safe callbacks.
>
> There is only a race if some application either reverts to no callbacks or
> sets unsafe callbacks. Both of those operations will still be fatal with the
> suggested change.

Setting the callback(s) is unsafe. Since another thread might be using
them. Do you not get that ? There is no locking around the setting of
them so therefore they are thread-unsafe, the method to set locking is
not re-entrant. I harp back to my request for "re-entrant thread-safe
OpenSSL APIs" for setting up the threading callbacks.

Of course if the compiler generates code that does a single instruction
store (of the native platform bit-width) of the same value over and
over, no other thread will ever observe any change in that memory
location. The point of the matter is there is no guarantee's provided
by the compiler over how it goes about doing that so in order to get an
engineering guarantee as required to be thread-safe a mutex would
provide assurance.

This ignores other issues that are implementation details to outside
users of OpenSSL what else is going on inside those OpenSSL API calls
that isn't expected to be called from other threads at the same time.

The API could work like a hybrid sigaction() allowing
get-and-test-and-set in one atomic operation. This will require
libpthread runtime linkage in libcrypto.


Darryl

Howard Chu

unread,
Mar 30, 2010, 6:04:39 PM3/30/10
to
Darryl Miles wrote:
> David Schwartz wrote:
>> Mark Phalan wrote:
>>
>>>> In this case, I presume 'pkinit' only supports one threading model
>>>> (or one
>>>> set of compatible threading models). So it can set the callbacks.
>>
>>> It can set the callbacks but it can't set them in a way which is safe
>>> from races.
>>
>> It can set them before it performs any OpenSSL operations. How is that not
>> safe from races?
>
> Still don't get it. Lets use Linux as an example.

This is actually one of the easiest to solve. Of course the bigger problem is
that solutions here are all platform-dependent, and maintenance will be a pain.

ELF shared libraries support .init and .fini sections to contain code that
should be executed just after load and just before unload. Assuming you had a
default set of callbacks in the library, it would be simple to set them here.
Likewise any other shared library that manipulates callbacks can do its own
cleanup safely in their own .fini section.

The other feature you need, to make this reasonable, is support for weak
external symbols. I don't know of any compiler support for these but certainly
they're supported at the assembler and linker level. The default callbacks
should reference pthread functions as weak externs, and just no-op if the
externs are unresolved at runtime.

As an aside, it's probably still unsafe to assume any particular thread model,
on any OS. Third party thread libraries are still out there that run
cross-platform (e.g. GNU Pth).

--
-- Howard Chu
CTO, Symas Corp. http://www.symas.com
Director, Highland Sun http://highlandsun.com/hyc/
Chief Architect, OpenLDAP http://www.openldap.org/project/

Darryl Miles

unread,
Mar 30, 2010, 6:53:05 PM3/30/10
to
Howard Chu wrote:

> Darryl Miles wrote:
>> Still don't get it. Lets use Linux as an example.
>
> This is actually one of the easiest to solve. Of course the bigger
> problem is that solutions here are all platform-dependent, and
> maintenance will be a pain.
>
> ELF shared libraries support .init and .fini sections to contain code
> that should be executed just after load and just before unload. Assuming
> you had a default set of callbacks in the library, it would be simple to
> set them here. Likewise any other shared library that manipulates
> callbacks can do its own cleanup safely in their own .fini section.
>
> The other feature you need, to make this reasonable, is support for weak
> external symbols. I don't know of any compiler support for these but
> certainly they're supported at the assembler and linker level. The
> default callbacks should reference pthread functions as weak externs,
> and just no-op if the externs are unresolved at runtime.

Since a dynamic linker requires the use of threading primitives (mutexes
and such) internally (if itself supports multi-threaded usage) it is
highly likely it has access to an implementation to advise from the
.init and .fini.

So the next matter would be for the .init and .fini functions to provide
a reference back to the dynamic linker as an argument when those
callbacks get invoked. I shall call this the "module handle".

From this "module handle" the dynamic linker needs to provide API
accessible implementations for:
* Symbol lookup (maybe this is already extern and implicitly available
to all DSOs)
* Mutex API (init, lock, unlock, trylock, end, sizeof())
* Reference counting increment/decrement API (init, increment,
decrement, end, sizeof()) - To be honest this can be written on top of
a mutex, everything can be built on top of a working mutex, but exposing
an API for something obviously useful here might stop wheel reinvention!

[FWIW - The sizeof() relates to the amount of space required for opaque
storage, in the interests of future proofing and the fact these are not
performance implementations more space than is required should be
reserved and 64bit should be reserving double the amount 32bit does]


Just to reiterate the major point of this reply ... THE DYNAMIC LINKER
NEEDS TO PROVIDE API ....


What I think I need to clarify is that from the module's point of view
it is the dynamic linker which is providing the implementations, not
libpthread. The fact these function pointers may directly access an
already mapped copy of similar libpthread function/symbols in some
platforms should be treated as a coincidence. Infact I would probably
advocate not doing that and having libdl at least use a delegation
pattern internally to allow a shim layer to iron out minor differences
between APIs (the mutex API is exposes and the mutex API is consumes).

I'm trying to remove the notion of a "symbol" out of it, since the
module (OpenSSL) can not assume any particular mutex implementation such
as POSIX Threads. It doesn't matter what the implementation is it just
needs an API provided by the dynamic linker. This means OpenSSL doesn't
directly access POSIX Thread definitions at compile time for this
purpose, it references some definitions supplied by <dlfcn.h>.


If you start using weak symbols, then you end up down the route of
making OpenSSL responsible for knowing about and at runtime trying to
detect which mutex implementation exists and is available. This is the
whole matter I'm trying to clearly push back to the dynamic linker.
This is not OpenSSL's problem!

Darryl Miles

unread,
Mar 30, 2010, 8:42:55 PM3/30/10
to
Howard Chu wrote:
> ELF shared libraries support .init and .fini sections to contain code
> that should be executed just after load and just before unload. Assuming
> you had a default set of callbacks in the library, it would be simple to
> set them here. Likewise any other shared library that manipulates
> callbacks can do its own cleanup safely in their own .fini section.

We could be in luck on this point, in that if the dynamic linker already
arbitrates the execution of .init/.fini sections by enforcing a
single-threaded model then the code within the section does not need to
be thread aware.

Now the next issue remains. Adding a new runtime dependency to
libcrypto.so on the platforms native threading implementation.

This is a issue since it is currently clean and some voices want to keep
it so (seemly even for platforms where multi-thread library support is
the norm and the most popular usage pattern on that platform).

It does seem that glibc can keep libpthread out of the mandatory
dependencies, I can only guess this is because it implements system
calls internally that can be built on top of to implement its own
locking requirements. Just the kind of thing it can do but other
libraries don't want to do.

So again back to the packaging idea could a libcrypto_r be created,
which is just a stub DSO.
* It has a mandatory dependency on libcrypto.
* It may have a mandatory dependency on libpthread (or whichever
platform threading library is in use) or it may detect and load at runtime.
* It re-exports all the libcrypto symbols (so the application doesn't
need to link against libcrypto directly at build link time).
* It adds the necessary .init/.fini stuff.
* It can even encapsulates some libcrypto API calls as necessary to
provide a change in policy.


Maybe this is the solution you were alluding to Howard ?


> As an aside, it's probably still unsafe to assume any particular thread
> model, on any OS. Third party thread libraries are still out there that
> run cross-platform (e.g. GNU Pth).

On this kind of subject libcrypto_r would need to provide a documented
way to override the assumed default. However how to do this without
relying on using either of them is another headache. I'm thinking
environment variables, configuration files, file existence tests and
other such ways to configure a DSO at runtime.

This is only an issue if the different threading libraries are used in
incompatible ways and/or if the expected default implementation is not
available on the platform.

For example there can many implementations of spinlocks within a single
application that all co-exist, fewer mutex implementations and fewer
still; ways to manage the creation of threads.

David Schwartz

unread,
Mar 30, 2010, 9:07:33 PM3/30/10
to
Darryl Miles wrote:

> How does each of the 3 threads arbitrate in a thread-safe manner the
> initialization of the OpenSSL related libraries. How does any one of
> them know it is the "first user" ?

For existing code, there is no fix. They will set incompatible callbacks and
they will break. I don't see anything OpenSSL can do to fix this other to
implement default callbacks and to claim attempts to change the callbacks
succeeded while silently failing them.



> Once each of the 3 users has finished using their copy of OpenSSL they
> can request the dynamic linker unload it "dlclose()". So it is also
> necessary for OpenSSL to know when the last user has closed the library
> and it needs to perform memory freeing and cleanup because there are no
> users left. How does any one of them know it is the "last user" ?

This is a great example of a case where OpenSSL should be wrapped. Again, I
don't think you can fix existing code. It's already going to do the wrong
thing, for example, shutting down OpenSSL. (Unless you want to make OpenSSL
shutdown functions silently do nothing but claim success.)



> You can still have a "default theading model" and still support all
> "known threading models" via reconfiguration before first use. There
> is
> no conflict here please stop implying there is one.

That's what we have now. The "default threading model" is single-threaded.
Others are supported by reconfiguration before first use.

> Setting the callback(s) is unsafe. Since another thread might be using
> them. Do you not get that ? There is no locking around the setting of
> them so therefore they are thread-unsafe, the method to set locking is
> not re-entrant. I harp back to my request for "re-entrant thread-safe
> OpenSSL APIs" for setting up the threading callbacks.

I agree, but I don't think there's anything we can do to help existing code.
Existing code already does the wrong thing. I suggested a "register OpenSSL
user" and "deregister OpenSSL user" function which permits the user to
specify the threading model it's using and trigger a reference count.
(Overlapping callers with different threading models would result in an
error.)

I don't think you can avoid a dependency on the system threading library
though, but I don't see why that would be an issue. Many single-threaded
programs wind up requiring the threading library on many platforms anyway as
it may contain functions like 'clock_gettime' or 'sched_yield'. (Does anyone
know of a platform where this is a problem?)

DS

Peter Waltenberg

unread,
Mar 30, 2010, 10:03:17 PM3/30/10
to
"
I don't think you can avoid a dependency on the system threading library
though, but I don't see why that would be an issue. Many single-threaded
programs wind up requiring the threading library on many platforms anyway
as
it may contain functions like 'clock_gettime' or 'sched_yield'. (Does
anyone
know of a platform where this is a problem?)
"

Alas, yes HP/UX.
Link code built threaded and code built unthreaded on that platform and
your application dies a horrible death.


Peter


From: "David Schwartz" <dav...@webmaster.com>

To: <opens...@openssl.org>

Cc: <Mark....@Sun.COM>

Date: 31/03/2010 11:37 AM

Subject: RE: libcrypto safe for library use?

Sent by: owner-op...@openssl.org

Howard Chu

unread,
Mar 30, 2010, 10:01:19 PM3/30/10
to
Peter Waltenberg wrote:
> "
> I don't think you can avoid a dependency on the system threading library
> though, but I don't see why that would be an issue. Many single-threaded
> programs wind up requiring the threading library on many platforms anyway
> as
> it may contain functions like 'clock_gettime' or 'sched_yield'. (Does
> anyone
> know of a platform where this is a problem?)
> "
>
> Alas, yes HP/UX.
> Link code built threaded and code built unthreaded on that platform and
> your application dies a horrible death.

This used to be a problem on Solaris too (at least SunOS 5.6 thru 5.8) but I
don't know if it still is. We ran into it all the time when configuring
LDAP-enabled authentication; the CDE login would crash if you didn't build
pam_ldap, nss_ldap, and libldap *just right*... The CDE libraries came along
with a malloc wrapper, and mixing threaded+nonthreaded code would bring in two
different malloc implementations. Instant death.

--

-- Howard Chu
CTO, Symas Corp. http://www.symas.com
Director, Highland Sun http://highlandsun.com/hyc/
Chief Architect, OpenLDAP http://www.openldap.org/project/

David Schwartz

unread,
Mar 31, 2010, 3:17:07 AM3/31/10
to

P Kamath wrote:

> "
> I don't think you can avoid a dependency on the system threading
> library
> though, but I don't see why that would be an issue. Many single-
> threaded
> programs wind up requiring the threading library on many platforms
> anyway
> as
> it may contain functions like 'clock_gettime' or 'sched_yield'. (Does
> anyone
> know of a platform where this is a problem?)
> "

> Alas, yes HP/UX.
> Link code built threaded and code built unthreaded on that platform and
> your application dies a horrible death.

That's not a problem. On those platforms, you have to a single-threaded and
a multi-threaded build of the library anyway. The single-threaded build
requires no thread safety features. The multi-threaded build can safely
refer to symbols in the threading library. The problem case would be a
platform where you could have code that was safe to use in both
single-threaded and multi-threaded applications, but it would cause an issue
(for single-threaded applications/libraries) if it referenced symbols in the
threading library (but didn't call them at run time).

DS

Mark Phalan

unread,
Mar 31, 2010, 6:42:44 AM3/31/10
to
On 03/30/10 09:16 PM, David Schwartz wrote:
>
> Mark Phalan wrote:
>
>>> In this case, I presume 'pkinit' only supports one threading model
>>> (or one
>>> set of compatible threading models). So it can set the callbacks.
>
>> It can set the callbacks but it can't set them in a way which is safe
>> from races.
>
> It can set them before it performs any OpenSSL operations. How is that not
> safe from races?

I think Darryl answered that.

>
>
>>> Then set default callbacks in your code that calls OpenSSL. OpenSSL
>>> can't do
>>> it, because it has no idea what threading models your code uses.
>

>> Perhaps I don't understand exactly what you mean by "threading model".
>> Are you referring to 1:1, n:1 etc?
>
> That's part of it. It's also what threading library you are using.
>

>> I think it would be reasonable for OpenSSL as delivered with an OS to
>> use the native threading model of the OS. Is there something I'm
>> missing?
>
> If you only support one threading model, there's no problem. Just set
> callbacks that are safe for that threading model before you use OpenSSL.
>

(Speaking as someone who cares mostly about OpenSolaris)
I think the special-case here is when someone decides not to use the OS
threading model. In that case the application can simple set the
callbacks replacing the ones automatically set.

...


>> Just to be totally clear. All I'd like to see is a compile-time option
>> (it can be disabled by default) to set a default set of locking
>> callbacks native to the OS it's compiling on. I'm not suggesting that
>> the ability to set locking callbacks be removed.
>

> If you are able to craft a default set of locking callbacks that are safe
> for your application, then do so and set them. I don't see what assistance
> you need from OpenSSL. If that is your case, your solution is trivial -- set
> those callbacks. If you know they're safe, set them.

I see no problem with applications. The problem only arises with
libraries linking against OpenSSL, especially when they are dlopen'ed
and the application isn't even aware of that that is happening and the
application isn't already using OpenSSL.

To use an example a colleague pointed out to me recently:
Application calls getpwnam()
getpwnam -> nsswitch -> dlopen nsswitch_ldap ->
ldap uses SSL -> libssl
ldap uses SASL ->
libsasl -> GSS-API
libgss -> Kerberos
dlopen mech_krb -> dlopen pkinit
pkinit -> OpenSSL libcrypto

..


>
> There is only a race if some application either reverts to no callbacks or
> sets unsafe callbacks. Both of those operations will still be fatal with the
> suggested change.

Imagine the above case happening in one thread while another thread
makes a similar seemingly innocuous call with a similar effect (dlopen a
library which uses OpenSSL). What should pkinit and the second library
which uses OpenSSL do? If they set callbacks they'll be racing against
each other. If they don't they will not be MT safe.
The application never sets the callbacks because as far as it's aware
it's only calling POSIX APIs.

-M

David Schwartz

unread,
Mar 31, 2010, 7:14:36 AM3/31/10
to

Mark Phalan wrote:

> Imagine the above case happening in one thread while another thread
> makes a similar seemingly innocuous call with a similar effect (dlopen
> a
> library which uses OpenSSL). What should pkinit and the second library
> which uses OpenSSL do? If they set callbacks they'll be racing against
> each other. If they don't they will not be MT safe.
> The application never sets the callbacks because as far as it's aware
> it's only calling POSIX APIs.

If we're talking about existing code, they *must* already set callbacks,
otherwise they're hopelessly broken. Since the setting of callbacks will
unsafely override the set defaults, the suggested fix (to default to
callbacks suitable for the platform's default threading model) actually will
*not* fix this case. If this is the case we care about, why implement a fix
that won't fix this case?

The purported advantage of this fix is that it solves the "horse has already
left the stable" case where we aren't willing to change the libraries that
call OpenSSL. But it doesn't fix that case.

The only way to fix that case that I can think of is for OpenSSL to start
out using callbacks that are safe for the platform's default threading API
and to ignore, but report success, on all attempts to change the locking
callbacks. That may actually be the right behavior for the existing API.
(And, of course, OpenSSL would implement a newer, better API that new
applications and libraries should use that would include reference counting
and being informed of the threading model in use.)

DS

Mark Phalan

unread,
Mar 31, 2010, 7:26:29 AM3/31/10
to
On 03/31/10 01:14 PM, David Schwartz wrote:
>
> Mark Phalan wrote:
>
>> Imagine the above case happening in one thread while another thread
>> makes a similar seemingly innocuous call with a similar effect (dlopen
>> a
>> library which uses OpenSSL). What should pkinit and the second library
>> which uses OpenSSL do? If they set callbacks they'll be racing against
>> each other. If they don't they will not be MT safe.
>> The application never sets the callbacks because as far as it's aware
>> it's only calling POSIX APIs.
>
> If we're talking about existing code, they *must* already set callbacks,
> otherwise they're hopelessly broken. Since the setting of callbacks will
> unsafely override the set defaults, the suggested fix (to default to
> callbacks suitable for the platform's default threading model) actually will
> *not* fix this case. If this is the case we care about, why implement a fix
> that won't fix this case?

Because it fixes the race when libraries are correctly checking to see
if the callbacks are already set before setting their own. It's a one or
two line change to modify the mis-behaving libraries and new libraries
can take advantage of the new locking.

>
> The purported advantage of this fix is that it solves the "horse has already
> left the stable" case where we aren't willing to change the libraries that
> call OpenSSL. But it doesn't fix that case.

My reference to the "horse has already left the stable" was referring to
the fact that its not possible to change every library API to include an
API for setting locking callbacks and to change every application to
actually set those callbacks. Sorry if I wasn't clear about that.
I think a one or two line change to a library is something that can be
reasonably done incrementally over time (and something the libraries
should be doing already anyway).

>
> The only way to fix that case that I can think of is for OpenSSL to start
> out using callbacks that are safe for the platform's default threading API
> and to ignore, but report success, on all attempts to change the locking
> callbacks. That may actually be the right behavior for the existing API.

This is something I'd considered but it may end up breaking
applications. I took a quick look at the BIND code and they seem to be
generating statistics from their locking callbacks. This may or may not
be acceptable in the long-term but it certainly would be a large change
with real impact. Removing the ability to set the callbacks will also
mean that using an alternative threading library (for example GNU pth as
someone pointed out) may prove difficult if not impossible.

-M

David Schwartz

unread,
Mar 31, 2010, 7:46:35 AM3/31/10
to
Mark Phalan wrote:

> Because it fixes the race when libraries are correctly checking to see
> if the callbacks are already set before setting their own. It's a one
> or
> two line change to modify the mis-behaving libraries and new libraries
> can take advantage of the new locking.

Two questions:

1) Are you suggesting that OpenSSL would report the callbacks *set* on
startup?

2) Is there a significant amount of existing code that checks if
CRYTPO_get_locking_callback returns NULL and calls
CRYPTO_set_locking_callback only if it does?

If the answer to both of these questions is "yes", then your suggested fix
would work for that code. Then your suggested fix along with a new API for
new code to use might be the best solution.

DS

Mark Phalan

unread,
Mar 31, 2010, 7:51:30 AM3/31/10
to
On 03/31/10 01:46 PM, David Schwartz wrote:
> Mark Phalan wrote:
>
>> Because it fixes the race when libraries are correctly checking to see
>> if the callbacks are already set before setting their own. It's a one
>> or
>> two line change to modify the mis-behaving libraries and new libraries
>> can take advantage of the new locking.
>
> Two questions:
>
> 1) Are you suggesting that OpenSSL would report the callbacks *set* on
> startup?

Yes.

>
> 2) Is there a significant amount of existing code that checks if
> CRYTPO_get_locking_callback returns NULL and calls
> CRYPTO_set_locking_callback only if it does?

I don't know.

>
> If the answer to both of these questions is "yes", then your suggested fix
> would work for that code. Then your suggested fix along with a new API for
> new code to use might be the best solution.

Yes and at least library developers can be told there is a way to make
their code MT-safe (safely).

-M

Peter Waltenberg

unread,
Mar 31, 2010, 5:20:59 PM3/31/10
to

Which is essentially what we did at IBM to resolve this - but - closed
ecosystem. It was a lot easier.

What you could do ....

Provide system default callbacks, allow them to be overridden at most once
ONLY if it's done before OpenSSL is usable - i.e. before any
OpenSSL_add_all_algorithms() type calls are made.

Document that this can only be done from the top level executable NOT from
a shared library - and the top level app can switch the lock model if it
wants. Changing the locking model is something that really can only be done
by whatever owns main() anyway - it's not something that can ever be safe
in a shared library.

Peter



From: "David Schwartz" <dav...@webmaster.com>

To: <Mark....@Sun.COM>, <opens...@openssl.org>

Date: 31/03/2010 09:21 PM


Subject: RE: libcrypto safe for library use?

Sent by: owner-op...@openssl.org


Mark Phalan wrote:

> Imagine the above case happening in one thread while another thread
> makes a similar seemingly innocuous call with a similar effect (dlopen
> a
> library which uses OpenSSL). What should pkinit and the second library
> which uses OpenSSL do? If they set callbacks they'll be racing against
> each other. If they don't they will not be MT safe.
> The application never sets the callbacks because as far as it's aware
> it's only calling POSIX APIs.

If we're talking about existing code, they *must* already set callbacks,
otherwise they're hopelessly broken. Since the setting of callbacks will
unsafely override the set defaults, the suggested fix (to default to
callbacks suitable for the platform's default threading model) actually
will
*not* fix this case. If this is the case we care about, why implement a fix
that won't fix this case?

The purported advantage of this fix is that it solves the "horse has


already
left the stable" case where we aren't willing to change the libraries that
call OpenSSL. But it doesn't fix that case.

The only way to fix that case that I can think of is for OpenSSL to start


out using callbacks that are safe for the platform's default threading API
and to ignore, but report success, on all attempts to change the locking
callbacks. That may actually be the right behavior for the existing API.

(And, of course, OpenSSL would implement a newer, better API that new
applications and libraries should use that would include reference counting
and being informed of the threading model in use.)

DS

______________________________________________________________________

David Schwartz

unread,
Apr 1, 2010, 2:20:16 AM4/1/10
to
Peter Waltenberg wrote:

> Document that this can only be done from the top level executable NOT
> from
> a shared library - and the top level app can switch the lock model if
> it
> wants. Changing the locking model is something that really can only be
> done
> by whatever owns main() anyway - it's not something that can ever be
> safe
> in a shared library.

With a newly-designed API, It could be made safe and, at least in some
cases, it could be needed. What if the default callbacks in OpenSSL are
completely unsuitable for the threading model the application is using, and
the application was never designed with OpenSSL in mind? The only fix that
doesn't require changing the application to be OpenSSL-aware is for a
library to be able to change the OpenSSL threading model.

One way would be a new call that allows a library or application to spin up
the OpenSSL callbacks. New OpenSSL-using programs would call this function
before they do anything with OpenSSL and also de-register before they
unload. They could set the default callbacks or point OpenSSL to a shared
library that it would load for custom callbacks. Additional OpenSSL-users
would be told that OpenSSL was already initialized appropriately for the
threading model the application uses. On de-register, the reference count
would be dropped. If OpenSSL dropped to zero, it could unlock the custom
callback library and itself, if desired.

For existing code, I still think the best solution is to ignore any attempt
to change the OpenSSL threading model callbacks but to report success. The
one exception would be allowing one change if no OpenSSL functions have yet
been called. The default could be left as is or could be callbacks that are
safe for the platform's default threading model -- I don't have a strong
feeling one way or the other about that as I haven't surveyed what existing
OpenSSL-using programs actually do. The existing calls would have to be
deprecated.

0 new messages