diff options
author | Jakob Kaivo <jkk@ung.org> | 2024-06-11 11:38:32 -0400 |
---|---|---|
committer | Jakob Kaivo <jkk@ung.org> | 2024-06-11 11:38:32 -0400 |
commit | a550833c70541ca909fc3d07771680b4162b6b41 (patch) | |
tree | 7018b7bb73efe5dfcd6fedf0143a572acac45141 | |
parent | be9ae97e15714cc258426dee47844c5ff905cb28 (diff) |
separate SIGSEGV handler from jkmalloc() so it can be installed without requiring dynamic memory use
-rw-r--r-- | mk/__jkmalloc.d | 1 | ||||
-rw-r--r-- | mk/__segv.d | 11 | ||||
-rw-r--r-- | mk/all.mk | 1 | ||||
-rw-r--r-- | mk/deps.mk | 4 | ||||
-rw-r--r-- | src/__main.c | 3 | ||||
-rw-r--r-- | src/signal/__segv.c | 147 | ||||
-rw-r--r-- | src/signal/_signal.h | 1 | ||||
-rw-r--r-- | src/stdlib/__jkmalloc.c | 131 | ||||
-rw-r--r-- | src/stdlib/_jkmalloc.h | 37 |
9 files changed, 207 insertions, 129 deletions
diff --git a/mk/__jkmalloc.d b/mk/__jkmalloc.d index 6436cbcf..5d4a1e77 100644 --- a/mk/__jkmalloc.d +++ b/mk/__jkmalloc.d @@ -4,7 +4,6 @@ libc.a(__jkmalloc.o): $(OBJDIR)/__jkmalloc.o $(OBJDIR)/__jkmalloc.o: src/stdlib/__jkmalloc.c $(OBJDIR)/__jkmalloc.o: src/_safety.h -$(OBJDIR)/__jkmalloc.o: src/_forced/sigaction.h $(OBJDIR)/__jkmalloc.o: src/_forced/mmap.h $(OBJDIR)/__jkmalloc.o: src/_forced/munmap.h $(OBJDIR)/__jkmalloc.o: src/_forced/mprotect.h diff --git a/mk/__segv.d b/mk/__segv.d new file mode 100644 index 00000000..ac2464a9 --- /dev/null +++ b/mk/__segv.d @@ -0,0 +1,11 @@ +libc_C.0: libc.a(__segv.o) +libc.a(__segv.o): $(OBJDIR)/__segv.o + @$(AR) $(ARFLAGS) $@ $(OBJDIR)/$% + +$(OBJDIR)/__segv.o: src/signal/__segv.c +$(OBJDIR)/__segv.o: src/_safety.h +$(OBJDIR)/__segv.o: src/_forced/sigaction.h +$(OBJDIR)/__segv.o: src/stdlib/_jkmalloc.h +$(OBJDIR)/__segv.o: + @mkdir -p $(@D) + $(CC) -c -o $@ $(CFLAGS) src/signal/__segv.c @@ -372,6 +372,7 @@ include mk/raise.d include mk/__signal_handler.d include mk/__sigsegv.d include mk/__signal_h.d +include mk/__segv.d include mk/frexp.d include mk/erfc.d include mk/rint.d @@ -1498,6 +1498,10 @@ all: mk/__signal_h.d mk/__signal_h.d: src/signal/__signal_h.c sh mk/deps.sh src/signal/__signal_h.c +all: mk/__segv.d +mk/__segv.d: src/signal/__segv.c + sh mk/deps.sh src/signal/__segv.c + all: mk/frexp.d mk/frexp.d: src/math/frexp.c sh mk/deps.sh src/math/frexp.c diff --git a/src/__main.c b/src/__main.c index a24c24ef..510def1e 100644 --- a/src/__main.c +++ b/src/__main.c @@ -3,6 +3,7 @@ #include <locale.h> #include "stdio/_stdio.h" #include "stdlib/_stdlib.h" +#include "signal/_signal.h" #undef stdin #undef stdout @@ -39,6 +40,8 @@ void __init_libc(void) extern char **environ; __stdlib_h.environ = environ; #endif + + __segv(); } void __main(int (*main)(int, char*[]), int argc, char **argv) diff --git a/src/signal/__segv.c b/src/signal/__segv.c new file mode 100644 index 00000000..7a4a2656 --- /dev/null +++ b/src/signal/__segv.c @@ -0,0 +1,147 @@ +#include <errno.h> +#include <limits.h> +#include <stdlib.h> +#include <signal.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> + +#include "_safety.h" + +#ifdef _XOPEN_SOURCE +#else +#include "_forced/sigaction.h" +#include "_forced/mprotect.h" + +#define sysconf(__n) 4096 +#define psiginfo(x, y) fprintf(stderr, "%s (%p)\n", (char*)(y), (void*)(x)) +#define sigemptyset(x) memset(x, 0, sizeof(*x)) +#endif + +#include "stdlib/_jkmalloc.h" + +static void __jk_undef(void) +{ + static int printed = 0; + if (printed == 0) { + printed = 1; + fprintf(stderr, "Undefined Behavior: "); + } +} + +static void __jk_error(const char *s, void *addr, struct jk_source *src) +{ + __jk_undef(); + + if (s && *s) { + fputs(s, stderr); + if (addr != NULL) { + fprintf(stderr, " %p", addr); + } + fputs("\n", stderr); + } + + if (src && src->bucket && src->bucket->trace[0] != '\0') { + fwrite(src->bucket->trace, src->bucket->tlen, 1, stderr); + fputs("\n", stderr); + } + + if (src && src->file) { + fprintf(stderr, "!!! %s() (%s:%ju)\n", src->func, src->file, src->line); + } + + _Exit(JKMALLOC_EXIT_VALUE); +} + +static void __jk_sigaction(int sig, siginfo_t *si, void *addr) +{ + __signal_h.current = 0; + + (void)sig; (void)addr; + + __jk_undef(); + + if (__dangerous[0].func) { + fprintf(stderr, "In call to %s, attempting to read parameter %s (%p)\n", __dangerous[0].func, __dangerous[0].param, __dangerous[0].addr); + } + + if (__dangerous[1].func) { + fprintf(stderr, "In call to %s, attempting to write parameter %s (%p)\n", __dangerous[1].func, __dangerous[1].param, __dangerous[1].addr); + } + + if (!si) { + __jk_error("No signal information provided", NULL, NULL); + } + + if (si->si_addr == NULL) { + psiginfo(si, "NULL pointer dereference"); + __jk_error(NULL, NULL, NULL); + } + + struct jk_bucket *bucket = jk_pageof(si->si_addr); + if (mprotect(bucket, __jk_pagesize, PROT_READ) != 0) { + psiginfo(si, NULL); + __jk_error(NULL, NULL, NULL); + } + + MAGIC_CHECK: + switch (bucket->magic) { + case JK_UNDER_MAGIC: + if (bucket->size == 0) { + psiginfo(si, "Attempt to use 0-byte allocation"); + } else { + psiginfo(si, "Heap underflow detected"); + } + break; + + case JK_OVER_MAGIC: + if (bucket->size == 0) { + psiginfo(si, "Attempt to use 0-byte allocation"); + } else { + psiginfo(si, "Heap overflow detected"); + fprintf(stderr, "Allocation of size %zu at %p, overflow at %p (offset %zu)\n", bucket->size, (void*)bucket->start, si->si_addr, (size_t)((char*)si->si_addr - (char*)bucket->start)); + fprintf(stderr, "Buffer begins with %4s\n", (char*)bucket->start); + } + break; + + case JK_FREE_MAGIC: + psiginfo(si, "Use after free() detected"); + break; + + case JK_RONLY_MAGIC: + psiginfo(si, "Attempt to modify read-only memory detected"); + break; + + default: + /* try to find the actual error */ + bucket = (void*)((char*)bucket - __jk_pagesize); + if (mprotect(bucket, __jk_pagesize, PROT_READ) != 0) { + psiginfo(si, NULL); + __jk_error(NULL, NULL, NULL); + } + goto MAGIC_CHECK; + } + + struct jk_source src = { .bucket = bucket }; + __jk_error(NULL, NULL, &src); +} + +GCC_SSE_HACK +void __segv(void) +{ + static int sa_set = 0; + if (!sa_set) { + struct sigaction sa = { + .sa_flags = SA_SIGINFO, + .sa_sigaction = __jk_sigaction, + }; + sigemptyset(&sa.sa_mask); + sigaction(SIGSEGV, &sa, NULL); + sa_set = 1; + } +} + +/* +SIGNAL_SAFE(0) +STDC(0) +*/ diff --git a/src/signal/_signal.h b/src/signal/_signal.h index 1e484f83..f0d038f5 100644 --- a/src/signal/_signal.h +++ b/src/signal/_signal.h @@ -13,6 +13,7 @@ extern struct __signal_h { } __signal_h; void __signal_handler(int); +void __segv(void); /* STDC(-1) diff --git a/src/stdlib/__jkmalloc.c b/src/stdlib/__jkmalloc.c index 34b34fbc..2f9bc3a3 100644 --- a/src/stdlib/__jkmalloc.c +++ b/src/stdlib/__jkmalloc.c @@ -1,7 +1,6 @@ #include <errno.h> #include <limits.h> #include <stdlib.h> -#include <signal.h> #include <stdint.h> #include <stdio.h> #include <string.h> @@ -13,66 +12,22 @@ #include <sys/mman.h> #include <unistd.h> #else -#include "_forced/sigaction.h" #include "_forced/mmap.h" #include "_forced/munmap.h" #include "_forced/mprotect.h" #define sysconf(__n) 4096 -#define psiginfo(x, y) fprintf(stderr, "%s (%p)\n", (char*)(y), (void*)(x)) -#define sigemptyset(x) memset(x, 0, sizeof(*x)) #endif #include "_jkmalloc.h" -#define PTR_BITS (CHAR_BIT * sizeof(uintptr_t)) - -#define JKMALLOC_EXIT_VALUE (127 + SIGSEGV) -#define JK_FREE_LIST_SIZE (8) - -/* magic numbers derived from CRC-32 of jk_foo_block */ -#define JK_FREE_MAGIC (0x551a51dc) -#define JK_UNDER_MAGIC (0xcb2873ac) -#define JK_OVER_MAGIC (0x18a12c17) -#define JK_RONLY_MAGIC (0x902faf31) - -#define jk_pages(bytes) (((bytes + __jk_pagesize - 1) / __jk_pagesize) + 2) -#define jk_pageof(addr) ((void*)((uintptr_t)addr - ((uintptr_t)addr % __jk_pagesize))) -#define jk_bucketof(addr) ((void*)((uintptr_t)jk_pageof(addr) - __jk_pagesize)) - -struct jk_bucket { - uint32_t magic; - uintptr_t start; - size_t size; - size_t align; - size_t pages; - size_t tlen; - char trace[]; -}; - -struct jk_source { - const char *file; - const char *func; - uintmax_t line; - struct jk_bucket *bucket; -}; - static struct jk_bucket *__jk_free_list[JK_FREE_LIST_SIZE]; static size_t __jk_free_buckets = 0; -static size_t __jk_pagesize = 0; - -static void __jk_undef(void) -{ - static int printed = 0; - if (printed == 0) { - printed = 1; - fprintf(stderr, "Undefined Behavior: "); - } -} +//static size_t __jk_pagesize = 0; static void __jk_error(const char *s, void *addr, struct jk_source *src) { - __jk_undef(); + fprintf(stderr, "Undefined Behavior: "); if (s && *s) { fputs(s, stderr); @@ -117,91 +72,11 @@ static void *__jk_page_alloc(size_t npages) return pages; } -static void __jk_sigaction(int sig, siginfo_t *si, void *addr) -{ - __signal_h.current = 0; - - (void)sig; (void)addr; - - __jk_undef(); - - if (__dangerous.func) { - fprintf(stderr, "In call to %s, accessing parameter %s (%p)\n", __dangerous.func, __dangerous.param, __dangerous.addr); - } - - if (!si) { - __jk_error("No signal information provided", NULL, NULL); - } - - if (si->si_addr == NULL) { - psiginfo(si, "NULL pointer dereference"); - __jk_error(NULL, NULL, NULL); - } - - struct jk_bucket *bucket = jk_pageof(si->si_addr); - if (mprotect(bucket, __jk_pagesize, PROT_READ) != 0) { - psiginfo(si, NULL); - __jk_error(NULL, NULL, NULL); - } - - MAGIC_CHECK: - switch (bucket->magic) { - case JK_UNDER_MAGIC: - if (bucket->size == 0) { - psiginfo(si, "Attempt to use 0-byte allocation"); - } else { - psiginfo(si, "Heap underflow detected"); - } - break; - - case JK_OVER_MAGIC: - if (bucket->size == 0) { - psiginfo(si, "Attempt to use 0-byte allocation"); - } else { - psiginfo(si, "Heap overflow detected"); - fprintf(stderr, "Allocation of size %zu at %p, overflow at %p (offset %zu)\n", bucket->size, (void*)bucket->start, si->si_addr, (size_t)((char*)si->si_addr - (char*)bucket->start)); - fprintf(stderr, "Buffer begins with %4s\n", (char*)bucket->start); - } - break; - - case JK_FREE_MAGIC: - psiginfo(si, "Use after free() detected"); - break; - - case JK_RONLY_MAGIC: - psiginfo(si, "Attempt to modify read-only memory detected"); - break; - - default: - /* try to find the actual error */ - bucket = (void*)((char*)bucket - __jk_pagesize); - if (mprotect(bucket, __jk_pagesize, PROT_READ) != 0) { - psiginfo(si, NULL); - __jk_error(NULL, NULL, NULL); - } - goto MAGIC_CHECK; - } - - struct jk_source src = { .bucket = bucket }; - __jk_error(NULL, NULL, &src); -} - GCC_SSE_HACK void* __jkmalloc(void *ptr, size_t alignment, size_t size1, size_t size2, const char *user) { - static int sa_set = 0; - if (!sa_set) { - struct sigaction sa = { - .sa_flags = SA_SIGINFO, - .sa_sigaction = __jk_sigaction, - }; - sigemptyset(&sa.sa_mask); - sigaction(SIGSEGV, &sa, NULL); - sa_set = 1; - } - if (__jk_pagesize == 0) { - __jk_pagesize = sysconf(_SC_PAGESIZE); + //__jk_pagesize = sysconf(_SC_PAGESIZE); } struct jk_source src = { diff --git a/src/stdlib/_jkmalloc.h b/src/stdlib/_jkmalloc.h index cab5cfcb..107bf904 100644 --- a/src/stdlib/_jkmalloc.h +++ b/src/stdlib/_jkmalloc.h @@ -3,6 +3,43 @@ #include <inttypes.h> +#define PTR_BITS (CHAR_BIT * sizeof(uintptr_t)) + +#define JKMALLOC_EXIT_VALUE (127 + SIGSEGV) +#define JK_FREE_LIST_SIZE (8) + +#define __jk_pagesize (4096) + +/* magic numbers derived from CRC-32 of jk_foo_block */ +#define JK_FREE_MAGIC (0x551a51dc) +#define JK_UNDER_MAGIC (0xcb2873ac) +#define JK_OVER_MAGIC (0x18a12c17) +#define JK_RONLY_MAGIC (0x902faf31) + +#define jk_pages(bytes) (((bytes + __jk_pagesize - 1) / __jk_pagesize) + 2) +#define jk_pageof(addr) ((void*)((uintptr_t)addr - ((uintptr_t)addr % __jk_pagesize))) +#define jk_bucketof(addr) ((void*)((uintptr_t)jk_pageof(addr) - __jk_pagesize)) + + +struct jk_bucket { + uint32_t magic; + uintptr_t start; + size_t size; + size_t align; + size_t pages; + size_t tlen; + char trace[]; +}; + + +struct jk_source { + const char *file; + const char *func; + uintmax_t line; + struct jk_bucket *bucket; +}; + + void* __jkmalloc(void *ptr, size_t alignment, size_t size1 , size_t size2, const char *user); #endif |