Avoid cancellable I/O primitives in ld.so.
commit329ea513b451ae8322aa7a24ed84da13992af2dd
authorZack Weinberg <zackw@panix.com>
Tue, 3 Apr 2018 22:26:44 +0000 (3 18:26 -0400)
committerZack Weinberg <zackw@panix.com>
Tue, 12 Jun 2018 13:53:04 +0000 (12 09:53 -0400)
tree64568fae803a1dbe3ccdf6897a708ff7fd8b4949
parent0221ce2a90be2d40fc90f0b5dcec77a1ec013f53
Avoid cancellable I/O primitives in ld.so.

Neither the <dlfcn.h> entry points, nor lazy symbol resolution, nor
initial shared library load-up, are cancellation points, so ld.so
should exclusively use I/O primitives that are not cancellable.  We
currently achieve this by having the cancellation hooks compile as
no-ops when IS_IN(rtld); this patch changes to using exclusively
_nocancel primitives in the source code instead, which makes the
intent clearer and significantly reduces the amount of code compiled
under IS_IN(rtld) as well as IS_IN(libc) -- in particular,
elf/Makefile no longer thinks we require a copy of unwind.c in
rtld-libc.a.  (The older mechanism is preserved as a backstop.)

The bulk of the change is splitting up the files that define the
_nocancel I/O functions, so they don't also define the variants that
*are* cancellation points; after which, the existing logic for picking
out the bits of libc that need to be recompiled as part of ld.so Just
Works.  I did this for all of the _nocancel functions, not just the
ones used by ld.so, for consistency.

fcntl was a little tricky because it's only a cancellation point for
certain opcodes (F_SETLKW(64), which can block), and the existing
__fcntl_nocancel wasn't applying the FCNTL_ADJUST_CMD hook, which
strikes me as asking for trouble, especially as the only nontrivial
definition of FCNTL_ADJUST_CMD (for powerpc64) changes F_*LK* opcodes.
To fix this, fcntl_common moves to fcntl_nocancel.c along with
__fcntl_nocancel, and changes its name to the extern (but hidden)
symbol __fcntl_nocancel_adjusted, so that regular fcntl can continue
calling it.  __fcntl_nocancel now applies FCNTL_ADJUST_CMD; so that
both both fcntl.c and fcntl_nocancel.c can see it, the only nontrivial
definition moves from sysdeps/u/s/l/powerpc/powerpc64/fcntl.c to
.../powerpc64/sysdep.h and becomes entirely a macro, instead of a macro
that calls an inline function.

The nptl version of libpthread also changes a little, because its
"compat-routines" formerly included files that defined all the
_nocancel functions it uses; instead of continuing to duplicate them,
I exported the relevant ones from libc.so as GLIBC_PRIVATE.  Since the
Linux fcntl.c calls a function defined by fcntl_nocancel.c, it can no
longer be used from libpthread.so; instead, introduce a custom
forwarder, pt-fcntl.c, and export __libc_fcntl from libc.so as
GLIBC_PRIVATE.  The nios2-linux ABI doesn't include a copy of vfork()
in libpthread, and it was handling that by manipulating
libpthread-routines in .../linux/nios2/Makefile; it is cleaner to do
what other such ports do, and have a pt-vfork.S that defines no symbols.

Right now, it appears that Hurd does not implement _nocancel I/O, so
sysdeps/generic/not-cancel.h will forward everything back to the
regular functions.  This changed the names of some of the functions
that sysdeps/mach/hurd/dl-sysdep.c needs to interpose.

* elf/dl-load.c, elf/dl-misc.c, elf/dl-profile.c, elf/rtld.c
* sysdeps/unix/sysv/linux/dl-sysdep.c
Include not-cancel.h.  Use __close_nocancel instead of __close,
__open64_nocancel instead of __open, __read_nocancel instead of
__libc_read, and __write_nocancel instead of __libc_write.

* csu/check_fds.c (check_one_fd)
* sysdeps/posix/fdopendir.c (__fdopendir)
* sysdeps/posix/opendir.c (__alloc_dir): Use __fcntl_nocancel
        instead of __fcntl and/or __libc_fcntl.

* sysdeps/unix/sysv/linux/pthread_setname.c (pthread_setname_np)
* sysdeps/unix/sysv/linux/pthread_getname.c (pthread_getname_np)
        * sysdeps/unix/sysv/linux/i386/smp.h (is_smp_system):
Use __open64_nocancel instead of __open_nocancel.

* sysdeps/unix/sysv/linux/not-cancel.h: Move all of the
hidden_proto declarations to the end and issue them if either
IS_IN(libc) or IS_IN(rtld).
* sysdeps/unix/sysv/linux/Makefile [subdir=io] (sysdep_routines):
Add close_nocancel, fcntl_nocancel, nanosleep_nocancel,
open_nocancel, open64_nocancel, openat_nocancel, pause_nocancel,
read_nocancel, waitpid_nocancel, write_nocancel.

        * io/Versions [GLIBC_PRIVATE]: Add __libc_fcntl,
        __fcntl_nocancel, __open64_nocancel, __write_nocancel.
        * posix/Versions: Add __nanosleep_nocancel, __pause_nocancel.

        * nptl/pt-fcntl.c: New file.
        * nptl/Makefile (pthread-compat-wrappers): Remove fcntl.
        (libpthread-routines): Add pt-fcntl.
        * include/fcntl.h (__fcntl_nocancel_adjusted): New function.
        (__libc_fcntl): Remove attribute_hidden.
* sysdeps/unix/sysv/linux/fcntl.c (__libc_fcntl): Call
__fcntl_nocancel_adjusted, not fcntl_common.
        (__fcntl_nocancel): Move to new file fcntl_nocancel.c.
(fcntl_common): Rename to __fcntl_nocancel_adjusted; also move
to fcntl_nocancel.c.
* sysdeps/unix/sysv/linux/fcntl_nocancel.c: New file.
* sysdeps/unix/sysv/linux/powerpc/powerpc64/fcntl.c: Remove file.
* sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep.h:
Define FCNTL_ADJUST_CMD here, as a self-contained macro.

* sysdeps/unix/sysv/linux/close.c: Move __close_nocancel to...
* sysdeps/unix/sysv/linux/close_nocancel.c: ...this new file.
* sysdeps/unix/sysv/linux/nanosleep.c: Move __nanosleep_nocancel to...
* sysdeps/unix/sysv/linux/nanosleep_nocancel.c: ...this new file.
* sysdeps/unix/sysv/linux/open.c: Move __open_nocancel to...
* sysdeps/unix/sysv/linux/open_nocancel.c: ...this new file.
* sysdeps/unix/sysv/linux/open64.c: Move __open64_nocancel to...
* sysdeps/unix/sysv/linux/open64_nocancel.c: ...this new file.
* sysdeps/unix/sysv/linux/openat.c: Move __openat_nocancel to...
* sysdeps/unix/sysv/linux/openat_nocancel.c: ...this new file.
* sysdeps/unix/sysv/linux/openat64.c: Move __openat64_nocancel to...
* sysdeps/unix/sysv/linux/openat64_nocancel.c: ...this new file.
* sysdeps/unix/sysv/linux/pause.c: Move __pause_nocancel to...
* sysdeps/unix/sysv/linux/pause_nocancel.c: ...this new file.
* sysdeps/unix/sysv/linux/read.c: Move __read_nocancel to...
* sysdeps/unix/sysv/linux/read_nocancel.c: ...this new file.
* sysdeps/unix/sysv/linux/waitpid.c: Move __waitpid_nocancel to...
* sysdeps/unix/sysv/linux/waitpid_nocancel.c: ...this new file.
* sysdeps/unix/sysv/linux/write.c: Move __write_nocancel to...
* sysdeps/unix/sysv/linux/write_nocancel.c: ...this new file.

        * sysdeps/unix/sysv/linux/nios2/Makefile: Don't override
        libpthread-routines.
        * sysdeps/unix/sysv/linux/nios2/pt-vfork.S: New file which
        defines nothing.

        * sysdeps/mach/hurd/dl-sysdep.c: Define __read instead of
        __libc_read, and __write instead of __libc_write.  Define
        __open64 in addition to __open.
45 files changed:
ChangeLog
csu/check_fds.c
elf/dl-load.c
elf/dl-misc.c
elf/dl-profile.c
elf/rtld.c
include/fcntl.h
io/Versions
nptl/Makefile
posix/Versions
sysdeps/mach/hurd/dl-sysdep.c
sysdeps/posix/fdopendir.c
sysdeps/posix/opendir.c
sysdeps/unix/pt-fcntl.c [new file with mode: 0644]
sysdeps/unix/sysv/linux/Makefile
sysdeps/unix/sysv/linux/close.c
sysdeps/unix/sysv/linux/close_nocancel.c [copied from sysdeps/unix/sysv/linux/powerpc/powerpc64/fcntl.c with 70% similarity]
sysdeps/unix/sysv/linux/dl-sysdep.c
sysdeps/unix/sysv/linux/fcntl.c
sysdeps/unix/sysv/linux/fcntl_nocancel.c [copied from sysdeps/unix/sysv/linux/fcntl.c with 66% similarity]
sysdeps/unix/sysv/linux/i386/smp.h
sysdeps/unix/sysv/linux/nanosleep.c
sysdeps/unix/sysv/linux/nanosleep_nocancel.c [copied from sysdeps/unix/sysv/linux/nanosleep.c with 72% similarity]
sysdeps/unix/sysv/linux/nios2/Makefile
sysdeps/unix/sysv/linux/nios2/pt-vfork.S [new file with mode: 0644]
sysdeps/unix/sysv/linux/not-cancel.h
sysdeps/unix/sysv/linux/open.c
sysdeps/unix/sysv/linux/open64.c
sysdeps/unix/sysv/linux/open64_nocancel.c [copied from sysdeps/unix/sysv/linux/open64.c with 60% similarity]
sysdeps/unix/sysv/linux/open_nocancel.c [copied from sysdeps/unix/sysv/linux/open.c with 61% similarity]
sysdeps/unix/sysv/linux/openat.c
sysdeps/unix/sysv/linux/openat64.c
sysdeps/unix/sysv/linux/openat64_nocancel.c [copied from sysdeps/unix/sysv/linux/openat64.c with 59% similarity]
sysdeps/unix/sysv/linux/openat_nocancel.c [copied from sysdeps/unix/sysv/linux/close.c with 60% similarity]
sysdeps/unix/sysv/linux/pause.c
sysdeps/unix/sysv/linux/pause_nocancel.c [copied from sysdeps/unix/sysv/linux/pause.c with 70% similarity]
sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep.h
sysdeps/unix/sysv/linux/pthread_getname.c
sysdeps/unix/sysv/linux/pthread_setname.c
sysdeps/unix/sysv/linux/read.c
sysdeps/unix/sysv/linux/read_nocancel.c [copied from sysdeps/unix/sysv/linux/powerpc/powerpc64/fcntl.c with 70% similarity]
sysdeps/unix/sysv/linux/waitpid.c
sysdeps/unix/sysv/linux/waitpid_nocancel.c [copied from sysdeps/unix/sysv/linux/waitpid.c with 76% similarity]
sysdeps/unix/sysv/linux/write.c
sysdeps/unix/sysv/linux/write_nocancel.c [moved from sysdeps/unix/sysv/linux/powerpc/powerpc64/fcntl.c with 70% similarity]