diff options
author | otto <> | 2006-02-22 07:16:32 +0000 |
---|---|---|
committer | otto <> | 2006-02-22 07:16:32 +0000 |
commit | f79af607fea8db71524b8a4a1553fb437b284616 (patch) | |
tree | b3ca7c28557a9e6e12c3c78b3442ef8b086ebff1 /src | |
parent | ac647c4699103a57b222ea6685c784a0445c0790 (diff) | |
download | openbsd-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')
-rw-r--r-- | src/lib/libc/include/thread_private.h | 13 | ||||
-rw-r--r-- | src/lib/libc/stdlib/atexit.c | 29 |
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 | ||
126 | void _thread_atexit_lock(void); | ||
127 | void _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 | ||
38 | int __atexit_invalid = 1; | 39 | int __atexit_invalid = 1; |
39 | struct atexit *__atexit; | 40 | struct atexit *__atexit; |
@@ -54,22 +55,25 @@ struct atexit *__atexit; | |||
54 | int | 55 | int |
55 | atexit(void (*fn)(void)) | 56 | atexit(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; |
93 | unlock: | ||
94 | _ATEXIT_UNLOCK(); | ||
95 | return (ret); | ||
89 | } | 96 | } |
90 | 97 | ||
91 | /* | 98 | /* |
@@ -94,18 +101,20 @@ atexit(void (*fn)(void)) | |||
94 | void | 101 | void |
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); |
131 | unlock: | ||
132 | _ATEXIT_UNLOCK(); | ||
122 | } | 133 | } |