diff options
author | Nicholas Marriott <nicm@cvs.openbsd.org> | 2009-07-12 17:33:19 +0000 |
---|---|---|
committer | Nicholas Marriott <nicm@cvs.openbsd.org> | 2009-07-12 17:33:19 +0000 |
commit | 3171f6dd9605b2063dfe56f53e3b2f9306e73337 (patch) | |
tree | 5cbe68d61a9bd2b41a59ad11b5f2adcb10eebc97 | |
parent | 087350fcc5450e687751ec30b73252f3c0e13543 (diff) |
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.
-rw-r--r-- | usr.bin/tmux/key-bindings.c | 31 | ||||
-rw-r--r-- | usr.bin/tmux/server.c | 5 |
2 files changed, 26 insertions, 10 deletions
diff --git a/usr.bin/tmux/key-bindings.c b/usr.bin/tmux/key-bindings.c index 743be1ee736..6f718d8c510 100644 --- a/usr.bin/tmux/key-bindings.c +++ b/usr.bin/tmux/key-bindings.c @@ -1,4 +1,4 @@ -/* $OpenBSD: key-bindings.c,v 1.1 2009/06/01 22:58:49 nicm Exp $ */ +/* $OpenBSD: key-bindings.c,v 1.2 2009/07/12 17:33:18 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> @@ -27,6 +27,7 @@ SPLAY_GENERATE(key_bindings, key_binding, entry, key_bindings_cmp); struct key_bindings key_bindings; +struct key_bindings dead_key_bindings; int 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; - if ((bd = key_bindings_lookup(key)) == NULL) { - bd = xmalloc(sizeof *bd); - bd->key = key; - SPLAY_INSERT(key_bindings, &key_bindings, bd); - } else - cmd_list_free(bd->cmdlist); + key_bindings_remove(key); + + bd = xmalloc(sizeof *bd); + bd->key = key; + SPLAY_INSERT(key_bindings, &key_bindings, bd); + bd->can_repeat = can_repeat; bd->cmdlist = cmdlist; } @@ -66,9 +67,20 @@ key_bindings_remove(int key) if ((bd = key_bindings_lookup(key)) == NULL) return; SPLAY_REMOVE(key_bindings, &key_bindings, bd); + SPLAY_INSERT(key_bindings, &dead_key_bindings, bd); +} - cmd_list_free(bd->cmdlist); - xfree(bd); +void +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 @@ -162,6 +174,7 @@ key_bindings_free(void) { struct key_binding *bd; + key_bindings_clean(); while (!SPLAY_EMPTY(&key_bindings)) { bd = SPLAY_ROOT(&key_bindings); SPLAY_REMOVE(key_bindings, &key_bindings, bd); diff --git a/usr.bin/tmux/server.c b/usr.bin/tmux/server.c index 1c45e64e71b..761f32161ac 100644 --- a/usr.bin/tmux/server.c +++ b/usr.bin/tmux/server.c @@ -1,4 +1,4 @@ -/* $OpenBSD: server.c,v 1.7 2009/07/12 16:07:56 nicm Exp $ */ +/* $OpenBSD: server.c,v 1.8 2009/07/12 17:33:18 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> @@ -346,6 +346,9 @@ server_main(int srv_fd) server_handle_windows(&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 * of here... |