diff --git a/sourcehook/sourcehook.cpp b/sourcehook/sourcehook.cpp index 9425568..380aab4 100644 --- a/sourcehook/sourcehook.cpp +++ b/sourcehook/sourcehook.cpp @@ -5,6 +5,7 @@ * License: zlib/libpng * * Author(s): Pavol "PM OnoTo" Marko +* Contributors: Scott "Damaged Soul" Ehlert * ============================ */ @@ -299,6 +300,13 @@ namespace SourceHook if (hookman == m_HookMans.end()) return false; + if (IsBadReadPtr(reinterpret_cast(adjustediface) + tmp.vtbl_offs, sizeof(char))) + { + hookman->vfnptrs.clear(); + hookman->func(HA_Unregister, NULL); + return true; + } + void **cur_vtptr = *reinterpret_cast( reinterpret_cast(adjustediface) + tmp.vtbl_offs); void *cur_vfnptr = reinterpret_cast(cur_vtptr + tmp.vtbl_idx); @@ -465,6 +473,38 @@ namespace SourceHook } } +#if __linux__ + // Windows has an implentation for this already, but Linux does not :( + static bool CSourceHookImpl::IsBadReadPtr(const void *ptr, size_t len) + { + void(*prevHandler)(int sig); + g_BadReadCalled = true; + + if (setjmp(g_BadReadJmpBuffer)) + return true; + + prevHandler = signal(SIGSEGV, BadReadHandler); + + volatile const char *p = reinterpret_cast(ptr); + char dummy; + + for (size_t i = 0; i < len; i++) + dummy = p[i]; + + g_BadReadCalled = false; + + signal(SIGSEGV, prevHandler); + + return false; + } + + static void CSourceHookImpl::BadReadHandler(int sig) + { + if (m_BadReadCalled) + longjmp(m_BadReadJmpBuf, 1); + } +#endif + CSourceHookImpl::HookManInfoList::iterator CSourceHookImpl::FindHookMan(HookManInfoList::iterator begin, HookManInfoList::iterator end, const char *proto, int vtblofs, int vtblidx) { diff --git a/sourcehook/sourcehook_impl.h b/sourcehook/sourcehook_impl.h index 6d83350..3f521f5 100644 --- a/sourcehook/sourcehook_impl.h +++ b/sourcehook/sourcehook_impl.h @@ -13,6 +13,11 @@ #include "sourcehook.h" +#ifdef __linux__ +#include +#include +#endif + // Set this to 1 to enable runtime code generation (faster) #define SH_RUNTIME_CODEGEN 1 @@ -77,6 +82,22 @@ namespace SourceHook void RemoveCallClassPatch(CallClassInfo &cc, int vtbl_offs, int vtbl_idx); void RemoveCallClassPatches(void *ifaceptr, int vtbl_offs, int vtbl_idx); +#ifdef __linux__ + /** + * @brief Checks to see if a memory value can be read from a given pointer. + * + * @return True if the value can be read and false if it cannot. + * + * @param ptr The pointer to the memory value. + * @param len The length of the memory value to be read from the pointer. + */ + static bool IsBadReadPtr(const void *ptr, size_t len); + static void BadReadHandler(int sig); + + bool m_BadReadCalled; + jmp_buf m_BadReadJmpBuf; +#endif + META_RES m_Status, m_PrevRes, m_CurRes; const void *m_OrigRet; const void *m_OverrideRet; diff --git a/sourcemm/changelog.txt b/sourcemm/changelog.txt index 61df775..b9d9419 100644 --- a/sourcemm/changelog.txt +++ b/sourcemm/changelog.txt @@ -13,6 +13,7 @@ - Fixed "meta clear" not unloading all plugins. - Fixed Metamod:Source loading plugins with a higher current API version. - Fixed whitespace being parsed in metaplugins.ini. + - Fixed bug where SourceHook tried to patch already destroyed/unavailable memory. - Bumped Plugin API version to 6. 2005/05/06 1.00-RC1: