From 7fe8fbec77343dc12cd90833d80eb7f721248bc7 Mon Sep 17 00:00:00 2001 From: kib Date: Sun, 18 Jan 2015 11:54:20 +0000 Subject: Fix known issues which blow up the process after dlopen("libthr.so") (or loading a dso linked to libthr.so into process which was not linked against threading library). MFC r276630: Remove interposing, fix malloc, reinstall signal handlers wrappers on libthr load. MFC r276681: Avoid calling internal libc function through PLT or accessing data though GOT. MFC r277032: Reduce the size of the interposing table and amount of cancellation-handling code in the libthr. MFC note: r276646 ("do not erronously export 'openat' symbol from rtld") is not applicable to stable/10 yet, since PATHFDS support was not merged. --- lib/libthr/Makefile | 1 - lib/libthr/pthread.map | 96 -------- lib/libthr/sys/thr_error.c | 3 +- lib/libthr/thread/thr_create.c | 8 +- lib/libthr/thread/thr_fork.c | 6 +- lib/libthr/thread/thr_init.c | 10 +- lib/libthr/thread/thr_printf.c | 1 + lib/libthr/thread/thr_private.h | 20 +- lib/libthr/thread/thr_sig.c | 177 ++++++------- lib/libthr/thread/thr_syscalls.c | 521 +++++++++++++-------------------------- 10 files changed, 297 insertions(+), 546 deletions(-) (limited to 'lib/libthr') diff --git a/lib/libthr/Makefile b/lib/libthr/Makefile index e13256c..05bf941 100644 --- a/lib/libthr/Makefile +++ b/lib/libthr/Makefile @@ -40,7 +40,6 @@ MAN= libthr.3 # enable extra internal consistancy checks CFLAGS+=-D_PTHREADS_INVARIANTS -#CFLAGS+=-g PRECIOUSLIB= diff --git a/lib/libthr/pthread.map b/lib/libthr/pthread.map index bbbd930e..0903989 100644 --- a/lib/libthr/pthread.map +++ b/lib/libthr/pthread.map @@ -6,22 +6,6 @@ * Use the same naming scheme as libc. */ FBSD_1.0 { - __error; - accept; - aio_suspend; - close; - connect; - creat; - execve; - fcntl; - fork; - fsync; - msync; - nanosleep; - open; - pause; - poll; - pselect; pthread_atfork; pthread_barrier_destroy; pthread_barrier_init; @@ -139,30 +123,6 @@ FBSD_1.0 { pthread_testcancel; pthread_timedjoin_np; pthread_yield; - raise; - read; - readv; - recvfrom; - recvmsg; - select; - sendmsg; - sendto; - sigaction; - sigprocmask; - sigsuspend; - sigwait; - sigwaitinfo; - sigtimedwait; - sleep; - system; - tcdrain; - usleep; - wait; - wait3; - wait4; - waitpid; - write; - writev; }; /* @@ -170,28 +130,6 @@ FBSD_1.0 { * These are not part of our application ABI. */ FBSDprivate_1.0 { - ___creat; - ___pause; - ___pselect; - ___sigwait; - ___sleep; - ___system; - ___tcdrain; - ___usleep; - ___wait; - ___waitpid; - __accept; - __accept4; - __aio_suspend; - __close; - __connect; - __fcntl; - __fsync; - __msync; - __nanosleep; - __open; - __openat; - __poll; __pthread_cond_timedwait; __pthread_cond_wait; __pthread_cxa_finalize; @@ -199,21 +137,6 @@ FBSDprivate_1.0 { __pthread_mutex_lock; __pthread_mutex_timedlock; __pthread_mutex_trylock; - __read; - __readv; - __recvfrom; - __recvmsg; - __select; - __sendmsg; - __sendto; - __sigsuspend; - __sigtimedwait; - __sigwaitinfo; - __wait3; - __wait4; - __write; - __writev; - _fork; _pthread_atfork; _pthread_barrier_destroy; _pthread_barrier_init; @@ -345,18 +268,6 @@ FBSDprivate_1.0 { _pthread_testcancel; _pthread_timedjoin_np; _pthread_yield; - _raise; - _setcontext; - _sigaction; - _sigprocmask; - _sigsuspend; - _sigtimedwait; - _sigwait; - _sigwaitinfo; - _spinlock; - _spinlock_debug; - _spinunlock; - _swapcontext; /* Debugger needs these. */ _libthr_debug; @@ -404,12 +315,5 @@ FBSD_1.1 { }; FBSD_1.2 { - openat; pthread_getthreadid_np; - setcontext; - swapcontext; -}; - -FBSD_1.3 { - accept4; }; diff --git a/lib/libthr/sys/thr_error.c b/lib/libthr/sys/thr_error.c index 45295c5..852588a 100644 --- a/lib/libthr/sys/thr_error.c +++ b/lib/libthr/sys/thr_error.c @@ -42,8 +42,9 @@ #undef errno extern int errno; +__weak_reference(__error_threaded, __error); int * -__error(void) +__error_threaded(void) { struct pthread *curthread; diff --git a/lib/libthr/thread/thr_create.c b/lib/libthr/thread/thr_create.c index a41b33f..df3509d 100644 --- a/lib/libthr/thread/thr_create.c +++ b/lib/libthr/thread/thr_create.c @@ -40,6 +40,7 @@ #include #include "un-namespace.h" +#include "libc_private.h" #include "thr_private.h" static int create_stack(struct pthread_attr *pattr); @@ -66,8 +67,11 @@ _pthread_create(pthread_t * thread, const pthread_attr_t * attr, /* * Tell libc and others now they need lock to protect their data. */ - if (_thr_isthreaded() == 0 && _thr_setthreaded(1)) - return (EAGAIN); + if (_thr_isthreaded() == 0) { + _malloc_first_thread(); + if (_thr_setthreaded(1)) + return (EAGAIN); + } curthread = _get_curthread(); if ((new_thread = _thr_alloc(curthread)) == NULL) diff --git a/lib/libthr/thread/thr_fork.c b/lib/libthr/thread/thr_fork.c index fc87688..7dc8ca8 100644 --- a/lib/libthr/thread/thr_fork.c +++ b/lib/libthr/thread/thr_fork.c @@ -128,12 +128,10 @@ __pthread_cxa_finalize(struct dl_phdr_info *phdr_info) _thr_sigact_unload(phdr_info); } -__weak_reference(_fork, fork); - -pid_t _fork(void); +__weak_reference(__thr_fork, _fork); pid_t -_fork(void) +__thr_fork(void) { struct pthread *curthread; struct pthread_atfork *af; diff --git a/lib/libthr/thread/thr_init.c b/lib/libthr/thread/thr_init.c index 6d6a532..9a1a67a 100644 --- a/lib/libthr/thread/thr_init.c +++ b/lib/libthr/thread/thr_init.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -302,7 +303,7 @@ _thread_init_hack(void) void _libpthread_init(struct pthread *curthread) { - int fd, first = 0; + int fd, first, dlopened; /* Check if this function has already been called: */ if ((_thr_initial != NULL) && (curthread == NULL)) @@ -316,6 +317,7 @@ _libpthread_init(struct pthread *curthread) if (sizeof(jmp_table) != (sizeof(pthread_func_t) * PJT_MAX * 2)) PANIC("Thread jump table not properly initialized"); memcpy(__thr_jtable, jmp_table, sizeof(jmp_table)); + __thr_interpose_libc(); /* * Check for the special case of this process running as @@ -349,7 +351,10 @@ _libpthread_init(struct pthread *curthread) if (curthread == NULL) PANIC("Can't allocate initial thread"); init_main_thread(curthread); + } else { + first = 0; } + /* * Add the thread to the thread list queue. */ @@ -361,7 +366,8 @@ _libpthread_init(struct pthread *curthread) if (first) { _thr_initial = curthread; - _thr_signal_init(); + dlopened = _rtld_is_dlopened(&_thread_autoinit_dummy_decl) != 0; + _thr_signal_init(dlopened); if (_thread_event_mask & TD_CREATE) _thr_report_creation(curthread, curthread); /* diff --git a/lib/libthr/thread/thr_printf.c b/lib/libthr/thread/thr_printf.c index 7d32ae7..a64b446 100644 --- a/lib/libthr/thread/thr_printf.c +++ b/lib/libthr/thread/thr_printf.c @@ -31,6 +31,7 @@ #include #include +#include "libc_private.h" #include "thr_private.h" static void pchar(int fd, char c); diff --git a/lib/libthr/thread/thr_private.h b/lib/libthr/thread/thr_private.h index c6651cd..d62de98 100644 --- a/lib/libthr/thread/thr_private.h +++ b/lib/libthr/thread/thr_private.h @@ -763,7 +763,7 @@ void _thr_cancel_leave(struct pthread *, int) __hidden; void _thr_testcancel(struct pthread *) __hidden; void _thr_signal_block(struct pthread *) __hidden; void _thr_signal_unblock(struct pthread *) __hidden; -void _thr_signal_init(void) __hidden; +void _thr_signal_init(int) __hidden; void _thr_signal_deinit(void) __hidden; int _thr_send_sig(struct pthread *, int sig) __hidden; void _thr_list_init(void) __hidden; @@ -839,7 +839,6 @@ int __sys_close(int); int __sys_fork(void); pid_t __sys_getpid(void); ssize_t __sys_read(int, void *, size_t); -ssize_t __sys_write(int, const void *, size_t); void __sys_exit(int); #endif @@ -906,12 +905,29 @@ int _sleepq_remove(struct sleepqueue *, struct pthread *) __hidden; void _sleepq_drop(struct sleepqueue *, void (*cb)(struct pthread *, void *arg), void *) __hidden; +int _pthread_mutex_init_calloc_cb(pthread_mutex_t *mutex, + void *(calloc_cb)(size_t, size_t)); + struct dl_phdr_info; void __pthread_cxa_finalize(struct dl_phdr_info *phdr_info); void _thr_tsd_unload(struct dl_phdr_info *phdr_info) __hidden; void _thr_sigact_unload(struct dl_phdr_info *phdr_info) __hidden; void _thr_stack_fix_protection(struct pthread *thrd); +int *__error_threaded(void) __hidden; +void __thr_interpose_libc(void) __hidden; +pid_t __thr_fork(void); +int __thr_setcontext(const ucontext_t *ucp); +int __thr_sigaction(int sig, const struct sigaction *act, + struct sigaction *oact) __hidden; +int __thr_sigprocmask(int how, const sigset_t *set, sigset_t *oset); +int __thr_sigsuspend(const sigset_t * set); +int __thr_sigtimedwait(const sigset_t *set, siginfo_t *info, + const struct timespec * timeout); +int __thr_sigwait(const sigset_t *set, int *sig); +int __thr_sigwaitinfo(const sigset_t *set, siginfo_t *info); +int __thr_swapcontext(ucontext_t *oucp, const ucontext_t *ucp); + __END_DECLS #endif /* !_THR_PRIVATE_H */ diff --git a/lib/libthr/thread/thr_sig.c b/lib/libthr/thread/thr_sig.c index 57c9406..7cd0f75 100644 --- a/lib/libthr/thread/thr_sig.c +++ b/lib/libthr/thread/thr_sig.c @@ -38,6 +38,7 @@ #include "un-namespace.h" #include "libc_private.h" +#include "libc_private.h" #include "thr_private.h" /* #define DEBUG_SIGNAL */ @@ -54,24 +55,23 @@ struct usigaction { static struct usigaction _thr_sigact[_SIG_MAXSIG]; +static inline struct usigaction * +__libc_sigaction_slot(int signo) +{ + + return (&_thr_sigact[signo - 1]); +} + static void thr_sighandler(int, siginfo_t *, void *); static void handle_signal(struct sigaction *, int, siginfo_t *, ucontext_t *); static void check_deferred_signal(struct pthread *); static void check_suspend(struct pthread *); static void check_cancel(struct pthread *curthread, ucontext_t *ucp); -int ___pause(void); -int _raise(int); -int __sigtimedwait(const sigset_t *set, siginfo_t *info, - const struct timespec * timeout); int _sigtimedwait(const sigset_t *set, siginfo_t *info, const struct timespec * timeout); -int __sigwaitinfo(const sigset_t *set, siginfo_t *info); int _sigwaitinfo(const sigset_t *set, siginfo_t *info); -int ___sigwait(const sigset_t *set, int *sig); int _sigwait(const sigset_t *set, int *sig); -int __sigsuspend(const sigset_t *sigmask); -int _sigaction(int, const struct sigaction *, struct sigaction *); int _setcontext(const ucontext_t *); int _swapcontext(ucontext_t *, const ucontext_t *); @@ -143,8 +143,8 @@ sigcancel_handler(int sig __unused, errno = err; } -typedef void (*ohandler)(int sig, int code, - struct sigcontext *scp, char *addr, __sighandler_t *catcher); +typedef void (*ohandler)(int sig, int code, struct sigcontext *scp, + char *addr, __sighandler_t *catcher); /* * The signal handler wrapper is entered with all signal masked. @@ -152,15 +152,19 @@ typedef void (*ohandler)(int sig, int code, static void thr_sighandler(int sig, siginfo_t *info, void *_ucp) { - struct pthread *curthread = _get_curthread(); - ucontext_t *ucp = _ucp; + struct pthread *curthread; + ucontext_t *ucp; struct sigaction act; + struct usigaction *usa; int err; err = errno; - _thr_rwl_rdlock(&_thr_sigact[sig-1].lock); - act = _thr_sigact[sig-1].sigact; - _thr_rwl_unlock(&_thr_sigact[sig-1].lock); + curthread = _get_curthread(); + ucp = _ucp; + usa = __libc_sigaction_slot(sig); + _thr_rwl_rdlock(&usa->lock); + act = usa->sigact; + _thr_rwl_unlock(&usa->lock); errno = err; curthread->deferred_run = 0; @@ -234,12 +238,12 @@ handle_signal(struct sigaction *actp, int sig, siginfo_t *info, ucontext_t *ucp) * so after setjmps() returns once more, the user code may need to * re-set cancel_enable flag by calling pthread_setcancelstate(). */ - if ((actp->sa_flags & SA_SIGINFO) != 0) - (*(sigfunc))(sig, info, ucp); - else { - ((ohandler)(*sigfunc))( - sig, info->si_code, (struct sigcontext *)ucp, - info->si_addr, (__sighandler_t *)sigfunc); + if ((actp->sa_flags & SA_SIGINFO) != 0) { + sigfunc(sig, info, ucp); + } else { + ((ohandler)sigfunc)(sig, info->si_code, + (struct sigcontext *)ucp, info->si_addr, + (__sighandler_t *)sigfunc); } err = errno; @@ -395,9 +399,34 @@ check_suspend(struct pthread *curthread) } void -_thr_signal_init(void) +_thr_signal_init(int dlopened) { - struct sigaction act; + struct sigaction act, nact, oact; + struct usigaction *usa; + sigset_t oldset; + int sig, error; + + if (dlopened) { + __sys_sigprocmask(SIG_SETMASK, &_thr_maskset, &oldset); + for (sig = 1; sig <= _SIG_MAXSIG; sig++) { + if (sig == SIGCANCEL) + continue; + error = __sys_sigaction(sig, NULL, &oact); + if (error == -1 || oact.sa_handler == SIG_DFL || + oact.sa_handler == SIG_IGN) + continue; + usa = __libc_sigaction_slot(sig); + usa->sigact = oact; + nact = oact; + remove_thr_signals(&usa->sigact.sa_mask); + nact.sa_flags &= ~SA_NODEFER; + nact.sa_flags |= SA_SIGINFO; + nact.sa_sigaction = thr_sighandler; + nact.sa_mask = _thr_maskset; + (void)__sys_sigaction(sig, &nact, NULL); + } + __sys_sigprocmask(SIG_SETMASK, &oldset, NULL); + } /* Install SIGCANCEL handler. */ SIGFILLSET(act.sa_mask); @@ -418,18 +447,20 @@ _thr_sigact_unload(struct dl_phdr_info *phdr_info) struct pthread *curthread = _get_curthread(); struct urwlock *rwlp; struct sigaction *actp; + struct usigaction *usa; struct sigaction kact; void (*handler)(int); int sig; _thr_signal_block(curthread); for (sig = 1; sig <= _SIG_MAXSIG; sig++) { - actp = &_thr_sigact[sig-1].sigact; + usa = __libc_sigaction_slot(sig); + actp = &usa->sigact; retry: handler = actp->sa_handler; if (handler != SIG_DFL && handler != SIG_IGN && __elf_phdr_match_addr(phdr_info, handler)) { - rwlp = &_thr_sigact[sig-1].lock; + rwlp = &usa->lock; _thr_rwl_wrlock(rwlp); if (handler != actp->sa_handler) { _thr_rwl_unlock(rwlp); @@ -455,7 +486,7 @@ _thr_signal_prefork(void) int i; for (i = 1; i <= _SIG_MAXSIG; ++i) - _thr_rwl_rdlock(&_thr_sigact[i-1].lock); + _thr_rwl_rdlock(&__libc_sigaction_slot(i)->lock); } void @@ -464,7 +495,7 @@ _thr_signal_postfork(void) int i; for (i = 1; i <= _SIG_MAXSIG; ++i) - _thr_rwl_unlock(&_thr_sigact[i-1].lock); + _thr_rwl_unlock(&__libc_sigaction_slot(i)->lock); } void @@ -472,8 +503,10 @@ _thr_signal_postfork_child(void) { int i; - for (i = 1; i <= _SIG_MAXSIG; ++i) - bzero(&_thr_sigact[i-1].lock, sizeof(struct urwlock)); + for (i = 1; i <= _SIG_MAXSIG; ++i) { + bzero(&__libc_sigaction_slot(i) -> lock, + sizeof(struct urwlock)); + } } void @@ -481,84 +514,64 @@ _thr_signal_deinit(void) { } -__weak_reference(___pause, pause); - int -___pause(void) -{ - sigset_t oset; - - if (_sigprocmask(SIG_BLOCK, NULL, &oset) == -1) - return (-1); - return (__sigsuspend(&oset)); -} - -__weak_reference(_raise, raise); - -int -_raise(int sig) -{ - return _thr_send_sig(_get_curthread(), sig); -} - -__weak_reference(_sigaction, sigaction); - -int -_sigaction(int sig, const struct sigaction * act, struct sigaction * oact) +__thr_sigaction(int sig, const struct sigaction *act, struct sigaction *oact) { struct sigaction newact, oldact, oldact2; sigset_t oldset; - int ret = 0, err = 0; + struct usigaction *usa; + int ret, err; if (!_SIG_VALID(sig) || sig == SIGCANCEL) { errno = EINVAL; return (-1); } - if (act) - newact = *act; + ret = 0; + err = 0; + usa = __libc_sigaction_slot(sig); __sys_sigprocmask(SIG_SETMASK, &_thr_maskset, &oldset); - _thr_rwl_wrlock(&_thr_sigact[sig-1].lock); + _thr_rwl_wrlock(&usa->lock); if (act != NULL) { - oldact2 = _thr_sigact[sig-1].sigact; + oldact2 = usa->sigact; + newact = *act; /* * if a new sig handler is SIG_DFL or SIG_IGN, - * don't remove old handler from _thr_sigact[], + * don't remove old handler from __libc_sigact[], * so deferred signals still can use the handlers, * multiple threads invoking sigaction itself is * a race condition, so it is not a problem. */ if (newact.sa_handler != SIG_DFL && newact.sa_handler != SIG_IGN) { - _thr_sigact[sig-1].sigact = newact; - remove_thr_signals( - &_thr_sigact[sig-1].sigact.sa_mask); + usa->sigact = newact; + remove_thr_signals(&usa->sigact.sa_mask); newact.sa_flags &= ~SA_NODEFER; newact.sa_flags |= SA_SIGINFO; newact.sa_sigaction = thr_sighandler; newact.sa_mask = _thr_maskset; /* mask all signals */ } - if ((ret = __sys_sigaction(sig, &newact, &oldact))) { + ret = __sys_sigaction(sig, &newact, &oldact); + if (ret == -1) { err = errno; - _thr_sigact[sig-1].sigact = oldact2; + usa->sigact = oldact2; } } else if (oact != NULL) { ret = __sys_sigaction(sig, NULL, &oldact); err = errno; } - if (oldact.sa_handler != SIG_DFL && - oldact.sa_handler != SIG_IGN) { + if (oldact.sa_handler != SIG_DFL && oldact.sa_handler != SIG_IGN) { if (act != NULL) oldact = oldact2; else if (oact != NULL) - oldact = _thr_sigact[sig-1].sigact; + oldact = usa->sigact; } - _thr_rwl_unlock(&_thr_sigact[sig-1].lock); + _thr_rwl_unlock(&usa->lock); __sys_sigprocmask(SIG_SETMASK, &oldset, NULL); if (ret == 0) { @@ -570,10 +583,8 @@ _sigaction(int sig, const struct sigaction * act, struct sigaction * oact) return (ret); } -__weak_reference(_sigprocmask, sigprocmask); - int -_sigprocmask(int how, const sigset_t *set, sigset_t *oset) +__thr_sigprocmask(int how, const sigset_t *set, sigset_t *oset) { const sigset_t *p = set; sigset_t newset; @@ -598,8 +609,6 @@ _pthread_sigmask(int how, const sigset_t *set, sigset_t *oset) return (0); } -__weak_reference(__sigsuspend, sigsuspend); - int _sigsuspend(const sigset_t * set) { @@ -609,7 +618,7 @@ _sigsuspend(const sigset_t * set) } int -__sigsuspend(const sigset_t * set) +__thr_sigsuspend(const sigset_t * set) { struct pthread *curthread; sigset_t newset; @@ -633,10 +642,6 @@ __sigsuspend(const sigset_t * set) return (ret); } -__weak_reference(___sigwait, sigwait); -__weak_reference(__sigtimedwait, sigtimedwait); -__weak_reference(__sigwaitinfo, sigwaitinfo); - int _sigtimedwait(const sigset_t *set, siginfo_t *info, const struct timespec * timeout) @@ -653,8 +658,8 @@ _sigtimedwait(const sigset_t *set, siginfo_t *info, * it is not canceled. */ int -__sigtimedwait(const sigset_t *set, siginfo_t *info, - const struct timespec * timeout) +__thr_sigtimedwait(const sigset_t *set, siginfo_t *info, + const struct timespec * timeout) { struct pthread *curthread = _get_curthread(); sigset_t newset; @@ -681,7 +686,7 @@ _sigwaitinfo(const sigset_t *set, siginfo_t *info) * it is not canceled. */ int -__sigwaitinfo(const sigset_t *set, siginfo_t *info) +__thr_sigwaitinfo(const sigset_t *set, siginfo_t *info) { struct pthread *curthread = _get_curthread(); sigset_t newset; @@ -707,7 +712,7 @@ _sigwait(const sigset_t *set, int *sig) * it is not canceled. */ int -___sigwait(const sigset_t *set, int *sig) +__thr_sigwait(const sigset_t *set, int *sig) { struct pthread *curthread = _get_curthread(); sigset_t newset; @@ -721,9 +726,8 @@ ___sigwait(const sigset_t *set, int *sig) return (ret); } -__weak_reference(_setcontext, setcontext); int -_setcontext(const ucontext_t *ucp) +__thr_setcontext(const ucontext_t *ucp) { ucontext_t uc; @@ -735,12 +739,11 @@ _setcontext(const ucontext_t *ucp) return __sys_setcontext(ucp); (void) memcpy(&uc, ucp, sizeof(uc)); SIGDELSET(uc.uc_sigmask, SIGCANCEL); - return __sys_setcontext(&uc); + return (__sys_setcontext(&uc)); } -__weak_reference(_swapcontext, swapcontext); int -_swapcontext(ucontext_t *oucp, const ucontext_t *ucp) +__thr_swapcontext(ucontext_t *oucp, const ucontext_t *ucp) { ucontext_t uc; @@ -753,5 +756,5 @@ _swapcontext(ucontext_t *oucp, const ucontext_t *ucp) SIGDELSET(uc.uc_sigmask, SIGCANCEL); ucp = &uc; } - return __sys_swapcontext(oucp, ucp); + return (__sys_swapcontext(oucp, ucp)); } diff --git a/lib/libthr/thread/thr_syscalls.c b/lib/libthr/thread/thr_syscalls.c index 7a08302..06b63c8 100644 --- a/lib/libthr/thread/thr_syscalls.c +++ b/lib/libthr/thread/thr_syscalls.c @@ -1,9 +1,13 @@ /* + * Copyright (c) 2014 The FreeBSD Foundation. * Copyright (C) 2005 David Xu . * Copyright (c) 2003 Daniel Eischen . * Copyright (C) 2000 Jason Evans . * All rights reserved. * + * Portions of this software were developed by Konstantin Belousov + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -27,8 +31,6 @@ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * $FreeBSD$ */ /* @@ -61,6 +63,9 @@ * */ +#include +__FBSDID("$FreeBSD$"); + #include "namespace.h" #include #include @@ -87,85 +92,15 @@ #include #include "un-namespace.h" +#include "libc_private.h" #include "thr_private.h" -extern int __creat(const char *, mode_t); -extern int __pselect(int, fd_set *, fd_set *, fd_set *, - const struct timespec *, const sigset_t *); -extern unsigned __sleep(unsigned int); -extern int __system(const char *); -extern int __tcdrain(int); -extern int __usleep(useconds_t); -extern pid_t __wait(int *); -extern pid_t __waitpid(pid_t, int *, int); -extern int __sys_aio_suspend(const struct aiocb * const[], int, - const struct timespec *); -extern int __sys_accept(int, struct sockaddr *, socklen_t *); -extern int __sys_accept4(int, struct sockaddr *, socklen_t *, int); -extern int __sys_connect(int, const struct sockaddr *, socklen_t); -extern int __sys_fsync(int); -extern int __sys_msync(void *, size_t, int); -extern int __sys_pselect(int, fd_set *, fd_set *, fd_set *, - const struct timespec *, const sigset_t *); -extern int __sys_poll(struct pollfd *, unsigned, int); -extern ssize_t __sys_recv(int, void *, size_t, int); -extern ssize_t __sys_recvfrom(int, void *, size_t, int, struct sockaddr *, socklen_t *); -extern ssize_t __sys_recvmsg(int, struct msghdr *, int); -extern int __sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *); -extern int __sys_sendfile(int, int, off_t, size_t, struct sf_hdtr *, - off_t *, int); -extern ssize_t __sys_sendmsg(int, const struct msghdr *, int); -extern ssize_t __sys_sendto(int, const void *,size_t, int, const struct sockaddr *, socklen_t); -extern ssize_t __sys_readv(int, const struct iovec *, int); -extern pid_t __sys_wait4(pid_t, int *, int, struct rusage *); -extern ssize_t __sys_writev(int, const struct iovec *, int); - -int ___creat(const char *, mode_t); -int ___pselect(int, fd_set *, fd_set *, fd_set *, - const struct timespec *, const sigset_t *); -unsigned ___sleep(unsigned); -int ___system(const char *); -int ___tcdrain(int); -int ___usleep(useconds_t useconds); -pid_t ___wait(int *); -pid_t ___waitpid(pid_t, int *, int); -int __accept(int, struct sockaddr *, socklen_t *); -int __accept4(int, struct sockaddr *, socklen_t *, int); -int __aio_suspend(const struct aiocb * const iocbs[], int, - const struct timespec *); -int __close(int); -int __connect(int, const struct sockaddr *, socklen_t); -int __fcntl(int, int,...); #ifdef SYSCALL_COMPAT -extern int __fcntl_compat(int, int,...); +extern int __fcntl_compat(int, int, ...); #endif -int __fsync(int); -int __msync(void *, size_t, int); -int __nanosleep(const struct timespec *, struct timespec *); -int __open(const char *, int,...); -int __openat(int, const char *, int,...); -int __poll(struct pollfd *, unsigned int, int); -ssize_t __read(int, void *buf, size_t); -ssize_t __readv(int, const struct iovec *, int); -ssize_t __recvfrom(int, void *, size_t, int f, struct sockaddr *, socklen_t *); -ssize_t __recvmsg(int, struct msghdr *, int); -int __select(int, fd_set *, fd_set *, fd_set *, struct timeval *); -ssize_t __sendmsg(int, const struct msghdr *, int); -ssize_t __sendto(int, const void *, size_t, int, - const struct sockaddr *, socklen_t); -pid_t __wait3(int *, int, struct rusage *); -pid_t __wait4(pid_t, int *, int, struct rusage *); -ssize_t __write(int, const void *, size_t); -ssize_t __writev(int, const struct iovec *, int); - -__weak_reference(__accept, accept); -/* - * Cancellation behavior: - * If thread is canceled, no socket is created. - */ -int -__accept(int s, struct sockaddr *addr, socklen_t *addrlen) +static int +__thr_accept(int s, struct sockaddr *addr, socklen_t *addrlen) { struct pthread *curthread; int ret; @@ -178,14 +113,12 @@ __accept(int s, struct sockaddr *addr, socklen_t *addrlen) return (ret); } -__weak_reference(__accept4, accept4); - /* * Cancellation behavior: * If thread is canceled, no socket is created. */ -int -__accept4(int s, struct sockaddr *addr, socklen_t *addrlen, int flags) +static int +__thr_accept4(int s, struct sockaddr *addr, socklen_t *addrlen, int flags) { struct pthread *curthread; int ret; @@ -198,15 +131,14 @@ __accept4(int s, struct sockaddr *addr, socklen_t *addrlen, int flags) return (ret); } -__weak_reference(__aio_suspend, aio_suspend); - -int -__aio_suspend(const struct aiocb * const iocbs[], int niocb, const struct +static int +__thr_aio_suspend(const struct aiocb * const iocbs[], int niocb, const struct timespec *timeout) { - struct pthread *curthread = _get_curthread(); + struct pthread *curthread; int ret; + curthread = _get_curthread(); _thr_cancel_enter(curthread); ret = __sys_aio_suspend(iocbs, niocb, timeout); _thr_cancel_leave(curthread, 1); @@ -214,8 +146,6 @@ __aio_suspend(const struct aiocb * const iocbs[], int niocb, const struct return (ret); } -__weak_reference(__close, close); - /* * Cancellation behavior: * According to manual of close(), the file descriptor is always deleted. @@ -223,12 +153,13 @@ __weak_reference(__close, close); * descriptor is always deleted despite whether the thread is canceled * or not. */ -int -__close(int fd) +static int +__thr_close(int fd) { - struct pthread *curthread = _get_curthread(); - int ret; + struct pthread *curthread; + int ret; + curthread = _get_curthread(); _thr_cancel_enter2(curthread, 0); ret = __sys_close(fd); _thr_cancel_leave(curthread, 1); @@ -236,18 +167,17 @@ __close(int fd) return (ret); } -__weak_reference(__connect, connect); - /* * Cancellation behavior: * If the thread is canceled, connection is not made. */ -int -__connect(int fd, const struct sockaddr *name, socklen_t namelen) +static int +__thr_connect(int fd, const struct sockaddr *name, socklen_t namelen) { - struct pthread *curthread = _get_curthread(); + struct pthread *curthread; int ret; + curthread = _get_curthread(); _thr_cancel_enter(curthread); ret = __sys_connect(fd, name, namelen); _thr_cancel_leave(curthread, ret == -1); @@ -255,27 +185,6 @@ __connect(int fd, const struct sockaddr *name, socklen_t namelen) return (ret); } -__weak_reference(___creat, creat); - -/* - * Cancellation behavior: - * If thread is canceled, file is not created. - */ -int -___creat(const char *path, mode_t mode) -{ - struct pthread *curthread = _get_curthread(); - int ret; - - _thr_cancel_enter(curthread); - ret = __creat(path, mode); - _thr_cancel_leave(curthread, ret == -1); - - return ret; -} - -__weak_reference(__fcntl, fcntl); - /* * Cancellation behavior: * According to specification, only F_SETLKW is a cancellation point. @@ -283,13 +192,14 @@ __weak_reference(__fcntl, fcntl); * is failure, this means the function does not generate side effect * if it is canceled. */ -int -__fcntl(int fd, int cmd,...) +static int +__thr_fcntl(int fd, int cmd, ...) { - struct pthread *curthread = _get_curthread(); - int ret; + struct pthread *curthread; + int ret; va_list ap; + curthread = _get_curthread(); va_start(ap, cmd); if (cmd == F_OSETLKW || cmd == F_SETLKW) { _thr_cancel_enter(curthread); @@ -311,18 +221,17 @@ __fcntl(int fd, int cmd,...) return (ret); } -__weak_reference(__fsync, fsync); - /* * Cancellation behavior: * Thread may be canceled after system call. */ -int -__fsync(int fd) +static int +__thr_fsync(int fd) { - struct pthread *curthread = _get_curthread(); - int ret; + struct pthread *curthread; + int ret; + curthread = _get_curthread(); _thr_cancel_enter2(curthread, 0); ret = __sys_fsync(fd); _thr_cancel_leave(curthread, 1); @@ -330,34 +239,32 @@ __fsync(int fd) return (ret); } -__weak_reference(__msync, msync); - /* * Cancellation behavior: * Thread may be canceled after system call. */ -int -__msync(void *addr, size_t len, int flags) +static int +__thr_msync(void *addr, size_t len, int flags) { - struct pthread *curthread = _get_curthread(); - int ret; + struct pthread *curthread; + int ret; + curthread = _get_curthread(); _thr_cancel_enter2(curthread, 0); ret = __sys_msync(addr, len, flags); _thr_cancel_leave(curthread, 1); - return ret; + return (ret); } -__weak_reference(__nanosleep, nanosleep); - -int -__nanosleep(const struct timespec *time_to_sleep, +static int +__thr_nanosleep(const struct timespec *time_to_sleep, struct timespec *time_remaining) { - struct pthread *curthread = _get_curthread(); - int ret; + struct pthread *curthread; + int ret; + curthread = _get_curthread(); _thr_cancel_enter(curthread); ret = __sys_nanosleep(time_to_sleep, time_remaining); _thr_cancel_leave(curthread, 1); @@ -365,99 +272,68 @@ __nanosleep(const struct timespec *time_to_sleep, return (ret); } -__weak_reference(__open, open); - -/* - * Cancellation behavior: - * If the thread is canceled, file is not opened. - */ -int -__open(const char *path, int flags,...) -{ - struct pthread *curthread = _get_curthread(); - int ret; - int mode = 0; - va_list ap; - - /* Check if the file is being created: */ - if (flags & O_CREAT) { - /* Get the creation mode: */ - va_start(ap, flags); - mode = va_arg(ap, int); - va_end(ap); - } - - _thr_cancel_enter(curthread); - ret = __sys_open(path, flags, mode); - _thr_cancel_leave(curthread, ret == -1); - - return ret; -} - -__weak_reference(__openat, openat); - /* * Cancellation behavior: * If the thread is canceled, file is not opened. */ -int -__openat(int fd, const char *path, int flags, ...) +static int +__thr_openat(int fd, const char *path, int flags, ...) { - struct pthread *curthread = _get_curthread(); - int ret; - int mode = 0; + struct pthread *curthread; + int mode, ret; va_list ap; /* Check if the file is being created: */ - if (flags & O_CREAT) { + if ((flags & O_CREAT) != 0) { /* Get the creation mode: */ va_start(ap, flags); mode = va_arg(ap, int); va_end(ap); + } else { + mode = 0; } + curthread = _get_curthread(); _thr_cancel_enter(curthread); ret = __sys_openat(fd, path, flags, mode); _thr_cancel_leave(curthread, ret == -1); - return ret; + return (ret); } -__weak_reference(__poll, poll); - /* * Cancellation behavior: * Thread may be canceled at start, but if the system call returns something, * the thread is not canceled. */ -int -__poll(struct pollfd *fds, unsigned int nfds, int timeout) +static int +__thr_poll(struct pollfd *fds, unsigned int nfds, int timeout) { - struct pthread *curthread = _get_curthread(); + struct pthread *curthread; int ret; + curthread = _get_curthread(); _thr_cancel_enter(curthread); ret = __sys_poll(fds, nfds, timeout); _thr_cancel_leave(curthread, ret == -1); - return ret; + return (ret); } -__weak_reference(___pselect, pselect); - /* * Cancellation behavior: * Thread may be canceled at start, but if the system call returns something, * the thread is not canceled. */ -int -___pselect(int count, fd_set *rfds, fd_set *wfds, fd_set *efds, +static int +__thr_pselect(int count, fd_set *rfds, fd_set *wfds, fd_set *efds, const struct timespec *timo, const sigset_t *mask) { - struct pthread *curthread = _get_curthread(); + struct pthread *curthread; int ret; + curthread = _get_curthread(); _thr_cancel_enter(curthread); ret = __sys_pselect(count, rfds, wfds, efds, timo, mask); _thr_cancel_leave(curthread, ret == -1); @@ -465,321 +341,264 @@ ___pselect(int count, fd_set *rfds, fd_set *wfds, fd_set *efds, return (ret); } -__weak_reference(__read, read); - /* * Cancellation behavior: * Thread may be canceled at start, but if the system call got some data, * the thread is not canceled. */ -ssize_t -__read(int fd, void *buf, size_t nbytes) +static ssize_t +__thr_read(int fd, void *buf, size_t nbytes) { - struct pthread *curthread = _get_curthread(); + struct pthread *curthread; ssize_t ret; + curthread = _get_curthread(); _thr_cancel_enter(curthread); ret = __sys_read(fd, buf, nbytes); _thr_cancel_leave(curthread, ret == -1); - return ret; + return (ret); } -__weak_reference(__readv, readv); - /* * Cancellation behavior: * Thread may be canceled at start, but if the system call got some data, * the thread is not canceled. */ -ssize_t -__readv(int fd, const struct iovec *iov, int iovcnt) +static ssize_t +__thr_readv(int fd, const struct iovec *iov, int iovcnt) { - struct pthread *curthread = _get_curthread(); + struct pthread *curthread; ssize_t ret; + curthread = _get_curthread(); _thr_cancel_enter(curthread); ret = __sys_readv(fd, iov, iovcnt); _thr_cancel_leave(curthread, ret == -1); - return ret; + return (ret); } -__weak_reference(__recvfrom, recvfrom); - /* * Cancellation behavior: * Thread may be canceled at start, but if the system call got some data, * the thread is not canceled. */ -ssize_t -__recvfrom(int s, void *b, size_t l, int f, struct sockaddr *from, +static ssize_t +__thr_recvfrom(int s, void *b, size_t l, int f, struct sockaddr *from, socklen_t *fl) { - struct pthread *curthread = _get_curthread(); + struct pthread *curthread; ssize_t ret; + curthread = _get_curthread(); _thr_cancel_enter(curthread); ret = __sys_recvfrom(s, b, l, f, from, fl); _thr_cancel_leave(curthread, ret == -1); return (ret); } -__weak_reference(__recvmsg, recvmsg); - /* * Cancellation behavior: * Thread may be canceled at start, but if the system call got some data, * the thread is not canceled. */ -ssize_t -__recvmsg(int s, struct msghdr *m, int f) +static ssize_t +__thr_recvmsg(int s, struct msghdr *m, int f) { - struct pthread *curthread = _get_curthread(); + struct pthread *curthread; ssize_t ret; + curthread = _get_curthread(); _thr_cancel_enter(curthread); ret = __sys_recvmsg(s, m, f); _thr_cancel_leave(curthread, ret == -1); return (ret); } -__weak_reference(__select, select); - /* * Cancellation behavior: * Thread may be canceled at start, but if the system call returns something, * the thread is not canceled. */ -int -__select(int numfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, +static int +__thr_select(int numfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) { - struct pthread *curthread = _get_curthread(); + struct pthread *curthread; int ret; + curthread = _get_curthread(); _thr_cancel_enter(curthread); ret = __sys_select(numfds, readfds, writefds, exceptfds, timeout); _thr_cancel_leave(curthread, ret == -1); - return ret; + return (ret); } -__weak_reference(__sendmsg, sendmsg); - /* * Cancellation behavior: * Thread may be canceled at start, but if the system call sent * data, the thread is not canceled. */ -ssize_t -__sendmsg(int s, const struct msghdr *m, int f) +static ssize_t +__thr_sendmsg(int s, const struct msghdr *m, int f) { - struct pthread *curthread = _get_curthread(); + struct pthread *curthread; ssize_t ret; + curthread = _get_curthread(); _thr_cancel_enter(curthread); ret = __sys_sendmsg(s, m, f); _thr_cancel_leave(curthread, ret <= 0); return (ret); } -__weak_reference(__sendto, sendto); - /* * Cancellation behavior: * Thread may be canceled at start, but if the system call sent some * data, the thread is not canceled. */ -ssize_t -__sendto(int s, const void *m, size_t l, int f, const struct sockaddr *t, +static ssize_t +__thr_sendto(int s, const void *m, size_t l, int f, const struct sockaddr *t, socklen_t tl) { - struct pthread *curthread = _get_curthread(); + struct pthread *curthread; ssize_t ret; + curthread = _get_curthread(); _thr_cancel_enter(curthread); ret = __sys_sendto(s, m, l, f, t, tl); _thr_cancel_leave(curthread, ret <= 0); return (ret); } -__weak_reference(___sleep, sleep); - -unsigned int -___sleep(unsigned int seconds) +static int +__thr_system(const char *string) { - struct pthread *curthread = _get_curthread(); - unsigned int ret; + struct pthread *curthread; + int ret; + curthread = _get_curthread(); _thr_cancel_enter(curthread); - ret = __sleep(seconds); + ret = __libc_system(string); _thr_cancel_leave(curthread, 1); - return (ret); } -__weak_reference(___system, system); - -int -___system(const char *string) -{ - struct pthread *curthread = _get_curthread(); - int ret; - - _thr_cancel_enter(curthread); - ret = __system(string); - _thr_cancel_leave(curthread, 1); - - return ret; -} - -__weak_reference(___tcdrain, tcdrain); - /* * Cancellation behavior: * If thread is canceled, the system call is not completed, * this means not all bytes were drained. */ -int -___tcdrain(int fd) +static int +__thr_tcdrain(int fd) { - struct pthread *curthread = _get_curthread(); - int ret; + struct pthread *curthread; + int ret; + curthread = _get_curthread(); _thr_cancel_enter(curthread); - ret = __tcdrain(fd); + ret = __libc_tcdrain(fd); _thr_cancel_leave(curthread, ret == -1); return (ret); } -__weak_reference(___usleep, usleep); - -int -___usleep(useconds_t useconds) -{ - struct pthread *curthread = _get_curthread(); - int ret; - - _thr_cancel_enter(curthread); - ret = __usleep(useconds); - _thr_cancel_leave(curthread, 1); - - return (ret); -} - -__weak_reference(___wait, wait); - /* * Cancellation behavior: * Thread may be canceled at start, but if the system call returns * a child pid, the thread is not canceled. */ -pid_t -___wait(int *istat) +static pid_t +__thr_wait4(pid_t pid, int *status, int options, struct rusage *rusage) { - struct pthread *curthread = _get_curthread(); - pid_t ret; - - _thr_cancel_enter(curthread); - ret = __wait(istat); - _thr_cancel_leave(curthread, ret <= 0); - - return ret; -} - -__weak_reference(__wait3, wait3); - -/* - * Cancellation behavior: - * Thread may be canceled at start, but if the system call returns - * a child pid, the thread is not canceled. - */ -pid_t -__wait3(int *status, int options, struct rusage *rusage) -{ - struct pthread *curthread = _get_curthread(); - pid_t ret; - - _thr_cancel_enter(curthread); - ret = _wait4(WAIT_ANY, status, options, rusage); - _thr_cancel_leave(curthread, ret <= 0); - - return (ret); -} - -__weak_reference(__wait4, wait4); - -/* - * Cancellation behavior: - * Thread may be canceled at start, but if the system call returns - * a child pid, the thread is not canceled. - */ -pid_t -__wait4(pid_t pid, int *status, int options, struct rusage *rusage) -{ - struct pthread *curthread = _get_curthread(); + struct pthread *curthread; pid_t ret; + curthread = _get_curthread(); _thr_cancel_enter(curthread); ret = __sys_wait4(pid, status, options, rusage); _thr_cancel_leave(curthread, ret <= 0); - - return ret; -} - -__weak_reference(___waitpid, waitpid); - -/* - * Cancellation behavior: - * Thread may be canceled at start, but if the system call returns - * a child pid, the thread is not canceled. - */ -pid_t -___waitpid(pid_t wpid, int *status, int options) -{ - struct pthread *curthread = _get_curthread(); - pid_t ret; - - _thr_cancel_enter(curthread); - ret = __waitpid(wpid, status, options); - _thr_cancel_leave(curthread, ret <= 0); - - return ret; + return (ret); } -__weak_reference(__write, write); - /* * Cancellation behavior: * Thread may be canceled at start, but if the thread wrote some data, * it is not canceled. */ -ssize_t -__write(int fd, const void *buf, size_t nbytes) +static ssize_t +__thr_write(int fd, const void *buf, size_t nbytes) { - struct pthread *curthread = _get_curthread(); + struct pthread *curthread; ssize_t ret; + curthread = _get_curthread(); _thr_cancel_enter(curthread); ret = __sys_write(fd, buf, nbytes); _thr_cancel_leave(curthread, (ret <= 0)); - return ret; + return (ret); } -__weak_reference(__writev, writev); - /* * Cancellation behavior: * Thread may be canceled at start, but if the thread wrote some data, * it is not canceled. */ -ssize_t -__writev(int fd, const struct iovec *iov, int iovcnt) +static ssize_t +__thr_writev(int fd, const struct iovec *iov, int iovcnt) { - struct pthread *curthread = _get_curthread(); + struct pthread *curthread; ssize_t ret; + curthread = _get_curthread(); _thr_cancel_enter(curthread); ret = __sys_writev(fd, iov, iovcnt); _thr_cancel_leave(curthread, (ret <= 0)); - return ret; + return (ret); +} + +void +__thr_interpose_libc(void) +{ + + __set_error_selector(__error_threaded); +#define SLOT(name) \ + *(__libc_interposing_slot(INTERPOS_##name)) = \ + (interpos_func_t)__thr_##name; + SLOT(accept); + SLOT(accept4); + SLOT(aio_suspend); + SLOT(close); + SLOT(connect); + SLOT(fcntl); + SLOT(fsync); + SLOT(fork); + SLOT(msync); + SLOT(nanosleep); + SLOT(openat); + SLOT(poll); + SLOT(pselect); + SLOT(read); + SLOT(readv); + SLOT(recvfrom); + SLOT(recvmsg); + SLOT(select); + SLOT(sendmsg); + SLOT(sendto); + SLOT(setcontext); + SLOT(sigaction); + SLOT(sigprocmask); + SLOT(sigsuspend); + SLOT(sigwait); + SLOT(sigtimedwait); + SLOT(sigwaitinfo); + SLOT(swapcontext); + SLOT(system); + SLOT(tcdrain); + SLOT(wait4); + SLOT(write); + SLOT(writev); +#undef SLOT + *(__libc_interposing_slot( + INTERPOS__pthread_mutex_init_calloc_cb)) = + (interpos_func_t)_pthread_mutex_init_calloc_cb; } -- cgit v1.1