[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#931143: marked as done (unblock: neovim/0.3.4-3)



Your message dated Thu, 27 Jun 2019 19:46:38 +0200
with message-id <c726b742-b29f-e151-6472-30e720bb18c6@debian.org>
and subject line Re: Bug#931143: unblock: neovim/0.3.4-3
has caused the Debian Bug report #931143,
regarding unblock: neovim/0.3.4-3
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact owner@bugs.debian.org
immediately.)


-- 
931143: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=931143
Debian Bug Tracking System
Contact owner@bugs.debian.org with problems
--- Begin Message ---
Package: release.debian.org
Severity: normal
User: release.debian.org@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 <jamessan@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 <jamessan@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" <justinkz@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 <jamessan@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" <justinkz@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 <jamessan@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.lazo@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 <jamessan@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.lazo@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 <jamessan@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.lazo@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 <jamessan@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 <jamessan@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 <jamessan@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.Brandt@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.linse@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 <jamessan@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

--- End Message ---
--- Begin Message ---
Hi James,

On 27-06-2019 04:21, James McCoy wrote:
> unblock neovim/0.3.4-3

Unblocked, thanks,

Paul

Attachment: signature.asc
Description: OpenPGP digital signature


--- End Message ---

Reply to: