summaryrefslogtreecommitdiff
path: root/src/lib/libc/stdlib/atexit.c
diff options
context:
space:
mode:
authordhartmei <>2002-09-14 22:03:14 +0000
committerdhartmei <>2002-09-14 22:03:14 +0000
commit99933708b28d8f1a889e6109eb237499bf59eba2 (patch)
tree95adbcf0e9cc0d976e8e7b18bd1836b0faa0ecbf /src/lib/libc/stdlib/atexit.c
parent3a3a489a756f2852d798376f20cc0d4ab609c866 (diff)
downloadopenbsd-99933708b28d8f1a889e6109eb237499bf59eba2.tar.gz
openbsd-99933708b28d8f1a889e6109eb237499bf59eba2.tar.bz2
openbsd-99933708b28d8f1a889e6109eb237499bf59eba2.zip
Move __cleanup into mprotect'ed page to prevent unintentional modifications
similar to the atexit handlers. Idea and help deraadt@, ok deraadt@
Diffstat (limited to 'src/lib/libc/stdlib/atexit.c')
-rw-r--r--src/lib/libc/stdlib/atexit.c61
1 files changed, 56 insertions, 5 deletions
diff --git a/src/lib/libc/stdlib/atexit.c b/src/lib/libc/stdlib/atexit.c
index da5a0ddda0..98564d0dd3 100644
--- a/src/lib/libc/stdlib/atexit.c
+++ b/src/lib/libc/stdlib/atexit.c
@@ -29,7 +29,7 @@
29 */ 29 */
30 30
31#if defined(LIBC_SCCS) && !defined(lint) 31#if defined(LIBC_SCCS) && !defined(lint)
32static char *rcsid = "$OpenBSD: atexit.c,v 1.6 2002/09/06 22:48:34 henning Exp $"; 32static char *rcsid = "$OpenBSD: atexit.c,v 1.7 2002/09/14 22:03:14 dhartmei Exp $";
33#endif /* LIBC_SCCS and not lint */ 33#endif /* LIBC_SCCS and not lint */
34 34
35#include <sys/types.h> 35#include <sys/types.h>
@@ -42,6 +42,20 @@ int __atexit_invalid = 1;
42struct atexit *__atexit; 42struct atexit *__atexit;
43 43
44/* 44/*
45 * Function pointers are stored in a linked list of pages. The list
46 * is initially empty, and pages are allocated on demand. The first
47 * function pointer in the first allocated page (the last one in
48 * the linked list) is reserved for the cleanup function.
49 *
50 * Outside the following two functions, all pages are mprotect()'ed
51 * to prevent unintentional/malicious corruption.
52 *
53 * The free(malloc(1)) is a workaround causing malloc_init() to
54 * ensure that malloc.c gets the first mmap() call for its sbrk()
55 * games.
56 */
57
58/*
45 * Register a function to be performed at exit. 59 * Register a function to be performed at exit.
46 */ 60 */
47int 61int
@@ -61,9 +75,6 @@ atexit(fn)
61 } 75 }
62 if (p == NULL) { 76 if (p == NULL) {
63 if (__atexit_invalid) { 77 if (__atexit_invalid) {
64 /* malloc.c wants the first mmap() for sbrk()
65 games ('nice hack'), so enforce
66 malloc_init() with a dummy call. */
67 free(malloc(1)); 78 free(malloc(1));
68 __atexit_invalid = 0; 79 __atexit_invalid = 0;
69 } 80 }
@@ -71,7 +82,11 @@ atexit(fn)
71 MAP_ANON | MAP_PRIVATE, -1, 0); 82 MAP_ANON | MAP_PRIVATE, -1, 0);
72 if (p == MAP_FAILED) 83 if (p == MAP_FAILED)
73 return (-1); 84 return (-1);
74 p->ind = 0; 85 if (__atexit == NULL) {
86 p->fns[0] = NULL;
87 p->ind = 1;
88 } else
89 p->ind = 0;
75 p->max = (pgsize - ((char *)&p->fns[0] - (char *)p)) / 90 p->max = (pgsize - ((char *)&p->fns[0] - (char *)p)) /
76 sizeof(p->fns[0]); 91 sizeof(p->fns[0]);
77 p->next = __atexit; 92 p->next = __atexit;
@@ -82,3 +97,39 @@ atexit(fn)
82 return (-1); 97 return (-1);
83 return (0); 98 return (0);
84} 99}
100
101/*
102 * Register the cleanup function
103 */
104void
105__atexit_register_cleanup(fn)
106 void (*fn)();
107{
108 register struct atexit *p = __atexit;
109 register int pgsize = getpagesize();
110
111 if (pgsize < sizeof(*p))
112 return;
113 while (p != NULL && p->next != NULL)
114 p = p->next;
115 if (p == NULL) {
116 if (__atexit_invalid) {
117 free(malloc(1));
118 __atexit_invalid = 0;
119 }
120 p = mmap(NULL, pgsize, PROT_READ | PROT_WRITE,
121 MAP_ANON | MAP_PRIVATE, -1, 0);
122 if (p == MAP_FAILED)
123 return;
124 p->ind = 1;
125 p->max = (pgsize - ((char *)&p->fns[0] - (char *)p)) /
126 sizeof(p->fns[0]);
127 p->next = NULL;
128 __atexit = p;
129 } else {
130 if (mprotect(p, pgsize, PROT_READ | PROT_WRITE))
131 return;
132 }
133 p->fns[0] = fn;
134 mprotect(p, pgsize, PROT_READ);
135}