From 7b6410135b2bf53efcdf7ecb9f073f73f5d84918 Mon Sep 17 00:00:00 2001 From: Ed Kellett Date: Sun, 17 Nov 2019 11:15:47 +0000 Subject: [PATCH] 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. --- include/modules.h | 7 +++++++ ircd/modules.c | 44 ++++++++++++++++++++++++++++++++++++++++ modules/core/m_modules.c | 38 +++++----------------------------- 3 files changed, 56 insertions(+), 33 deletions(-) diff --git a/include/modules.h b/include/modules.h index bfc502f1..49539865 100644 --- a/include/modules.h +++ b/include/modules.h @@ -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); diff --git a/ircd/modules.c b/ircd/modules.c index b477e182..8cbf5113 100644 --- a/ircd/modules.c +++ b/ircd/modules.c @@ -36,6 +36,7 @@ #include "match.h" #include "s_serv.h" #include "capability.h" +#include "hash.h" #include @@ -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) { diff --git a/modules/core/m_modules.c b/modules/core/m_modules.c index ecc54b2d..4078c2b8 100644 --- a/modules/core/m_modules.c +++ b/modules/core/m_modules.c @@ -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