summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorOtto Moerbeek <otto@cvs.openbsd.org>2021-01-06 19:54:18 +0000
committerOtto Moerbeek <otto@cvs.openbsd.org>2021-01-06 19:54:18 +0000
commit1eae642a007756b023d33590ab1c478bac2b5ae2 (patch)
treeb7a50caff757bbbeeb0c83563fd401302a13fe62 /lib
parente7610731ce07a09ed70e5d9beacc579b38fb305e (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.c24
-rw-r--r--lib/libc/include/thread_private.h13
-rw-r--r--lib/libc/thread/rthread_cb.h4
-rw-r--r--lib/libc/thread/rthread_libc.c28
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;
}