mirror of
https://gitlab.com/buildroot.org/buildroot.git
synced 2026-09-30 22:11:59 -09:00
package/znc: add patch for CVE-2026-82373
This fixes the following vulnerability:
CVE-2026-82373: Use-after-free when unloading modules, triggered by
unprivileged users
Signed-off-by: Titouan Christophe <titouan.christophe@mind.be>
(alternative to commit 43558e103b)
Signed-off-by: Thomas Perale <thomas.perale@mind.be>
This commit is contained in:
committed by
Thomas Perale
parent
592df64b46
commit
bef43a2af1
497
package/znc/0001-fix-crash-while-unloading-modules.patch
Normal file
497
package/znc/0001-fix-crash-while-unloading-modules.patch
Normal file
@@ -0,0 +1,497 @@
|
|||||||
|
From: Alexey Sokolov <alexey+znc@asokolov.org>
|
||||||
|
Date: Sat, 5 Sep 2026 23:09:25 +0100
|
||||||
|
Subject: Fix crash while unloading modules
|
||||||
|
|
||||||
|
The bug allowed unprivileged users to trigger use-after-free while
|
||||||
|
unloading modules
|
||||||
|
|
||||||
|
Note that the fix requires a slight API change for OnEmbeddedWebRequest:
|
||||||
|
now the callers (webadmin is the only known caller of it) call it via
|
||||||
|
DoEmbeddedWebRequest() instead. The modules which implement this hook
|
||||||
|
need no changes.
|
||||||
|
|
||||||
|
CVE-2026-82373
|
||||||
|
|
||||||
|
Found by Claude from Anthropic, reported by Ada Logics.
|
||||||
|
|
||||||
|
---
|
||||||
|
Upstream: https://github.com/znc/znc/commit/4b88c64c6e8df29c73568ae1c8b35d797bfa509a
|
||||||
|
CVE: CVE-2026-82373
|
||||||
|
Signed-off-by: Titouan Christophe <titouan.christophe@mind.be>
|
||||||
|
---
|
||||||
|
include/znc/Modules.h | 71 ++++++++++++++++++++-
|
||||||
|
include/znc/main.h | 30 ++-------
|
||||||
|
modules/modperl/functions.in | 2 +-
|
||||||
|
modules/modpython/functions.in | 2 +-
|
||||||
|
modules/webadmin.cpp | 12 ++--
|
||||||
|
src/Client.cpp | 29 +++------
|
||||||
|
src/Modules.cpp | 112 +++++++++++++++------------------
|
||||||
|
7 files changed, 145 insertions(+), 113 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/include/znc/Modules.h b/include/znc/Modules.h
|
||||||
|
index ec8b36f883..d842390675 100644
|
||||||
|
--- a/include/znc/Modules.h
|
||||||
|
+++ b/include/znc/Modules.h
|
||||||
|
@@ -465,6 +465,9 @@ class CModule {
|
||||||
|
void SetNetwork(CIRCNetwork* pNetwork);
|
||||||
|
void SetClient(CClient* pClient);
|
||||||
|
|
||||||
|
+ /** True if the module can be safely unloaded. */
|
||||||
|
+ bool IsCallStackEmpty() const;
|
||||||
|
+
|
||||||
|
/** This function throws CModule::UNLOAD which causes this module to be unloaded.
|
||||||
|
*/
|
||||||
|
void Unload() { throw UNLOAD; }
|
||||||
|
@@ -535,9 +538,11 @@ class CModule {
|
||||||
|
* @return The List.
|
||||||
|
*/
|
||||||
|
virtual VWebSubPages& GetSubPages() { return m_vSubPages; }
|
||||||
|
+ private:
|
||||||
|
/** Using this hook, module can embed web stuff directly to different places.
|
||||||
|
- * This method is called whenever embededded modules I/O happens.
|
||||||
|
+ * This method is called whenever embedded modules I/O happens.
|
||||||
|
* Name of used .tmpl file (if any) is up to caller.
|
||||||
|
+ * Callers call it via `DoEmbeddedWebRequest()`.
|
||||||
|
* @param WebSock Socket for web connection, don't do bad things with it.
|
||||||
|
* @param sPageName Describes the place where web stuff is embedded to.
|
||||||
|
* @param Tmpl Template. Depending on context, you can do various stuff with it.
|
||||||
|
@@ -547,6 +552,9 @@ class CModule {
|
||||||
|
virtual bool OnEmbeddedWebRequest(CWebSock& WebSock,
|
||||||
|
const CString& sPageName,
|
||||||
|
CTemplate& Tmpl);
|
||||||
|
+ public:
|
||||||
|
+ bool DoEmbeddedWebRequest(CWebSock& WebSock, const CString& sPageName,
|
||||||
|
+ CTemplate& Tmpl);
|
||||||
|
|
||||||
|
/** Called just before znc.conf is rehashed */
|
||||||
|
virtual void OnPreRehash();
|
||||||
|
@@ -1528,6 +1536,9 @@ class CModule {
|
||||||
|
m_mssRegistry; //!< way to save name/value pairs. Note there is no encryption involved in this
|
||||||
|
VWebSubPages m_vSubPages;
|
||||||
|
std::map<CString, CModCommand> m_mCommands;
|
||||||
|
+ int m_iCallStackDepth = 0;
|
||||||
|
+
|
||||||
|
+ friend struct CModCallProtector;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CModules : public std::vector<CModule*>, private CCoreTranslationMixin {
|
||||||
|
@@ -1766,4 +1777,62 @@ class CModules : public std::vector<CModule*>, private CCoreTranslationMixin {
|
||||||
|
CClient* m_pClient;
|
||||||
|
};
|
||||||
|
|
||||||
|
+struct CModCallProtector {
|
||||||
|
+ explicit CModCallProtector(CModule& pMod) : m_pMod(&pMod) {
|
||||||
|
+ pMod.m_iCallStackDepth++;
|
||||||
|
+ }
|
||||||
|
+ ~CModCallProtector() { m_pMod->m_iCallStackDepth--; }
|
||||||
|
+
|
||||||
|
+ CModule* m_pMod;
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+#ifndef SWIG
|
||||||
|
+template <typename T, T* (CModule::*Getter)() const, void (CModule::*Setter)(T*)>
|
||||||
|
+struct CTemporaryModField {
|
||||||
|
+ CTemporaryModField(CModule& pMod, T* pValue) {
|
||||||
|
+ m_pMod = &pMod;
|
||||||
|
+ m_pOldT = (pMod.*Getter)();
|
||||||
|
+ if (pValue) {
|
||||||
|
+ (pMod.*Setter)(pValue);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ ~CTemporaryModField() { (m_pMod->*Setter)(m_pOldT); }
|
||||||
|
+
|
||||||
|
+ CModule* m_pMod;
|
||||||
|
+ T* m_pOldT;
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+using CTemporaryModClient =
|
||||||
|
+ CTemporaryModField<CClient, &CModule::GetClient, &CModule::SetClient>;
|
||||||
|
+using CTemporaryModNetwork =
|
||||||
|
+ CTemporaryModField<CIRCNetwork, &CModule::GetNetwork, &CModule::SetNetwork>;
|
||||||
|
+using CTemporaryModUser =
|
||||||
|
+ CTemporaryModField<CUser, &CModule::GetUser, &CModule::SetUser>;
|
||||||
|
+
|
||||||
|
+// Same as above, but for plural CModules
|
||||||
|
+template <typename T, T* (CModules::*Getter)() const, void (CModules::*Setter)(T*)>
|
||||||
|
+struct CTemporaryModsField {
|
||||||
|
+ CTemporaryModsField(CModules& pMods, T* pValue) {
|
||||||
|
+ m_pMods = &pMods;
|
||||||
|
+ m_pOldT = (pMods.*Getter)();
|
||||||
|
+ if (pValue) {
|
||||||
|
+ (pMods.*Setter)(pValue);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ ~CTemporaryModsField() { (m_pMods->*Setter)(m_pOldT); }
|
||||||
|
+
|
||||||
|
+ CModules* m_pMods;
|
||||||
|
+ T* m_pOldT;
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+using CTemporaryModsClient =
|
||||||
|
+ CTemporaryModsField<CClient, &CModules::GetClient, &CModules::SetClient>;
|
||||||
|
+using CTemporaryModsNetwork =
|
||||||
|
+ CTemporaryModsField<CIRCNetwork, &CModules::GetNetwork, &CModules::SetNetwork>;
|
||||||
|
+using CTemporaryModsUser =
|
||||||
|
+ CTemporaryModsField<CUser, &CModules::GetUser, &CModules::SetUser>;
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
#endif // !ZNC_MODULES_H
|
||||||
|
diff --git a/include/znc/main.h b/include/znc/main.h
|
||||||
|
index 7d22fd43d4..28924d2c02 100644
|
||||||
|
--- a/include/znc/main.h
|
||||||
|
+++ b/include/znc/main.h
|
||||||
|
@@ -56,21 +56,12 @@ extern bool ZNC_NO_NEED_TO_DO_ANYTHING_ON_MODULE_CALL_EXITER;
|
||||||
|
#define _GLOBALMODULECALL(macFUNC, macUSER, macNETWORK, macCLIENT, macEXITER) \
|
||||||
|
do { \
|
||||||
|
CModules& GMods = CZNC::Get().GetModules(); \
|
||||||
|
- CUser* pOldGUser = GMods.GetUser(); \
|
||||||
|
- CIRCNetwork* pOldGNetwork = GMods.GetNetwork(); \
|
||||||
|
- CClient* pOldGClient = GMods.GetClient(); \
|
||||||
|
- GMods.SetUser(macUSER); \
|
||||||
|
- GMods.SetNetwork(macNETWORK); \
|
||||||
|
- GMods.SetClient(macCLIENT); \
|
||||||
|
+ CTemporaryModsUser TempUser(GMods, macUSER); \
|
||||||
|
+ CTemporaryModsNetwork TempNetwork(GMods, macNETWORK); \
|
||||||
|
+ CTemporaryModsClient TempClient(GMods, macCLIENT); \
|
||||||
|
if (GMods.macFUNC) { \
|
||||||
|
- GMods.SetUser(pOldGUser); \
|
||||||
|
- GMods.SetNetwork(pOldGNetwork); \
|
||||||
|
- GMods.SetClient(pOldGClient); \
|
||||||
|
*macEXITER = true; \
|
||||||
|
} \
|
||||||
|
- GMods.SetUser(pOldGUser); \
|
||||||
|
- GMods.SetNetwork(pOldGNetwork); \
|
||||||
|
- GMods.SetClient(pOldGClient); \
|
||||||
|
} while (false)
|
||||||
|
|
||||||
|
#define _USERMODULECALL(macFUNC, macUSER, macNETWORK, macCLIENT, macEXITER) \
|
||||||
|
@@ -84,17 +75,11 @@ extern bool ZNC_NO_NEED_TO_DO_ANYTHING_ON_MODULE_CALL_EXITER;
|
||||||
|
} \
|
||||||
|
if (macUSER != nullptr) { \
|
||||||
|
CModules& UMods = macUSER->GetModules(); \
|
||||||
|
- CIRCNetwork* pOldUNetwork = UMods.GetNetwork(); \
|
||||||
|
- CClient* pOldUClient = UMods.GetClient(); \
|
||||||
|
- UMods.SetNetwork(macNETWORK); \
|
||||||
|
- UMods.SetClient(macCLIENT); \
|
||||||
|
+ CTemporaryModsNetwork TempNetwork(UMods, macNETWORK); \
|
||||||
|
+ CTemporaryModsClient TempClient(UMods, macCLIENT); \
|
||||||
|
if (UMods.macFUNC) { \
|
||||||
|
- UMods.SetNetwork(pOldUNetwork); \
|
||||||
|
- UMods.SetClient(pOldUClient); \
|
||||||
|
*macEXITER = true; \
|
||||||
|
} \
|
||||||
|
- UMods.SetNetwork(pOldUNetwork); \
|
||||||
|
- UMods.SetClient(pOldUClient); \
|
||||||
|
} \
|
||||||
|
} while (false)
|
||||||
|
|
||||||
|
@@ -109,13 +94,10 @@ extern bool ZNC_NO_NEED_TO_DO_ANYTHING_ON_MODULE_CALL_EXITER;
|
||||||
|
} \
|
||||||
|
if (macNETWORK != nullptr) { \
|
||||||
|
CModules& NMods = macNETWORK->GetModules(); \
|
||||||
|
- CClient* pOldNClient = NMods.GetClient(); \
|
||||||
|
- NMods.SetClient(macCLIENT); \
|
||||||
|
+ CTemporaryModsClient TempClient(NMods, macCLIENT); \
|
||||||
|
if (NMods.macFUNC) { \
|
||||||
|
- NMods.SetClient(pOldNClient); \
|
||||||
|
*macEXITER = true; \
|
||||||
|
} \
|
||||||
|
- NMods.SetClient(pOldNClient); \
|
||||||
|
} \
|
||||||
|
} while (false)
|
||||||
|
|
||||||
|
diff --git a/modules/modperl/functions.in b/modules/modperl/functions.in
|
||||||
|
index a44c818a62..bfa671191c 100644
|
||||||
|
--- a/modules/modperl/functions.in
|
||||||
|
+++ b/modules/modperl/functions.in
|
||||||
|
@@ -66,7 +66,7 @@ void OnServerCapResult(const CString& sCap, bool bSuccess)
|
||||||
|
void OnClientAttached()
|
||||||
|
void OnClientDetached()
|
||||||
|
EModRet OnTimerAutoJoin(CChan& Channel)
|
||||||
|
-bool OnEmbeddedWebRequest(CWebSock& WebSock, const CString& sPageName, CTemplate& Tmpl)
|
||||||
|
+bool OnEmbeddedWebRequest(CWebSock& WebSock, const CString& sPageName, CTemplate& Tmpl)=false
|
||||||
|
EModRet OnAddNetwork(CIRCNetwork& Network, CString& sErrorRet)
|
||||||
|
EModRet OnDeleteNetwork(CIRCNetwork& Network)
|
||||||
|
EModRet OnSendToClient(CString& sLine, CClient& Client)
|
||||||
|
diff --git a/modules/modpython/functions.in b/modules/modpython/functions.in
|
||||||
|
index 76ed437a2c..d2914f9dad 100644
|
||||||
|
--- a/modules/modpython/functions.in
|
||||||
|
+++ b/modules/modpython/functions.in
|
||||||
|
@@ -66,7 +66,7 @@ void OnServerCapResult(const CString& sCap, bool bSuccess)
|
||||||
|
void OnClientAttached()
|
||||||
|
void OnClientDetached()
|
||||||
|
EModRet OnTimerAutoJoin(CChan& Channel)
|
||||||
|
-bool OnEmbeddedWebRequest(CWebSock& WebSock, const CString& sPageName, CTemplate& Tmpl)
|
||||||
|
+bool OnEmbeddedWebRequest(CWebSock& WebSock, const CString& sPageName, CTemplate& Tmpl)=false
|
||||||
|
EModRet OnAddNetwork(CIRCNetwork& Network, CString& sErrorRet)
|
||||||
|
EModRet OnDeleteNetwork(CIRCNetwork& Network)
|
||||||
|
EModRet OnSendToClient(CString& sLine, CClient& Client)
|
||||||
|
diff --git a/modules/webadmin.cpp b/modules/webadmin.cpp
|
||||||
|
index 0b72413813..ac77517c11 100644
|
||||||
|
--- a/modules/webadmin.cpp
|
||||||
|
+++ b/modules/webadmin.cpp
|
||||||
|
@@ -742,7 +742,7 @@ class CWebAdminMod : public CModule {
|
||||||
|
CTemplate& mod = Tmpl.AddRow("EmbeddedModuleLoop");
|
||||||
|
mod.insert(Tmpl.begin(), Tmpl.end());
|
||||||
|
mod["WebadminAction"] = "display";
|
||||||
|
- if ((*i)->OnEmbeddedWebRequest(WebSock, "webadmin/channel",
|
||||||
|
+ if ((*i)->DoEmbeddedWebRequest(WebSock, "webadmin/channel",
|
||||||
|
mod)) {
|
||||||
|
mod["Embed"] = WebSock.FindTmpl(*i, "WebadminChan.tmpl");
|
||||||
|
mod["ModName"] = (*i)->GetModName();
|
||||||
|
@@ -816,7 +816,7 @@ class CWebAdminMod : public CModule {
|
||||||
|
TmplMod["ChanName"] = pChan->GetName();
|
||||||
|
TmplMod["WebadminAction"] = "change";
|
||||||
|
FOR_EACH_MODULE(it, pNetwork) {
|
||||||
|
- (*it)->OnEmbeddedWebRequest(WebSock, "webadmin/channel", TmplMod);
|
||||||
|
+ (*it)->DoEmbeddedWebRequest(WebSock, "webadmin/channel", TmplMod);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!CZNC::Get().WriteConfig()) {
|
||||||
|
@@ -1027,7 +1027,7 @@ class CWebAdminMod : public CModule {
|
||||||
|
CTemplate& mod = Tmpl.AddRow("EmbeddedModuleLoop");
|
||||||
|
mod.insert(Tmpl.begin(), Tmpl.end());
|
||||||
|
mod["WebadminAction"] = "display";
|
||||||
|
- if ((*i)->OnEmbeddedWebRequest(WebSock, "webadmin/network",
|
||||||
|
+ if ((*i)->DoEmbeddedWebRequest(WebSock, "webadmin/network",
|
||||||
|
mod)) {
|
||||||
|
mod["Embed"] = WebSock.FindTmpl(*i, "WebadminNetwork.tmpl");
|
||||||
|
mod["ModName"] = (*i)->GetModName();
|
||||||
|
@@ -1246,7 +1246,7 @@ class CWebAdminMod : public CModule {
|
||||||
|
TmplMod["Name"] = pNetwork->GetName();
|
||||||
|
TmplMod["WebadminAction"] = "change";
|
||||||
|
FOR_EACH_MODULE(it, make_pair(pUser, pNetwork)) {
|
||||||
|
- (*it)->OnEmbeddedWebRequest(WebSock, "webadmin/network", TmplMod);
|
||||||
|
+ (*it)->DoEmbeddedWebRequest(WebSock, "webadmin/network", TmplMod);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!CZNC::Get().WriteConfig()) {
|
||||||
|
@@ -1670,7 +1670,7 @@ class CWebAdminMod : public CModule {
|
||||||
|
CTemplate& mod = Tmpl.AddRow("EmbeddedModuleLoop");
|
||||||
|
mod.insert(Tmpl.begin(), Tmpl.end());
|
||||||
|
mod["WebadminAction"] = "display";
|
||||||
|
- if ((*i)->OnEmbeddedWebRequest(WebSock, "webadmin/user", mod)) {
|
||||||
|
+ if ((*i)->DoEmbeddedWebRequest(WebSock, "webadmin/user", mod)) {
|
||||||
|
mod["Embed"] = WebSock.FindTmpl(*i, "WebadminUser.tmpl");
|
||||||
|
mod["ModName"] = (*i)->GetModName();
|
||||||
|
}
|
||||||
|
@@ -1731,7 +1731,7 @@ class CWebAdminMod : public CModule {
|
||||||
|
TmplMod["Username"] = sUsername;
|
||||||
|
TmplMod["WebadminAction"] = "change";
|
||||||
|
FOR_EACH_MODULE(it, pUser) {
|
||||||
|
- (*it)->OnEmbeddedWebRequest(WebSock, "webadmin/user", TmplMod);
|
||||||
|
+ (*it)->DoEmbeddedWebRequest(WebSock, "webadmin/user", TmplMod);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!CZNC::Get().WriteConfig()) {
|
||||||
|
diff --git a/src/Client.cpp b/src/Client.cpp
|
||||||
|
index 0f60f9a11c..db1ec7a62e 100644
|
||||||
|
--- a/src/Client.cpp
|
||||||
|
+++ b/src/Client.cpp
|
||||||
|
@@ -21,8 +21,8 @@
|
||||||
|
#include <znc/IRCNetwork.h>
|
||||||
|
#include <znc/Query.h>
|
||||||
|
|
||||||
|
-using std::set;
|
||||||
|
using std::map;
|
||||||
|
+using std::set;
|
||||||
|
using std::vector;
|
||||||
|
|
||||||
|
#define CALLMOD(MOD, CLIENT, USER, NETWORK, FUNC) \
|
||||||
|
@@ -30,10 +30,9 @@ using std::vector;
|
||||||
|
CModule* pModule = nullptr; \
|
||||||
|
if (NETWORK && (pModule = (NETWORK)->GetModules().FindModule(MOD))) { \
|
||||||
|
try { \
|
||||||
|
- CClient* pOldClient = pModule->GetClient(); \
|
||||||
|
- pModule->SetClient(CLIENT); \
|
||||||
|
+ CModCallProtector Inside(*pModule); \
|
||||||
|
+ CTemporaryModClient TempClient(*pModule, CLIENT); \
|
||||||
|
pModule->FUNC; \
|
||||||
|
- pModule->SetClient(pOldClient); \
|
||||||
|
} catch (const CModule::EModException& e) { \
|
||||||
|
if (e == CModule::UNLOAD) { \
|
||||||
|
(NETWORK)->GetModules().UnloadModule(MOD); \
|
||||||
|
@@ -41,13 +40,10 @@ using std::vector;
|
||||||
|
} \
|
||||||
|
} else if ((pModule = (USER)->GetModules().FindModule(MOD))) { \
|
||||||
|
try { \
|
||||||
|
- CClient* pOldClient = pModule->GetClient(); \
|
||||||
|
- CIRCNetwork* pOldNetwork = pModule->GetNetwork(); \
|
||||||
|
- pModule->SetClient(CLIENT); \
|
||||||
|
- pModule->SetNetwork(NETWORK); \
|
||||||
|
+ CModCallProtector Inside(*pModule); \
|
||||||
|
+ CTemporaryModClient TempClient(*pModule, CLIENT); \
|
||||||
|
+ CTemporaryModNetwork TempNetwork(*pModule, NETWORK); \
|
||||||
|
pModule->FUNC; \
|
||||||
|
- pModule->SetClient(pOldClient); \
|
||||||
|
- pModule->SetNetwork(pOldNetwork); \
|
||||||
|
} catch (const CModule::EModException& e) { \
|
||||||
|
if (e == CModule::UNLOAD) { \
|
||||||
|
(USER)->GetModules().UnloadModule(MOD); \
|
||||||
|
@@ -55,16 +51,11 @@ using std::vector;
|
||||||
|
} \
|
||||||
|
} else if ((pModule = CZNC::Get().GetModules().FindModule(MOD))) { \
|
||||||
|
try { \
|
||||||
|
- CClient* pOldClient = pModule->GetClient(); \
|
||||||
|
- CIRCNetwork* pOldNetwork = pModule->GetNetwork(); \
|
||||||
|
- CUser* pOldUser = pModule->GetUser(); \
|
||||||
|
- pModule->SetClient(CLIENT); \
|
||||||
|
- pModule->SetNetwork(NETWORK); \
|
||||||
|
- pModule->SetUser(USER); \
|
||||||
|
+ CModCallProtector Inside(*pModule); \
|
||||||
|
+ CTemporaryModClient TempClient(*pModule, CLIENT); \
|
||||||
|
+ CTemporaryModNetwork TempNetwork(*pModule, NETWORK); \
|
||||||
|
+ CTemporaryModUser TempUser(*pModule, USER); \
|
||||||
|
pModule->FUNC; \
|
||||||
|
- pModule->SetClient(pOldClient); \
|
||||||
|
- pModule->SetNetwork(pOldNetwork); \
|
||||||
|
- pModule->SetUser(pOldUser); \
|
||||||
|
} catch (const CModule::EModException& e) { \
|
||||||
|
if (e == CModule::UNLOAD) { \
|
||||||
|
CZNC::Get().GetModules().UnloadModule(MOD); \
|
||||||
|
diff --git a/src/Modules.cpp b/src/Modules.cpp
|
||||||
|
index d553cbb794..2c4c056fa1 100644
|
||||||
|
--- a/src/Modules.cpp
|
||||||
|
+++ b/src/Modules.cpp
|
||||||
|
@@ -36,67 +36,45 @@ bool ZNC_NO_NEED_TO_DO_ANYTHING_ON_MODULE_CALL_EXITER;
|
||||||
|
#warning "your crap box doesn't define RTLD_LOCAL !?"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
-#define MODUNLOADCHK(func) \
|
||||||
|
- for (CModule * pMod : *this) { \
|
||||||
|
- try { \
|
||||||
|
- CClient* pOldClient = pMod->GetClient(); \
|
||||||
|
- pMod->SetClient(m_pClient); \
|
||||||
|
- CUser* pOldUser = nullptr; \
|
||||||
|
- if (m_pUser) { \
|
||||||
|
- pOldUser = pMod->GetUser(); \
|
||||||
|
- pMod->SetUser(m_pUser); \
|
||||||
|
- } \
|
||||||
|
- CIRCNetwork* pNetwork = nullptr; \
|
||||||
|
- if (m_pNetwork) { \
|
||||||
|
- pNetwork = pMod->GetNetwork(); \
|
||||||
|
- pMod->SetNetwork(m_pNetwork); \
|
||||||
|
- } \
|
||||||
|
- pMod->func; \
|
||||||
|
- if (m_pUser) pMod->SetUser(pOldUser); \
|
||||||
|
- if (m_pNetwork) pMod->SetNetwork(pNetwork); \
|
||||||
|
- pMod->SetClient(pOldClient); \
|
||||||
|
- } catch (const CModule::EModException& e) { \
|
||||||
|
- if (e == CModule::UNLOAD) { \
|
||||||
|
- UnloadModule(pMod->GetModName()); \
|
||||||
|
- } \
|
||||||
|
- } \
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
-#define MODHALTCHK(func) \
|
||||||
|
- bool bHaltCore = false; \
|
||||||
|
- for (CModule * pMod : *this) { \
|
||||||
|
- try { \
|
||||||
|
- CModule::EModRet e = CModule::CONTINUE; \
|
||||||
|
- CClient* pOldClient = pMod->GetClient(); \
|
||||||
|
- pMod->SetClient(m_pClient); \
|
||||||
|
- CUser* pOldUser = nullptr; \
|
||||||
|
- if (m_pUser) { \
|
||||||
|
- pOldUser = pMod->GetUser(); \
|
||||||
|
- pMod->SetUser(m_pUser); \
|
||||||
|
- } \
|
||||||
|
- CIRCNetwork* pNetwork = nullptr; \
|
||||||
|
- if (m_pNetwork) { \
|
||||||
|
- pNetwork = pMod->GetNetwork(); \
|
||||||
|
- pMod->SetNetwork(m_pNetwork); \
|
||||||
|
- } \
|
||||||
|
- e = pMod->func; \
|
||||||
|
- if (m_pUser) pMod->SetUser(pOldUser); \
|
||||||
|
- if (m_pNetwork) pMod->SetNetwork(pNetwork); \
|
||||||
|
- pMod->SetClient(pOldClient); \
|
||||||
|
- if (e == CModule::HALTMODS) { \
|
||||||
|
- break; \
|
||||||
|
- } else if (e == CModule::HALTCORE) { \
|
||||||
|
- bHaltCore = true; \
|
||||||
|
- } else if (e == CModule::HALT) { \
|
||||||
|
- bHaltCore = true; \
|
||||||
|
- break; \
|
||||||
|
- } \
|
||||||
|
- } catch (const CModule::EModException& e) { \
|
||||||
|
- if (e == CModule::UNLOAD) { \
|
||||||
|
- UnloadModule(pMod->GetModName()); \
|
||||||
|
- } \
|
||||||
|
- } \
|
||||||
|
- } \
|
||||||
|
+#define MODUNLOADCHK(func) \
|
||||||
|
+ for (CModule* pMod : *this) { \
|
||||||
|
+ try { \
|
||||||
|
+ CModCallProtector inside(*pMod); \
|
||||||
|
+ CTemporaryModClient TempClient(*pMod, m_pClient); \
|
||||||
|
+ CTemporaryModUser TempUser(*pMod, m_pUser); \
|
||||||
|
+ CTemporaryModNetwork TempNetwork(*pMod, m_pNetwork); \
|
||||||
|
+ pMod->func; \
|
||||||
|
+ } catch (const CModule::EModException& e) { \
|
||||||
|
+ if (e == CModule::UNLOAD) { \
|
||||||
|
+ UnloadModule(pMod->GetModName()); \
|
||||||
|
+ } \
|
||||||
|
+ } \
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+#define MODHALTCHK(func) \
|
||||||
|
+ bool bHaltCore = false; \
|
||||||
|
+ for (CModule* pMod : *this) { \
|
||||||
|
+ try { \
|
||||||
|
+ CModCallProtector inside(*pMod); \
|
||||||
|
+ CModule::EModRet e = CModule::CONTINUE; \
|
||||||
|
+ CTemporaryModClient TempClient(*pMod, m_pClient); \
|
||||||
|
+ CTemporaryModUser TempUser(*pMod, m_pUser); \
|
||||||
|
+ CTemporaryModNetwork TempNetwork(*pMod, m_pNetwork); \
|
||||||
|
+ e = pMod->func; \
|
||||||
|
+ if (e == CModule::HALTMODS) { \
|
||||||
|
+ break; \
|
||||||
|
+ } else if (e == CModule::HALTCORE) { \
|
||||||
|
+ bHaltCore = true; \
|
||||||
|
+ } else if (e == CModule::HALT) { \
|
||||||
|
+ bHaltCore = true; \
|
||||||
|
+ break; \
|
||||||
|
+ } \
|
||||||
|
+ } catch (const CModule::EModException& e) { \
|
||||||
|
+ if (e == CModule::UNLOAD) { \
|
||||||
|
+ UnloadModule(pMod->GetModName()); \
|
||||||
|
+ } \
|
||||||
|
+ } \
|
||||||
|
+ } \
|
||||||
|
return bHaltCore;
|
||||||
|
|
||||||
|
/////////////////// Timer ///////////////////
|
||||||
|
@@ -205,6 +183,8 @@ void CModule::SetUser(CUser* pUser) { m_pUser = pUser; }
|
||||||
|
void CModule::SetNetwork(CIRCNetwork* pNetwork) { m_pNetwork = pNetwork; }
|
||||||
|
void CModule::SetClient(CClient* pClient) { m_pClient = pClient; }
|
||||||
|
|
||||||
|
+bool CModule::IsCallStackEmpty() const { return m_iCallStackDepth == 0; }
|
||||||
|
+
|
||||||
|
CString CModule::ExpandString(const CString& sStr) const {
|
||||||
|
CString sRet;
|
||||||
|
return ExpandString(sStr, sRet);
|
||||||
|
@@ -622,6 +602,11 @@ bool CModule::OnEmbeddedWebRequest(CWebSock& WebSock, const CString& sPageName,
|
||||||
|
CTemplate& Tmpl) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
+bool CModule::DoEmbeddedWebRequest(CWebSock& WebSock, const CString& sPageName,
|
||||||
|
+ CTemplate& Tmpl) {
|
||||||
|
+ CModCallProtector inside(*this);
|
||||||
|
+ return OnEmbeddedWebRequest(WebSock, sPageName, Tmpl);
|
||||||
|
+}
|
||||||
|
// !Webmods
|
||||||
|
|
||||||
|
bool CModule::OnLoad(const CString& sArgs, CString& sMessage) {
|
||||||
|
@@ -1953,6 +1938,11 @@ bool CModules::UnloadModule(const CString& sModule, CString& sRetMsg) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ if (!pModule->IsCallStackEmpty()) {
|
||||||
|
+ sRetMsg = t_f("Module [{1}] is being called, cannot unload.")(sMod);
|
||||||
|
+ return false;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
bool bSuccess;
|
||||||
|
bool bHandled = false;
|
||||||
|
_GLOBALMODULECALL(OnModuleUnloading(pModule, bSuccess, sRetMsg),
|
||||||
@@ -12,6 +12,9 @@ ZNC_CPE_ID_VENDOR = znc
|
|||||||
ZNC_DEPENDENCIES = host-pkgconf
|
ZNC_DEPENDENCIES = host-pkgconf
|
||||||
ZNC_CONF_OPTS = -DWANT_CYRUS=OFF -DWANT_I18N=OFF -DWANT_PERL=OFF
|
ZNC_CONF_OPTS = -DWANT_CYRUS=OFF -DWANT_I18N=OFF -DWANT_PERL=OFF
|
||||||
|
|
||||||
|
# 0001-fix-crash-while-unloading-modules.patch
|
||||||
|
ZNC_IGNORE_CVES += CVE-2026-82373
|
||||||
|
|
||||||
ifeq ($(BR2_PACKAGE_ICU),y)
|
ifeq ($(BR2_PACKAGE_ICU),y)
|
||||||
ZNC_DEPENDENCIES += icu
|
ZNC_DEPENDENCIES += icu
|
||||||
ZNC_CONF_OPTS += -DWANT_ICU=ON
|
ZNC_CONF_OPTS += -DWANT_ICU=ON
|
||||||
|
|||||||
Reference in New Issue
Block a user