Package: release.debian.org Severity: normal User: release.debian....@packages.debian.org Usertags: unblock
Please unblock package neovim This upload contains the rest of the fixes needed to address CVE-2019-12735/#930024. unblock neovim/0.3.4-3 -- System Information: Debian Release: 10.0 APT prefers unstable-debug APT policy: (500, 'unstable-debug'), (500, 'unstable'), (1, 'experimental-debug'), (1, 'experimental') Architecture: amd64 (x86_64) Kernel: Linux 4.19.0-5-amd64 (SMP w/4 CPU cores) Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8), LANGUAGE=en_US.UTF-8 (charmap=UTF-8) Shell: /bin/sh linked to /usr/bin/dash Init: systemd (via /run/systemd/system) LSM: AppArmor: enabled
diffstat for neovim-0.3.4 neovim-0.3.4 changelog | 28 patches/0001-debcherry-fixup-patch.patch | 1066 ++++++++++ patches/0001-vim-patch-8.1.1365-source-should-check-sandbox-10082.patch | 36 patches/0002-vim-patch-8.1.1365-source-should-check-sandbox-10082.patch | 36 patches/0003-vim-patch-8.1.0177-defining-function-in-sandbox-is-i.patch | 104 patches/0004-vim-patch-8.1.0189-function-defined-in-sandbox-not-t.patch | 41 patches/0005-vim-patch-8.1.0206-duplicate-test-function-name.patch | 35 patches/0006-vim-patch-8.1.1382-error-when-editing-test-file.patch | 59 patches/0007-eval-api-don-t-allow-the-API-to-be-called-in-the-san.patch | 57 patches/series | 8 10 files changed, 1433 insertions(+), 37 deletions(-) diff -Nru neovim-0.3.4/debian/changelog neovim-0.3.4/debian/changelog --- neovim-0.3.4/debian/changelog 2019-06-05 21:38:14.000000000 -0400 +++ neovim-0.3.4/debian/changelog 2019-06-26 21:21:33.000000000 -0400 @@ -1,3 +1,31 @@ +neovim (0.3.4-3) unstable; urgency=high + + * Backport additional changes to address CVE-2019-12735 (Closes: #930024) + + vim-patch:8.1.0177: defining function in sandbox is inconsistent + + vim-patch:8.1.0189: function defined in sandbox not tested + + vim-patch:8.1.0538: evaluating a modeline might invoke using a shell + command + + vim-patch:8.1.0539: cannot build without the sandbox + + vim-patch:8.1.0540: may evaluate insecure value when appending to option + + vim-patch:8.1.0544: setting 'filetype' in a modeline causes an error + + vim-patch:8.1.0613: when executing an insecure function the secure flag + is stuck + + vim-patch:8.1.1046: the "secure" variable is used inconsistently + + vim-patch:8.1.0205: invalid memory access with invalid modeline + + vim-patch:8.1.0206: duplicate test function name + + vim-patch:8.1.0506: modeline test fails when run by root + + vim-patch:8.1.0546: modeline test with keymap fails + + vim-patch:8.1.0547: modeline test with keymap still fails + + vim-patch:8.1.1366: using expressions in a modeline is unsafe + + vim-patch:8.1.1367: can set 'modelineexpr' in modeline + + vim-patch:8.1.1368: modeline test fails with python but without + pythonhome + + vim-patch:8.1.1382: error when editing test file + + vim-patch:8.1.1401: misspelled mkspellmem as makespellmem + * Backport patch to prevent use of nvim's API within the sandbox + + -- James McCoy <james...@debian.org> Wed, 26 Jun 2019 21:21:33 -0400 + neovim (0.3.4-2) unstable; urgency=high [ Efraim Flashner ] diff -Nru neovim-0.3.4/debian/patches/0001-debcherry-fixup-patch.patch neovim-0.3.4/debian/patches/0001-debcherry-fixup-patch.patch --- neovim-0.3.4/debian/patches/0001-debcherry-fixup-patch.patch 1969-12-31 19:00:00.000000000 -0500 +++ neovim-0.3.4/debian/patches/0001-debcherry-fixup-patch.patch 2019-06-26 21:21:33.000000000 -0400 @@ -0,0 +1,1066 @@ +From d39c384696e94bd8cb4a8830f0ec2e801619a970 Mon Sep 17 00:00:00 2001 +From: James McCoy <james...@jamessan.com> +Date: Wed, 26 Jun 2019 21:32:44 -0400 +Subject: [PATCH 1/7] debcherry fixup patch + +ed179f931 vim-patch:8.1.1401: misspelled mkspellmem as makespellmem + - no changes against upstream or conflicts +41a3ff9fe vim-patch:8.1.1368: modeline test fails with python but without pythonhome + - no changes against upstream or conflicts +12c5b6885 vim-patch:8.1.1367: can set 'modelineexpr' in modeline + - no changes against upstream or conflicts +cffc3f5f8 vim-patch:8.1.1366: using expressions in a modeline is unsafe + - extra changes or conflicts +a15defc3c vim-patch:8.1.0547: modeline test with keymap still fails + - extra changes or conflicts +c550a5e94 vim-patch:8.1.0546: modeline test with keymap fails + - no changes against upstream or conflicts +0605eb856 vim-patch:8.1.0506: modeline test fails when run by root + - no changes against upstream or conflicts +cbec04e98 vim-patch:8.1.0205: invalid memory access with invalid modeline + - extra changes or conflicts +ed7ca8f1e vim-patch:8.1.1046: the "secure" variable is used inconsistently + - no changes against upstream or conflicts +4f223fb12 vim-patch:8.1.0613: when executing an insecure function the secure flag is stuck + - extra changes or conflicts +4fc181350 fixup: use vim_snprintf, ASCII_ISALNUM + - no changes against upstream or conflicts +2789ea195 vim-patch:8.1.0544: setting 'filetype' in a modeline causes an error + - extra changes or conflicts +94b32dd17 vim-patch:8.1.0540: may evaluate insecure value when appending to option + - extra changes or conflicts +a36f7e776 vim-patch:8.1.0539: cannot build without the sandbox + - extra changes or conflicts +b1ab0ee1a vim-patch:8.1.0538: evaluating a modeline might invoke using a shell command + - extra changes or conflicts +bc4e31de5 vim-patch:8.0.0003 + - no changes against upstream or conflicts +53bde37a8 vim-patch:8.0.0376 + - extra changes or conflicts +aa0c704e7 vim-patch:8.0.0322 + - extra changes or conflicts +29b888573 vim-patch:8.0.0057 + - no changes against upstream or conflicts +fb1670cdd vim-patch:8.0.0056 + - extra changes or conflicts +--- + runtime/doc/options.txt | 75 +++++++++--- + src/nvim/buffer.c | 6 + + src/nvim/generators/gen_options.lua | 1 + + src/nvim/option.c | 177 +++++++++++++++++++--------- + src/nvim/option_defs.h | 1 + + src/nvim/options.lua | 21 ++++ + src/nvim/testdir/test49.in | 2 +- + src/nvim/testdir/test_alot.vim | 1 + + src/nvim/testdir/test_autocmd.vim | 23 ++++ + src/nvim/testdir/test_modeline.vim | 173 +++++++++++++++++++++++++++ + 10 files changed, 406 insertions(+), 74 deletions(-) + create mode 100644 src/nvim/testdir/test_modeline.vim + +diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt +index 534b2025c..e8471d561 100644 +--- a/runtime/doc/options.txt ++++ b/runtime/doc/options.txt +@@ -478,14 +478,17 @@ backslash in front of the ':' will be removed. Example: + /* vi:set dir=c\:\tmp: */ ~ + This sets the 'dir' option to "c:\tmp". Only a single backslash before the + ':' is removed. Thus to include "\:" you have to specify "\\:". +- ++ *E992* + No other commands than "set" are supported, for security reasons (somebody + might create a Trojan horse text file with modelines). And not all options +-can be set. For some options a flag is set, so that when it's used the +-|sandbox| is effective. Still, there is always a small risk that a modeline +-causes trouble. E.g., when some joker sets 'textwidth' to 5 all your lines +-are wrapped unexpectedly. So disable modelines before editing untrusted text. +-The mail ftplugin does this, for example. ++can be set. For some options a flag is set, so that when the value is used ++the |sandbox| is effective. Some options can only be set from the modeline ++when 'modelineexpr' is set (the default is off). ++ ++Still, there is always a small risk that a modeline causes trouble. E.g., ++when some joker sets 'textwidth' to 5 all your lines are wrapped unexpectedly. ++So disable modelines before editing untrusted text. The mail ftplugin does ++this, for example. + + Hint: If you would like to do something else than setting an option, you could + define an autocommand that checks the file for a specific string. For +@@ -2439,7 +2442,7 @@ A jump table for the options with a short description can be found at |Q_op|. + The expression will be evaluated in the |sandbox| if set from a + modeline, see |sandbox-option|. + This option can't be set from a |modeline| when the 'diff' option is +- on. ++ on or the 'modelineexpr' option is off. + + It is not allowed to change text or jump to another window while + evaluating 'foldexpr' |textlock|. +@@ -2554,6 +2557,7 @@ A jump table for the options with a short description can be found at |Q_op|. + + The expression will be evaluated in the |sandbox| if set from a + modeline, see |sandbox-option|. ++ This option cannot be set in a modeline when 'modelineexpr' is off. + + It is not allowed to change text or jump to another window while + evaluating 'foldtext' |textlock|. +@@ -2589,16 +2593,8 @@ A jump table for the options with a short description can be found at |Q_op|. + The expression will be evaluated in the |sandbox| when set from a + modeline, see |sandbox-option|. That stops the option from working, + since changing the buffer text is not allowed. +- +- *'formatoptions'* *'fo'* +-'formatoptions' 'fo' string (default: "tcqj", Vi default: "vt") +- local to buffer +- This is a sequence of letters which describes how automatic +- formatting is to be done. See |fo-table|. When the 'paste' option is +- on, no formatting is done (like 'formatoptions' is empty). Commas can +- be inserted for readability. +- To avoid problems with flags that are added in the future, use the +- "+=" and "-=" feature of ":set" |add-option-flags|. ++ This option cannot be set in a modeline when 'modelineexpr' is off. ++ NOTE: This option is set to "" when 'compatible' is set. + + *'formatlistpat'* *'flp'* + 'formatlistpat' 'flp' string (default: "^\s*\d\+[\]:.)}\t ]\s*") +@@ -2613,6 +2609,16 @@ A jump table for the options with a short description can be found at |Q_op|. + The default recognizes a number, followed by an optional punctuation + character and white space. + ++ *'formatoptions'* *'fo'* ++'formatoptions' 'fo' string (default: "tcqj", Vi default: "vt") ++ local to buffer ++ This is a sequence of letters which describes how automatic ++ formatting is to be done. See |fo-table|. When the 'paste' option is ++ on, no formatting is done (like 'formatoptions' is empty). Commas can ++ be inserted for readability. ++ To avoid problems with flags that are added in the future, use the ++ "+=" and "-=" feature of ":set" |add-option-flags|. ++ + *'formatprg'* *'fp'* + 'formatprg' 'fp' string (default "") + global or local to buffer |global-local| +@@ -2643,6 +2649,9 @@ A jump table for the options with a short description can be found at |Q_op|. + - system signals low battery life + - Nvim exits abnormally + ++ This option cannot be set from a |modeline| or in the |sandbox|, for ++ security reasons. ++ + *'gdefault'* *'gd'* *'nogdefault'* *'nogd'* + 'gdefault' 'gd' boolean (default off) + global +@@ -2978,6 +2987,7 @@ A jump table for the options with a short description can be found at |Q_op|. + 'guitabtooltip' is used for the tooltip, see below. + The expression will be evaluated in the |sandbox| when set from a + modeline, see |sandbox-option|. ++ This option cannot be set in a modeline when 'modelineexpr' is off. + + Only used when the GUI tab pages line is displayed. 'e' must be + present in 'guioptions'. For the non-GUI tab pages line 'tabline' is +@@ -3106,6 +3116,7 @@ A jump table for the options with a short description can be found at |Q_op|. + When this option contains printf-style '%' items, they will be + expanded according to the rules used for 'statusline'. See + 'titlestring' for example settings. ++ This option cannot be set in a modeline when 'modelineexpr' is off. + + *'ignorecase'* *'ic'* *'noignorecase'* *'noic'* + 'ignorecase' 'ic' boolean (default off) +@@ -3209,6 +3220,7 @@ A jump table for the options with a short description can be found at |Q_op|. + + The expression will be evaluated in the |sandbox| when set from a + modeline, see |sandbox-option|. ++ This option cannot be set in a modeline when 'modelineexpr' is off. + + It is not allowed to change text or jump to another window while + evaluating 'includeexpr' |textlock|. +@@ -3277,6 +3289,7 @@ A jump table for the options with a short description can be found at |Q_op|. + + The expression will be evaluated in the |sandbox| when set from a + modeline, see |sandbox-option|. ++ This option cannot be set in a modeline when 'modelineexpr' is off. + + It is not allowed to change text or jump to another window while + evaluating 'indentexpr' |textlock|. +@@ -3879,10 +3892,23 @@ A jump table for the options with a short description can be found at |Q_op|. + < If you have less than 512 Mbyte |:mkspell| may fail for some + languages, no matter what you set 'mkspellmem' to. + ++ This option cannot be set from a |modeline| or in the |sandbox|. ++ + *'modeline'* *'ml'* *'nomodeline'* *'noml'* + 'modeline' 'ml' boolean (Vim default: on (off for root), + Vi default: off) + local to buffer ++ If 'modeline' is on 'modelines' gives the number of lines that is ++ checked for set commands. If 'modeline' is off or 'modelines' is zero ++ no lines are checked. See |modeline|. ++ ++ *'modelineexpr'* *'mle'* *'nomodelineexpr'* *'nomle'* ++'modelineexpr' 'mle' boolean (default: off) ++ global ++ When on allow some options that are an expression to be set in the ++ modeline. Check the option for whether it is affected by ++ 'modelineexpr'. Also see |modeline|. ++ + *'modelines'* *'mls'* + 'modelines' 'mls' number (default 5) + global +@@ -4622,6 +4648,8 @@ A jump table for the options with a short description can be found at |Q_op|. + When this option is not empty, it determines the content of the ruler + string, as displayed for the 'ruler' option. + The format of this option is like that of 'statusline'. ++ This option cannot be set in a modeline when 'modelineexpr' is off. ++ + The default ruler width is 17 characters. To make the ruler 15 + characters wide, put "%15(" at the start and "%)" at the end. + Example: > +@@ -5252,7 +5280,8 @@ A jump table for the options with a short description can be found at |Q_op|. + "Pattern not found", "Back at original", etc. + q use "recording" instead of "recording @a" + F don't give the file info when editing a file, like `:silent` +- was used for the command ++ was used for the command; note that this also affects messages ++ from autocommands + + This gives you the opportunity to avoid that a change between buffers + requires you to hit <Enter>, but still gives as useful a message as +@@ -5527,7 +5556,7 @@ A jump table for the options with a short description can be found at |Q_op|. + + After this option has been set successfully, Vim will source the files + "spell/LANG.vim" in 'runtimepath'. "LANG" is the value of 'spelllang' +- up to the first comma, dot or underscore. ++ up to the first character that is not an ASCII letter and not a dash. + Also see |set-spc-auto|. + + +@@ -5773,6 +5802,7 @@ A jump table for the options with a short description can be found at |Q_op|. + + The 'statusline' option will be evaluated in the |sandbox| if set from + a modeline, see |sandbox-option|. ++ This option cannot be set in a modeline when 'modelineexpr' is off. + + It is not allowed to change text or jump to another window while + evaluating 'statusline' |textlock|. +@@ -5927,6 +5957,8 @@ A jump table for the options with a short description can be found at |Q_op|. + the text to be displayed. Use "%1T" for the first label, "%2T" for + the second one, etc. Use "%X" items for closing labels. + ++ This option cannot be set in a modeline when 'modelineexpr' is off. ++ + Keep in mind that only one of the tab pages is the current one, others + are invisible and you can't jump to their windows. + +@@ -6203,8 +6235,11 @@ A jump table for the options with a short description can be found at |Q_op|. + global + When this option is not empty, it will be used for the title of the + window. This happens only when the 'title' option is on. ++ + When this option contains printf-style '%' items, they will be + expanded according to the rules used for 'statusline'. ++ This option cannot be set in a modeline when 'modelineexpr' is off. ++ + Example: > + :auto BufEnter * let &titlestring = hostname() . "/" . expand("%:p") + :set title titlestring=%<%F%=%l/%L-%P titlelen=70 +@@ -6238,6 +6273,8 @@ A jump table for the options with a short description can be found at |Q_op|. + undo file that exists is used. When it cannot be read an error is + given, no further entry is used. + See |undo-persistence|. ++ This option cannot be set from a |modeline| or in the |sandbox|, for ++ security reasons. + + *'undofile'* *'noundofile'* *'udf'* *'noudf'* + 'undofile' 'udf' boolean (default off) +diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c +index 8b107041b..99e910d15 100644 +--- a/src/nvim/buffer.c ++++ b/src/nvim/buffer.c +@@ -4923,9 +4923,15 @@ chk_modeline ( + *e = NUL; /* truncate the set command */ + + if (*s != NUL) { /* skip over an empty "::" */ ++ const int secure_save = secure; + save_SID = current_SID; + current_SID = SID_MODELINE; ++ // Make sure no risky things are executed as a side effect. ++ secure = 1; ++ + retval = do_set(s, OPT_MODELINE | OPT_LOCAL | flags); ++ ++ secure = secure_save; + current_SID = save_SID; + if (retval == FAIL) /* stop if error found */ + break; +diff --git a/src/nvim/generators/gen_options.lua b/src/nvim/generators/gen_options.lua +index fdc00d5dc..d9c65e17c 100644 +--- a/src/nvim/generators/gen_options.lua ++++ b/src/nvim/generators/gen_options.lua +@@ -79,6 +79,7 @@ local get_flags = function(o) + {'pri_mkrc'}, + {'deny_in_modelines', 'P_NO_ML'}, + {'deny_duplicates', 'P_NODUP'}, ++ {'modelineexpr', 'P_MLE'}, + }) do + local key_name = flag_desc[1] + local def_name = flag_desc[2] or ('P_' .. key_name:upper()) +diff --git a/src/nvim/option.c b/src/nvim/option.c +index 8c692f9f4..d36a5de20 100644 +--- a/src/nvim/option.c ++++ b/src/nvim/option.c +@@ -251,6 +251,7 @@ typedef struct vimoption { + #define P_RWINONLY 0x10000000U ///< only redraw current window + #define P_NDNAME 0x20000000U ///< only normal dir name chars allowed + #define P_UI_OPTION 0x40000000U ///< send option to remote ui ++#define P_MLE 0x80000000U ///< under control of 'modelineexpr' + + #define HIGHLIGHT_INIT \ + "8:SpecialKey,~:EndOfBuffer,z:TermCursor,Z:TermCursorNC,@:NonText," \ +@@ -1200,7 +1201,7 @@ do_set ( + } + len++; + if (opt_idx == -1) { +- key = find_key_option(arg + 1); ++ key = find_key_option(arg + 1, true); + } + } else { + len = 0; +@@ -1214,7 +1215,7 @@ do_set ( + } + opt_idx = findoption_len((const char *)arg, (size_t)len); + if (opt_idx == -1) { +- key = find_key_option(arg); ++ key = find_key_option(arg, false); + } + } + +@@ -1281,6 +1282,11 @@ do_set ( + errmsg = (char_u *)_("E520: Not allowed in a modeline"); + goto skip; + } ++ if ((flags & P_MLE) && !p_mle) { ++ errmsg = (char_u *)_( ++ "E992: Not allowed in a modeline when 'modelineexpr' is off"); ++ goto skip; ++ } + /* In diff mode some options are overruled. This avoids that + * 'foldmethod' becomes "marker" instead of "diff" and that + * "wrap" gets set. */ +@@ -1355,6 +1361,10 @@ do_set ( + && nextchar != NUL && !ascii_iswhite(afterchar)) + errmsg = e_trailing; + } else { ++ ++ int value_is_replaced = !prepending && !adding && !removing; ++ int value_checked = false; ++ + if (flags & P_BOOL) { /* boolean */ + if (nextchar == '=' || nextchar == ':') { + errmsg = e_invarg; +@@ -1774,12 +1784,32 @@ do_set ( + // buffer is closed by autocommands. + saved_newval = (newval != NULL) ? xstrdup((char *)newval) : 0; + +- // Handle side effects, and set the global value for +- // ":set" on local options. Note: when setting 'syntax' +- // or 'filetype' autocommands may be triggered that can +- // cause havoc. +- errmsg = did_set_string_option(opt_idx, (char_u **)varp, +- new_value_alloced, oldval, errbuf, opt_flags); ++ { ++ uint32_t *p = insecure_flag(opt_idx, opt_flags); ++ const int secure_saved = secure; ++ ++ // When an option is set in the sandbox, from a ++ // modeline or in secure mode, then deal with side ++ // effects in secure mode. Also when the value was ++ // set with the P_INSECURE flag and is not ++ // completely replaced. ++ if ((opt_flags & OPT_MODELINE) ++ || sandbox != 0 ++ || (!value_is_replaced && (*p & P_INSECURE))) { ++ secure = 1; ++ } ++ ++ // Handle side effects, and set the global value ++ // for ":set" on local options. Note: when setting ++ // 'syntax' or 'filetype' autocommands may be ++ // triggered that can cause havoc. ++ errmsg = did_set_string_option(opt_idx, (char_u **)varp, ++ new_value_alloced, oldval, ++ errbuf, sizeof(errbuf), ++ opt_flags, &value_checked); ++ ++ secure = secure_saved; ++ } + + if (errmsg == NULL) { + if (!starting) { +@@ -1806,8 +1836,7 @@ do_set ( + } + + if (opt_idx >= 0) +- did_set_option(opt_idx, opt_flags, +- !prepending && !adding && !removing); ++ did_set_option(opt_idx, opt_flags, value_is_replaced, value_checked); + } + + skip: +@@ -1872,7 +1901,9 @@ static void + did_set_option ( + int opt_idx, + int opt_flags, /* possibly with OPT_MODELINE */ +- int new_value /* value was replaced completely */ ++ int new_value, /* value was replaced completely */ ++ int value_checked /* value was checked to be safe, no need to ++ set P_INSECURE */ + ) + { + options[opt_idx].flags |= P_WAS_SET; +@@ -1881,20 +1912,22 @@ did_set_option ( + * set the P_INSECURE flag. Otherwise, if a new value is stored reset the + * flag. */ + uint32_t *p = insecure_flag(opt_idx, opt_flags); +- if (secure +- || sandbox != 0 +- || (opt_flags & OPT_MODELINE)) ++ if (!value_checked && (secure ++ || sandbox != 0 ++ || (opt_flags & OPT_MODELINE))) { + *p = *p | P_INSECURE; +- else if (new_value) ++ } else if (new_value) { + *p = *p & ~P_INSECURE; ++ } + } + +-static char_u *illegal_char(char_u *errbuf, int c) ++static char_u *illegal_char(char_u *errbuf, size_t errbuflen, int c) + { +- if (errbuf == NULL) ++ if (errbuf == NULL) { + return (char_u *)""; +- sprintf((char *)errbuf, _("E539: Illegal character <%s>"), +- (char *)transchar(c)); ++ } ++ vim_snprintf((char *)errbuf, errbuflen, _("E539: Illegal character <%s>"), ++ (char *)transchar(c)); + return errbuf; + } + +@@ -1904,10 +1937,12 @@ static char_u *illegal_char(char_u *errbuf, int c) + */ + static int string_to_key(char_u *arg) + { +- if (*arg == '<') +- return find_key_option(arg + 1); +- if (*arg == '^') ++ if (*arg == '<') { ++ return find_key_option(arg + 1, true); ++ } ++ if (*arg == '^') { + return Ctrl_chr(arg[1]); ++ } + return *arg; + } + +@@ -2383,10 +2418,12 @@ static char *set_string_option(const int opt_idx, const char *const value, + char *const saved_oldval = xstrdup(oldval); + char *const saved_newval = xstrdup(s); + ++ int value_checked = false; + char *const r = (char *)did_set_string_option( +- opt_idx, (char_u **)varp, (int)true, (char_u *)oldval, NULL, opt_flags); ++ opt_idx, (char_u **)varp, (int)true, (char_u *)oldval, ++ NULL, 0, opt_flags, &value_checked); + if (r == NULL) { +- did_set_option(opt_idx, opt_flags, true); ++ did_set_option(opt_idx, opt_flags, true, value_checked); + } + + // call autocommand after handling side effects +@@ -2427,13 +2464,16 @@ static bool valid_filetype(char_u *val) + * Returns NULL for success, or an error message for an error. + */ + static char_u * +-did_set_string_option ( +- int opt_idx, /* index in options[] table */ +- char_u **varp, /* pointer to the option variable */ +- int new_value_alloced, /* new value was allocated */ +- char_u *oldval, /* previous value of the option */ +- char_u *errbuf, /* buffer for errors, or NULL */ +- int opt_flags /* OPT_LOCAL and/or OPT_GLOBAL */ ++did_set_string_option( ++ int opt_idx, // index in options[] table ++ char_u **varp, // pointer to the option variable ++ int new_value_alloced, // new value was allocated ++ char_u *oldval, // previous value of the option ++ char_u *errbuf, // buffer for errors, or NULL ++ size_t errbuflen, // length of errors buffer ++ int opt_flags, // OPT_LOCAL and/or OPT_GLOBAL ++ int *value_checked // value was checked to be safe, no ++ // need to set P_INSECURE + ) + { + char_u *errmsg = NULL; +@@ -2651,8 +2691,20 @@ did_set_string_option ( + if (!valid_filetype(*varp)) { + errmsg = e_invarg; + } else { ++ int secure_save = secure; ++ ++ // Reset the secure flag, since the value of 'keymap' has ++ // been checked to be safe. ++ secure = 0; ++ + // load or unload key mapping tables + errmsg = keymap_init(); ++ ++ secure = secure_save; ++ ++ // Since we check the value, there is no need to set P_INSECURE, ++ // even when the value comes from a modeline. ++ *value_checked = true; + } + + if (errmsg == NULL) { +@@ -2738,7 +2790,7 @@ did_set_string_option ( + while (*s && *s != ':') { + if (vim_strchr((char_u *)COM_ALL, *s) == NULL + && !ascii_isdigit(*s) && *s != '-') { +- errmsg = illegal_char(errbuf, *s); ++ errmsg = illegal_char(errbuf, errbuflen, *s); + break; + } + ++s; +@@ -2790,7 +2842,7 @@ did_set_string_option ( + for (s = p_shada; *s; ) { + /* Check it's a valid character */ + if (vim_strchr((char_u *)"!\"%'/:<@cfhnrs", *s) == NULL) { +- errmsg = illegal_char(errbuf, *s); ++ errmsg = illegal_char(errbuf, errbuflen, *s); + break; + } + if (*s == 'n') { /* name is always last one */ +@@ -2810,9 +2862,9 @@ did_set_string_option ( + + if (!ascii_isdigit(*(s - 1))) { + if (errbuf != NULL) { +- sprintf((char *)errbuf, +- _("E526: Missing number after <%s>"), +- transchar_byte(*(s - 1))); ++ vim_snprintf((char *)errbuf, errbuflen, ++ _("E526: Missing number after <%s>"), ++ transchar_byte(*(s - 1))); + errmsg = errbuf; + } else + errmsg = (char_u *)""; +@@ -2990,7 +3042,7 @@ did_set_string_option ( + if (!*s) + break; + if (vim_strchr((char_u *)".wbuksid]tU", *s) == NULL) { +- errmsg = illegal_char(errbuf, *s); ++ errmsg = illegal_char(errbuf, errbuflen, *s); + break; + } + if (*++s != NUL && *s != ',' && *s != ' ') { +@@ -3004,9 +3056,9 @@ did_set_string_option ( + } + } else { + if (errbuf != NULL) { +- sprintf((char *)errbuf, +- _("E535: Illegal character after <%c>"), +- *--s); ++ vim_snprintf((char *)errbuf, errbuflen, ++ _("E535: Illegal character after <%c>"), ++ *--s); + errmsg = errbuf; + } else + errmsg = (char_u *)""; +@@ -3163,12 +3215,20 @@ did_set_string_option ( + errmsg = e_invarg; + } else { + value_changed = STRCMP(oldval, *varp) != 0; ++ ++ // Since we check the value, there is no need to set P_INSECURE, ++ // even when the value comes from a modeline. ++ *value_checked = true; + } + } else if (gvarp == &p_syn) { + if (!valid_filetype(*varp)) { + errmsg = e_invarg; + } else { + value_changed = STRCMP(oldval, *varp) != 0; ++ ++ // Since we check the value, there is no need to set P_INSECURE, ++ // even when the value comes from a modeline. ++ *value_checked = true; + } + } else if (varp == &curwin->w_p_winhl) { + if (!parse_winhl_opt(curwin)) { +@@ -3194,7 +3254,7 @@ did_set_string_option ( + if (p != NULL) { + for (s = *varp; *s; ++s) + if (vim_strchr(p, *s) == NULL) { +- errmsg = illegal_char(errbuf, *s); ++ errmsg = illegal_char(errbuf, errbuflen, *s); + break; + } + } +@@ -3258,6 +3318,11 @@ did_set_string_option ( + // already set to this value. + if (!(opt_flags & OPT_MODELINE) || value_changed) { + static int ft_recursive = 0; ++ int secure_save = secure; ++ ++ // Reset the secure flag, since the value of 'filetype' has ++ // been checked to be safe. ++ secure = 0; + + ft_recursive++; + did_filetype = true; +@@ -3270,6 +3335,7 @@ did_set_string_option ( + if (varp != &(curbuf->b_p_ft)) { + varp = NULL; + } ++ secure = secure_save; + } + } + if (varp == &(curwin->w_s->b_p_spl)) { +@@ -3287,11 +3353,13 @@ did_set_string_option ( + * '.encoding'. + */ + for (p = q; *p != NUL; ++p) +- if (vim_strchr((char_u *)"_.,", *p) != NULL) ++ if (!ASCII_ISALNUM(*p) && *p != '-') + break; +- vim_snprintf((char *)fname, sizeof(fname), "spell/%.*s.vim", +- (int)(p - q), q); +- source_runtime(fname, DIP_ALL); ++ if (p > q) { ++ vim_snprintf((char *)fname, sizeof(fname), "spell/%.*s.vim", ++ (int)(p - q), q); ++ source_runtime(fname, DIP_ALL); ++ } + } + } + +@@ -3553,7 +3621,7 @@ char_u *check_stl_option(char_u *s) + continue; + } + if (vim_strchr(STL_ALL, *s) == NULL) { +- return illegal_char(errbuf, *s); ++ return illegal_char(errbuf, sizeof(errbuf), *s); + } + if (*s == '{') { + s++; +@@ -4892,19 +4960,20 @@ char *set_option_value(const char *const name, const long number, + return NULL; + } + +-/* +- * Translate a string like "t_xx", "<t_xx>" or "<S-Tab>" to a key number. +- */ +-int find_key_option_len(const char_u *arg, size_t len) ++// Translate a string like "t_xx", "<t_xx>" or "<S-Tab>" to a key number. ++// When "has_lt" is true there is a '<' before "*arg_arg". ++// Returns 0 when the key is not recognized. ++int find_key_option_len(const char_u *arg_arg, size_t len, bool has_lt) + { +- int key; ++ int key = 0; + int modifiers; ++ const char_u *arg = arg_arg; + + // Don't use get_special_key_code() for t_xx, we don't want it to call + // add_termcap_entry(). + if (len >= 4 && arg[0] == 't' && arg[1] == '_') { + key = TERMCAP2KEY(arg[2], arg[3]); +- } else { ++ } else if (has_lt) { + arg--; // put arg at the '<' + modifiers = 0; + key = find_special_key(&arg, len + 1, &modifiers, true, true, false); +@@ -4915,9 +4984,9 @@ int find_key_option_len(const char_u *arg, size_t len) + return key; + } + +-static int find_key_option(const char_u *arg) ++static int find_key_option(const char_u *arg, bool has_lt) + { +- return find_key_option_len(arg, STRLEN(arg)); ++ return find_key_option_len(arg, STRLEN(arg), has_lt); + } + + /* +diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h +index 6a0d0e32e..f64b07c27 100644 +--- a/src/nvim/option_defs.h ++++ b/src/nvim/option_defs.h +@@ -503,6 +503,7 @@ EXTERN long p_mmd; // 'maxmapdepth' + EXTERN long p_mmp; // 'maxmempattern' + EXTERN long p_mis; // 'menuitems' + EXTERN char_u *p_msm; // 'mkspellmem' ++EXTERN long p_mle; // 'modelineexpr' + EXTERN long p_mls; // 'modelines' + EXTERN char_u *p_mouse; // 'mouse' + EXTERN char_u *p_mousem; // 'mousemodel' +diff --git a/src/nvim/options.lua b/src/nvim/options.lua +index 0cc6f58c5..7ca1b4d64 100644 +--- a/src/nvim/options.lua ++++ b/src/nvim/options.lua +@@ -8,6 +8,7 @@ + -- defaults={condition=nil, if_true={vi=224, vim=0}, if_false=nil}, + -- secure=nil, gettext=nil, noglob=nil, normal_fname_chars=nil, + -- pri_mkrc=nil, deny_in_modelines=nil, normal_dname_chars=nil, ++-- modelineexpr=nil, + -- expand=nil, nodefault=nil, no_mkrc=nil, vi_def=true, vim=true, + -- alloced=nil, + -- save_pv_indir=nil, +@@ -286,6 +287,7 @@ return { + deny_duplicates=true, + vi_def=true, + expand=true, ++ secure=true, + varname='p_cdpath', + defaults={if_true={vi=",,"}} + }, +@@ -856,6 +858,7 @@ return { + type='string', scope={'window'}, + vi_def=true, + vim=true, ++ modelineexpr=true, + alloced=true, + redraw={'current_window'}, + defaults={if_true={vi="0"}} +@@ -931,6 +934,7 @@ return { + type='string', scope={'window'}, + vi_def=true, + vim=true, ++ modelineexpr=true, + alloced=true, + redraw={'current_window'}, + defaults={if_true={vi="foldtext()"}} +@@ -940,6 +944,7 @@ return { + type='string', scope={'buffer'}, + vi_def=true, + vim=true, ++ modelineexpr=true, + alloced=true, + varname='p_fex', + defaults={if_true={vi=""}} +@@ -1053,6 +1058,7 @@ return { + full_name='guitablabel', abbreviation='gtl', + type='string', scope={'global'}, + vi_def=true, ++ modelineexpr=true, + redraw={'current_window'}, + enable_if=false, + }, +@@ -1143,6 +1149,7 @@ return { + full_name='iconstring', + type='string', scope={'global'}, + vi_def=true, ++ modelineexpr=true, + varname='p_iconstring', + defaults={if_true={vi=""}} + }, +@@ -1209,6 +1216,7 @@ return { + full_name='includeexpr', abbreviation='inex', + type='string', scope={'buffer'}, + vi_def=true, ++ modelineexpr=true, + alloced=true, + varname='p_inex', + defaults={if_true={vi=""}} +@@ -1225,6 +1233,7 @@ return { + type='string', scope={'buffer'}, + vi_def=true, + vim=true, ++ modelineexpr=true, + alloced=true, + varname='p_inde', + defaults={if_true={vi=""}} +@@ -1538,6 +1547,14 @@ return { + varname='p_ml', + defaults={if_true={vi=false, vim=true}} + }, ++ { ++ full_name='modelineexpr', abbreviation='mle', ++ type='bool', scope={'global'}, ++ vi_def=true, ++ secure=true, ++ varname='p_mle', ++ defaults={if_true={vi=false}} ++ }, + { + full_name='modelines', abbreviation='mls', + type='number', scope={'global'}, +@@ -1898,6 +1915,7 @@ return { + type='string', scope={'global'}, + vi_def=true, + alloced=true, ++ modelineexpr=true, + redraw={'statuslines'}, + varname='p_ruf', + defaults={if_true={vi=""}} +@@ -2293,6 +2311,7 @@ return { + type='string', scope={'global', 'window'}, + vi_def=true, + alloced=true, ++ modelineexpr=true, + redraw={'statuslines'}, + varname='p_stl', + defaults={if_true={vi=""}} +@@ -2352,6 +2371,7 @@ return { + full_name='tabline', abbreviation='tal', + type='string', scope={'global'}, + vi_def=true, ++ modelineexpr=true, + redraw={'all_windows'}, + varname='p_tal', + defaults={if_true={vi=""}} +@@ -2511,6 +2531,7 @@ return { + full_name='titlestring', + type='string', scope={'global'}, + vi_def=true, ++ modelineexpr=true, + varname='p_titlestring', + defaults={if_true={vi=""}} + }, +diff --git a/src/nvim/testdir/test49.in b/src/nvim/testdir/test49.in +index 435e62765..eb17ace2f 100644 +--- a/src/nvim/testdir/test49.in ++++ b/src/nvim/testdir/test49.in +@@ -4,7 +4,7 @@ If after adding a new test, the test output doesn't appear properly in + test49.failed, try to add one or more "G"s at the line ending in "test.out" + + STARTTEST +-:se nomore ++:se nomore modelineexpr + :lang mess C + :so test49.vim + :" Go back to this file and append the results from register r. +diff --git a/src/nvim/testdir/test_alot.vim b/src/nvim/testdir/test_alot.vim +index 0602ff6a4..9d81d2162 100644 +--- a/src/nvim/testdir/test_alot.vim ++++ b/src/nvim/testdir/test_alot.vim +@@ -28,6 +28,7 @@ source test_lambda.vim + source test_mapping.vim + source test_menu.vim + source test_messages.vim ++source test_modeline.vim + source test_move.vim + source test_partial.vim + source test_popup.vim +diff --git a/src/nvim/testdir/test_autocmd.vim b/src/nvim/testdir/test_autocmd.vim +index 253d6750e..12b6a38ef 100644 +--- a/src/nvim/testdir/test_autocmd.vim ++++ b/src/nvim/testdir/test_autocmd.vim +@@ -652,6 +652,29 @@ func Test_OptionSet_diffmode_close() + "delfunc! AutoCommandOptionSet + endfunc + ++func Test_OptionSet_modeline() ++ throw 'skipped: Nvim does not support test_override()' ++ call test_override('starting', 1) ++ au! OptionSet ++ augroup set_tabstop ++ au OptionSet tabstop call timer_start(1, {-> execute("echo 'Handler called'", "")}) ++ augroup END ++ call writefile(['vim: set ts=7 sw=5 :', 'something'], 'XoptionsetModeline') ++ set modeline ++ let v:errmsg = '' ++ call assert_fails('split XoptionsetModeline', 'E12:') ++ call assert_equal(7, &ts) ++ call assert_equal('', v:errmsg) ++ ++ augroup set_tabstop ++ au! ++ augroup END ++ bwipe! ++ set ts& ++ call delete('XoptionsetModeline') ++ call test_override('starting', 0) ++endfunc ++ + " Test for Bufleave autocommand that deletes the buffer we are about to edit. + func Test_BufleaveWithDelete() + new | edit Xfile1 +diff --git a/src/nvim/testdir/test_modeline.vim b/src/nvim/testdir/test_modeline.vim +new file mode 100644 +index 000000000..1e196e07f +--- /dev/null ++++ b/src/nvim/testdir/test_modeline.vim +@@ -0,0 +1,173 @@ ++" Tests for parsing the modeline. ++ ++func Test_modeline_invalid() ++ " This was reading allocated memory in the past. ++ call writefile(['vi:0', 'nothing'], 'Xmodeline') ++ let modeline = &modeline ++ set modeline ++ call assert_fails('set Xmodeline', 'E518:') ++ ++ let &modeline = modeline ++ bwipe! ++ call delete('Xmodeline') ++ endfunc ++ ++func Test_modeline_filetype() ++ call writefile(['vim: set ft=c :', 'nothing'], 'Xmodeline_filetype') ++ let modeline = &modeline ++ set modeline ++ filetype plugin on ++ split Xmodeline_filetype ++ call assert_equal("c", &filetype) ++ call assert_equal(1, b:did_ftplugin) ++ call assert_equal("ccomplete#Complete", &ofu) ++ ++ bwipe! ++ call delete('Xmodeline_filetype') ++ let &modeline = modeline ++ filetype plugin off ++endfunc ++ ++func Test_modeline_syntax() ++ call writefile(['vim: set syn=c :', 'nothing'], 'Xmodeline_syntax') ++ let modeline = &modeline ++ set modeline ++ syntax enable ++ split Xmodeline_syntax ++ call assert_equal("c", &syntax) ++ call assert_equal("c", b:current_syntax) ++ ++ bwipe! ++ call delete('Xmodeline_syntax') ++ let &modeline = modeline ++ syntax off ++endfunc ++ ++func Test_modeline_keymap() ++ if !has('keymap') ++ return ++ endif ++ call writefile(['vim: set keymap=greek :', 'nothing'], 'Xmodeline_keymap') ++ let modeline = &modeline ++ set modeline ++ split Xmodeline_keymap ++ call assert_equal("greek", &keymap) ++ call assert_match('greek\|grk', b:keymap_name) ++ ++ bwipe! ++ call delete('Xmodeline_keymap') ++ let &modeline = modeline ++ set keymap= iminsert=0 imsearch=-1 ++endfunc ++ ++func s:modeline_fails(what, text, error) ++ if !exists('+' . a:what) ++ return ++ endif ++ let fname = "Xmodeline_fails_" . a:what ++ call writefile(['vim: set ' . a:text . ' :', 'nothing'], fname) ++ let modeline = &modeline ++ set modeline ++ filetype plugin on ++ syntax enable ++ call assert_fails('split ' . fname, a:error) ++ call assert_equal("", &filetype) ++ call assert_equal("", &syntax) ++ ++ bwipe! ++ call delete(fname) ++ let &modeline = modeline ++ filetype plugin off ++ syntax off ++endfunc ++ ++func Test_modeline_filetype_fails() ++ call s:modeline_fails('filetype', 'ft=evil$CMD', 'E474:') ++endfunc ++ ++func Test_modeline_syntax_fails() ++ call s:modeline_fails('syntax', 'syn=evil$CMD', 'E474:') ++endfunc ++ ++func Test_modeline_keymap_fails() ++ call s:modeline_fails('keymap', 'keymap=evil$CMD', 'E474:') ++endfunc ++ ++func Test_modeline_fails_always() ++ call s:modeline_fails('backupdir', 'backupdir=Something()', 'E520:') ++ call s:modeline_fails('cdpath', 'cdpath=Something()', 'E520:') ++ call s:modeline_fails('charconvert', 'charconvert=Something()', 'E520:') ++ call s:modeline_fails('completefunc', 'completefunc=Something()', 'E520:') ++ call s:modeline_fails('cscopeprg', 'cscopeprg=Something()', 'E520:') ++ call s:modeline_fails('diffexpr', 'diffexpr=Something()', 'E520:') ++ call s:modeline_fails('directory', 'directory=Something()', 'E520:') ++ call s:modeline_fails('equalprg', 'equalprg=Something()', 'E520:') ++ call s:modeline_fails('errorfile', 'errorfile=Something()', 'E520:') ++ call s:modeline_fails('exrc', 'exrc=Something()', 'E520:') ++ call s:modeline_fails('formatprg', 'formatprg=Something()', 'E520:') ++ call s:modeline_fails('fsync', 'fsync=Something()', 'E520:') ++ call s:modeline_fails('grepprg', 'grepprg=Something()', 'E520:') ++ call s:modeline_fails('helpfile', 'helpfile=Something()', 'E520:') ++ call s:modeline_fails('imactivatefunc', 'imactivatefunc=Something()', 'E520:') ++ call s:modeline_fails('imstatusfunc', 'imstatusfunc=Something()', 'E520:') ++ call s:modeline_fails('imstyle', 'imstyle=Something()', 'E520:') ++ call s:modeline_fails('keywordprg', 'keywordprg=Something()', 'E520:') ++ call s:modeline_fails('langmap', 'langmap=Something()', 'E520:') ++ call s:modeline_fails('luadll', 'luadll=Something()', 'E520:') ++ call s:modeline_fails('makeef', 'makeef=Something()', 'E520:') ++ call s:modeline_fails('makeprg', 'makeprg=Something()', 'E520:') ++ call s:modeline_fails('mkspellmem', 'mkspellmem=Something()', 'E520:') ++ call s:modeline_fails('mzschemedll', 'mzschemedll=Something()', 'E520:') ++ call s:modeline_fails('mzschemegcdll', 'mzschemegcdll=Something()', 'E520:') ++ call s:modeline_fails('modelineexpr', 'modelineexpr=Something()', 'E520:') ++ call s:modeline_fails('omnifunc', 'omnifunc=Something()', 'E520:') ++ call s:modeline_fails('operatorfunc', 'operatorfunc=Something()', 'E520:') ++ call s:modeline_fails('perldll', 'perldll=Something()', 'E520:') ++ call s:modeline_fails('printdevice', 'printdevice=Something()', 'E520:') ++ call s:modeline_fails('patchexpr', 'patchexpr=Something()', 'E520:') ++ call s:modeline_fails('printexpr', 'printexpr=Something()', 'E520:') ++ call s:modeline_fails('pythondll', 'pythondll=Something()', 'E520:') ++ call s:modeline_fails('pythonhome', 'pythonhome=Something()', 'E520:') ++ call s:modeline_fails('pythonthreedll', 'pythonthreedll=Something()', 'E520:') ++ call s:modeline_fails('pythonthreehome', 'pythonthreehome=Something()', 'E520:') ++ call s:modeline_fails('pyxversion', 'pyxversion=Something()', 'E520:') ++ call s:modeline_fails('rubydll', 'rubydll=Something()', 'E520:') ++ call s:modeline_fails('runtimepath', 'runtimepath=Something()', 'E520:') ++ call s:modeline_fails('secure', 'secure=Something()', 'E520:') ++ call s:modeline_fails('shell', 'shell=Something()', 'E520:') ++ call s:modeline_fails('shellcmdflag', 'shellcmdflag=Something()', 'E520:') ++ call s:modeline_fails('shellpipe', 'shellpipe=Something()', 'E520:') ++ call s:modeline_fails('shellquote', 'shellquote=Something()', 'E520:') ++ call s:modeline_fails('shellredir', 'shellredir=Something()', 'E520:') ++ call s:modeline_fails('shellxquote', 'shellxquote=Something()', 'E520:') ++ call s:modeline_fails('spellfile', 'spellfile=Something()', 'E520:') ++ call s:modeline_fails('spellsuggest', 'spellsuggest=Something()', 'E520:') ++ call s:modeline_fails('tcldll', 'tcldll=Something()', 'E520:') ++ call s:modeline_fails('titleold', 'titleold=Something()', 'E520:') ++ call s:modeline_fails('viewdir', 'viewdir=Something()', 'E520:') ++ call s:modeline_fails('viminfo', 'viminfo=Something()', 'E520:') ++ call s:modeline_fails('viminfofile', 'viminfofile=Something()', 'E520:') ++ call s:modeline_fails('winptydll', 'winptydll=Something()', 'E520:') ++ call s:modeline_fails('undodir', 'undodir=Something()', 'E520:') ++ " only check a few terminal options ++ " Skip these since nvim doesn't support termcodes as options ++ "call s:modeline_fails('t_AB', 't_AB=Something()', 'E520:') ++ "call s:modeline_fails('t_ce', 't_ce=Something()', 'E520:') ++ "call s:modeline_fails('t_sr', 't_sr=Something()', 'E520:') ++ "call s:modeline_fails('t_8b', 't_8b=Something()', 'E520:') ++endfunc ++ ++func Test_modeline_fails_modelineexpr() ++ call s:modeline_fails('balloonexpr', 'balloonexpr=Something()', 'E992:') ++ call s:modeline_fails('foldexpr', 'foldexpr=Something()', 'E992:') ++ call s:modeline_fails('foldtext', 'foldtext=Something()', 'E992:') ++ call s:modeline_fails('formatexpr', 'formatexpr=Something()', 'E992:') ++ call s:modeline_fails('guitablabel', 'guitablabel=Something()', 'E992:') ++ call s:modeline_fails('iconstring', 'iconstring=Something()', 'E992:') ++ call s:modeline_fails('includeexpr', 'includeexpr=Something()', 'E992:') ++ call s:modeline_fails('indentexpr', 'indentexpr=Something()', 'E992:') ++ call s:modeline_fails('rulerformat', 'rulerformat=Something()', 'E992:') ++ call s:modeline_fails('statusline', 'statusline=Something()', 'E992:') ++ call s:modeline_fails('tabline', 'tabline=Something()', 'E992:') ++ call s:modeline_fails('titlestring', 'titlestring=Something()', 'E992:') ++endfunc diff -Nru neovim-0.3.4/debian/patches/0001-vim-patch-8.1.1365-source-should-check-sandbox-10082.patch neovim-0.3.4/debian/patches/0001-vim-patch-8.1.1365-source-should-check-sandbox-10082.patch --- neovim-0.3.4/debian/patches/0001-vim-patch-8.1.1365-source-should-check-sandbox-10082.patch 2019-06-05 21:38:14.000000000 -0400 +++ neovim-0.3.4/debian/patches/0001-vim-patch-8.1.1365-source-should-check-sandbox-10082.patch 1969-12-31 19:00:00.000000000 -0500 @@ -1,36 +0,0 @@ -From 46112054bf3c6d00c53cf8a904e0687b508a4f0a Mon Sep 17 00:00:00 2001 -From: "Justin M. Keyes" <justi...@gmail.com> -Date: Wed, 29 May 2019 00:33:22 +0200 -Subject: [PATCH] vim-patch:8.1.1365: :source should check sandbox #10082 - -Problem: Source command doesn't check for the sandbox. (Armin Razmjou) -Solution: Check for the sandbox when sourcing a file. -https://github.com/vim/vim/commit/53575521406739cf20bbe4e384d88e7dca11f040 - -(cherry picked from commit 4553fc5e6cb6c8c43f57c173d01b31a61e51d13f) - -Signed-off-by: James McCoy <james...@debian.org> -Closes: CVE-2019-12735 -Closes: #930024 ---- - src/nvim/getchar.c | 7 +++++++ - 1 file changed, 7 insertions(+) - -diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c -index 94702a9a3..243e6afce 100644 ---- a/src/nvim/getchar.c -+++ b/src/nvim/getchar.c -@@ -1244,6 +1244,13 @@ openscript ( - EMSG(_(e_nesting)); - return; - } -+ -+ // Disallow sourcing a file in the sandbox, the commands would be executed -+ // later, possibly outside of the sandbox. -+ if (check_secure()) { -+ return; -+ } -+ - if (ignore_script) - /* Not reading from script, also don't open one. Warning message? */ - return; diff -Nru neovim-0.3.4/debian/patches/0002-vim-patch-8.1.1365-source-should-check-sandbox-10082.patch neovim-0.3.4/debian/patches/0002-vim-patch-8.1.1365-source-should-check-sandbox-10082.patch --- neovim-0.3.4/debian/patches/0002-vim-patch-8.1.1365-source-should-check-sandbox-10082.patch 1969-12-31 19:00:00.000000000 -0500 +++ neovim-0.3.4/debian/patches/0002-vim-patch-8.1.1365-source-should-check-sandbox-10082.patch 2019-06-26 21:21:33.000000000 -0400 @@ -0,0 +1,36 @@ +From 0deb5bd4710ca912420bd796e74f6a7175d7753f Mon Sep 17 00:00:00 2001 +From: "Justin M. Keyes" <justi...@gmail.com> +Date: Wed, 29 May 2019 00:33:22 +0200 +Subject: [PATCH 2/7] vim-patch:8.1.1365: :source should check sandbox #10082 + +Problem: Source command doesn't check for the sandbox. (Armin Razmjou) +Solution: Check for the sandbox when sourcing a file. +https://github.com/vim/vim/commit/53575521406739cf20bbe4e384d88e7dca11f040 + +(cherry picked from commit 4553fc5e6cb6c8c43f57c173d01b31a61e51d13f) + +Signed-off-by: James McCoy <james...@debian.org> +Closes: CVE-2019-12735 +Closes: #930024 +--- + src/nvim/getchar.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c +index 94702a9a3..243e6afce 100644 +--- a/src/nvim/getchar.c ++++ b/src/nvim/getchar.c +@@ -1244,6 +1244,13 @@ openscript ( + EMSG(_(e_nesting)); + return; + } ++ ++ // Disallow sourcing a file in the sandbox, the commands would be executed ++ // later, possibly outside of the sandbox. ++ if (check_secure()) { ++ return; ++ } ++ + if (ignore_script) + /* Not reading from script, also don't open one. Warning message? */ + return; diff -Nru neovim-0.3.4/debian/patches/0003-vim-patch-8.1.0177-defining-function-in-sandbox-is-i.patch neovim-0.3.4/debian/patches/0003-vim-patch-8.1.0177-defining-function-in-sandbox-is-i.patch --- neovim-0.3.4/debian/patches/0003-vim-patch-8.1.0177-defining-function-in-sandbox-is-i.patch 1969-12-31 19:00:00.000000000 -0500 +++ neovim-0.3.4/debian/patches/0003-vim-patch-8.1.0177-defining-function-in-sandbox-is-i.patch 2019-06-26 21:21:33.000000000 -0400 @@ -0,0 +1,104 @@ +From ee6325436e32803a8b2e4678ff334c7b9423ef7e Mon Sep 17 00:00:00 2001 +From: Jan Edmund Lazo <jan.l...@mail.utoronto.ca> +Date: Sat, 23 Mar 2019 00:58:00 -0400 +Subject: [PATCH 3/7] vim-patch:8.1.0177: defining function in sandbox is + inconsistent + +Problem: Defining function in sandbox is inconsistent, cannot use :function + but can define a lambda. +Solution: Allow defining a function in the sandbox, but also use the sandbox + when executing it. (closes vim/vim#3182) +https://github.com/vim/vim/commit/93343725b5fa1cf580a24302455980faacae8ee2 + +(cherry picked from commit c202e4a86856594a6602a795314a081c497c2df5) + +Signed-off-by: James McCoy <james...@debian.org> +--- + src/nvim/eval.c | 19 ++++++++++++++++++- + src/nvim/ex_cmds.lua | 2 +- + 2 files changed, 19 insertions(+), 2 deletions(-) + +diff --git a/src/nvim/eval.c b/src/nvim/eval.c +index 5191328b5..9163673a3 100644 +--- a/src/nvim/eval.c ++++ b/src/nvim/eval.c +@@ -241,13 +241,14 @@ typedef enum { + ///< the value (prevents error message). + } GetLvalFlags; + +-// function flags ++// flags used in uf_flags + #define FC_ABORT 0x01 // abort function on error + #define FC_RANGE 0x02 // function accepts range + #define FC_DICT 0x04 // Dict function, uses "self" + #define FC_CLOSURE 0x08 // closure, uses outer scope variables + #define FC_DELETED 0x10 // :delfunction used while uf_refcount > 0 + #define FC_REMOVED 0x20 // function redefined while uf_refcount > 0 ++#define FC_SANDBOX 0x40 // function defined in the sandbox + + // The names of packages that once were loaded are remembered. + static garray_T ga_loaded = { 0, 0, sizeof(char_u *), 4, NULL }; +@@ -5853,6 +5854,9 @@ static int get_lambda_tv(char_u **arg, typval_T *rettv, bool evaluate) + if (prof_def_func()) { + func_do_profile(fp); + } ++ if (sandbox) { ++ flags |= FC_SANDBOX; ++ } + fp->uf_varargs = true; + fp->uf_flags = flags; + fp->uf_calls = 0; +@@ -20315,6 +20319,9 @@ void ex_function(exarg_T *eap) + if (prof_def_func()) + func_do_profile(fp); + fp->uf_varargs = varargs; ++ if (sandbox) { ++ flags |= FC_SANDBOX; ++ } + fp->uf_flags = flags; + fp->uf_calls = 0; + fp->uf_script_ID = current_SID; +@@ -21305,6 +21312,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, + char_u *save_sourcing_name; + linenr_T save_sourcing_lnum; + scid_T save_current_SID; ++ bool using_sandbox = false; + funccall_T *fc; + int save_did_emsg; + static int depth = 0; +@@ -21462,6 +21470,12 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, + save_sourcing_name = sourcing_name; + save_sourcing_lnum = sourcing_lnum; + sourcing_lnum = 1; ++ ++ if (fp->uf_flags & FC_SANDBOX) { ++ using_sandbox = true; ++ sandbox++; ++ } ++ + // need space for new sourcing_name: + // * save_sourcing_name + // * "["number"].." or "function " +@@ -21622,6 +21636,9 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, + if (do_profiling_yes) { + script_prof_restore(&wait_start); + } ++ if (using_sandbox) { ++ sandbox--; ++ } + + if (p_verbose >= 12 && sourcing_name != NULL) { + ++no_wait_return; +diff --git a/src/nvim/ex_cmds.lua b/src/nvim/ex_cmds.lua +index 79ca5363e..fae21d8c9 100644 +--- a/src/nvim/ex_cmds.lua ++++ b/src/nvim/ex_cmds.lua +@@ -1004,7 +1004,7 @@ return { + }, + { + command='function', +- flags=bit.bor(EXTRA, BANG, CMDWIN), ++ flags=bit.bor(EXTRA, BANG, SBOXOK, CMDWIN), + addr_type=ADDR_LINES, + func='ex_function', + }, diff -Nru neovim-0.3.4/debian/patches/0004-vim-patch-8.1.0189-function-defined-in-sandbox-not-t.patch neovim-0.3.4/debian/patches/0004-vim-patch-8.1.0189-function-defined-in-sandbox-not-t.patch --- neovim-0.3.4/debian/patches/0004-vim-patch-8.1.0189-function-defined-in-sandbox-not-t.patch 1969-12-31 19:00:00.000000000 -0500 +++ neovim-0.3.4/debian/patches/0004-vim-patch-8.1.0189-function-defined-in-sandbox-not-t.patch 2019-06-26 21:21:33.000000000 -0400 @@ -0,0 +1,41 @@ +From 5be949ce2df74446f33ea2949620234b41c046b0 Mon Sep 17 00:00:00 2001 +From: Jan Edmund Lazo <jan.l...@mail.utoronto.ca> +Date: Sat, 23 Mar 2019 01:26:07 -0400 +Subject: [PATCH 4/7] vim-patch:8.1.0189: function defined in sandbox not + tested + +Problem: Function defined in sandbox not tested. +Solution: Add a text. +https://github.com/vim/vim/commit/d90a144eda047816acffc7a8f297b43a7120710e + +(cherry picked from commit f514b7fbbc75b4464af5abe44d5f859a0d904495) + +Signed-off-by: James McCoy <james...@debian.org> +--- + src/nvim/testdir/test_functions.vim | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/src/nvim/testdir/test_functions.vim b/src/nvim/testdir/test_functions.vim +index 7dc9f31ce..292f69d70 100644 +--- a/src/nvim/testdir/test_functions.vim ++++ b/src/nvim/testdir/test_functions.vim +@@ -1037,3 +1037,19 @@ func Test_func_range_with_edit() + call delete('Xfuncrange2') + bwipe! + endfunc ++ ++sandbox function Fsandbox() ++ normal ix ++endfunc ++ ++func Test_func_sandbox() ++ sandbox let F = {-> 'hello'} ++ call assert_equal('hello', F()) ++ ++ sandbox let F = {-> execute("normal ix\<Esc>")} ++ call assert_fails('call F()', 'E48:') ++ unlet F ++ ++ call assert_fails('call Fsandbox()', 'E48:') ++ delfunc Fsandbox ++endfunc diff -Nru neovim-0.3.4/debian/patches/0005-vim-patch-8.1.0206-duplicate-test-function-name.patch neovim-0.3.4/debian/patches/0005-vim-patch-8.1.0206-duplicate-test-function-name.patch --- neovim-0.3.4/debian/patches/0005-vim-patch-8.1.0206-duplicate-test-function-name.patch 1969-12-31 19:00:00.000000000 -0500 +++ neovim-0.3.4/debian/patches/0005-vim-patch-8.1.0206-duplicate-test-function-name.patch 2019-06-26 21:21:33.000000000 -0400 @@ -0,0 +1,35 @@ +From 86093f2847efb7e0579247b7ff850e4cafe71912 Mon Sep 17 00:00:00 2001 +From: Jan Edmund Lazo <jan.l...@mail.utoronto.ca> +Date: Sat, 25 May 2019 14:47:17 -0400 +Subject: [PATCH 5/7] vim-patch:8.1.0206: duplicate test function name + +Problem: Duplicate test function name. +Solution: Rename both functions. +https://github.com/vim/vim/commit/cd96eef3a869557bd3d2d4497861d87cb525db06 + +(cherry picked from commit 6683cb60b805fa305a069cf7873be8b605d78a3d) + +Signed-off-by: James McCoy <james...@debian.org> +--- + src/nvim/testdir/test_glob2regpat.vim | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/nvim/testdir/test_glob2regpat.vim b/src/nvim/testdir/test_glob2regpat.vim +index fdf17946b..e6e41f13e 100644 +--- a/src/nvim/testdir/test_glob2regpat.vim ++++ b/src/nvim/testdir/test_glob2regpat.vim +@@ -1,12 +1,12 @@ + " Test glob2regpat() + +-func Test_invalid() ++func Test_glob2regpat_invalid() + call assert_fails('call glob2regpat(1.33)', 'E806:') + call assert_fails('call glob2regpat("}")', 'E219:') + call assert_fails('call glob2regpat("{")', 'E220:') + endfunc + +-func Test_valid() ++func Test_glob2regpat_valid() + call assert_equal('^foo\.', glob2regpat('foo.*')) + call assert_equal('^foo.$', glob2regpat('foo?')) + call assert_equal('\.vim$', glob2regpat('*.vim')) diff -Nru neovim-0.3.4/debian/patches/0006-vim-patch-8.1.1382-error-when-editing-test-file.patch neovim-0.3.4/debian/patches/0006-vim-patch-8.1.1382-error-when-editing-test-file.patch --- neovim-0.3.4/debian/patches/0006-vim-patch-8.1.1382-error-when-editing-test-file.patch 1969-12-31 19:00:00.000000000 -0500 +++ neovim-0.3.4/debian/patches/0006-vim-patch-8.1.1382-error-when-editing-test-file.patch 2019-06-26 21:21:33.000000000 -0400 @@ -0,0 +1,59 @@ +From e45938b8c7465d854b3d4feeff6acfc71835078f Mon Sep 17 00:00:00 2001 +From: James McCoy <james...@jamessan.com> +Date: Sat, 22 Jun 2019 22:09:32 -0400 +Subject: [PATCH 6/7] vim-patch:8.1.1382: error when editing test file + +Problem: Error when editing test file. +Solution: Remove part of modeline. +https://github.com/vim/vim/commit/3020a87cb121123abf1e9a1eca0eddac241fc481 + +(cherry picked from commit 13f3a21226fdd31c42ba927ff12ac6c34c940311) + +Signed-off-by: James McCoy <james...@debian.org> +--- + src/nvim/testdir/test49.in | 2 +- + src/nvim/testdir/test49.vim | 3 +-- + src/nvim/testdir/test_vimscript.vim | 1 - + 3 files changed, 2 insertions(+), 4 deletions(-) + +diff --git a/src/nvim/testdir/test49.in b/src/nvim/testdir/test49.in +index eb17ace2f..435e62765 100644 +--- a/src/nvim/testdir/test49.in ++++ b/src/nvim/testdir/test49.in +@@ -4,7 +4,7 @@ If after adding a new test, the test output doesn't appear properly in + test49.failed, try to add one or more "G"s at the line ending in "test.out" + + STARTTEST +-:se nomore modelineexpr ++:se nomore + :lang mess C + :so test49.vim + :" Go back to this file and append the results from register r. +diff --git a/src/nvim/testdir/test49.vim b/src/nvim/testdir/test49.vim +index 467abcd9b..837e55ebc 100644 +--- a/src/nvim/testdir/test49.vim ++++ b/src/nvim/testdir/test49.vim +@@ -1,6 +1,6 @@ + " Vim script language tests + " Author: Servatius Brandt <servatius.bra...@fujitsu-siemens.com> +-" Last Change: 2016 Feb 07 ++" Last Change: 2019 May 24 + + "------------------------------------------------------------------------------- + " Test environment {{{1 +@@ -9005,5 +9005,4 @@ Xcheck 50443995 + "------------------------------------------------------------------------------- + " Modelines {{{1 + " vim: ts=8 sw=4 tw=80 fdm=marker +-" vim: fdt=substitute(substitute(foldtext(),\ '\\%(^+--\\)\\@<=\\(\\s*\\)\\(.\\{-}\\)\:\ \\%(\"\ \\)\\=\\(Test\ \\d*\\)\:\\s*',\ '\\3\ (\\2)\:\ \\1',\ \"\"),\ '\\(Test\\s*\\)\\(\\d\\)\\D\\@=',\ '\\1\ \\2',\ "") + "------------------------------------------------------------------------------- +diff --git a/src/nvim/testdir/test_vimscript.vim b/src/nvim/testdir/test_vimscript.vim +index 5b16f6d20..c856fd720 100644 +--- a/src/nvim/testdir/test_vimscript.vim ++++ b/src/nvim/testdir/test_vimscript.vim +@@ -1297,5 +1297,4 @@ endfunc + "------------------------------------------------------------------------------- + " Modelines {{{1 + " vim: ts=8 sw=4 tw=80 fdm=marker +-" vim: fdt=substitute(substitute(foldtext(),\ '\\%(^+--\\)\\@<=\\(\\s*\\)\\(.\\{-}\\)\:\ \\%(\"\ \\)\\=\\(Test\ \\d*\\)\:\\s*',\ '\\3\ (\\2)\:\ \\1',\ \"\"),\ '\\(Test\\s*\\)\\(\\d\\)\\D\\@=',\ '\\1\ \\2',\ "") + "------------------------------------------------------------------------------- diff -Nru neovim-0.3.4/debian/patches/0007-eval-api-don-t-allow-the-API-to-be-called-in-the-san.patch neovim-0.3.4/debian/patches/0007-eval-api-don-t-allow-the-API-to-be-called-in-the-san.patch --- neovim-0.3.4/debian/patches/0007-eval-api-don-t-allow-the-API-to-be-called-in-the-san.patch 1969-12-31 19:00:00.000000000 -0500 +++ neovim-0.3.4/debian/patches/0007-eval-api-don-t-allow-the-API-to-be-called-in-the-san.patch 2019-06-26 21:21:33.000000000 -0400 @@ -0,0 +1,57 @@ +From 3e2e812f17fd05687dd9ffdbd42ccf9d31ee9bc7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Bj=C3=B6rn=20Linse?= <bjorn.li...@gmail.com> +Date: Wed, 26 Jun 2019 08:11:51 +0200 +Subject: [PATCH 7/7] eval/api: don't allow the API to be called in the + sandbox. + +Identifying and maintaining a "secure" subset of the API would be too +much busywork. So just disable the entire thing. + +(cherry picked from commit 413b313ad2cfd5a1ee32369b944436e14fc8bfb3) + +Signed-off-by: James McCoy <james...@debian.org> +--- + src/nvim/eval.c | 4 ++++ + test/functional/eval/api_functions_spec.lua | 9 ++++++++- + 2 files changed, 12 insertions(+), 1 deletion(-) + +diff --git a/src/nvim/eval.c b/src/nvim/eval.c +index 9163673a3..618cd50a7 100644 +--- a/src/nvim/eval.c ++++ b/src/nvim/eval.c +@@ -6516,6 +6516,10 @@ static void float_op_wrapper(typval_T *argvars, typval_T *rettv, FunPtr fptr) + + static void api_wrapper(typval_T *argvars, typval_T *rettv, FunPtr fptr) + { ++ if (check_restricted() || check_secure()) { ++ return; ++ } ++ + ApiDispatchWrapper fn = (ApiDispatchWrapper)fptr; + + Array args = ARRAY_DICT_INIT; +diff --git a/test/functional/eval/api_functions_spec.lua b/test/functional/eval/api_functions_spec.lua +index 6f440c7d8..951c5d685 100644 +--- a/test/functional/eval/api_functions_spec.lua ++++ b/test/functional/eval/api_functions_spec.lua +@@ -4,7 +4,8 @@ local lfs = require('lfs') + local neq, eq, command = helpers.neq, helpers.eq, helpers.command + local clear, curbufmeths = helpers.clear, helpers.curbufmeths + local exc_exec, expect, eval = helpers.exc_exec, helpers.expect, helpers.eval +-local insert = helpers.insert ++local insert, meth_pcall = helpers.insert, helpers.meth_pcall ++local meths = helpers.meths + + describe('api functions', function() + before_each(clear) +@@ -145,4 +146,10 @@ describe('api functions', function() + ]]) + screen:detach() + end) ++ ++ it('cannot be called from sandbox', function() ++ eq({false, 'Vim(call):E48: Not allowed in sandbox'}, ++ meth_pcall(command, "sandbox call nvim_input('ievil')")) ++ eq({''}, meths.buf_get_lines(0, 0, -1, true)) ++ end) + end) diff -Nru neovim-0.3.4/debian/patches/series neovim-0.3.4/debian/patches/series --- neovim-0.3.4/debian/patches/series 2019-06-05 21:38:14.000000000 -0400 +++ neovim-0.3.4/debian/patches/series 2019-06-26 21:21:33.000000000 -0400 @@ -1,2 +1,8 @@ # exported from git by git-debcherry -0001-vim-patch-8.1.1365-source-should-check-sandbox-10082.patch +0001-debcherry-fixup-patch.patch +0002-vim-patch-8.1.1365-source-should-check-sandbox-10082.patch +0003-vim-patch-8.1.0177-defining-function-in-sandbox-is-i.patch +0004-vim-patch-8.1.0189-function-defined-in-sandbox-not-t.patch +0005-vim-patch-8.1.0206-duplicate-test-function-name.patch +0006-vim-patch-8.1.1382-error-when-editing-test-file.patch +0007-eval-api-don-t-allow-the-API-to-be-called-in-the-san.patch