summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
authorotto <>2006-02-22 07:16:32 +0000
committerotto <>2006-02-22 07:16:32 +0000
commitf79af607fea8db71524b8a4a1553fb437b284616 (patch)
treeb3ca7c28557a9e6e12c3c78b3442ef8b086ebff1 /src/lib
parentac647c4699103a57b222ea6685c784a0445c0790 (diff)
downloadopenbsd-f79af607fea8db71524b8a4a1553fb437b284616.tar.gz
openbsd-f79af607fea8db71524b8a4a1553fb437b284616.tar.bz2
openbsd-f79af607fea8db71524b8a4a1553fb437b284616.zip
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 'src/lib')
-rw-r--r--src/lib/libc/include/thread_private.h13
-rw-r--r--src/lib/libc/stdlib/atexit.c29
2 files changed, 32 insertions, 10 deletions
diff --git a/src/lib/libc/include/thread_private.h b/src/lib/libc/include/thread_private.h
index 9fbadce008..5fbbf592a4 100644
--- a/src/lib/libc/include/thread_private.h
+++ b/src/lib/libc/include/thread_private.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: thread_private.h,v 1.17 2005/11/15 11:56:40 millert Exp $ */ 1/* $OpenBSD: thread_private.h,v 1.18 2006/02/22 07:16:31 otto Exp $ */
2 2
3/* PUBLIC DOMAIN: No Rights Reserved. Marco S Hyman <marc@snafu.org> */ 3/* PUBLIC DOMAIN: No Rights Reserved. Marco S Hyman <marc@snafu.org> */
4 4
@@ -123,5 +123,16 @@ void _thread_malloc_unlock(void);
123 _thread_malloc_init();\ 123 _thread_malloc_init();\
124 } while (0) 124 } while (0)
125 125
126void _thread_atexit_lock(void);
127void _thread_atexit_unlock(void);
128
129#define _ATEXIT_LOCK() do { \
130 if (__isthreaded) \
131 _thread_atexit_lock(); \
132 } while (0)
133#define _ATEXIT_UNLOCK() do { \
134 if (__isthreaded) \
135 _thread_atexit_unlock();\
136 } while (0)
126 137
127#endif /* _THREAD_PRIVATE_H_ */ 138#endif /* _THREAD_PRIVATE_H_ */
diff --git a/src/lib/libc/stdlib/atexit.c b/src/lib/libc/stdlib/atexit.c
index cb96bf0aa9..50f8ec9372 100644
--- a/src/lib/libc/stdlib/atexit.c
+++ b/src/lib/libc/stdlib/atexit.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: atexit.c,v 1.11 2005/10/26 18:55:26 otto Exp $ */ 1/* $OpenBSD: atexit.c,v 1.12 2006/02/22 07:16:32 otto Exp $ */
2/* 2/*
3 * Copyright (c) 2002 Daniel Hartmeier 3 * Copyright (c) 2002 Daniel Hartmeier
4 * All rights reserved. 4 * All rights reserved.
@@ -34,6 +34,7 @@
34#include <stdlib.h> 34#include <stdlib.h>
35#include <unistd.h> 35#include <unistd.h>
36#include "atexit.h" 36#include "atexit.h"
37#include "thread_private.h"
37 38
38int __atexit_invalid = 1; 39int __atexit_invalid = 1;
39struct atexit *__atexit; 40struct atexit *__atexit;
@@ -54,22 +55,25 @@ struct atexit *__atexit;
54int 55int
55atexit(void (*fn)(void)) 56atexit(void (*fn)(void))
56{ 57{
57 struct atexit *p = __atexit; 58 struct atexit *p;
58 int pgsize = getpagesize(); 59 int pgsize = getpagesize();
60 int ret = -1;
59 61
60 if (pgsize < sizeof(*p)) 62 if (pgsize < sizeof(*p))
61 return (-1); 63 return (-1);
64 _ATEXIT_LOCK();
65 p = __atexit;
62 if (p != NULL) { 66 if (p != NULL) {
63 if (p->ind + 1 >= p->max) 67 if (p->ind + 1 >= p->max)
64 p = NULL; 68 p = NULL;
65 else if (mprotect(p, pgsize, PROT_READ | PROT_WRITE)) 69 else if (mprotect(p, pgsize, PROT_READ | PROT_WRITE))
66 return (-1); 70 goto unlock;
67 } 71 }
68 if (p == NULL) { 72 if (p == NULL) {
69 p = mmap(NULL, pgsize, PROT_READ | PROT_WRITE, 73 p = mmap(NULL, pgsize, PROT_READ | PROT_WRITE,
70 MAP_ANON | MAP_PRIVATE, -1, 0); 74 MAP_ANON | MAP_PRIVATE, -1, 0);
71 if (p == MAP_FAILED) 75 if (p == MAP_FAILED)
72 return (-1); 76 goto unlock;
73 if (__atexit == NULL) { 77 if (__atexit == NULL) {
74 p->fns[0] = NULL; 78 p->fns[0] = NULL;
75 p->ind = 1; 79 p->ind = 1;
@@ -84,8 +88,11 @@ atexit(void (*fn)(void))
84 } 88 }
85 p->fns[p->ind++] = fn; 89 p->fns[p->ind++] = fn;
86 if (mprotect(p, pgsize, PROT_READ)) 90 if (mprotect(p, pgsize, PROT_READ))
87 return (-1); 91 goto unlock;
88 return (0); 92 ret = 0;
93unlock:
94 _ATEXIT_UNLOCK();
95 return (ret);
89} 96}
90 97
91/* 98/*
@@ -94,18 +101,20 @@ atexit(void (*fn)(void))
94void 101void
95__atexit_register_cleanup(void (*fn)(void)) 102__atexit_register_cleanup(void (*fn)(void))
96{ 103{
97 struct atexit *p = __atexit; 104 struct atexit *p;
98 int pgsize = getpagesize(); 105 int pgsize = getpagesize();
99 106
100 if (pgsize < sizeof(*p)) 107 if (pgsize < sizeof(*p))
101 return; 108 return;
109 _ATEXIT_LOCK();
110 p = __atexit;
102 while (p != NULL && p->next != NULL) 111 while (p != NULL && p->next != NULL)
103 p = p->next; 112 p = p->next;
104 if (p == NULL) { 113 if (p == NULL) {
105 p = mmap(NULL, pgsize, PROT_READ | PROT_WRITE, 114 p = mmap(NULL, pgsize, PROT_READ | PROT_WRITE,
106 MAP_ANON | MAP_PRIVATE, -1, 0); 115 MAP_ANON | MAP_PRIVATE, -1, 0);
107 if (p == MAP_FAILED) 116 if (p == MAP_FAILED)
108 return; 117 goto unlock;
109 p->ind = 1; 118 p->ind = 1;
110 p->max = (pgsize - ((char *)&p->fns[0] - (char *)p)) / 119 p->max = (pgsize - ((char *)&p->fns[0] - (char *)p)) /
111 sizeof(p->fns[0]); 120 sizeof(p->fns[0]);
@@ -115,8 +124,10 @@ __atexit_register_cleanup(void (*fn)(void))
115 __atexit_invalid = 0; 124 __atexit_invalid = 0;
116 } else { 125 } else {
117 if (mprotect(p, pgsize, PROT_READ | PROT_WRITE)) 126 if (mprotect(p, pgsize, PROT_READ | PROT_WRITE))
118 return; 127 goto unlock;
119 } 128 }
120 p->fns[0] = fn; 129 p->fns[0] = fn;
121 mprotect(p, pgsize, PROT_READ); 130 mprotect(p, pgsize, PROT_READ);
131unlock:
132 _ATEXIT_UNLOCK();
122} 133}