dnkl/foot
41
2.0k
Fork
You've already forked foot
243

Fix parsing key-bindings config to not read past the end of the string. #810

Manually merged
dnkl merged 1 commit from :fix-809 into master 2021年11月21日 17:45:35 +01:00
Contributor
Copy link

pipe_argv_from_value itself stripped the cmd-to-exec from ctx->value,
so the callers should not be doing that themselves.

Fixes #809

pipe_argv_from_value itself stripped the cmd-to-exec from ctx->value, so the callers should not be doing that themselves. Fixes #809
Fix parsing key-bindings config to not read past the end of the string.
All checks were successful
continuous-integration/woodpecker the build was successful
31c1b91a7c
pipe_argv_from_value itself stripped the cmd-to-exec from ctx->value,
so the callers should not be doing that themselves.
Fixes #809 
dnkl left a comment
Copy link

Thanks!

This patch handles correctly written key bindings, but there are still issues with invalid bindings. First, there's a memory leak:

==10456==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 15 byte(s) in 1 object(s) allocated from:
 #0 0x7ff882c94279 in __interceptor_malloc /build/gcc/src/gcc/libsanitizer/asan/asan_malloc_linux.cpp:145
 #1 0x7ff882c34363 in __interceptor_strndup /build/gcc/src/gcc/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:414
 #2 0x5585d986fcfc in xstrndup ../../xmalloc.c:57
 #3 0x5585d9764d9c in push_argv ../../tokenize.c:28
 #4 0x5585d9765412 in tokenize_cmdline ../../tokenize.c:57
 #5 0x5585d9688d5f in pipe_argv_from_value ../../config.c:1666
 #6 0x5585d96899e5 in parse_key_binding_section ../../config.c:1728
 #7 0x5585d968c4eb in parse_section_key_bindings ../../config.c:1889
 #8 0x5585d9693bd6 in parse_config_file ../../config.c:2564
 #9 0x5585d96989b5 in config_load ../../config.c:2912
 #10 0x5585d96df4c5 in main ../../main.c:432
 #11 0x7ff881c01b24 in __libc_start_main (/usr/lib/libc.so.6+0x27b24)

This can be fixed with the following patch:

diff --git a/config.c b/config.c
index 9e290c65..ef6133a3 100644
--- a/config.c
+++ b/config.c
@@ -1647,9 +1647,9 @@ argv_compare(char *const *argv1, char *const *argv2)
 * - argv: allocated array containing {"cmd", "arg1", "arg2", NULL}. Caller frees.
 */
 static ssize_t
-pipe_argv_from_value(struct context *ctx, char ***argv)
+pipe_argv_from_value(struct context *ctx, struct argv *argv)
 {
- *argv = NULL;
+ argv->args = NULL;
 
 if (ctx->value[0] != '[')
 return 0;
@@ -1663,7 +1663,7 @@ pipe_argv_from_value(struct context *ctx, char ***argv)
 size_t pipe_len = pipe_cmd_end - ctx->value - 1;
 char *cmd = xstrndup(&ctx->value[1], pipe_len);
 
- if (!tokenize_cmdline(cmd, argv)) {
+ if (!tokenize_cmdline(cmd, &argv->args)) {
 LOG_CONTEXTUAL_ERR("syntax error in command line");
 free(cmd);
 return -1;
@@ -1723,7 +1723,7 @@ parse_key_binding_section(struct context *ctx,
 const char *const action_map[static action_count],
 struct config_key_binding_list *bindings)
 {
- char **pipe_argv;
+ struct argv pipe_argv;
 
 ssize_t pipe_remove_len = pipe_argv_from_value(ctx, &pipe_argv);
 if (pipe_remove_len < 0)
@@ -1738,8 +1738,8 @@ parse_key_binding_section(struct context *ctx,
 
 /* Unset binding */
 if (strcasecmp(ctx->value, "none") == 0) {
- remove_action_from_key_bindings_list(bindings, action, pipe_argv);
- free(pipe_argv);
+ remove_action_from_key_bindings_list(bindings, action, pipe_argv.args);
+ free_argv(&pipe_argv);
 return true;
 }
 
@@ -1748,12 +1748,12 @@ parse_key_binding_section(struct context *ctx,
 has_key_binding_collisions(
 ctx, action, action_map, bindings, &key_combos))
 {
- free(pipe_argv);
+ free_argv(&pipe_argv);
 free_key_combo_list(&key_combos);
 return false;
 }
 
- remove_action_from_key_bindings_list(bindings, action, pipe_argv);
+ remove_action_from_key_bindings_list(bindings, action, pipe_argv.args);
 
 /* Emit key bindings */
 size_t ofs = bindings->count;
@@ -1769,9 +1769,7 @@ parse_key_binding_section(struct context *ctx,
 .modifiers = combo->modifiers,
 .sym = combo->sym,
 .pipe = {
- .argv = {
- .args = pipe_argv,
- },
+ .argv = pipe_argv,
 .master_copy = first,
 },
 };
@@ -1786,7 +1784,7 @@ parse_key_binding_section(struct context *ctx,
 }
 
 LOG_CONTEXTUAL_ERR("not a valid action: %s", ctx->key);
- free(pipe_argv);
+ free_argv(&pipe_argv);
 return false;
 }
 
@@ -2099,7 +2097,7 @@ parse_section_mouse_bindings(struct context *ctx)
 const char *key = ctx->key;
 const char *value = ctx->value;
 
- char **pipe_argv;
+ struct argv pipe_argv;
 
 ssize_t pipe_remove_len = pipe_argv_from_value(ctx, &pipe_argv);
 if (pipe_remove_len < 0)
@@ -2127,7 +2125,7 @@ parse_section_mouse_bindings(struct context *ctx)
 binding->action = BIND_ACTION_NONE;
 }
 }
- free(pipe_argv);
+ free_argv(&pipe_argv);
 return true;
 }
 
@@ -2135,7 +2133,7 @@ parse_section_mouse_bindings(struct context *ctx)
 if (!value_to_mouse_combos(ctx, &key_combos) ||
 has_mouse_binding_collisions(ctx, &key_combos))
 {
- free(pipe_argv);
+ free_argv(&pipe_argv);
 free_key_combo_list(&key_combos);
 return false;
 }
@@ -2145,9 +2143,9 @@ parse_section_mouse_bindings(struct context *ctx)
 struct config_mouse_binding *binding = &conf->bindings.mouse.arr[i];
 
 if (binding->action == action &&
- ((binding->pipe.argv.args == NULL && pipe_argv == NULL) ||
- (binding->pipe.argv.args != NULL && pipe_argv != NULL &&
- argv_compare(binding->pipe.argv.args, pipe_argv) == 0)))
+ ((binding->pipe.argv.args == NULL && pipe_argv.args == NULL) ||
+ (binding->pipe.argv.args != NULL && pipe_argv.args != NULL &&
+ argv_compare(binding->pipe.argv.args, pipe_argv.args) == 0)))
 {
 if (binding->pipe.master_copy)
 free_argv(&binding->pipe.argv);
@@ -2171,9 +2169,7 @@ parse_section_mouse_bindings(struct context *ctx)
 .button = combo->m.button,
 .count = combo->m.count,
 .pipe = {
- .argv = {
- .args = pipe_argv,
- },
+ .argv = pipe_argv,
 .master_copy = first,
 },
 };
@@ -2187,7 +2183,7 @@ parse_section_mouse_bindings(struct context *ctx)
 }
 
 LOG_CONTEXTUAL_ERR("not a valid option: %s", key);
- free(pipe_argv);
+ free_argv(&pipe_argv);
 return false;
 }
 

But, then there's a problem with the error message. For example, this configuration (typo in Shift):

[key-bindings]
pipe-visible=[/usr/bin/false] Control+Shifts+a

Prints this:

error: /home/daniel/.config/foot/foot.ini:74: [ipe-visible].pipe-visible: Control+Shifts+a: not a valid modifier name: Shifts

Note the string inside the [] - ipe-visible. This is supposed to be the section name, i.e. key-bindings.

Thanks! This patch handles correctly written key bindings, but there are still issues with invalid bindings. First, there's a memory leak: ``` ==10456==ERROR: LeakSanitizer: detected memory leaks Direct leak of 15 byte(s) in 1 object(s) allocated from: #0 0x7ff882c94279 in __interceptor_malloc /build/gcc/src/gcc/libsanitizer/asan/asan_malloc_linux.cpp:145 #1 0x7ff882c34363 in __interceptor_strndup /build/gcc/src/gcc/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:414 #2 0x5585d986fcfc in xstrndup ../../xmalloc.c:57 #3 0x5585d9764d9c in push_argv ../../tokenize.c:28 #4 0x5585d9765412 in tokenize_cmdline ../../tokenize.c:57 #5 0x5585d9688d5f in pipe_argv_from_value ../../config.c:1666 #6 0x5585d96899e5 in parse_key_binding_section ../../config.c:1728 #7 0x5585d968c4eb in parse_section_key_bindings ../../config.c:1889 #8 0x5585d9693bd6 in parse_config_file ../../config.c:2564 #9 0x5585d96989b5 in config_load ../../config.c:2912 #10 0x5585d96df4c5 in main ../../main.c:432 #11 0x7ff881c01b24 in __libc_start_main (/usr/lib/libc.so.6+0x27b24) ``` This can be fixed with the following patch: ```diff diff --git a/config.c b/config.c index 9e290c65..ef6133a3 100644 --- a/config.c +++ b/config.c @@ -1647,9 +1647,9 @@ argv_compare(char *const *argv1, char *const *argv2) * - argv: allocated array containing {"cmd", "arg1", "arg2", NULL}. Caller frees. */ static ssize_t -pipe_argv_from_value(struct context *ctx, char ***argv) +pipe_argv_from_value(struct context *ctx, struct argv *argv) { - *argv = NULL; + argv->args = NULL; if (ctx->value[0] != '[') return 0; @@ -1663,7 +1663,7 @@ pipe_argv_from_value(struct context *ctx, char ***argv) size_t pipe_len = pipe_cmd_end - ctx->value - 1; char *cmd = xstrndup(&ctx->value[1], pipe_len); - if (!tokenize_cmdline(cmd, argv)) { + if (!tokenize_cmdline(cmd, &argv->args)) { LOG_CONTEXTUAL_ERR("syntax error in command line"); free(cmd); return -1; @@ -1723,7 +1723,7 @@ parse_key_binding_section(struct context *ctx, const char *const action_map[static action_count], struct config_key_binding_list *bindings) { - char **pipe_argv; + struct argv pipe_argv; ssize_t pipe_remove_len = pipe_argv_from_value(ctx, &pipe_argv); if (pipe_remove_len < 0) @@ -1738,8 +1738,8 @@ parse_key_binding_section(struct context *ctx, /* Unset binding */ if (strcasecmp(ctx->value, "none") == 0) { - remove_action_from_key_bindings_list(bindings, action, pipe_argv); - free(pipe_argv); + remove_action_from_key_bindings_list(bindings, action, pipe_argv.args); + free_argv(&pipe_argv); return true; } @@ -1748,12 +1748,12 @@ parse_key_binding_section(struct context *ctx, has_key_binding_collisions( ctx, action, action_map, bindings, &key_combos)) { - free(pipe_argv); + free_argv(&pipe_argv); free_key_combo_list(&key_combos); return false; } - remove_action_from_key_bindings_list(bindings, action, pipe_argv); + remove_action_from_key_bindings_list(bindings, action, pipe_argv.args); /* Emit key bindings */ size_t ofs = bindings->count; @@ -1769,9 +1769,7 @@ parse_key_binding_section(struct context *ctx, .modifiers = combo->modifiers, .sym = combo->sym, .pipe = { - .argv = { - .args = pipe_argv, - }, + .argv = pipe_argv, .master_copy = first, }, }; @@ -1786,7 +1784,7 @@ parse_key_binding_section(struct context *ctx, } LOG_CONTEXTUAL_ERR("not a valid action: %s", ctx->key); - free(pipe_argv); + free_argv(&pipe_argv); return false; } @@ -2099,7 +2097,7 @@ parse_section_mouse_bindings(struct context *ctx) const char *key = ctx->key; const char *value = ctx->value; - char **pipe_argv; + struct argv pipe_argv; ssize_t pipe_remove_len = pipe_argv_from_value(ctx, &pipe_argv); if (pipe_remove_len < 0) @@ -2127,7 +2125,7 @@ parse_section_mouse_bindings(struct context *ctx) binding->action = BIND_ACTION_NONE; } } - free(pipe_argv); + free_argv(&pipe_argv); return true; } @@ -2135,7 +2133,7 @@ parse_section_mouse_bindings(struct context *ctx) if (!value_to_mouse_combos(ctx, &key_combos) || has_mouse_binding_collisions(ctx, &key_combos)) { - free(pipe_argv); + free_argv(&pipe_argv); free_key_combo_list(&key_combos); return false; } @@ -2145,9 +2143,9 @@ parse_section_mouse_bindings(struct context *ctx) struct config_mouse_binding *binding = &conf->bindings.mouse.arr[i]; if (binding->action == action && - ((binding->pipe.argv.args == NULL && pipe_argv == NULL) || - (binding->pipe.argv.args != NULL && pipe_argv != NULL && - argv_compare(binding->pipe.argv.args, pipe_argv) == 0))) + ((binding->pipe.argv.args == NULL && pipe_argv.args == NULL) || + (binding->pipe.argv.args != NULL && pipe_argv.args != NULL && + argv_compare(binding->pipe.argv.args, pipe_argv.args) == 0))) { if (binding->pipe.master_copy) free_argv(&binding->pipe.argv); @@ -2171,9 +2169,7 @@ parse_section_mouse_bindings(struct context *ctx) .button = combo->m.button, .count = combo->m.count, .pipe = { - .argv = { - .args = pipe_argv, - }, + .argv = pipe_argv, .master_copy = first, }, }; @@ -2187,7 +2183,7 @@ parse_section_mouse_bindings(struct context *ctx) } LOG_CONTEXTUAL_ERR("not a valid option: %s", key); - free(pipe_argv); + free_argv(&pipe_argv); return false; } ``` But, then there's a problem with the error message. For example, this configuration (typo in <kbd>Shift</kbd>): ```ini [key-bindings] pipe-visible=[/usr/bin/false] Control+Shifts+a ``` Prints this: ``` error: /home/daniel/.config/foot/foot.ini:74: [ipe-visible].pipe-visible: Control+Shifts+a: not a valid modifier name: Shifts ``` Note the string inside the `[]` - `ipe-visible`. This is supposed to be the section name, i.e. `key-bindings`.
Owner
Copy link

This is supposed to be the section name, i.e. key-bindings.

... seems to be a general issue, not specific to this patch/bug. Ignore this for now.

> This is supposed to be the section name, i.e. key-bindings. ... seems to be a general issue, not specific to this patch/bug. Ignore this for now.
Owner
Copy link

... seems to be a general issue, not specific to this patch/bug. Ignore this for now.

Fixed in 9b232e07f9

That leaves the argv memory leak.

> ... seems to be a general issue, not specific to this patch/bug. Ignore this for now. Fixed in https://codeberg.org/dnkl/foot/commit/9b232e07f9b24a16d496939ec44c37fb772cd0b7 That leaves the argv memory leak.
Owner
Copy link

Oh, I also think we should add a changelog for this, since it's a very user visible regression...

Oh, I also think we should add a changelog for this, since it's a very user visible regression...
Owner
Copy link

I'll just go ahead and merge this (trying to speed things up for a patch release...).

I'll just go ahead and merge this (trying to speed things up for a patch release...).
dnkl manually merged commit 106e14391f into master 2021年11月21日 17:45:35 +01:00
Owner
Copy link
Related: * https://codeberg.org/dnkl/foot/commit/9174e6d79a1a57016973ef989ff9366b713b3f01 * https://codeberg.org/dnkl/foot/commit/cdb2d90b893f35326146dbc657952265f1bf61ac
Sign in to join this conversation.
No reviewers
Milestone
Clear milestone
No items
No milestone
Projects
Clear projects
No items
No project
Assignees
Clear assignees
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
dnkl/foot!810
Reference in a new issue
dnkl/foot
No description provided.
Delete branch ":fix-809"

Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?