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 | |
| 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 '')
| -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 | } |
