When a remote MODRESTART command is received, it will pass through the
ENCAP module. The ms_encap function is responsible for dispatching the
command handler and then the modules will eventually be reloaded.
However, if the ENCAP module is reloaded to a different address, the
stack now contains the address of a function that no longer exists.
Also, in this version of the IRCd, the module restarting functionality
was located in a function that is itself located in a module, so things
will also go badly if that module is reloaded to a different address,
too.
Return immediately from the command handler and have the event loop
call the function responsible for reloading the modules instead.
c.f. release/3.5 commit db05a36210
Reported-by: mniip (Freenode)
This commit is contained in:
parent
6002ccec6b
commit
41390bfe5f
2 changed files with 48 additions and 30 deletions
|
@ -668,3 +668,38 @@ load_a_module(const char *path, bool warn, int origin, bool core)
|
||||||
rb_free(mod_displayname);
|
rb_free(mod_displayname);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
modules_do_restart(void *unused)
|
||||||
|
{
|
||||||
|
unsigned int modnum = 0;
|
||||||
|
rb_dlink_node *ptr, *nptr;
|
||||||
|
|
||||||
|
RB_DLINK_FOREACH_SAFE(ptr, nptr, module_list.head)
|
||||||
|
{
|
||||||
|
struct module *mod = ptr->data;
|
||||||
|
if(!unload_one_module(mod->name, false))
|
||||||
|
{
|
||||||
|
ilog(L_MAIN, "Module Restart: %s was not unloaded %s",
|
||||||
|
mod->name,
|
||||||
|
mod->core? "(core module)" : "");
|
||||||
|
|
||||||
|
if(!mod->core)
|
||||||
|
sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
|
||||||
|
"Module Restart: %s failed to unload",
|
||||||
|
mod->name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
modnum++;
|
||||||
|
}
|
||||||
|
|
||||||
|
load_all_modules(false);
|
||||||
|
load_core_modules(false);
|
||||||
|
rehash(false);
|
||||||
|
|
||||||
|
sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
|
||||||
|
"Module Restart: %u modules unloaded, %lu modules loaded",
|
||||||
|
modnum, rb_dlink_list_length(&module_list));
|
||||||
|
ilog(L_MAIN, "Module Restart: %u modules unloaded, %lu modules loaded", modnum, rb_dlink_list_length(&module_list));
|
||||||
|
}
|
||||||
|
|
|
@ -54,6 +54,8 @@ static void do_modreload(struct Client *, const char *);
|
||||||
static void do_modlist(struct Client *, const char *);
|
static void do_modlist(struct Client *, const char *);
|
||||||
static void do_modrestart(struct Client *);
|
static void do_modrestart(struct Client *);
|
||||||
|
|
||||||
|
extern void modules_do_restart(void *); /* end of ircd/modules.c */
|
||||||
|
|
||||||
struct Message modload_msgtab = {
|
struct Message modload_msgtab = {
|
||||||
"MODLOAD", 0, 0, 0, 0,
|
"MODLOAD", 0, 0, 0, 0,
|
||||||
{mg_unreg, mg_not_oper, mg_ignore, mg_ignore, {me_modload, 2}, {mo_modload, 2}}
|
{mg_unreg, mg_not_oper, mg_ignore, mg_ignore, {me_modload, 2}, {mo_modload, 2}}
|
||||||
|
@ -341,38 +343,19 @@ do_modreload(struct Client *source_p, const char *module)
|
||||||
static void
|
static void
|
||||||
do_modrestart(struct Client *source_p)
|
do_modrestart(struct Client *source_p)
|
||||||
{
|
{
|
||||||
unsigned int modnum = 0;
|
|
||||||
rb_dlink_node *ptr, *nptr;
|
|
||||||
|
|
||||||
sendto_one_notice(source_p, ":Reloading all modules");
|
sendto_one_notice(source_p, ":Reloading all modules");
|
||||||
|
|
||||||
RB_DLINK_FOREACH_SAFE(ptr, nptr, module_list.head)
|
/*
|
||||||
{
|
* If a remote MODRESTART is received, m_encap.so will be reloaded,
|
||||||
struct module *mod = ptr->data;
|
* but ms_encap is in the call stack (it indirectly calls this
|
||||||
if(!unload_one_module(mod->name, false))
|
* function). Also, this function is itself in a module.
|
||||||
{
|
*
|
||||||
ilog(L_MAIN, "Module Restart: %s was not unloaded %s",
|
* This will go horribly wrong if either module is reloaded to a
|
||||||
mod->name,
|
* different address.
|
||||||
mod->core? "(core module)" : "");
|
*
|
||||||
|
* So, defer the restart to the event loop and return now.
|
||||||
if(!mod->core)
|
*/
|
||||||
sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
|
rb_event_addonce("modules_do_restart", modules_do_restart, NULL, 1);
|
||||||
"Module Restart: %s failed to unload",
|
|
||||||
mod->name);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
modnum++;
|
|
||||||
}
|
|
||||||
|
|
||||||
load_all_modules(false);
|
|
||||||
load_core_modules(false);
|
|
||||||
rehash(false);
|
|
||||||
|
|
||||||
sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
|
|
||||||
"Module Restart: %u modules unloaded, %lu modules loaded",
|
|
||||||
modnum, rb_dlink_list_length(&module_list));
|
|
||||||
ilog(L_MAIN, "Module Restart: %u modules unloaded, %lu modules loaded", modnum, rb_dlink_list_length(&module_list));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
Loading…
Reference in a new issue