diff --git a/cve-2022-3647.patch b/cve-2022-3647.patch new file mode 100644 index 0000000..685b426 --- /dev/null +++ b/cve-2022-3647.patch @@ -0,0 +1,202 @@ +From 0bf90d944313919eb8e63d3588bf63a367f020a3 Mon Sep 17 00:00:00 2001 +From: "Meir Shpilraien (Spielrein)" +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(-) + +diff --git a/src/debug.c b/src/debug.c +index 8cc811be444b..b15ac8780d83 100644 +--- a/src/debug.c ++++ b/src/debug.c +@@ -1123,73 +1123,88 @@ 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 NOT_SUPPORTED() do {\ + UNUSED(uc);\ ++ UNUSED(eip);\ + return NULL;\ + } while(0) ++#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 + NOT_SUPPORTED(); + #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); + #else + NOT_SUPPORTED(); + #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); + #else + NOT_SUPPORTED(); + #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); + #else + NOT_SUPPORTED(); + #endif + #elif defined(__DragonFly__) +- return (void*) uc->uc_mcontext.mc_rip; ++ GET_SET_RETURN(uc->uc_mcontext.mc_rip, eip); + #else + NOT_SUPPORTED(); + #endif +@@ -1951,6 +1966,10 @@ void dumpCodeAroundEIP(void *eip) { + } + } + ++void invalidFunctionWasCalled() {} ++ ++typedef void (*invalidFunctionWasCalledType)(); ++ + void sigsegvHandler(int sig, siginfo_t *info, void *secret) { + UNUSED(secret); + UNUSED(info); +@@ -1968,13 +1987,30 @@ void sigsegvHandler(int sig, siginfo_t *info, void *secret) { + + #ifdef HAVE_BACKTRACE + ucontext_t *uc = (ucontext_t*) secret; +- void *eip = getMcontextEip(uc); ++ void *eip = getAndSetMcontextEip(uc, NULL); + if (eip != NULL) { + serverLog(LL_WARNING, + "Crashed running the instruction at: %p", eip); + } + +- logStackTrace(getMcontextEip(uc), 1); ++ 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); ++ } + + logRegisters(uc); + #endif +@@ -2079,7 +2115,7 @@ void watchdogSignalHandler(int sig, siginfo_t *info, void *secret) { + + serverLogFromHandler(LL_WARNING,"\n--- WATCHDOG TIMER EXPIRED ---"); + #ifdef HAVE_BACKTRACE +- logStackTrace(getMcontextEip(uc), 1); ++ logStackTrace(getAndSetMcontextEip(uc, NULL), 1); + #else + serverLogFromHandler(LL_WARNING,"Sorry: no support for backtrace()."); + #endif diff --git a/redis.changes b/redis.changes index 10e09f8..66e295d 100644 --- a/redis.changes +++ b/redis.changes @@ -1,3 +1,10 @@ +------------------------------------------------------------------- +Mon Oct 24 14:56:10 UTC 2022 - Danilo Spinella + +- Fix CVE-2022-3647, crash in sigsegvHandler debug function + (CVE-2022-3647, bsc#1204633) + * cve-2022-3647.patch + ------------------------------------------------------------------- Wed Sep 21 20:36:11 UTC 2022 - Michael Ströder diff --git a/redis.spec b/redis.spec index 7e42a9a..dd33d65 100644 --- a/redis.spec +++ b/redis.spec @@ -40,6 +40,9 @@ Source10: https://raw.githubusercontent.com/redis/redis-hashes/master/READ Patch0: %{name}-conf.patch Patch3: reproducible.patch Patch4: ppc-atomic.patch +# PATCH-FIX-UPSTREAm bsc#1204633 danilo.spinella@suse.com CVE-2022-3647 +# crash in sigsegvHandler debug function +Patch5: cve-2022-3647.patch BuildRequires: jemalloc-devel BuildRequires: libopenssl-devel >= 1.1.1 BuildRequires: pkgconfig @@ -67,6 +70,7 @@ echo "`grep -F %{name}-%{version}.tar.gz %{SOURCE10} | cut -d' ' -f4` %{SOURCE0 %patch0 %patch3 -p1 %patch4 -p1 +%patch5 -p1 %build export HOST=OBS # for reproducible builds