1
0
mirror of https://github.com/unrealircd/unrealircd.git synced 2026-07-09 11:53:13 +02:00

Fix potentially sending invalid data over websockets on REHASH.

This makes websocket_common unload last (and near-last: rpc & websocket)
and makes us call Mod_Init for these three modules first.
This way, the period where the websocket handler is unavailable is kept
to a minimum.

This also renames the ModuleSetOptions option MOD_OPT_UNLOAD_PRIORITY
to MOD_OPT_PRIORITY since it dynamically changes the module priority
in the list. For 6.x compatibility, MOD_OPT_UNLOAD_PRIORITY can still
be used.
This commit is contained in:
Bram Matthys
2022-11-04 10:37:42 +01:00
parent 02285f468d
commit c3824ad47d
9 changed files with 43 additions and 15 deletions
+7 -1
View File
@@ -777,9 +777,15 @@ struct Module
#define MOD_OPT_OFFICIAL 0x0002 /* Official module, do not set "tainted" */
#define MOD_OPT_PERM_RELOADABLE 0x0004 /* Module is semi-permanent: it can be re-loaded but not un-loaded */
#define MOD_OPT_GLOBAL 0x0008 /* Module is required to be loaded globally (i.e. across the entire network) */
#define MOD_OPT_UNLOAD_PRIORITY 0x1000 /* Module wants a higher or lower unload priority */
#define MOD_OPT_PRIORITY 0x1000 /* Module wants a higher or lower priority for unloading, init, load, etc */
#define MOD_OPT_UNLOAD_PRIORITY 0x1000 /* Alias for MOD_OPT_PRIORITY */
#define MOD_Dep(name, container,module) {#name, (vFP *) &container, module}
/** Websocket module should init 'first' because it handles sockets */
#define WEBSOCKET_MODULE_PRIORITY_INIT -1000000000
/** Websocket module should unload 'last' because it handles sockets */
#define WEBSOCKET_MODULE_PRIORITY_UNLOAD 1000000000
/** Event structs */
struct Event {
Event *prev; /**< Previous event (linked list) */
+2 -2
View File
@@ -2091,8 +2091,6 @@ int config_test(void)
safe_strdup(old_pid_file, conf_files->pid_file);
unrealdns_delasyncconnects();
config_rehash();
Unload_all_loaded_modules();
/* Notify permanent modules of the rehash */
for (h = Hooks[HOOKTYPE_REHASH]; h; h = h->next)
{
@@ -2102,6 +2100,8 @@ int config_test(void)
continue;
(*(h->func.intfunc))();
}
/* Last step: */
Unload_all_loaded_modules();
}
config_pre_run_log();
+6 -5
View File
@@ -430,18 +430,19 @@ const char *Module_Create(const char *path_)
if (Mod_Handle)
*Mod_Handle = mod;
irc_dlsym(Mod, "Mod_Test", Mod_Test);
/* add module here, so ModuleSetOptions() w/MOD_OPT_PRIORITY is available in Mod_Test() */
AddListItemPrio(mod, Modules, 0);
if (Mod_Test)
{
if ((ret = (*Mod_Test)(&mod->modinfo)) < MOD_SUCCESS) {
ircsnprintf(errorbuf, sizeof(errorbuf), "Mod_Test returned %i",
ret);
if ((ret = (*Mod_Test)(&mod->modinfo)) < MOD_SUCCESS)
{
ircsnprintf(errorbuf, sizeof(errorbuf), "Mod_Test returned %i", ret);
/* We EXPECT the module to have cleaned up its mess */
Module_free(mod);
return (errorbuf);
}
}
mod->flags = MODFLAG_TESTING;
AddListItemPrio(mod, Modules, 0);
return NULL;
}
else
@@ -1221,7 +1222,7 @@ void ModuleSetOptions(Module *module, unsigned int options, int action)
{
unsigned int oldopts = module->options;
if (options == MOD_OPT_UNLOAD_PRIORITY)
if (options == MOD_OPT_PRIORITY)
{
DelListItem(module, Modules);
AddListItemPrio(module, Modules, action);
+1 -1
View File
@@ -93,7 +93,7 @@ MOD_INIT()
{
MARK_AS_OFFICIAL_MODULE(modinfo);
/* We must unload early, when all channel modes and such are still in place: */
ModuleSetOptions(modinfo->handle, MOD_OPT_UNLOAD_PRIORITY, -99999999);
ModuleSetOptions(modinfo->handle, MOD_OPT_PRIORITY, -99999999);
LoadPersistentLong(modinfo, channeldb_next_event);
+1 -1
View File
@@ -132,7 +132,7 @@ MOD_INIT()
MARK_AS_OFFICIAL_MODULE(modinfo);
/* We must unload early, when all channel modes and such are still in place: */
ModuleSetOptions(modinfo->handle, MOD_OPT_UNLOAD_PRIORITY, -99999999);
ModuleSetOptions(modinfo->handle, MOD_OPT_PRIORITY, -99999999);
setcfg(&cfg);
+9 -1
View File
@@ -70,6 +70,10 @@ MOD_TEST()
EfunctionAddVoid(modinfo->handle, EFUNC_RPC_RESPONSE, _rpc_response);
EfunctionAddVoid(modinfo->handle, EFUNC_RPC_ERROR, _rpc_error);
EfunctionAddVoid(modinfo->handle, EFUNC_RPC_ERROR_FMT, TO_VOIDFUNC(_rpc_error_fmt));
/* Call MOD_INIT very early, since we manage sockets, but depend on websocket_common */
ModuleSetOptions(modinfo->handle, MOD_OPT_PRIORITY, WEBSOCKET_MODULE_PRIORITY_INIT+1);
return MOD_SUCCESS;
}
@@ -79,17 +83,21 @@ MOD_INIT()
MARK_AS_OFFICIAL_MODULE(modinfo);
websocket_md = findmoddata_byname("websocket", MODDATATYPE_CLIENT); /* can be NULL */
HookAdd(modinfo->handle, HOOKTYPE_CONFIGRUN_EX, 0, rpc_config_run_ex_listen);
HookAdd(modinfo->handle, HOOKTYPE_CONFIGRUN, 0, rpc_config_run_rpc_user);
HookAdd(modinfo->handle, HOOKTYPE_HANDSHAKE, -5000, rpc_client_accept);
HookAdd(modinfo->handle, HOOKTYPE_RAWPACKET_IN, INT_MIN, rpc_packet_in_unix_socket);
/* Call MOD_LOAD very late, since we manage sockets, but depend on websocket_common */
ModuleSetOptions(modinfo->handle, MOD_OPT_PRIORITY, WEBSOCKET_MODULE_PRIORITY_UNLOAD-1);
return MOD_SUCCESS;
}
MOD_LOAD()
{
websocket_md = findmoddata_byname("websocket", MODDATATYPE_CLIENT); /* can be NULL */
return MOD_SUCCESS;
}
+1 -1
View File
@@ -128,7 +128,7 @@ MOD_TEST()
MOD_INIT()
{
MARK_AS_OFFICIAL_MODULE(modinfo);
ModuleSetOptions(modinfo->handle, MOD_OPT_UNLOAD_PRIORITY, -9999);
ModuleSetOptions(modinfo->handle, MOD_OPT_PRIORITY, -9999);
LoadPersistentLong(modinfo, tkldb_next_event);
+9 -3
View File
@@ -64,6 +64,9 @@ MOD_TEST()
{
HookAdd(modinfo->handle, HOOKTYPE_CONFIGTEST, 0, websocket_config_test);
HookAdd(modinfo->handle, HOOKTYPE_CONFIGPOSTTEST, 0, websocket_config_posttest);
/* Call MOD_INIT very early, since we manage sockets, but depend on websocket_common */
ModuleSetOptions(modinfo->handle, MOD_OPT_PRIORITY, WEBSOCKET_MODULE_PRIORITY_INIT+1);
return MOD_SUCCESS;
}
@@ -73,18 +76,21 @@ MOD_INIT()
MARK_AS_OFFICIAL_MODULE(modinfo);
websocket_md = findmoddata_byname("websocket", MODDATATYPE_CLIENT);
if (!websocket_md)
config_warn("The 'websocket_common' module is not loaded, even though it was promised to be ???");
HookAdd(modinfo->handle, HOOKTYPE_CONFIGRUN_EX, 0, websocket_config_run_ex);
HookAdd(modinfo->handle, HOOKTYPE_PACKET, INT_MAX, websocket_packet_out);
HookAdd(modinfo->handle, HOOKTYPE_SECURE_CONNECT, 0, websocket_secure_connect);
/* Call MOD_LOAD very late, since we manage sockets, but depend on websocket_common */
ModuleSetOptions(modinfo->handle, MOD_OPT_PRIORITY, WEBSOCKET_MODULE_PRIORITY_UNLOAD-1);
return MOD_SUCCESS;
}
MOD_LOAD()
{
websocket_md = findmoddata_byname("websocket", MODDATATYPE_CLIENT);
if (!websocket_md)
config_warn("The 'websocket_common' module is not loaded, even though it was promised to be ???");
if (non_utf8_nick_chars_in_use || (iConf.allowed_channelchars == ALLOWED_CHANNELCHARS_ANY))
ws_text_mode_available = 0;
return MOD_SUCCESS;
+7
View File
@@ -58,6 +58,10 @@ MOD_TEST()
EfunctionAdd(modinfo->handle, EFUNC_WEBSOCKET_HANDLE_WEBSOCKET, _websocket_handle_websocket);
EfunctionAdd(modinfo->handle, EFUNC_WEBSOCKET_CREATE_PACKET, _websocket_create_packet);
EfunctionAdd(modinfo->handle, EFUNC_WEBSOCKET_CREATE_PACKET_SIMPLE, _websocket_create_packet_simple);
/* Init first, since we manage sockets */
ModuleSetOptions(modinfo->handle, MOD_OPT_PRIORITY, WEBSOCKET_MODULE_PRIORITY_INIT);
return MOD_SUCCESS;
}
@@ -76,6 +80,9 @@ MOD_INIT()
mreq.type = MODDATATYPE_CLIENT;
websocket_md = ModDataAdd(modinfo->handle, mreq);
/* Unload last, since we manage sockets */
ModuleSetOptions(modinfo->handle, MOD_OPT_PRIORITY, WEBSOCKET_MODULE_PRIORITY_UNLOAD);
return MOD_SUCCESS;
}