Browse Source

Move __cleanup into mprotect'ed page to prevent unintentional modifications

similar to the atexit handlers. Idea and help deraadt@, ok deraadt@
OPENBSD_3_2
dhartmei 22 years ago
parent
commit
f29e2452e5
3 changed files with 70 additions and 17 deletions
  1. +10
    -6
      src/lib/libc/stdlib/abort.c
  2. +56
    -5
      src/lib/libc/stdlib/atexit.c
  3. +4
    -6
      src/lib/libc/stdlib/exit.c

+ 10
- 6
src/lib/libc/stdlib/abort.c View File

@ -32,19 +32,19 @@
*/ */
#if defined(LIBC_SCCS) && !defined(lint) #if defined(LIBC_SCCS) && !defined(lint)
static char *rcsid = "$OpenBSD: abort.c,v 1.7 2001/08/12 12:03:01 heko Exp $";
static char *rcsid = "$OpenBSD: abort.c,v 1.8 2002/09/14 22:03:14 dhartmei Exp $";
#endif /* LIBC_SCCS and not lint */ #endif /* LIBC_SCCS and not lint */
#include <signal.h> #include <signal.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include "thread_private.h" #include "thread_private.h"
void (*__cleanup)();
#include "atexit.h"
void void
abort() abort()
{ {
struct atexit *p = __atexit;
static int cleanup_called = 0; static int cleanup_called = 0;
sigset_t mask; sigset_t mask;
@ -64,9 +64,13 @@ abort()
/* /*
* POSIX requires we flush stdio buffers on abort * POSIX requires we flush stdio buffers on abort
*/ */
if (cleanup_called == 0 && __cleanup != NULL) {
cleanup_called = 1;
(*__cleanup)();
if (cleanup_called == 0) {
while (p != NULL && p->next != NULL)
p = p->next;
if (p != NULL && p->fns[0] != NULL) {
cleanup_called = 1;
(*p->fns[0])();
}
} }
(void)kill(getpid(), SIGABRT); (void)kill(getpid(), SIGABRT);


+ 56
- 5
src/lib/libc/stdlib/atexit.c View File

@ -29,7 +29,7 @@
*/ */
#if defined(LIBC_SCCS) && !defined(lint) #if defined(LIBC_SCCS) && !defined(lint)
static char *rcsid = "$OpenBSD: atexit.c,v 1.6 2002/09/06 22:48:34 henning Exp $";
static char *rcsid = "$OpenBSD: atexit.c,v 1.7 2002/09/14 22:03:14 dhartmei Exp $";
#endif /* LIBC_SCCS and not lint */ #endif /* LIBC_SCCS and not lint */
#include <sys/types.h> #include <sys/types.h>
@ -41,6 +41,20 @@ static char *rcsid = "$OpenBSD: atexit.c,v 1.6 2002/09/06 22:48:34 henning Exp $
int __atexit_invalid = 1; int __atexit_invalid = 1;
struct atexit *__atexit; struct atexit *__atexit;
/*
* Function pointers are stored in a linked list of pages. The list
* is initially empty, and pages are allocated on demand. The first
* function pointer in the first allocated page (the last one in
* the linked list) is reserved for the cleanup function.
*
* Outside the following two functions, all pages are mprotect()'ed
* to prevent unintentional/malicious corruption.
*
* The free(malloc(1)) is a workaround causing malloc_init() to
* ensure that malloc.c gets the first mmap() call for its sbrk()
* games.
*/
/* /*
* Register a function to be performed at exit. * Register a function to be performed at exit.
*/ */
@ -61,9 +75,6 @@ atexit(fn)
} }
if (p == NULL) { if (p == NULL) {
if (__atexit_invalid) { if (__atexit_invalid) {
/* malloc.c wants the first mmap() for sbrk()
games ('nice hack'), so enforce
malloc_init() with a dummy call. */
free(malloc(1)); free(malloc(1));
__atexit_invalid = 0; __atexit_invalid = 0;
} }
@ -71,7 +82,11 @@ atexit(fn)
MAP_ANON | MAP_PRIVATE, -1, 0); MAP_ANON | MAP_PRIVATE, -1, 0);
if (p == MAP_FAILED) if (p == MAP_FAILED)
return (-1); return (-1);
p->ind = 0;
if (__atexit == NULL) {
p->fns[0] = NULL;
p->ind = 1;
} else
p->ind = 0;
p->max = (pgsize - ((char *)&p->fns[0] - (char *)p)) / p->max = (pgsize - ((char *)&p->fns[0] - (char *)p)) /
sizeof(p->fns[0]); sizeof(p->fns[0]);
p->next = __atexit; p->next = __atexit;
@ -82,3 +97,39 @@ atexit(fn)
return (-1); return (-1);
return (0); return (0);
} }
/*
* Register the cleanup function
*/
void
__atexit_register_cleanup(fn)
void (*fn)();
{
register struct atexit *p = __atexit;
register int pgsize = getpagesize();
if (pgsize < sizeof(*p))
return;
while (p != NULL && p->next != NULL)
p = p->next;
if (p == NULL) {
if (__atexit_invalid) {
free(malloc(1));
__atexit_invalid = 0;
}
p = mmap(NULL, pgsize, PROT_READ | PROT_WRITE,
MAP_ANON | MAP_PRIVATE, -1, 0);
if (p == MAP_FAILED)
return;
p->ind = 1;
p->max = (pgsize - ((char *)&p->fns[0] - (char *)p)) /
sizeof(p->fns[0]);
p->next = NULL;
__atexit = p;
} else {
if (mprotect(p, pgsize, PROT_READ | PROT_WRITE))
return;
}
p->fns[0] = fn;
mprotect(p, pgsize, PROT_READ);
}

+ 4
- 6
src/lib/libc/stdlib/exit.c View File

@ -32,7 +32,7 @@
*/ */
#if defined(LIBC_SCCS) && !defined(lint) #if defined(LIBC_SCCS) && !defined(lint)
static char *rcsid = "$OpenBSD: exit.c,v 1.7 2002/08/30 07:58:07 dhartmei Exp $";
static char *rcsid = "$OpenBSD: exit.c,v 1.8 2002/09/14 22:03:14 dhartmei Exp $";
#endif /* LIBC_SCCS and not lint */ #endif /* LIBC_SCCS and not lint */
#include <sys/types.h> #include <sys/types.h>
@ -42,8 +42,6 @@ static char *rcsid = "$OpenBSD: exit.c,v 1.7 2002/08/30 07:58:07 dhartmei Exp $"
#include "atexit.h" #include "atexit.h"
#include "thread_private.h" #include "thread_private.h"
void (*__cleanup)();
/* /*
* This variable is zero until a process has created a thread. * This variable is zero until a process has created a thread.
* It is used to avoid calling locking functions in libc when they * It is used to avoid calling locking functions in libc when they
@ -67,13 +65,13 @@ exit(status)
p = __atexit; p = __atexit;
while (p != NULL) { while (p != NULL) {
for (n = p->ind; --n >= 0;) for (n = p->ind; --n >= 0;)
(*p->fns[n])();
if (p->fns[n] != NULL)
(*p->fns[n])();
q = p; q = p;
p = p->next; p = p->next;
munmap(q, pgsize); munmap(q, pgsize);
} }
} }
if (__cleanup)
(*__cleanup)();
/* cleanup, if registered, was called through fns[0] in the last page */
_exit(status); _exit(status);
} }

Loading…
Cancel
Save