1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-09 09:27:59 +00:00

Avoid crash in MIT Kerberos for Windows on session restart.

A user reports that if you have MIT KfW loaded, and your PuTTY session
terminates without the PuTTY process exiting, and you select 'Restart
Session' from the menu, then a crash occurs inside the Kerberos
library itself. Scuttlebutt on the Internet suggested this might be to
do with unloading and then reloading the DLL within the process
lifetime, which indeed we were doing.

Now we avoid doing that for the KfW library in particular, by keeping
a tree234 of module handles marked 'never unload this'.

This is a workaround at best, but it seems to stop the problem
happening in my own tests.
This commit is contained in:
Simon Tatham 2021-07-01 18:59:44 +01:00
parent c714dfc936
commit 058e390ab5

View File

@ -95,6 +95,28 @@ const char *gsslogmsg = NULL;
static void ssh_sspi_bind_fns(struct ssh_gss_library *lib);
static tree234 *libraries_to_never_unload;
static int library_to_never_unload_cmp(void *av, void *bv)
{
uintptr_t a = (uintptr_t)av, b = (uintptr_t)bv;
return a < b ? -1 : a > b ? +1 : 0;
}
static void ensure_library_tree_exists(void)
{
if (!libraries_to_never_unload)
libraries_to_never_unload = newtree234(library_to_never_unload_cmp);
}
static bool library_is_in_never_unload_tree(HMODULE module)
{
ensure_library_tree_exists();
return find234(libraries_to_never_unload, module, NULL);
}
static void add_library_to_never_unload_tree(HMODULE module)
{
ensure_library_tree_exists();
add234(libraries_to_never_unload, module);
}
struct ssh_gss_liblist *ssh_gss_setup(Conf *conf)
{
HMODULE module;
@ -145,6 +167,23 @@ struct ssh_gss_liblist *ssh_gss_setup(Conf *conf)
LOAD_LIBRARY_SEARCH_SYSTEM32 |
LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR |
LOAD_LIBRARY_SEARCH_USER_DIRS);
/*
* The MIT Kerberos DLL suffers an internal segfault
* for some reason if you unload and reload one within
* the same process. So, make sure that after we load
* this library, we never free it.
*
* Or rather: after we've loaded it once, if any
* _further_ load returns the same module handle, we
* immediately free it again (to prevent the Windows
* API's internal reference count growing without
* bound). But on the other hand we never free it in
* ssh_gss_cleanup.
*/
if (library_is_in_never_unload_tree(module))
FreeLibrary(module);
add_library_to_never_unload_tree(module);
}
sfree(buffer);
}
@ -280,7 +319,11 @@ void ssh_gss_cleanup(struct ssh_gss_liblist *list)
* another SSH instance still using it.
*/
for (i = 0; i < list->nlibraries; i++) {
FreeLibrary((HMODULE)list->libraries[i].handle);
if (list->libraries[i].id != 0) {
HMODULE module = (HMODULE)list->libraries[i].handle;
if (!library_is_in_never_unload_tree(module))
FreeLibrary(module);
}
if (list->libraries[i].id == 2) {
/* The 'custom' id involves a dynamically allocated message.
* Note that we must cast away the 'const' to free it. */