mirror of
https://github.com/neovim/neovim.git
synced 2026-02-20 09:19:43 +10:00
vim-patch:9.1.1947: [security]: Windows: Vim may execute commands from current directory
Problem: [security]: Windows: Vim may execute commands from current
directory (Simon Zuckerbraun)
Solution: Set the $NoDefaultCurrentDirectoryInExePath before running
external commands.
Github Advisory:
https://github.com/vim/vim/security/advisories/GHSA-g77q-xrww-p834
083ec6d9a3
Co-authored-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
@@ -1877,7 +1877,8 @@ executable({expr}) *executable()*
|
||||
*NoDefaultCurrentDirectoryInExePath*
|
||||
On MS-Windows an executable in Vim's current working directory
|
||||
is also normally found, but this can be disabled by setting
|
||||
the $NoDefaultCurrentDirectoryInExePath environment variable.
|
||||
the `$NoDefaultCurrentDirectoryInExePath` environment variable.
|
||||
This is always done for |:!| commands, for security reasons.
|
||||
|
||||
The result is a Number:
|
||||
1 exists
|
||||
|
||||
3
runtime/lua/vim/_meta/vimfn.lua
generated
3
runtime/lua/vim/_meta/vimfn.lua
generated
@@ -1652,7 +1652,8 @@ function vim.fn.eventhandler() end
|
||||
--- *NoDefaultCurrentDirectoryInExePath*
|
||||
--- On MS-Windows an executable in Vim's current working directory
|
||||
--- is also normally found, but this can be disabled by setting
|
||||
--- the $NoDefaultCurrentDirectoryInExePath environment variable.
|
||||
--- the `$NoDefaultCurrentDirectoryInExePath` environment variable.
|
||||
--- This is always done for |:!| commands, for security reasons.
|
||||
---
|
||||
--- The result is a Number:
|
||||
--- 1 exists
|
||||
|
||||
@@ -2163,7 +2163,8 @@ M.funcs = {
|
||||
*NoDefaultCurrentDirectoryInExePath*
|
||||
On MS-Windows an executable in Vim's current working directory
|
||||
is also normally found, but this can be disabled by setting
|
||||
the $NoDefaultCurrentDirectoryInExePath environment variable.
|
||||
the `$NoDefaultCurrentDirectoryInExePath` environment variable.
|
||||
This is always done for |:!| commands, for security reasons.
|
||||
|
||||
The result is a Number:
|
||||
1 exists
|
||||
|
||||
@@ -1291,3 +1291,19 @@ void vim_setenv_ext(const char *name, const char *val)
|
||||
didset_vimruntime = false;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef MSWIN
|
||||
/// Restore a previous environment variable value, or unset it if NULL.
|
||||
/// "must_free" indicates whether "old_value" was allocated.
|
||||
void restore_env_var(const char *name, char *old_value, bool must_free)
|
||||
{
|
||||
if (old_value != NULL) {
|
||||
os_setenv(name, old_value, true);
|
||||
if (must_free) {
|
||||
xfree(old_value);
|
||||
}
|
||||
return;
|
||||
}
|
||||
os_unsetenv(name);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "nvim/message.h"
|
||||
#include "nvim/option_vars.h"
|
||||
#include "nvim/os/fs.h"
|
||||
#include "nvim/os/os.h"
|
||||
#include "nvim/os/os_defs.h"
|
||||
#include "nvim/os/shell.h"
|
||||
#include "nvim/os/signal.h"
|
||||
@@ -857,6 +858,15 @@ int os_system(char **argv, const char *input, size_t len, char **output,
|
||||
static int do_os_system(char **argv, const char *input, size_t len, char **output, size_t *nread,
|
||||
bool silent, bool forward_output)
|
||||
{
|
||||
int exitcode = -1;
|
||||
|
||||
#ifdef MSWIN
|
||||
// do not execute anything from the current directory by setting the
|
||||
// environemnt variable $NoDefaultCurrentDirectoryInExePath
|
||||
char *oldval = os_getenv("NoDefaultCurrentDirectoryInExePath");
|
||||
os_setenv("NoDefaultCurrentDirectoryInExePath", "1", true);
|
||||
#endif
|
||||
|
||||
out_data_decide_throttle(0); // Initialize throttle decider.
|
||||
out_data_ring(NULL, 0); // Initialize output ring-buffer.
|
||||
bool has_input = (input != NULL && len > 0);
|
||||
@@ -894,8 +904,7 @@ static int do_os_system(char **argv, const char *input, size_t len, char **outpu
|
||||
msg_outtrans(prog, 0, false);
|
||||
msg_putchar('\n');
|
||||
}
|
||||
multiqueue_free(events);
|
||||
return -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
// Note: unlike process events, stream events are not queued, as we want to
|
||||
@@ -917,7 +926,7 @@ static int do_os_system(char **argv, const char *input, size_t len, char **outpu
|
||||
if (!wstream_write(&proc->in, input_buffer)) {
|
||||
// couldn't write, stop the process and tell the user about it
|
||||
proc_stop(proc);
|
||||
return -1;
|
||||
goto end;
|
||||
}
|
||||
// close the input stream after everything is written
|
||||
wstream_set_write_cb(&proc->in, shell_write_cb, NULL);
|
||||
@@ -933,7 +942,7 @@ static int do_os_system(char **argv, const char *input, size_t len, char **outpu
|
||||
msg_no_more = true;
|
||||
lines_left = -1;
|
||||
}
|
||||
int exitcode = proc_wait(proc, -1, NULL);
|
||||
exitcode = proc_wait(proc, -1, NULL);
|
||||
if (!got_int && out_data_decide_throttle(0)) {
|
||||
// Last chunk of output was skipped; display it now.
|
||||
out_data_ring(NULL, SIZE_MAX);
|
||||
@@ -965,8 +974,14 @@ static int do_os_system(char **argv, const char *input, size_t len, char **outpu
|
||||
}
|
||||
|
||||
assert(multiqueue_empty(events));
|
||||
end:
|
||||
multiqueue_free(events);
|
||||
|
||||
#ifdef MSWIN
|
||||
// Restore original value of NoDefaultCurrentDirectoryInExePath
|
||||
restore_env_var("NoDefaultCurrentDirectoryInExePath", oldval, true);
|
||||
#endif
|
||||
|
||||
return exitcode;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user