diff --git a/core/logic/HandleSys.cpp b/core/logic/HandleSys.cpp index 10c9791c78..959473c222 100644 --- a/core/logic/HandleSys.cpp +++ b/core/logic/HandleSys.cpp @@ -532,6 +532,9 @@ bool HandleSystem::CheckAccess(QHandle *pHandle, HandleAccessRight right, const /* Check if the owner is allowed */ if (access & HANDLE_RESTRICT_OWNER) { + if ((access & HANDLE_RESTRICT_IDENTEXCLUSIVE) == HANDLE_RESTRICT_IDENTEXCLUSIVE) + return false; + IdentityToken_t *owner = pHandle->owner; if (owner && (!pSecurity || pSecurity->pOwner != owner)) @@ -1166,3 +1169,15 @@ void HandleSystem::Dump(const HandleReporter &fn) rep(fn, "-- Approximately %d bytes of memory are in use by Handles.\n", total_size); } +HandleError HandleSystem::GetHandleAccess(Handle_t handle, HandleAccess *&pAccess) +{ + unsigned int index; + QHandle *pHandle; + IdentityToken_t *ident = NULL; + HandleError err = GetHandle(handle, ident, &pHandle, &index); + + if (err == HandleError_None) + pAccess = &(pHandle->sec); + + return err; +} diff --git a/core/logic/HandleSys.h b/core/logic/HandleSys.h index 54e9175143..f741bd051d 100644 --- a/core/logic/HandleSys.h +++ b/core/logic/HandleSys.h @@ -173,6 +173,8 @@ class HandleSystem : /* Bypasses security checks. */ Handle_t FastCloneHandle(Handle_t hndl); + + HandleError GetHandleAccess(Handle_t handle, HandleAccess *&pSecurity); protected: /** * Decodes a handle with sanity and security checking. @@ -260,4 +262,50 @@ struct AutoHandleRooter Handle_t hndl; }; +struct AutoHandleIdentLocker +{ +public: + AutoHandleIdentLocker() : pSecurity(nullptr) + { + } + + AutoHandleIdentLocker(Handle_t hndl) : pSecurity(nullptr) + { + if (hndl != BAD_HANDLE) + { + if (g_HandleSys.GetHandleAccess(hndl, this->pSecurity) == HandleError_None) + { + if ((this->pSecurity->access[HandleAccess_Delete] & HANDLE_RESTRICT_IDENTEXCLUSIVE) == HANDLE_RESTRICT_IDENTEXCLUSIVE) + this->pSecurity = nullptr; + else + this->pSecurity->access[HandleAccess_Delete] |= HANDLE_RESTRICT_IDENTEXCLUSIVE; + } + } + } + + ~AutoHandleIdentLocker() + { + this->Nuke(); + } + +public: + AutoHandleIdentLocker &operator =(const AutoHandleIdentLocker &other) + { + this->Nuke(); + this->pSecurity = other.pSecurity; + return *this; + }; +private: + void Nuke(void) + { + if (this->pSecurity) + { + this->pSecurity->access[HandleAccess_Delete] &= ~HANDLE_RESTRICT_IDENTEXCLUSIVE; + this->pSecurity = nullptr; + } + } +private: + HandleAccess *pSecurity; +}; + #endif //_INCLUDE_SOURCEMOD_HANDLESYSTEM_H_ diff --git a/core/logic/smn_functions.cpp b/core/logic/smn_functions.cpp index 606b7855bb..d5addaea35 100644 --- a/core/logic/smn_functions.cpp +++ b/core/logic/smn_functions.cpp @@ -35,6 +35,7 @@ #include #include #include +#include HandleType_t g_GlobalFwdType = 0; HandleType_t g_PrivateFwdType = 0; @@ -43,6 +44,7 @@ static bool s_CallStarted = false; static ICallable *s_pCallable = NULL; static IPluginFunction *s_pFunction = NULL; static IForward *s_pForward = NULL; +static Handle_t s_ForwardHndl = BAD_HANDLE; class ForwardNativeHelpers : public SMGlobalClass, @@ -330,6 +332,7 @@ static cell_t sm_CallStartFunction(IPluginContext *pContext, const cell_t *param if (!s_pFunction) { + ResetCall(); return pContext->ThrowNativeError("Invalid function id (%X)", params[2]); } @@ -337,6 +340,8 @@ static cell_t sm_CallStartFunction(IPluginContext *pContext, const cell_t *param s_CallStarted = true; + s_ForwardHndl = hndl; + return 1; } @@ -362,6 +367,7 @@ static cell_t sm_CallStartForward(IPluginContext *pContext, const cell_t *params s_pCallable = static_cast(pForward); s_CallStarted = true; + s_ForwardHndl = hndl; return 1; } @@ -646,6 +652,7 @@ static cell_t sm_CallFinish(IPluginContext *pContext, const cell_t *params) pContext->LocalToPhysAddr(params[1], &result); + AutoHandleIdentLocker lock(s_ForwardHndl); // Note: Execute() swallows exceptions, so this is okay. if (s_pFunction) { diff --git a/public/AutoHandleRooter.h b/public/AutoHandleRooter.h index d7aae7b0af..3528a3a6d5 100644 --- a/public/AutoHandleRooter.h +++ b/public/AutoHandleRooter.h @@ -87,5 +87,51 @@ class AutoHandleCloner } }; +class AutoHandleIdentLocker +{ +public: + AutoHandleIdentLocker() : pSecurity(nullptr) + { + } + + AutoHandleIdentLocker(Handle_t hndl) : pSecurity(nullptr) + { + if (hndl != BAD_HANDLE) + { + if (handlesys->GetHandleAccess(hndl, this->pSecurity) == HandleError_None) + { + if ((this->pSecurity->access[HandleAccess_Delete] & HANDLE_RESTRICT_IDENTEXCLUSIVE) == HANDLE_RESTRICT_IDENTEXCLUSIVE) + this->pSecurity = nullptr; + else + this->pSecurity->access[HandleAccess_Delete] |= HANDLE_RESTRICT_IDENTEXCLUSIVE; + } + } + } + + ~AutoHandleIdentLocker() + { + this->Nuke(); + } + +public: + AutoHandleIdentLocker &operator =(const AutoHandleIdentLocker &other) + { + this->Nuke(); + this->pSecurity = other.pSecurity; + return *this; + }; +private: + void Nuke(void) + { + if (this->pSecurity) + { + this->pSecurity->access[HandleAccess_Delete] &= ~HANDLE_RESTRICT_IDENTEXCLUSIVE; + this->pSecurity = nullptr; + } + } +private: + HandleAccess *pSecurity; +}; + #endif /* _INCLUDE_SOURCEMOD_AUTO_HANDLE_ROOTER_H_ */ diff --git a/public/IHandleSys.h b/public/IHandleSys.h index e2387b5835..fe12a5824f 100644 --- a/public/IHandleSys.h +++ b/public/IHandleSys.h @@ -52,7 +52,7 @@ #include #define SMINTERFACE_HANDLESYSTEM_NAME "IHandleSys" -#define SMINTERFACE_HANDLESYSTEM_VERSION 5 +#define SMINTERFACE_HANDLESYSTEM_VERSION 6 /** Specifies no Identity */ #define DEFAULT_IDENTITY NULL @@ -135,6 +135,8 @@ namespace SourceMod #define HANDLE_RESTRICT_IDENTITY (1<<0) /** Access is restricted to the owner */ #define HANDLE_RESTRICT_OWNER (1<<1) + /** Access is identity exclusive */ + #define HANDLE_RESTRICT_IDENTEXCLUSIVE (1<<2) /** * @brief This is used to define per-type access rights. @@ -373,6 +375,15 @@ namespace SourceMod * @return True if "given" is a subtype of "actual", false otherwise. */ virtual bool TypeCheck(HandleType_t given, HandleType_t actual) = 0; + + /** + * @brief Obtain the HandleAccess address from the passed in handle. + * + * @param handle Handle_t identifier to destroy. + * @param pAccess Access information struct. + * @return HandleError error code. + */ + virtual HandleError GetHandleAccess(Handle_t handle, HandleAccess *&pAccess) = 0; }; }