From: Ariadne Conill <ariadne@dereferenced.org>
To: musl@lists.openwall.com
Cc: Ariadne Conill <ariadne@dereferenced.org>
Subject: [musl] [PATCH] harden against unauthorized writes to the atexit function lists
Date: Tue, 1 Dec 2020 17:55:39 -0700 [thread overview]
Message-ID: <20201202005539.6418-1-ariadne@dereferenced.org> (raw)
previously, the first atexit list block was stored in BSS, which means an
attacker could potentially ascertain its location and modify it, allowing
for its abuse as a code execution mechanism.
by moving the atexit list into a series of anonymous mmaped pages, we can
use mprotect to protect the atexit lists by keeping them readonly when they
are not being mutated by the __cxa_atexit() function.
---
src/exit/atexit.c | 69 ++++++++++++++++++++++++++++++++---------------
1 file changed, 47 insertions(+), 22 deletions(-)
diff --git a/src/exit/atexit.c b/src/exit/atexit.c
index 854e9fdd..8bf1cfcb 100644
--- a/src/exit/atexit.c
+++ b/src/exit/atexit.c
@@ -1,5 +1,6 @@
#include <stdlib.h>
#include <stdint.h>
+#include <sys/mman.h>
#include "libc.h"
#include "lock.h"
#include "fork_impl.h"
@@ -9,17 +10,17 @@
#define realloc undef
#define free undef
-/* Ensure that at least 32 atexit handlers can be registered without malloc */
-#define COUNT 32
-
static struct fl
{
struct fl *next;
- void (*f[COUNT])(void *);
- void *a[COUNT];
-} builtin, *head;
+ struct fl_pair {
+ void (*f)(void *);
+ void *a;
+ } pairs[];
+} *head;
static int slot;
+static size_t slot_max;
static volatile int lock[1];
volatile int *const __atexit_lockptr = lock;
@@ -27,12 +28,19 @@ void __funcs_on_exit()
{
void (*func)(void *), *arg;
LOCK(lock);
- for (; head; head=head->next, slot=COUNT) while(slot-->0) {
- func = head->f[slot];
- arg = head->a[slot];
- UNLOCK(lock);
- func(arg);
- LOCK(lock);
+ for (; head; head=head->next, slot=slot_max) {
+ struct fl *next = head->next;
+
+ while(slot-->0) {
+ func = head->pairs[slot].f;
+ arg = head->pairs[slot].a;
+ UNLOCK(lock);
+ func(arg);
+ LOCK(lock);
+ }
+
+ munmap(head, PAGE_SIZE);
+ head = next;
}
}
@@ -42,28 +50,45 @@ void __cxa_finalize(void *dso)
int __cxa_atexit(void (*func)(void *), void *arg, void *dso)
{
+ struct fl *cursor;
+
LOCK(lock);
- /* Defer initialization of head so it can be in BSS */
- if (!head) head = &builtin;
+ /* Figure out how many slots we can have per page: page size minus one pointer then divided by two for function-argument pairs. */
+ slot_max = (PAGE_SIZE - sizeof(void *)) / sizeof(struct fl_pair);
+
+ /* Determine if a new allocation is necessary. */
+ if (!head || slot == slot_max)
+ cursor = 0;
+ else
+ cursor = head;
- /* If the current function list is full, add a new one */
- if (slot==COUNT) {
- struct fl *new_fl = calloc(sizeof(struct fl), 1);
- if (!new_fl) {
+ /* If a new allocation is necessary, allocate it read-write, otherwise make the current atexit list read-write. */
+ if (!cursor) {
+ cursor = mmap(0, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
+ if (cursor == MAP_FAILED) {
UNLOCK(lock);
return -1;
}
- new_fl->next = head;
- head = new_fl;
+ cursor->next = head;
+ head = cursor;
slot = 0;
+ } else if (mprotect(cursor, PAGE_SIZE, PROT_READ | PROT_WRITE)) {
+ UNLOCK(lock);
+ return -1;
}
/* Append function to the list. */
- head->f[slot] = func;
- head->a[slot] = arg;
+ cursor->pairs[slot].f = func;
+ cursor->pairs[slot].a = arg;
slot++;
+ /* Mark the atexit list read-only to avoid its abuse. */
+ if (mprotect(cursor, PAGE_SIZE, PROT_READ)) {
+ UNLOCK(lock);
+ return -1;
+ }
+
UNLOCK(lock);
return 0;
}
--
2.29.2
next reply other threads:[~2020-12-02 0:56 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-12-02 0:55 Ariadne Conill [this message]
2020-12-02 1:37 ` Rich Felker
2020-12-03 17:55 ` Matthew Maurer
2020-12-03 19:16 ` Rich Felker
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20201202005539.6418-1-ariadne@dereferenced.org \
--to=ariadne@dereferenced.org \
--cc=musl@lists.openwall.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://git.vuxu.org/mirror/musl/
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).