From 7bb4e1335435397243c9b63a64a5c61c82691357 Mon Sep 17 00:00:00 2001 From: Sylvain Gault Date: Mon, 12 Oct 2015 05:03:26 +0200 Subject: ldlinux: fix stack overflow when running COM32 modules When a COM32 module exits, the functions never return and a new call to ldlinux_enter_command is made. This could fill the stack and overflow on some data present in memory. This patch use setjmp/longjmp to return to the main function and restart from there when a COM32 module exits. Signed-off-by: Sylvain Gault --- com32/elflink/ldlinux/execute.c | 4 +++- com32/elflink/ldlinux/ldlinux.c | 28 ++++++++++++++++++++-------- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/com32/elflink/ldlinux/execute.c b/com32/elflink/ldlinux/execute.c index 653c880d..39555715 100644 --- a/com32/elflink/ldlinux/execute.c +++ b/com32/elflink/ldlinux/execute.c @@ -44,6 +44,7 @@ const struct image_types image_boot_types[] = { { NULL, 0 }, }; +extern jmp_buf __return_to_command_prompt; extern int create_args_and_load(char *); __export void execute(const char *cmdline, uint32_t type, bool sysappend) @@ -136,7 +137,8 @@ __export void execute(const char *cmdline, uint32_t type, bool sysappend) /* Restore the console */ ldlinux_console_init(); - ldlinux_enter_command(); + /* Jump back to the main to call ldlinux_enter_command */ + longjmp(__return_to_command_prompt, 1); } else if (type == IMAGE_TYPE_CONFIG) { char *argv[] = { LDLINUX, NULL, NULL }; char *config; diff --git a/com32/elflink/ldlinux/ldlinux.c b/com32/elflink/ldlinux/ldlinux.c index 9b01dd3a..0172117b 100644 --- a/com32/elflink/ldlinux/ldlinux.c +++ b/com32/elflink/ldlinux/ldlinux.c @@ -31,6 +31,8 @@ static const struct file_ext file_extensions[] = { { NULL, 0 }, }; +jmp_buf __return_to_command_prompt; + /* * Return a pointer to one byte after the last character of the * command. @@ -302,6 +304,7 @@ __export int main(int argc __unused, char **argv) const void *adv; const char *cmdline; size_t count = 0; + int retval; ldlinux_console_init(); @@ -333,16 +336,25 @@ __export int main(int argc __unused, char **argv) if (!syslinux_setadv(ADV_BOOTONCE, 0, NULL)) syslinux_adv_write(); - load_kernel(cmdline); /* Shouldn't return */ - ldlinux_enter_command(); - } - - if (!forceprompt && !shift_is_held()) - ldlinux_auto_boot(); + /* + * The corresponding longjmp is located in the execute function + * after a COM32 module has returned. + */ + retval = setjmp(__return_to_command_prompt); + if (retval == 0) + load_kernel(cmdline); /* Shouldn't return */ + } else { + retval = setjmp(__return_to_command_prompt); + if (retval == 0) { + if (!forceprompt && !shift_is_held()) + ldlinux_auto_boot(); - if (defaultlevel > 1) - ldlinux_auto_boot(); + if (defaultlevel > 1) + ldlinux_auto_boot(); + } + } + retval = setjmp(__return_to_command_prompt); ldlinux_enter_command(); return 0; } -- cgit v1.2.1 From 19d0d592ee115e8772b7dc6d5594748a49b63b0c Mon Sep 17 00:00:00 2001 From: Sylvain Gault Date: Tue, 13 Oct 2015 05:26:30 +0200 Subject: core: Fix stack overflow when reloading config The behavior when running a "CONFIG" command line is to reload ldlinux.c32 with the new file as argument. This call never return. In order to avoid stacking up the calls to start_ldlinux, this patch introduce a setjmp/longjmp to return to the first call to start_ldlinux, thus freeing all the stack space. Signed-off-by: Sylvain Gault --- core/elflink/load_env32.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) diff --git a/core/elflink/load_env32.c b/core/elflink/load_env32.c index 492cc095..db19c7aa 100644 --- a/core/elflink/load_env32.c +++ b/core/elflink/load_env32.c @@ -55,7 +55,7 @@ void init_module_subsystem(struct elf_module *module) list_add(&module->list, &modules_head); } -__export int start_ldlinux(int argc, char **argv) +static int _start_ldlinux(int argc, char **argv) { int rv; @@ -96,6 +96,62 @@ again: return rv; } +__export int start_ldlinux(int argc, char **argv) +{ + /* These variables are static to survive the longjmp. */ + static int has_jmpbuf = 0; + static jmp_buf restart; + static int savedargc; + static char *heapargs; + static size_t argsmem = 0; + char **stackargv; + char *stackargs; + char *p, *q; + int i; + + + /* 1. Save the arguments on the heap */ + for (i = 0; i < argc; i++) + argsmem += strlen(argv[i]) + 1; + + savedargc = argc; + heapargs = malloc(argsmem); + + p = heapargs; + for (i = 0; i < savedargc; i++) { + q = argv[i]; + while (*q) + *p++ = *q++; + + *p++ = '\0'; + } + + /* 2. Undo the stack if we're restarting ldlinux */ + if (has_jmpbuf) + longjmp(restart, 1); + + setjmp(restart); + has_jmpbuf = 1; + + /* 3. Convert the heap memory to stack memory to avoid memory leaks */ + stackargs = alloca(argsmem); + stackargv = alloca(savedargc * (sizeof(char *) + 1)); + + memcpy(stackargs, heapargs, argsmem); + + p = stackargs; + for (i = 0; i < savedargc; i++) { + stackargv[i] = p; + p += strlen(p) + 1; + } + + stackargv[savedargc] = NULL; + + free(heapargs); + + return _start_ldlinux(savedargc, stackargv); +} + /* note to self: do _*NOT*_ use static key word on this function */ void load_env32(com32sys_t * regs __unused) { -- cgit v1.2.1