From 672981b35d2e6262d47f42d1ae4ab880262509e7 Mon Sep 17 00:00:00 2001 From: Greg Haerr Date: Fri, 6 Dec 2024 21:04:33 -0700 Subject: [PATCH 1/2] [kernel] Remove CONFIG_EXEC_LOW_STACK allowing stack below .data section --- elks/arch/i86/kernel/process.c | 7 ------- elks/arch/i86/mm/malloc.c | 4 ---- elks/fs/exec.c | 28 ---------------------------- 3 files changed, 39 deletions(-) diff --git a/elks/arch/i86/kernel/process.c b/elks/arch/i86/kernel/process.c index a3695dd7c..d50a2c9bc 100644 --- a/elks/arch/i86/kernel/process.c +++ b/elks/arch/i86/kernel/process.c @@ -50,13 +50,6 @@ void stack_check(void) { segoff_t end = current->t_endbrk; -#ifdef CONFIG_EXEC_LOW_STACK - if (current->t_begstack <= current->t_enddata) { /* stack below heap?*/ - if (current->t_regs.sp < end) - return; - end = 0; - } else -#endif { /* optional: check stack over min stack*/ if (current->t_regs.sp < current->t_begstack - current->t_minstack) { diff --git a/elks/arch/i86/mm/malloc.c b/elks/arch/i86/mm/malloc.c index 06aae746d..d8fea63ae 100644 --- a/elks/arch/i86/mm/malloc.c +++ b/elks/arch/i86/mm/malloc.c @@ -249,10 +249,6 @@ int sys_brk(segoff_t newbrk) return -ENOMEM; } } -#ifdef CONFIG_EXEC_LOW_STACK - if (newbrk > current->t_endseg) - return -ENOMEM; -#endif current->t_endbrk = newbrk; return 0; diff --git a/elks/fs/exec.c b/elks/fs/exec.c index 68d1f4429..af102060e 100644 --- a/elks/fs/exec.c +++ b/elks/fs/exec.c @@ -266,18 +266,8 @@ static int execve_aout(struct inode *inode, struct file *filp, char *sptr, size_ if (esuph.msh_tbase != 0) goto error_exec3; base_data = esuph.msh_dbase; -#ifdef CONFIG_EXEC_LOW_STACK - if (base_data & 0xf) - goto error_exec3; if (base_data != 0) - debug("EXEC: New type executable stack = %x\n", base_data); - - if (add_overflow(min_len, base_data, &min_len)) /* adds stack size*/ goto error_exec3; -#else - if (base_data != 0) - goto error_exec3; -#endif break; #endif /* CONFIG_EXEC_MMODEL*/ default: @@ -293,9 +283,6 @@ static int execve_aout(struct inode *inode, struct file *filp, char *sptr, size_ goto error_exec3; case 1: len = min_len; -#ifdef CONFIG_EXEC_LOW_STACK - if (!base_data) -#endif { stack = mh.minstack? mh.minstack: INIT_STACK; if (add_overflow(len, stack, &len)) { /* add stack */ @@ -335,14 +322,6 @@ static int execve_aout(struct inode *inode, struct file *filp, char *sptr, size_ } else { stack = INIT_STACK; len = min_len; -#ifdef CONFIG_EXEC_LOW_STACK - if (base_data) { - if (add_overflow(len, INIT_HEAP, &len)) { - retval = -EFBIG; - goto error_exec3; - } - } else -#endif { if (add_overflow(len, INIT_HEAP + INIT_STACK, &len)) { retval = -EFBIG; @@ -495,14 +474,7 @@ static int execve_aout(struct inode *inode, struct file *filp, char *sptr, size_ currentp->t_enddata = (size_t)mh.dseg + (size_t)mh.bseg + base_data; currentp->t_endseg = len; currentp->t_regs.dx = currentp->t_minstack = stack; - -#ifdef CONFIG_EXEC_LOW_STACK - currentp->t_begstack = ((base_data /* Just above the top of stack */ - ? base_data - : currentp->t_endseg) - slen) & ~1; -#else currentp->t_begstack = (currentp->t_endseg - slen) & ~1; /* force even SP and argv */ -#endif fmemcpyb((char *)currentp->t_begstack, seg_data->base, sptr, ds, slen); finalize_exec(inode, seg_code, seg_data, (word_t)mh.entry, 0); From c5ce605da0b6e5991742cf4bd4a717f13db05a1a Mon Sep 17 00:00:00 2001 From: Greg Haerr Date: Sat, 7 Dec 2024 17:49:29 -0700 Subject: [PATCH 2/2] [kernel,libc] Rewrite kernel brk/sbrk, fix C library malloc --- elks/arch/i86/kernel/process.c | 34 +++++++++++------------ elks/arch/i86/mm/malloc.c | 49 +++++++++++++++++++++------------- libc/malloc/Makefile | 9 ++++--- libc/malloc/__mini_malloc.c | 8 +++--- libc/malloc/malloc.c | 6 ++++- 5 files changed, 63 insertions(+), 43 deletions(-) diff --git a/elks/arch/i86/kernel/process.c b/elks/arch/i86/kernel/process.c index d50a2c9bc..95740bd4e 100644 --- a/elks/arch/i86/kernel/process.c +++ b/elks/arch/i86/kernel/process.c @@ -43,27 +43,27 @@ int run_init_process_sptr(const char *cmd, char *sptr, int slen) } /* - * We only need to do this as long as we support old format binaries - * that grow stack and heap towards each other + * Check that SP is within proper range, called before every syscall. */ void stack_check(void) { - segoff_t end = current->t_endbrk; - - { - /* optional: check stack over min stack*/ - if (current->t_regs.sp < current->t_begstack - current->t_minstack) { - if (current->t_minstack) /* display if protected stack*/ - printk("(%P)STACK OUTSIDE PROTECTED LIMIT by %u\n", - current->t_begstack - current->t_minstack - current->t_regs.sp); - } - - /* check stack overflow heap*/ - if (current->t_regs.sp > end) - return; + segoff_t sp = current->t_regs.sp; + segoff_t brk = current->t_endbrk; + segoff_t stacklow = current->t_begstack - current->t_minstack; + + if (sp < brk) { + printk("(%P)STACK OVERFLOW by %u\n", brk - sp); + printk("curbreak %u, SP %u\n", current->t_endbrk, current->t_regs.sp); + do_exit(SIGSEGV); + } + if (sp < stacklow) { + /* notification only, allow process to continue */ + printk("(%P)STACK USING %u UNUSED HEAP\n", stacklow - sp); + } + if (sp > current->t_begstack) { + printk("(%P)STACK UNDERFLOW\n"); + do_exit(SIGSEGV); } - printk("(%P)STACK OVERFLOW by %u\n", end - current->t_regs.sp); - do_exit(SIGSEGV); } /* diff --git a/elks/arch/i86/mm/malloc.c b/elks/arch/i86/mm/malloc.c index d8fea63ae..d14d56f8b 100644 --- a/elks/arch/i86/mm/malloc.c +++ b/elks/arch/i86/mm/malloc.c @@ -230,8 +230,11 @@ void mm_get_usage (unsigned int * pfree, unsigned int * pused) // User data segment functions -int sys_brk(segoff_t newbrk) +static int set_brk(segoff_t brk, int increment) { + segoff_t newbrk = brk + increment; + segoff_t stacklow; + /***unsigned int memfree, memused; mm_get_usage(&memfree, &memused); printk("brk(%P): new %x, edat %x, ebrk %x, free %x sp %x, eseg %x, %d/%dK\n", @@ -239,36 +242,46 @@ int sys_brk(segoff_t newbrk) current->t_regs.sp - current->t_endbrk, current->t_regs.sp, current->t_endseg, memfree, memused);***/ - if (newbrk < current->t_enddata) + if (newbrk < current->t_enddata) { + printk("(%P)SBRK %d FAIL, BELOW HEAP\n", increment); return -ENOMEM; + } - if (current->t_begstack > current->t_endbrk) { /* stack above heap?*/ - if (newbrk > current->t_begstack - current->t_minstack) { - printk("(%d)CAN'T EXPAND HEAP by %u\n", - current->pid, newbrk - (current->t_begstack - current->t_minstack)); - return -ENOMEM; - } + stacklow = current->t_begstack - current->t_minstack; + if (newbrk > stacklow) { + printk("(%P)SBRK %d FAIL, OUT OF HEAP SPACE\n", increment); + return -ENOMEM; + } + if (newbrk > current->t_regs.sp) { + printk("(%P)SBRK %d FAIL, WOULD OVERWRITE STACK\n", increment); + return -ENOMEM; } - current->t_endbrk = newbrk; + current->t_endbrk = newbrk; return 0; } +int sys_brk(segoff_t newbrk) +{ + dprintk("(%P)BRK %u\n", newbrk); + return set_brk(newbrk, 0); +} -int sys_sbrk (int increment, segoff_t *pbrk) +int sys_sbrk(int increment, segoff_t *pbrk) { segoff_t brk = current->t_endbrk; /* always return start of old break*/ int err; - debug("sbrk incr %u pointer %04x curbreak %04x\n", increment, pbrk, brk); + if (increment) + dprintk("(%P)SBRK %d, curbreak %u, SP %u\n", + increment, current->t_endbrk, current->t_regs.sp); err = verify_area(VERIFY_WRITE, pbrk, sizeof(*pbrk)); if (err) return err; - if (increment) { - err = sys_brk(brk + increment); - if (err) return err; - } - + /* FIXME test for brk+increment overflow/underflow here */ + err = set_brk(brk, increment); + if (err) + return err; put_user (brk, pbrk); return 0; } @@ -303,12 +316,12 @@ int sys_fmemfree(unsigned short segment) seg_free(seg); return 0; } - debug("sys_fmemfree: not owner %04x\n", segment); + printk("sys_fmemfree: not owner %04x\n", segment); return -EACCES; } n = seg->all.next; } - debug("sys_fmemfree: segment not found %04x\n", segment); + printk("sys_fmemfree: segment not found %04x\n", segment); return -EINVAL; } diff --git a/libc/malloc/Makefile b/libc/malloc/Makefile index d332c967a..1a85fae90 100644 --- a/libc/malloc/Makefile +++ b/libc/malloc/Makefile @@ -4,12 +4,13 @@ COMPILER ?= ia16 LIB ?= out.a include $(TOPDIR)/libc/$(COMPILER).inc -#CFLAGS += -DL_alloca -#CFLAGS += -DLAZY_FREE -# MCHUNK is word not byte min allocation size -CFLAGS += -DMCHUNK=512 +# allocations smaller than MCHUNK words (not bytes) are rounded up, +# larger requests are allocated from heap as is. +CFLAGS += -DMCHUNK=16 #CFLAGS += -DMINALLOC +#CFLAGS += -DLAZY_FREE #CFLAGS += -DVERBOSE +#CFLAGS += -DL_alloca # use V7 malloc for heap integrity checking #OBJS = v7malloc.o calloc.o sbrk.o brk.o diff --git a/libc/malloc/__mini_malloc.c b/libc/malloc/__mini_malloc.c index c6c1c0f1f..91b7b2e88 100644 --- a/libc/malloc/__mini_malloc.c +++ b/libc/malloc/__mini_malloc.c @@ -8,12 +8,16 @@ void __wcnear * __mini_malloc(size_t size) { mem __wcnear *ptr; - size_t sz; +#if 0 + size_t sz; /* First time round this _might_ be odd, But we won't do that! */ sz = (size_t)sbrk(0); if(sz & (sizeof(mem) - 1)) sbrk(4 - (sz & (sizeof(mem) - 1))); +#endif + + size += sizeof(mem) * 2 - 1; /* Round up and leave space for size field */ /* Minor oops here, sbrk has a signed argument */ if((int)size <= 0 || size > (((unsigned)-1) >> 1) - sizeof(mem) * 3) @@ -22,9 +26,7 @@ __mini_malloc(size_t size) return 0; } - size += sizeof(mem) * 2 - 1; /* Round up and leave space for size field */ size /= sizeof(mem); - ptr = (mem __wcnear *) sbrk(size * sizeof(mem)); /*if((uintptr_t)ptr == (intptr_t)-1)*/ /* this is better only when not __wcnear */ if ((int)ptr == -1) diff --git a/libc/malloc/malloc.c b/libc/malloc/malloc.c index cc7d31a1e..58a2dd2e4 100644 --- a/libc/malloc/malloc.c +++ b/libc/malloc/malloc.c @@ -265,10 +265,13 @@ malloc(size_t size) { #ifdef MCHUNK unsigned int alloc; - alloc = sizeof(mem) * (MCHUNK * ((sz + MCHUNK - 1) / MCHUNK) - 1); + if (sz < MCHUNK) + alloc = sizeof(mem) * (MCHUNK * ((sz + MCHUNK - 1) / MCHUNK) - 1); + else alloc = sz * sizeof(mem); ptr = __mini_malloc(alloc); if (ptr) __insert_chunk(ptr - 1); +#if MCHUNK >= 256 else /* Oooo, near end of RAM */ { unsigned int needed = alloc; @@ -283,6 +286,7 @@ malloc(size_t size) else alloc/=2; } } +#endif ptr = __search_chunk(sz); if (ptr == 0) #endif