mirror of
https://github.com/tmate-io/tmate.git
synced 2025-04-02 20:06:47 +02:00
Creating a key binding which replaces itself (such as "bind x bind x lsw")
frees the command list bound to the key while it is still being executed, leading to a use after free. To prevent this, create a dead keys list and defer freeing replaced or removed key bindings until the main loop when the key binding will have finished executing. Found by Johan Friis when creating a key binding to reload his configuration file.
This commit is contained in:
parent
22d51ec1ea
commit
9e49ec6cd3
@ -27,6 +27,7 @@
|
|||||||
SPLAY_GENERATE(key_bindings, key_binding, entry, key_bindings_cmp);
|
SPLAY_GENERATE(key_bindings, key_binding, entry, key_bindings_cmp);
|
||||||
|
|
||||||
struct key_bindings key_bindings;
|
struct key_bindings key_bindings;
|
||||||
|
struct key_bindings dead_key_bindings;
|
||||||
|
|
||||||
int
|
int
|
||||||
key_bindings_cmp(struct key_binding *bd1, struct key_binding *bd2)
|
key_bindings_cmp(struct key_binding *bd1, struct key_binding *bd2)
|
||||||
@ -48,12 +49,12 @@ key_bindings_add(int key, int can_repeat, struct cmd_list *cmdlist)
|
|||||||
{
|
{
|
||||||
struct key_binding *bd;
|
struct key_binding *bd;
|
||||||
|
|
||||||
if ((bd = key_bindings_lookup(key)) == NULL) {
|
key_bindings_remove(key);
|
||||||
bd = xmalloc(sizeof *bd);
|
|
||||||
bd->key = key;
|
bd = xmalloc(sizeof *bd);
|
||||||
SPLAY_INSERT(key_bindings, &key_bindings, bd);
|
bd->key = key;
|
||||||
} else
|
SPLAY_INSERT(key_bindings, &key_bindings, bd);
|
||||||
cmd_list_free(bd->cmdlist);
|
|
||||||
bd->can_repeat = can_repeat;
|
bd->can_repeat = can_repeat;
|
||||||
bd->cmdlist = cmdlist;
|
bd->cmdlist = cmdlist;
|
||||||
}
|
}
|
||||||
@ -66,9 +67,20 @@ key_bindings_remove(int key)
|
|||||||
if ((bd = key_bindings_lookup(key)) == NULL)
|
if ((bd = key_bindings_lookup(key)) == NULL)
|
||||||
return;
|
return;
|
||||||
SPLAY_REMOVE(key_bindings, &key_bindings, bd);
|
SPLAY_REMOVE(key_bindings, &key_bindings, bd);
|
||||||
|
SPLAY_INSERT(key_bindings, &dead_key_bindings, bd);
|
||||||
|
}
|
||||||
|
|
||||||
cmd_list_free(bd->cmdlist);
|
void
|
||||||
xfree(bd);
|
key_bindings_clean(void)
|
||||||
|
{
|
||||||
|
struct key_binding *bd;
|
||||||
|
|
||||||
|
while (!SPLAY_EMPTY(&dead_key_bindings)) {
|
||||||
|
bd = SPLAY_ROOT(&dead_key_bindings);
|
||||||
|
SPLAY_REMOVE(key_bindings, &dead_key_bindings, bd);
|
||||||
|
cmd_list_free(bd->cmdlist);
|
||||||
|
xfree(bd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -162,6 +174,7 @@ key_bindings_free(void)
|
|||||||
{
|
{
|
||||||
struct key_binding *bd;
|
struct key_binding *bd;
|
||||||
|
|
||||||
|
key_bindings_clean();
|
||||||
while (!SPLAY_EMPTY(&key_bindings)) {
|
while (!SPLAY_EMPTY(&key_bindings)) {
|
||||||
bd = SPLAY_ROOT(&key_bindings);
|
bd = SPLAY_ROOT(&key_bindings);
|
||||||
SPLAY_REMOVE(key_bindings, &key_bindings, bd);
|
SPLAY_REMOVE(key_bindings, &key_bindings, bd);
|
||||||
|
3
server.c
3
server.c
@ -346,6 +346,9 @@ server_main(int srv_fd)
|
|||||||
server_handle_windows(&pfd);
|
server_handle_windows(&pfd);
|
||||||
server_handle_clients(&pfd);
|
server_handle_clients(&pfd);
|
||||||
|
|
||||||
|
/* Collect any unset key bindings. */
|
||||||
|
key_bindings_clean();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we have no sessions and clients left, let's get out
|
* If we have no sessions and clients left, let's get out
|
||||||
* of here...
|
* of here...
|
||||||
|
Loading…
Reference in New Issue
Block a user