On Tue, Oct 29, 2013 at 09:58:25PM +0100, Andy Polyakov wrote:
> I feel like saying few words. One should recognize that by the time
> multi-threading support was taking shape there was a whole variety
> of threading implementations and callbacks were the only way to
> convey the specifics. Nowadays we're pretty much talking only about

Certainly.  I'm not saying "omg, that OpenSSL is insanez!!".

I should repeat my problem case: we have libraries that depend on
OpenSSL libraries, and it should be possible to for our libraries to
work in threaded programs.  But right now a Java program that uses JGSS
with the JNI shim to the C GSS-API libraries using Heimdal's libgss
crashes in RAND_bytes().  Heimdal can't provide locking callbacks (how
could it? it might step on some other caller's toes in the same
process).  The app can't either (since in this case it's not using
OpenSSL directly at all).

> pthreads and Windows, and one can indeed argue why wouldn't OpenSSL
> simply default to either of the two when appropriate. While it's
> more than appropriate on Windows as it is, on pthreads-powered
> Unices it's not as obvious. Because pthreads can be undesired in
> some situations. Basically it boils down to question whether or not
> libcrypto may be linked with libpthread or not. And answer is
> actually "not desired." Ideally libcrypto should *detect* if

More details would be nice.  What follows is speculation of mine as to
what you might have in mind (or even if you don't, it might be
relevant).

To summarize the below:

    OpenSSL .so's should always be linked with -lpthread on OSes where
    there's a standard libpthread that threaded apps are expected to
    use; OpenSSL static link archives should assume no threading
    libraries and rely on the callers to provide the threading
    callbacks.

    Distros that focus on static linking should ship OpenSSL static link
    archives only and shuld ensure that dependents of OpenSSL initialize
    it correctly when used in threaded programs.

Linux still has the multiple process models problem that Solaris <9 used
to have:

 - statically linked with libc but not -lpthread
 - statically linked with libc and -lpthread
 - dynamically linked with libc but not -lpthread
 - dynamically linked with libc and -lpthread

 - mixed: not originally linked with -lpthread but a dlopen()ed object brought
   it in

I dunno about Linux, but IIUC loading libpthread at run-time in the
third case works fine.  It also works fine in S8 and S9.  It's loading
libpthread at run-time in the first case that leads to fireworks.

The mixed case is a very difficult one to handle correctly in any
library.  Merely using dlsym() on RTLD_DEFAULT is not good enough:
pthreads symbols might appear later on.

Typically the mixed case results when an app uses the name service
switch without nscd, or PAM, and one of those pluggable things loads
libcrypto.  If the app also uses libcrypto then... who knows.

(It's clearly insane to support a static libc and have an RTLD.  And yet
Solaris used to support that...  But then, it stopped supporting that
for a reason: it was insanely expensive in terms of engineering costs.)

I'm not sure that OpenSSL should support such madness in any way other
than at ./Configure time: the builder person picks.

I.e., this is the distro builder's problem.  Some distros are very
focused on static linking.  Others are not.

Static link archives don't record dependencies, so we can't speak of
building libcrypto.a with -lpthread.  So in the static link build option
OpenSSL needs to know whether to assume pthreads or not, and only the
builder can tell OpenSSL.

In the shared object build of OpenSSL it's just easier to link with
-lpthread if the target has pthreads.

E.g., a distro that is mostly-dynamically-linked should just ship
OpenSSL libs linked with -lpthread, while a distro that is
mostly-statically-linked should ship OpenSSL .a's built to not use
pthreads.  A distro with both should *probably* build OpenSSL .a's w/o
pthread and .so's with.  A distro might want to require that pthreads is
*always* available, even with linking statically.

Or perhaps you were thinking of apps that use GNU Pth, but those should
either build their own private OpenSSL libs or they should use static
link OpenSSL archives.  I don't think OpenSSL should bend over backwards
to support third-party alternate threading libraries where the OS has a
single supported standard.  If an OS has multiple supported alternatives
then OpenSSL should pick one at run-time, but this is very difficult
(see below).

> *hosting* application is linked with libpthread and only *then*
> adjust accordingly. Is there way to detect if application is linked
> with libpthread at run-time? There is DSO_global_lookup.

See above.  Using weak symbols might work, but it might be very
OS-dependent; I'm not prepared to research that for every target, or
even more than one or two targets.  Using dlsym() seems like asking for
trouble.

> As for pthread_once [and Windows counterpart]. I'd argue that it
> would be more appropriate to initialize the default callbacks
> through initialization segment (facility used for "pre-main"
> execution of "constructors"), which is guaranteed to be MT-safe.
> Such framework (as well as "destructors") would be useful in more
> places.

Like DllMain and .init?  .init in particular is fraught with risk:

https://blogs.oracle.com/rie/entry/init_and_fini_processing_who

.init execution order is basically unreliable: by design.  We should
assume that it can change at any time in any ELF RTLD that doesn't
guarantee otherwise (and they should keep their options open), and since
at least one RTLD won't...

At least OpenSSL shouldn't be involved in circular dependencies...

DllMain clearly would work for Windows, but there's no need to worry
about the statically-linked-with-libc-not-with-pthreads-then-dlopen case
on Windows, so it seems like unnecessary complexity unless we also
decide to use .init on ELF targets.

My advice: stay away from .init.  Let the distro builder decide how to
build OpenSSL.  But if we must pick from several threading libraries at
run-time then hopefully the RTLD can make that choice for us, else the
only choice left would be to use a .init.

> As for config-time detection. My major objection is following.
> Software is called so for a reason, and config-time detection is
> effectively against its nature. Because it "hardwires" it to
> specific set of interfaces. Wouldn't it be more natural for
> *soft*ware to detect feature at *run-time* and adapt? This is
> actually what's is implemented in several places in OpenSSL.

Sort of.  On Solaris 10 and up, for example, threading is *always*
there, as is the RTLD, and there's no static link archives for core OS
libraries (static linking is supported, just not for libc and friends).
On Solaris 10 the correct answer is to just use pthreads.

On a Linux distro that's only/mostly dynamically linked the same answer
applies as to Solaris.

On other Linux distros there will be sadness regardless of what OpenSSL
does.

> >A few notes and questions:
> >
> > - Locks in OpenSSL are really reader-writer locks, but the sample code
> >   in crypto/threads/*.c uses mutexes only.
> >
> >   How important is it that reader/writer locks be used instead of
> >   exclusive locks?
> 
> For historical reasons mentioned above mutexes are common
> denominator. Whether or not one should switch to more sophisticated
> primitives is question about whether or not do we want to support
> legacy multi-threading systems. The answer is probably yes. Of
> course one can add more callbacks, see which one are set and opt for
> more refined methods if available. But

But OpenSSL explicitly treats all locks as reader/writer locks.  Using
exclusive locks under the hood clearly does not break anything.  Using
reader/writer locks *might* improve performance, and will expose as bugs
any cases where reader/writer locks are not used correctly.

> > - The add_lock stuff should just use OPENSSL_atomic_add() wherever it
> >   exists.
> >
> >   How would I determine at build-time (in ./Configure and in
> >   ./crypto/lock.c) whether OPENSSL_atomic_add is available?
> 
> #ifdef OPENSSL_CPUID_OBJ

Ah, excellent, thanks!

> Well, DSO_global_lookup is more consistent with above:-) While we
> are at it, it's appropriate to add atomic pointer swap that can be
> used to maintain linked lists without mutex-ing.

Well, if it's exported anyways.  But I don't see OPENSSL_atomic_add in
libeay.num!

Nico
-- 
______________________________________________________________________
OpenSSL Project                                 http://www.openssl.org
Development Mailing List                       openssl-dev@openssl.org
Automated List Manager                           majord...@openssl.org

Reply via email to