What's the rationale behind calling read_mainconfig() before daemonizing? There's a comment /* Read the configuration files, BEFORE doing anything else. */ suggesting this is intentional. However, during that, mutexes are created via pthread_mutex_init(). To my understanding, fork()ing while holding mutexes (and without intervening via a pthread_atfork() handler) calls for undefined behaviour. Indeed, on NetBSD, I get radiusd: Error detected by libpthread: Invalid mutex. Detected by file [...], line [...], function "pthread_mutex_lock_slow". See pthread(3) for information. unless I use one of the dont_fork options. Running radiusd -f & works as a workaround. Also, moving the configuration reading block after the daemonizing block seems to work, but I'm afraid there was a good reason for reading the configuration before doing the fork.
Edgar Fuß wrote:
What's the rationale behind calling read_mainconfig() before daemonizing?
So that it can read the configuration before daemonizing. It needs to know which files to load, modules, etc. It also changes UIDs so that any files it writes are correct. And that if there are issues reading the configuration files, they get logged to the correct place.
There's a comment /* Read the configuration files, BEFORE doing anything else. */ suggesting this is intentional.
Yes.
However, during that, mutexes are created via pthread_mutex_init(). To my understanding, fork()ing while holding mutexes (and without intervening via a pthread_atfork() handler) calls for undefined behaviour.
Hmm... it's not *holding* the mutex, it's *creating* it. That should be allowed, IIRC.
Indeed, on NetBSD, I get radiusd: Error detected by libpthread: Invalid mutex. Detected by file [...], line [...], function "pthread_mutex_lock_slow". See pthread(3) for information. unless I use one of the dont_fork options.
Running radiusd -f & works as a workaround.
Also, moving the configuration reading block after the daemonizing block seems to work, but I'm afraid there was a good reason for reading the configuration before doing the fork.
I recall things breaking if we did it the other way around, but that may be from a long time ago. Alan DeKok.
Hmm... it's not *holding* the mutex, it's *creating* it. Yes, sorry for mis-phrasing that.
That should be allowed, IIRC. Yes, it probably is.
Just for the sake of the archives: This turned out NOT to be a FreeRADIUS bug. After a lot of debugging, it turned out that radiusd, via initgroups() and nsswitch.conf, loaded nss_ldap, which pulled in libldap (the non-reentrant version). Also, radiusd, via rlm_ldap, pulled in libldap_r (the reentrant version). However, nss_ldap had registered a pthread_atfork handler, which intended to call ldap_drop_conenction() from libldap, but, because of PLT load-time-linking, in fact ended up calling ldap_drop_connection() from libldap_r. Boom (inside fork()).
On 05/13/2013 08:03 PM, Edgar Fuß wrote:
registered a pthread_atfork handler, which intended to call ldap_drop_conenction() from libldap, but, because of PLT load-time-linking, in fact ended up calling ldap_drop_connection() from libldap_r. Boom (inside fork()).
Oh yuck... NSS really is a disaster - "dynload in arbitrary linked-libraries every time I lookup a uid->user mapping, why sure!". You might find that running nscd helps, as it'll confine nss_ldap to the nscd process.
Definitely run nscd or similar to avoid the nasties (I know nscd itself can be icky but i'll have that pain over applications breaking just because of NSS library loading)… I've had SSL library fun with NSS for the same reasons utter nightmare to spot in the debug when the two libs were almost binary compatible. On 14 May 2013, at 08:21, Phil Mayers <p.mayers@imperial.ac.uk> wrote:
On 05/13/2013 08:03 PM, Edgar Fuß wrote:
registered a pthread_atfork handler, which intended to call ldap_drop_conenction() from libldap, but, because of PLT load-time-linking, in fact ended up calling ldap_drop_connection() from libldap_r. Boom (inside fork()).
Oh yuck...
NSS really is a disaster - "dynload in arbitrary linked-libraries every time I lookup a uid->user mapping, why sure!".
You might find that running nscd helps, as it'll confine nss_ldap to the nscd process. - List info/subscribe/unsubscribe? See http://www.freeradius.org/list/devel.html
Edgar Fuß wrote:
Just for the sake of the archives: This turned out NOT to be a FreeRADIUS bug.
That's nice.
After a lot of debugging, it turned out that radiusd, via initgroups() and nsswitch.conf, loaded nss_ldap, which pulled in libldap (the non-reentrant version). Also, radiusd, via rlm_ldap, pulled in libldap_r (the reentrant version). However, nss_ldap had registered a pthread_atfork handler, which intended to call ldap_drop_conenction() from libldap, but, because of PLT load-time-linking, in fact ended up calling ldap_drop_connection() from libldap_r. Boom (inside fork()).
Ah. The simple answer is "don't do that". Having layers of competing library dependencies is wrong. Alan DeKok.
On Fri, May 03, 2013 at 04:04:42PM +0200, Edgar Fuß wrote:
Also, moving the configuration reading block after the daemonizing block seems to work, but I'm afraid there was a good reason for reading the configuration before doing the fork.
This is usually done so that config file read/parse errors can be spat out to the user before stderr is closed. I would guess it's the same here. Matthew -- Matthew Newton, Ph.D. <mcn4@le.ac.uk> Systems Specialist, Infrastructure Services, I.T. Services, University of Leicester, Leicester LE1 7RH, United Kingdom For IT help contact helpdesk extn. 2253, <ithelp@le.ac.uk>
participants (5)
-
Alan DeKok -
Alister Winfield -
Edgar Fuß -
Matthew Newton -
Phil Mayers