Bug 509575 - Forcing -lpthread upon all -lselinux users is a bad idea
Forcing -lpthread upon all -lselinux users is a bad idea
Product: Fedora
Classification: Fedora
Component: libselinux (Show other bugs)
All Linux
urgent Severity medium
: ---
: ---
Assigned To: Daniel Walsh
Fedora Extras Quality Assurance
Depends On:
  Show dependency treegraph
Reported: 2009-07-03 13:32 EDT by Jakub Jelinek
Modified: 2009-07-14 11:31 EDT (History)
8 users (show)

See Also:
Fixed In Version:
Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of:
Last Closed: 2009-07-14 11:31:23 EDT
Type: ---
Regression: ---
Mount Type: ---
Documentation: ---
Verified Versions:
Category: ---
oVirt Team: ---
RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: ---

Attachments (Terms of Use)
libselinux-weakref.patch (2.37 KB, patch)
2009-07-03 13:32 EDT, Jakub Jelinek
no flags Details | Diff
libselinux-weakref.patch (7.14 KB, patch)
2009-07-07 10:01 EDT, Jakub Jelinek
no flags Details | Diff

  None (edit)
Description Jakub Jelinek 2009-07-03 13:32:57 EDT
Created attachment 350449 [details]

prelink fails to build, because libselinux.a now in rawhide now needs libpthread symbols, prelink is linked statically and definitely doesn't want to link with libpthread.a.
But even for dynamically linked apps, forcing -lpthread upon all programs that don't ever use pthreads just because libselinux might be used even in threaded apps is overkill.

Look what gthr-posix.h in gcc does (used by libgcc, libstdc++, ...).

I'll attach an untested patch.

The patch does two things:
1) use weak references to the pthread_* functions, if they are non-NULL (i.e. -lpthread is linked in), it will call the pthread_* functions, otherwise only one thread is present, no locking is needed and we can use global variables
2) (optionally) uses __thread to speed up the pthread_{s,g}etspecific macros.

Only using 1) is certainly possible, just use a global array instead of __thread,
call weakref_pthread_key_create always if -lpthread is linked in, remove the special destructor handling and implement pthread_{g,s}etspecific as conditional call to weakref_pthread_{g,s}etspecific or global array access.

Not sure how portable libselinux aims to be, weakref attribute is available in this form only in GCC 4.2+ and TLS in most temporary glibcs (as in, last 8 years or so).
Comment 1 Stephen Smalley 2009-07-06 07:43:05 EDT
Comment 2 Stephen Smalley 2009-07-06 07:51:48 EDT
Sorry about the prior mangled comment.
The pthread dependency was introduced by a patch by tmraz (cc'd) to address a problem with freeing thread local storage, see:
And I was going to further use it for lazy init:

Willing to consider your patch, but obviously someone needs to test it and someone needs to post it to selinux@tycho.nsa.gov for consideration there.  And it will need to be extended to address the lazy init stuff too. The original lazy init patch did use a weak reference as well, but I dropped that since we already had a hard dependency via the setrans code:
Comment 3 Stephen Smalley 2009-07-06 09:20:31 EDT
Would it be so bad to just revert tmraz's patch that introduced the pthread dependency and instead just drop fini_context_translations(), i.e. not worry about freeing the 6 small strings cached by setrans_client.c until process exit?
Then we'd only need the weak ref support for pthread_once for lazy init, and we already have code for that in the original patch.
Comment 4 Jakub Jelinek 2009-07-07 10:01:47 EDT
Created attachment 350800 [details]

If you were using __thread unconditionally before (not sure what tmraz's patch actually did), then just going back to using it should work (i.e. tmraz's patch definitely should be reverted).
It can even cause segfaults, if you dlclose libselinux.so.*, but some other thread has some translation cached at that point, then libselinux is unmapped, but when that thread terminates libpthread will crash, because the destructor for the key isn't available (forgotten pthread_key_delete call).

If you don't care about leaking memory, then no pthread_once/pthread_key_create stuff is needed (but you can potentially leak memory in many threads), if you do,
then it should be just used to register one key which will destruct all the __thread variables (and be only called if -lpthread is linked in).

__thread variables are always initialized before they are first accessed in each thread, if initialized explicitly with that initializer, if without initializer, then they are zeroed (.tbss section).  If fini_*translations crashed and setrans_client.c hadn't ever touched those variables, then you'd be looking at a toolchain bug, in that case you'd want to actually fix that bug rather than writing a buggy workarounds.  For GD/LD __thread models there have been two bugs fixed in October last year in glibc, IE model might be a safer choice (but then, it would be more polite to use just one pointer instead of 6 in __thread space, make that a pointer to a struct containing those 6 pointers).
Comment 5 Stephen Smalley 2009-07-07 10:24:14 EDT
We were getting reports of segfaults in fini_context_translations() in libselinux from Debian and Ubuntu, as reported here:

Tomas came up with a patch to fix this bug by replacing unconditional use of __thread to using pthread functions here:

We confirmed that his patch did eliminate the seg faults and merged it.

I'd be inclined to revert the patch, drop fini_context_translations, live with potential leak of 6 small strings until process exit, and thus avoid the whole mess.  Ok with all parties?
Comment 6 Daniel Walsh 2009-07-09 08:49:07 EDT
Ok with me.  We should comment in the library that this is what is happening.
Comment 7 Stephen Smalley 2009-07-14 11:00:40 EDT
Fixed in libselinux 2.0.85.
Comment 8 Daniel Walsh 2009-07-14 11:31:23 EDT
Hey thats my line...

Fixed in libselinux 2.0.85-1.fc12

Note You need to log in before you can comment on or make changes to this bug.