* Jerry James:
Awhile back, I mentioned that GCL was building in mock on my local
machine, but was segfaulting on the koji builders. By dint of much
experimentation, I now know what is going on. For the enlightenment
of anybody who cares:
- GCL is linked with libtirpc.
- libtirpc is linked with libselinux.
- libselinux has a "constructor" function, init_lib(), that runs before
main().
- init_lib() calls init_selinuxmnt()
- init_selinuxmnt() checks that /sys/fs/selinux exists, has type
SELINUX_MAGIC (see statfs(2)), and is not read-only. In mock on my
home machine, all of this is true, so execution stops there; the
library is initialized.
- On the koji builders, /sys/fs/selinux does exist, but is read-only,
so it fails the test. The code then does the same check on /selinux,
but that doesn't exist. Due to both failures, selinuxfs_exists() is
called to see if the running kernel even knows about selinuxfs.
- selinuxfs_exists() walks through the contents of /proc/filesystems.
That walk involves calls to getline(), which calls malloc(), and
free().
- GCL has its own definitions of malloc() and free(), but those
definitions require that address randomization be turned off. GCL
accomplishes this with a call to personality() early in main(), but
the libselinux initializer runs before main(), resulting in GCL
segfaulting in free().
Nice analysis.
I'm surprised that you can turn off ASLR for a running process.
Clearly, this can only be partially effective. I think the other bits
(adjusting the heap break) are what matters. You need to move that
initialization code into malloc itself, and do these steps as part of
the malloc initialization procedure.
I can't help but think that one should be very careful about what
code
is executed in an __attribute__((constructor)) function in a library,
though. In particular, invoking malloc() and free() just doesn't seem
like a great idea; there are lots of executables that use alternate
malloc()/free() functions, so perturbing the heap before they have a
chance to be set up can cause problems. In the case of libselinux, it
seems to me that such invocations are not necessary, although I have
not yet made the effort to code up a replacement. I will try to do
that when I have a little free time.
Sorry, I disagree. malloc must work before main starts running. It's
nice to avoid excessive heap usage, but depending on what a library
does, this may not be possible.
Thanks,
Florian