diff options
author | Otto Moerbeek <otto@cvs.openbsd.org> | 2021-01-06 19:54:18 +0000 |
---|---|---|
committer | Otto Moerbeek <otto@cvs.openbsd.org> | 2021-01-06 19:54:18 +0000 |
commit | 1eae642a007756b023d33590ab1c478bac2b5ae2 (patch) | |
tree | b7a50caff757bbbeeb0c83563fd401302a13fe62 /lib | |
parent | e7610731ce07a09ed70e5d9beacc579b38fb305e (diff) |
Fix two issues related to thread private data in asr.
- setting up asr in single thread mode and then starting threads using asr
would lead to multiple threads sharing the same resolver.
- destruction of a thread that has been using asr would leak data.
Problem originally reported by Alexey Sokolov and Uli Schlachter.
ok kettenis@
Diffstat (limited to 'lib')
-rw-r--r-- | lib/libc/asr/asr.c | 24 | ||||
-rw-r--r-- | lib/libc/include/thread_private.h | 13 | ||||
-rw-r--r-- | lib/libc/thread/rthread_cb.h | 4 | ||||
-rw-r--r-- | lib/libc/thread/rthread_libc.c | 28 |
4 files changed, 49 insertions, 20 deletions
diff --git a/lib/libc/asr/asr.c b/lib/libc/asr/asr.c index 8bc25fd82bd..c3e32228cd7 100644 --- a/lib/libc/asr/asr.c +++ b/lib/libc/asr/asr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: asr.c,v 1.64 2020/07/06 13:33:05 pirofti Exp $ */ +/* $OpenBSD: asr.c,v 1.65 2021/01/06 19:54:17 otto Exp $ */ /* * Copyright (c) 2010-2012 Eric Faurot <eric@openbsd.org> * @@ -117,7 +117,7 @@ _asr_resolver_done(void *arg) _asr_ctx_unref(ac); return; } else { - priv = _THREAD_PRIVATE(_asr, _asr, &_asr); + priv = _THREAD_PRIVATE_DT(_asr, _asr, NULL, &_asr); if (*priv == NULL) return; asr = *priv; @@ -128,6 +128,23 @@ _asr_resolver_done(void *arg) free(asr); } +static void +_asr_resolver_done_tp(void *arg) +{ + char buf[100]; + int len; + struct asr **priv = arg; + struct asr *asr; + + if (*priv == NULL) + return; + asr = *priv; + + _asr_ctx_unref(asr->a_ctx); + free(asr); + free(priv); +} + void * asr_resolver_from_string(const char *str) { @@ -349,7 +366,8 @@ _asr_use_resolver(void *arg) } else { DPRINT("using thread-local resolver\n"); - priv = _THREAD_PRIVATE(_asr, _asr, &_asr); + priv = _THREAD_PRIVATE_DT(_asr, _asr, _asr_resolver_done_tp, + &_asr); if (*priv == NULL) { DPRINT("setting up thread-local resolver\n"); *priv = _asr_resolver(); diff --git a/lib/libc/include/thread_private.h b/lib/libc/include/thread_private.h index 98dfaa63223..237c3fbd034 100644 --- a/lib/libc/include/thread_private.h +++ b/lib/libc/include/thread_private.h @@ -1,4 +1,4 @@ -/* $OpenBSD: thread_private.h,v 1.35 2019/02/13 13:22:14 mpi Exp $ */ +/* $OpenBSD: thread_private.h,v 1.36 2021/01/06 19:54:17 otto Exp $ */ /* PUBLIC DOMAIN: No Rights Reserved. Marco S Hyman <marc@snafu.org> */ @@ -98,7 +98,8 @@ struct thread_callbacks { void (*tc_mutex_destroy)(void **); void (*tc_tag_lock)(void **); void (*tc_tag_unlock)(void **); - void *(*tc_tag_storage)(void **, void *, size_t, void *); + void *(*tc_tag_storage)(void **, void *, size_t, void (*)(void *), + void *); __pid_t (*tc_fork)(void); __pid_t (*tc_vfork)(void); void (*tc_thread_release)(struct pthread *); @@ -142,6 +143,7 @@ __END_HIDDEN_DECLS #define _THREAD_PRIVATE_MUTEX_LOCK(name) do {} while (0) #define _THREAD_PRIVATE_MUTEX_UNLOCK(name) do {} while (0) #define _THREAD_PRIVATE(keyname, storage, error) &(storage) +#define _THREAD_PRIVATE_DT(keyname, storage, dt, error) &(storage) #define _MUTEX_LOCK(mutex) do {} while (0) #define _MUTEX_UNLOCK(mutex) do {} while (0) #define _MUTEX_DESTROY(mutex) do {} while (0) @@ -168,7 +170,12 @@ __END_HIDDEN_DECLS #define _THREAD_PRIVATE(keyname, storage, error) \ (_thread_cb.tc_tag_storage == NULL ? &(storage) : \ _thread_cb.tc_tag_storage(&(__THREAD_NAME(keyname)), \ - &(storage), sizeof(storage), error)) + &(storage), sizeof(storage), NULL, (error))) + +#define _THREAD_PRIVATE_DT(keyname, storage, dt, error) \ + (_thread_cb.tc_tag_storage == NULL ? &(storage) : \ + _thread_cb.tc_tag_storage(&(__THREAD_NAME(keyname)), \ + &(storage), sizeof(storage), (dt), (error))) /* * Macros used in libc to access mutexes. diff --git a/lib/libc/thread/rthread_cb.h b/lib/libc/thread/rthread_cb.h index 3e8604c4ed4..d82c8b649e8 100644 --- a/lib/libc/thread/rthread_cb.h +++ b/lib/libc/thread/rthread_cb.h @@ -1,4 +1,4 @@ -/* $OpenBSD: rthread_cb.h,v 1.2 2017/09/05 02:40:54 guenther Exp $ */ +/* $OpenBSD: rthread_cb.h,v 1.3 2021/01/06 19:54:17 otto Exp $ */ /* * Copyright (c) 2016 Philip Guenther <guenther@openbsd.org> * All Rights Reserved. @@ -35,5 +35,5 @@ void _thread_mutex_unlock(void **); void _thread_mutex_destroy(void **); void _thread_tag_lock(void **); void _thread_tag_unlock(void **); -void *_thread_tag_storage(void **, void *, size_t, void *); +void *_thread_tag_storage(void **, void *, size_t, void (*)(void*), void *); __END_HIDDEN_DECLS diff --git a/lib/libc/thread/rthread_libc.c b/lib/libc/thread/rthread_libc.c index b99d6d19704..2a117c14f6e 100644 --- a/lib/libc/thread/rthread_libc.c +++ b/lib/libc/thread/rthread_libc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rthread_libc.c,v 1.3 2019/01/10 18:45:33 otto Exp $ */ +/* $OpenBSD: rthread_libc.c,v 1.4 2021/01/06 19:54:17 otto Exp $ */ /* PUBLIC DOMAIN: No Rights Reserved. Marco S Hyman <marc@snafu.org> */ @@ -31,7 +31,7 @@ static pthread_mutex_t _thread_tag_mutex = PTHREAD_MUTEX_INITIALIZER; * This function will never return NULL. */ static void -_thread_tag_init(void **tag) +_thread_tag_init(void **tag, void (*dt)(void *)) { struct _thread_tag *tt; int result; @@ -42,7 +42,8 @@ _thread_tag_init(void **tag) tt = malloc(sizeof *tt); if (tt != NULL) { result = pthread_mutex_init(&tt->m, NULL); - result |= pthread_key_create(&tt->k, free); + result |= pthread_key_create(&tt->k, dt ? dt : + free); *tag = tt; } } @@ -62,7 +63,7 @@ _thread_tag_lock(void **tag) if (__isthreaded) { if (*tag == NULL) - _thread_tag_init(tag); + _thread_tag_init(tag, NULL); tt = *tag; if (pthread_mutex_lock(&tt->m) != 0) _rthread_debug(1, "tag mutex lock failure"); @@ -79,7 +80,7 @@ _thread_tag_unlock(void **tag) if (__isthreaded) { if (*tag == NULL) - _thread_tag_init(tag); + _thread_tag_init(tag, NULL); tt = *tag; if (pthread_mutex_unlock(&tt->m) != 0) _rthread_debug(1, "tag mutex unlock failure"); @@ -88,28 +89,31 @@ _thread_tag_unlock(void **tag) /* * return the thread specific data for the given tag. If there - * is no data for this thread initialize it from 'storage'. + * is no data for this thread allocate and initialize it from 'storage' + * or clear it for non-main threads. * On any error return 'err'. */ void * -_thread_tag_storage(void **tag, void *storage, size_t sz, void *err) +_thread_tag_storage(void **tag, void *storage, size_t sz, void (*dt)(void *), + void *err) { struct _thread_tag *tt; void *ret; if (*tag == NULL) - _thread_tag_init(tag); + _thread_tag_init(tag, dt); tt = *tag; ret = pthread_getspecific(tt->k); if (ret == NULL) { - ret = malloc(sz); + ret = calloc(1, sz); if (ret == NULL) ret = err; else { - if (pthread_setspecific(tt->k, ret) == 0) - memcpy(ret, storage, sz); - else { + if (pthread_setspecific(tt->k, ret) == 0) { + if (pthread_self() == &_initial_thread) + memcpy(ret, storage, sz); + } else { free(ret); ret = err; } |