Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:Step:15-SP4
redis.28793
cve-2022-3647.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File cve-2022-3647.patch of Package redis.28793
From 0bf90d944313919eb8e63d3588bf63a367f020a3 Mon Sep 17 00:00:00 2001 From: "Meir Shpilraien (Spielrein)" <meir@redis.com> Date: Thu, 29 Sep 2022 08:58:58 +0300 Subject: [PATCH] Avoid crash on crash report when a bad function pointer was called (#11298) If Redis crashes due to calling an invalid function pointer, the `backtrace` function will try to dereference this invalid pointer which will cause a crash inside the crash report and will kill the processes without having all the crash report information. Example: ``` === REDIS BUG REPORT START: Cut & paste starting from here === 198672:M 19 Sep 2022 18:06:12.936 # Redis 255.255.255 crashed by signal: 11, si_code: 1 198672:M 19 Sep 2022 18:06:12.936 # Accessing address: 0x1 198672:M 19 Sep 2022 18:06:12.936 # Crashed running the instruction at: 0x1 // here the processes is crashing ``` This PR tries to fix this crash be: 1. Identify the issue when it happened. 2. Replace the invalid pointer with a pointer to some dummy function so that `backtrace` will not crash. I identification is done by comparing `eip` to `info->si_addr`, if they are the same we know that the crash happened on the same address it tries to accesses and we can conclude that it tries to call and invalid function pointer. To replace the invalid pointer we introduce a new function, `setMcontextEip`, which is very similar to `getMcontextEip` and it knows to set the Eip for the different supported OS's. After printing the trace we retrieve the old `Eip` value. --- src/debug.c | 80 ++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 58 insertions(+), 22 deletions(-) Index: redis-6.0.14/src/debug.c =================================================================== --- redis-6.0.14.orig/src/debug.c +++ redis-6.0.14/src/debug.c @@ -924,63 +924,77 @@ void bugReportStart(void) { } #ifdef HAVE_BACKTRACE -static void *getMcontextEip(ucontext_t *uc) { + +/* Returns the current eip and set it to the given new value (if its not NULL) */ +static void* getAndSetMcontextEip(ucontext_t *uc, void *eip) { +#define GET_SET_RETURN(target_var, new_val) do {\ + void *old_val = (void*)target_var; \ + if (new_val) { \ + void **temp = (void**)&target_var; \ + *temp = new_val; \ + } \ + return old_val; \ +} while(0) #if defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_6) /* OSX < 10.6 */ #if defined(__x86_64__) - return (void*) uc->uc_mcontext->__ss.__rip; + GET_SET_RETURN(uc->uc_mcontext->__ss.__rip, eip); #elif defined(__i386__) - return (void*) uc->uc_mcontext->__ss.__eip; + GET_SET_RETURN(uc->uc_mcontext->__ss.__eip, eip); #else - return (void*) uc->uc_mcontext->__ss.__srr0; + GET_SET_RETURN(uc->uc_mcontext->__ss.__srr0, eip); #endif #elif defined(__APPLE__) && defined(MAC_OS_X_VERSION_10_6) /* OSX >= 10.6 */ #if defined(_STRUCT_X86_THREAD_STATE64) && !defined(__i386__) - return (void*) uc->uc_mcontext->__ss.__rip; + GET_SET_RETURN(uc->uc_mcontext->__ss.__rip, eip); #elif defined(__i386__) - return (void*) uc->uc_mcontext->__ss.__eip; + GET_SET_RETURN(uc->uc_mcontext->__ss.__eip, eip); #else /* OSX ARM64 */ - return (void*) arm_thread_state64_get_pc(uc->uc_mcontext->__ss); + void *old_val = (void*)arm_thread_state64_get_pc(uc->uc_mcontext->__ss); + if (eip) { + arm_thread_state64_set_pc_fptr(uc->uc_mcontext->__ss, eip); + } + return old_val; #endif #elif defined(__linux__) /* Linux */ #if defined(__i386__) || ((defined(__X86_64__) || defined(__x86_64__)) && defined(__ILP32__)) - return (void*) uc->uc_mcontext.gregs[14]; /* Linux 32 */ + GET_SET_RETURN(uc->uc_mcontext.gregs[14], eip); #elif defined(__X86_64__) || defined(__x86_64__) - return (void*) uc->uc_mcontext.gregs[16]; /* Linux 64 */ + GET_SET_RETURN(uc->uc_mcontext.gregs[16], eip); #elif defined(__ia64__) /* Linux IA64 */ - return (void*) uc->uc_mcontext.sc_ip; + GET_SET_RETURN(uc->uc_mcontext.sc_ip, eip); #elif defined(__arm__) /* Linux ARM */ - return (void*) uc->uc_mcontext.arm_pc; + GET_SET_RETURN(uc->uc_mcontext.arm_pc, eip); #elif defined(__aarch64__) /* Linux AArch64 */ - return (void*) uc->uc_mcontext.pc; + GET_SET_RETURN(uc->uc_mcontext.pc, eip); #else return NULL; #endif #elif defined(__FreeBSD__) /* FreeBSD */ #if defined(__i386__) - return (void*) uc->uc_mcontext.mc_eip; + GET_SET_RETURN(uc->uc_mcontext.mc_eip, eip); #elif defined(__x86_64__) - return (void*) uc->uc_mcontext.mc_rip; + GET_SET_RETURN(uc->uc_mcontext.mc_rip, eip); #endif #elif defined(__OpenBSD__) /* OpenBSD */ #if defined(__i386__) - return (void*) uc->sc_eip; + GET_SET_RETURN(uc->sc_eip, eip); #elif defined(__x86_64__) - return (void*) uc->sc_rip; + GET_SET_RETURN(uc->sc_rip, eip); #endif #elif defined(__NetBSD__) #if defined(__i386__) - return (void*) uc->uc_mcontext.__gregs[_REG_EIP]; + GET_SET_RETURN(uc->uc_mcontext.__gregs[_REG_EIP], eip); #elif defined(__x86_64__) - return (void*) uc->uc_mcontext.__gregs[_REG_RIP]; + GET_SET_RETURN(uc->uc_mcontext.__gregs[_REG_RIP], eip); #endif #elif defined(__DragonFly__) - return (void*) uc->uc_mcontext.mc_rip; + GET_SET_RETURN(uc->uc_mcontext.mc_rip, eip); #else return NULL; #endif @@ -1445,27 +1459,35 @@ void closeDirectLogFiledes(int fd) { } /* Logs the stack trace using the backtrace() call. This function is designed - * to be called from signal handlers safely. */ -void logStackTrace(ucontext_t *uc) { - void *trace[101]; + * to be called from signal handlers safely. + * The eip argument is optional (can take NULL). + * The uplevel argument indicates how many of the calling functions to skip. + */ +void logStackTrace(void *eip, int uplevel) { + void *trace[100]; int trace_size = 0, fd = openDirectLogFiledes(); + char *msg; + uplevel++; /* skip this function */ if (fd == -1) return; /* If we can't log there is anything to do. */ - /* Generate the stack trace */ - trace_size = backtrace(trace+1, 100); + /* Get the stack trace first! */ + trace_size = backtrace(trace, 100); - if (getMcontextEip(uc) != NULL) { - char *msg1 = "EIP:\n"; - char *msg2 = "\nBacktrace:\n"; - if (write(fd,msg1,strlen(msg1)) == -1) {/* Avoid warning. */}; - trace[0] = getMcontextEip(uc); - backtrace_symbols_fd(trace, 1, fd); - if (write(fd,msg2,strlen(msg2)) == -1) {/* Avoid warning. */}; + msg = "\n------ STACK TRACE ------\n"; + if (write(fd,msg,strlen(msg)) == -1) {/* Avoid warning. */}; + + if (eip) { + /* Write EIP to the log file*/ + msg = "EIP:\n"; + if (write(fd,msg,strlen(msg)) == -1) {/* Avoid warning. */}; + backtrace_symbols_fd(&eip, 1, fd); } /* Write symbols to log file */ - backtrace_symbols_fd(trace+1, trace_size, fd); + msg = "\nBacktrace:\n"; + if (write(fd,msg,strlen(msg)) == -1) {/* Avoid warning. */}; + backtrace_symbols_fd(trace+uplevel, trace_size-uplevel, fd); /* Cleanup */ closeDirectLogFiledes(fd); @@ -1624,9 +1646,13 @@ void dumpX86Calls(void *addr, size_t len } } +void invalidFunctionWasCalled() {} + +typedef void (*invalidFunctionWasCalledType)(); + void sigsegvHandler(int sig, siginfo_t *info, void *secret) { ucontext_t *uc = (ucontext_t*) secret; - void *eip = getMcontextEip(uc); + void *eip = getAndSetMcontextEip(uc, NULL); sds infostring, clients; struct sigaction act; UNUSED(info); @@ -1651,7 +1677,24 @@ void sigsegvHandler(int sig, siginfo_t * /* Log the stack trace */ serverLogRaw(LL_WARNING|LL_RAW, "\n------ STACK TRACE ------\n"); - logStackTrace(uc); + if (eip == info->si_addr) { + /* When eip matches the bad address, it's an indication that we crashed when calling a non-mapped + * function pointer. In that case the call to backtrace will crash trying to access that address and we + * won't get a crash report logged. Set it to a valid point to avoid that crash. */ + + /* This trick allow to avoid compiler warning */ + void *ptr; + invalidFunctionWasCalledType *ptr_ptr = (invalidFunctionWasCalledType*)&ptr; + *ptr_ptr = invalidFunctionWasCalled; + getAndSetMcontextEip(uc, ptr); + } + + logStackTrace(eip, 1); + + if (eip == info->si_addr) { + /* Restore old eip */ + getAndSetMcontextEip(uc, eip); + } /* Log INFO and CLIENT LIST */ serverLogRaw(LL_WARNING|LL_RAW, "\n------ INFO OUTPUT ------\n"); @@ -1776,8 +1819,7 @@ void watchdogSignalHandler(int sig, sigi serverLogFromHandler(LL_WARNING,"\n--- WATCHDOG TIMER EXPIRED ---"); #ifdef HAVE_BACKTRACE - logStackTrace(uc); -#else + logStackTrace(getAndSetMcontextEip(uc, NULL), 1); serverLogFromHandler(LL_WARNING,"Sorry: no support for backtrace()."); #endif serverLogFromHandler(LL_WARNING,"--------\n");
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor