summaryrefslogtreecommitdiff
path: root/lib/libc
diff options
context:
space:
mode:
authorOtto Moerbeek <otto@cvs.openbsd.org>2006-02-22 07:16:33 +0000
committerOtto Moerbeek <otto@cvs.openbsd.org>2006-02-22 07:16:33 +0000
commitb15dc3c23fde71fcea97932c743ca4e3ecaab843 (patch)
treea5624c757a10783ff14aac8e2209ed66b9450f29 /lib/libc
parent60672e19a3317a0a19615e0a50f42ad89c53bf02 (diff)
Avouid a race in atexit() handling by introducing a lock. Problem
originally reported by Gergely Kovacs; help from dhartmei@; ok tedu@ millert@
Diffstat (limited to 'lib/libc')
-rw-r--r--lib/libc/include/thread_private.h13
-rw-r--r--lib/libc/stdlib/atexit.c29
-rw-r--r--lib/libc/thread/unithread_malloc_lock.c20
3 files changed, 51 insertions, 11 deletions
diff --git a/lib/libc/include/thread_private.h b/lib/libc/include/thread_private.h
index 9fbadce008e..5fbbf592a41 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.17 2005/11/15 11:56:40 millert Exp $ */
+/* $OpenBSD: thread_private.h,v 1.18 2006/02/22 07:16:31 otto Exp $ */
/* PUBLIC DOMAIN: No Rights Reserved. Marco S Hyman <marc@snafu.org> */
@@ -123,5 +123,16 @@ void _thread_malloc_unlock(void);
_thread_malloc_init();\
} while (0)
+void _thread_atexit_lock(void);
+void _thread_atexit_unlock(void);
+
+#define _ATEXIT_LOCK() do { \
+ if (__isthreaded) \
+ _thread_atexit_lock(); \
+ } while (0)
+#define _ATEXIT_UNLOCK() do { \
+ if (__isthreaded) \
+ _thread_atexit_unlock();\
+ } while (0)
#endif /* _THREAD_PRIVATE_H_ */
diff --git a/lib/libc/stdlib/atexit.c b/lib/libc/stdlib/atexit.c
index cb96bf0aa93..50f8ec93728 100644
--- a/lib/libc/stdlib/atexit.c
+++ b/lib/libc/stdlib/atexit.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: atexit.c,v 1.11 2005/10/26 18:55:26 otto Exp $ */
+/* $OpenBSD: atexit.c,v 1.12 2006/02/22 07:16:32 otto Exp $ */
/*
* Copyright (c) 2002 Daniel Hartmeier
* All rights reserved.
@@ -34,6 +34,7 @@
#include <stdlib.h>
#include <unistd.h>
#include "atexit.h"
+#include "thread_private.h"
int __atexit_invalid = 1;
struct atexit *__atexit;
@@ -54,22 +55,25 @@ struct atexit *__atexit;
int
atexit(void (*fn)(void))
{
- struct atexit *p = __atexit;
+ struct atexit *p;
int pgsize = getpagesize();
+ int ret = -1;
if (pgsize < sizeof(*p))
return (-1);
+ _ATEXIT_LOCK();
+ p = __atexit;
if (p != NULL) {
if (p->ind + 1 >= p->max)
p = NULL;
else if (mprotect(p, pgsize, PROT_READ | PROT_WRITE))
- return (-1);
+ goto unlock;
}
if (p == NULL) {
p = mmap(NULL, pgsize, PROT_READ | PROT_WRITE,
MAP_ANON | MAP_PRIVATE, -1, 0);
if (p == MAP_FAILED)
- return (-1);
+ goto unlock;
if (__atexit == NULL) {
p->fns[0] = NULL;
p->ind = 1;
@@ -84,8 +88,11 @@ atexit(void (*fn)(void))
}
p->fns[p->ind++] = fn;
if (mprotect(p, pgsize, PROT_READ))
- return (-1);
- return (0);
+ goto unlock;
+ ret = 0;
+unlock:
+ _ATEXIT_UNLOCK();
+ return (ret);
}
/*
@@ -94,18 +101,20 @@ atexit(void (*fn)(void))
void
__atexit_register_cleanup(void (*fn)(void))
{
- struct atexit *p = __atexit;
+ struct atexit *p;
int pgsize = getpagesize();
if (pgsize < sizeof(*p))
return;
+ _ATEXIT_LOCK();
+ p = __atexit;
while (p != NULL && p->next != NULL)
p = p->next;
if (p == NULL) {
p = mmap(NULL, pgsize, PROT_READ | PROT_WRITE,
MAP_ANON | MAP_PRIVATE, -1, 0);
if (p == MAP_FAILED)
- return;
+ goto unlock;
p->ind = 1;
p->max = (pgsize - ((char *)&p->fns[0] - (char *)p)) /
sizeof(p->fns[0]);
@@ -115,8 +124,10 @@ __atexit_register_cleanup(void (*fn)(void))
__atexit_invalid = 0;
} else {
if (mprotect(p, pgsize, PROT_READ | PROT_WRITE))
- return;
+ goto unlock;
}
p->fns[0] = fn;
mprotect(p, pgsize, PROT_READ);
+unlock:
+ _ATEXIT_UNLOCK();
}
diff --git a/lib/libc/thread/unithread_malloc_lock.c b/lib/libc/thread/unithread_malloc_lock.c
index 2c195a9a95c..f7231915d6f 100644
--- a/lib/libc/thread/unithread_malloc_lock.c
+++ b/lib/libc/thread/unithread_malloc_lock.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: unithread_malloc_lock.c,v 1.5 2004/06/07 21:11:23 marc Exp $ */
+/* $OpenBSD: unithread_malloc_lock.c,v 1.6 2006/02/22 07:16:32 otto Exp $ */
#include <sys/time.h>
#include "thread_private.h"
@@ -11,6 +11,12 @@ WEAK_ALIAS(_thread_malloc_lock);
WEAK_ALIAS(_thread_malloc_unlock);
WEAK_ALIAS(_thread_malloc_init);
+WEAK_PROTOTYPE(_thread_atexit_lock);
+WEAK_PROTOTYPE(_thread_atexit_unlock);
+
+WEAK_ALIAS(_thread_atexit_lock);
+WEAK_ALIAS(_thread_atexit_unlock);
+
void
WEAK_NAME(_thread_malloc_lock)(void)
{
@@ -28,3 +34,15 @@ WEAK_NAME(_thread_malloc_init)(void)
{
return;
}
+
+void
+WEAK_NAME(_thread_atexit_lock)(void)
+{
+ return;
+}
+
+void
+WEAK_NAME(_thread_atexit_unlock)(void)
+{
+ return;
+}