m_modules: make modreload work like restart

/modrestart used to be implemented as a normal command and could crash
when used remotely because it would reload m_encap, which was on the
call stack at the time. This was fixed in 41390bfe5f. However,
/modreload has exactly the same problem, so I'm giving it the
same treatment.

Incidentally: This bug was first discovered in ircd-seven, where the
`/mod*` commands themselves live in the core, so m_encap was the only way
the crash could happen (and it didn't most of the time, because m_encap
would only be moved if you got unlucky). But `/mod*` are in modules in
charybdis, so /modrestart would have unloaded the code it was in the
middle of executing. With that in mind, I'm not sure how it ever
appeared to work.
This commit is contained in:
Ed Kellett 2019-11-17 11:15:47 +00:00
parent 58a7048006
commit 7b6410135b
No known key found for this signature in database
GPG Key ID: CB9986DEF342FABC
3 changed files with 56 additions and 33 deletions

View File

@ -28,6 +28,7 @@
#include "defaults.h"
#include "setup.h"
#include "parse.h"
#include "client.h" /* for IDLEN */
#define MAPI_CHARYBDIS 2
@ -118,6 +119,12 @@ struct mapi_mheader_av2
#define DECLARE_MODULE_AV2(name, reg, unreg, cl, hl, hfnlist, caplist, v, desc) \
struct mapi_mheader_av2 _mheader = { MAPI_V2, reg, unreg, cl, hl, hfnlist, caplist, v, desc, DATECODE}
struct modreload
{
char module[BUFSIZE];
char id[IDLEN];
};
/* add a path */
void mod_add_path(const char *path);
void mod_clear_paths(void);

View File

@ -36,6 +36,7 @@
#include "match.h"
#include "s_serv.h"
#include "capability.h"
#include "hash.h"
#include <ltdl.h>
@ -682,6 +683,49 @@ load_a_module(const char *path, bool warn, int origin, bool core)
return true;
}
void
modules_do_reload(void *info_)
{
struct modreload *info = info_;
struct module *mod;
int check_core;
char *m_bn = rb_basename(info->module);
struct Client *source_p = find_id(info->id);
if((mod = findmodule_byname(m_bn)) == NULL)
{
if (source_p) sendto_one_notice(source_p, ":Module %s is not loaded", m_bn);
rb_free(info);
rb_free(m_bn);
return;
}
check_core = mod->core;
mod_remember_clicaps();
if(unload_one_module(m_bn, true) == false)
{
if (source_p) sendto_one_notice(source_p, ":Module %s is not loaded", m_bn);
rb_free(info);
rb_free(m_bn);
return;
}
if((load_one_module(m_bn, mod->origin, check_core) == false) && check_core)
{
sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
"Error reloading core module: %s: terminating ircd", m_bn);
ilog(L_MAIN, "Error loading core module %s: terminating ircd", m_bn);
exit(0);
}
mod_notify_clicaps();
rb_free(info);
rb_free(m_bn);
}
void
modules_do_restart(void *unused)
{

View File

@ -54,6 +54,7 @@ static void do_modreload(struct Client *, const char *);
static void do_modlist(struct Client *, const char *);
static void do_modrestart(struct Client *);
extern void modules_do_reload(void *); /* end of ircd/modules.c */
extern void modules_do_restart(void *); /* end of ircd/modules.c */
struct Message modload_msgtab = {
@ -317,39 +318,10 @@ do_modunload(struct Client *source_p, const char *module)
static void
do_modreload(struct Client *source_p, const char *module)
{
struct module *mod;
int check_core;
char *m_bn = rb_basename(module);
if((mod = findmodule_byname(m_bn)) == NULL)
{
sendto_one_notice(source_p, ":Module %s is not loaded", m_bn);
rb_free(m_bn);
return;
}
check_core = mod->core;
mod_remember_clicaps();
if(unload_one_module(m_bn, true) == false)
{
sendto_one_notice(source_p, ":Module %s is not loaded", m_bn);
rb_free(m_bn);
return;
}
if((load_one_module(m_bn, mod->origin, check_core) == false) && check_core)
{
sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
"Error reloading core module: %s: terminating ircd", m_bn);
ilog(L_MAIN, "Error loading core module %s: terminating ircd", m_bn);
exit(0);
}
mod_notify_clicaps();
rb_free(m_bn);
struct modreload *info = rb_malloc(sizeof *info);
strcpy(info->module, module);
strcpy(info->id, source_p->id);
rb_event_addonce("modules_do_reload", modules_do_reload, info, 1);
}
static void