Skip to content

Commit 8f4fb00

Browse files
ychinchrisbra
authored andcommitted
patch 9.0.2035: [security] use-after-free with wildmenu
Problem: [security] use-after-free with wildmenu Solution: properly clean up the wildmenu when exiting Fix wildchar/wildmenu/pum memory corruption with special wildchar's Currently, using `wildchar=<Esc>` or `wildchar=<C-\>` can lead to a memory corruption if using wildmenu+pum, or wrong states if only using wildmenu. This is due to the code only using one single place inside the cmdline process loop to perform wild menu clean up (by checking `end_wildmenu`) but there are other odd situations where the loop could have exited and we need a post-loop clean up just to be sure. If the clean up was not done you would have a stale popup menu referring to invalid memory, or if not using popup menu, incorrect status line (if `laststatus=0`). For example, if you hit `<Esc>` two times when it's wildchar, there's a hard-coded behavior to exit command-line as a failsafe for user, and if you hit `<C-\><C-\><C-N>` it will also exit command-line, but the clean up code would not have hit because of specialized `<C-\>` handling. Fix Ctrl-E / Ctrl-Y to not cancel/accept wildmenu if they are also used for 'wildchar'/'wildcharm'. Currently they don't behave properly, and also have potentially memory unsafe behavior as the logic is currently not accounting for this situation and try to do both. (Previous patch that addressed this: #11677) Also, correctly document Escape key behavior (double-hit it to escape) in wildchar docs as it's previously undocumented. In addition, block known invalid chars to be set in `wildchar` option, such as Ctrl-C and `<CR>`. This is just to make it clear to the user they shouldn't be set, and is not required for this bug fix. closes: #13361 Signed-off-by: Christian Brabandt <[email protected]> Co-authored-by: Yee Cheng Chin <[email protected]>
1 parent 5a679b2 commit 8f4fb00

13 files changed

+121
-9
lines changed

runtime/doc/options.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9253,6 +9253,8 @@ A jump table for the options with a short description can be found at |Q_op|.
92539253
The character is not recognized when used inside a macro. See
92549254
'wildcharm' for that.
92559255
Some keys will not work, such as CTRL-C, <CR> and Enter.
9256+
<Esc> can be used, but hitting it twice in a row will still exit
9257+
command-line as a failsafe measure.
92569258
Although 'wc' is a number option, you can set it to a special key: >
92579259
:set wc=<Tab>
92589260
< NOTE: This option is set to the Vi default value when 'compatible' is

src/ex_getln.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1877,7 +1877,8 @@ getcmdline_int(
18771877
if (p_wmnu)
18781878
c = wildmenu_translate_key(&ccline, c, &xpc, did_wild_list);
18791879

1880-
if (cmdline_pum_active())
1880+
int key_is_wc = (c == p_wc && KeyTyped) || c == p_wcm;
1881+
if (cmdline_pum_active() && !key_is_wc)
18811882
{
18821883
// Ctrl-Y: Accept the current selection and close the popup menu.
18831884
// Ctrl-E: cancel the cmdline popup menu and return the original
@@ -1897,7 +1898,7 @@ getcmdline_int(
18971898
// 'wildcharm' or Ctrl-N or Ctrl-P or Ctrl-A or Ctrl-L).
18981899
// If the popup menu is displayed, then PageDown and PageUp keys are
18991900
// also used to navigate the menu.
1900-
end_wildmenu = (!(c == p_wc && KeyTyped) && c != p_wcm
1901+
end_wildmenu = (!key_is_wc
19011902
&& c != Ctrl_N && c != Ctrl_P && c != Ctrl_A && c != Ctrl_L);
19021903
end_wildmenu = end_wildmenu && (!cmdline_pum_active() ||
19031904
(c != K_PAGEDOWN && c != K_PAGEUP
@@ -2504,6 +2505,15 @@ getcmdline_int(
25042505
cmdmsg_rl = FALSE;
25052506
#endif
25062507

2508+
// We could have reached here without having a chance to clean up wild menu
2509+
// if certain special keys like <Esc> or <C-\> were used as wildchar. Make
2510+
// sure to still clean up to avoid memory corruption.
2511+
if (cmdline_pum_active())
2512+
cmdline_pum_remove();
2513+
wildmenu_cleanup(&ccline);
2514+
did_wild_list = FALSE;
2515+
wim_index = 0;
2516+
25072517
ExpandCleanup(&xpc);
25082518
ccline.xpc = NULL;
25092519

src/option.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4392,6 +4392,21 @@ did_set_weirdinvert(optset_T *args)
43924392
return NULL;
43934393
}
43944394

4395+
/*
4396+
* Process the new 'wildchar' / 'wildcharm' option value.
4397+
*/
4398+
char *
4399+
did_set_wildchar(optset_T *args)
4400+
{
4401+
long c = *(long *)args->os_varp;
4402+
4403+
// Don't allow key values that wouldn't work as wildchar.
4404+
if (c == Ctrl_C || c == '\n' || c == '\r' || c == K_KENTER)
4405+
return e_invalid_argument;
4406+
4407+
return NULL;
4408+
}
4409+
43954410
/*
43964411
* Process the new 'window' option value.
43974412
*/

src/optiondefs.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2812,11 +2812,11 @@ static struct vimoption options[] =
28122812
(char_u *)&p_ww, PV_NONE, did_set_whichwrap, expand_set_whichwrap,
28132813
{(char_u *)"", (char_u *)"b,s"} SCTX_INIT},
28142814
{"wildchar", "wc", P_NUM|P_VIM,
2815-
(char_u *)&p_wc, PV_NONE, NULL, NULL,
2815+
(char_u *)&p_wc, PV_NONE, did_set_wildchar, NULL,
28162816
{(char_u *)(long)Ctrl_E, (char_u *)(long)TAB}
28172817
SCTX_INIT},
28182818
{"wildcharm", "wcm", P_NUM|P_VI_DEF,
2819-
(char_u *)&p_wcm, PV_NONE, NULL, NULL,
2819+
(char_u *)&p_wcm, PV_NONE, did_set_wildchar, NULL,
28202820
{(char_u *)0L, (char_u *)0L} SCTX_INIT},
28212821
{"wildignore", "wig", P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP,
28222822
(char_u *)&p_wig, PV_NONE, NULL, NULL,

src/proto/option.pro

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ char *did_set_undofile(optset_T *args);
8181
char *did_set_undolevels(optset_T *args);
8282
char *did_set_updatecount(optset_T *args);
8383
char *did_set_weirdinvert(optset_T *args);
84+
char *did_set_wildchar(optset_T *args);
8485
char *did_set_window(optset_T *args);
8586
char *did_set_winheight_helpheight(optset_T *args);
8687
char *did_set_winminheight(optset_T *args);
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
| +0&#ffffff0@74
2+
|~+0#4040ff13&| @73
3+
|~| @73
4+
|~| @73
5+
|~| @73
6+
|~| @73
7+
|~| @73
8+
|:+0#0000000&|v|i|m| > @69
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
> +0&#ffffff0@74
2+
|~+0#4040ff13&| @73
3+
|~| @73
4+
|~| @73
5+
|~| @73
6+
|~| @73
7+
|~| @73
8+
| +0#0000000&@56|0|,|0|-|1| @8|A|l@1|

src/testdir/dumps/Test_wildmenu_pum_clear_entries_1.dump renamed to src/testdir/dumps/Test_wildmenu_pum_odd_wildchar_1.dump

File renamed without changes.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
| +0#0000001#ffd7ff255|!| @14| +0#0000000#0000001| +0&#ffffff0@56
2+
| +0#0000001#e0e0e08|#| @14| +0#0000000#a8a8a8255| +0#4040ff13#ffffff0@56
3+
| +0#0000001#ffd7ff255|&| @14| +0#0000000#a8a8a8255| +0#4040ff13#ffffff0@56
4+
| +0#0000001#ffd7ff255|*| @14| +0#0000000#a8a8a8255| +0#4040ff13#ffffff0@56
5+
| +0#0000001#ffd7ff255|+@1| @13| +0#0000000#a8a8a8255| +0#4040ff13#ffffff0@56
6+
| +0#0000001#ffd7ff255|-@1| @13| +0#0000000#a8a8a8255| +0#4040ff13#ffffff0@56
7+
| +0#0000001#ffd7ff255|<| @14| +0#0000000#a8a8a8255| +0#4040ff13#ffffff0@56
8+
| +0#0000001#ffd7ff255|=| @14| +0#0000000#a8a8a8255| +0#4040ff13#ffffff0@56
9+
| +0#0000001#ffd7ff255|>| @14| +0#0000000#a8a8a8255| +0#4040ff13#ffffff0@56
10+
|:+0#0000000&|#> @72
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
> +0&#ffffff0@74
2+
|~+0#4040ff13&| @73
3+
|~| @73
4+
|~| @73
5+
|~| @73
6+
|~| @73
7+
|~| @73
8+
|~| @73
9+
|~| @73
10+
| +0#0000000&@56|0|,|0|-|1| @8|A|l@1|

0 commit comments

Comments
 (0)