mirror of
https://github.com/neovim/neovim.git
synced 2026-04-20 14:25:32 +00: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*
|
*NoDefaultCurrentDirectoryInExePath*
|
||||||
On MS-Windows an executable in Vim's current working directory
|
On MS-Windows an executable in Vim's current working directory
|
||||||
is also normally found, but this can be disabled by setting
|
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:
|
The result is a Number:
|
||||||
1 exists
|
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*
|
--- *NoDefaultCurrentDirectoryInExePath*
|
||||||
--- On MS-Windows an executable in Vim's current working directory
|
--- On MS-Windows an executable in Vim's current working directory
|
||||||
--- is also normally found, but this can be disabled by setting
|
--- 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:
|
--- The result is a Number:
|
||||||
--- 1 exists
|
--- 1 exists
|
||||||
|
|||||||
@@ -2163,7 +2163,8 @@ M.funcs = {
|
|||||||
*NoDefaultCurrentDirectoryInExePath*
|
*NoDefaultCurrentDirectoryInExePath*
|
||||||
On MS-Windows an executable in Vim's current working directory
|
On MS-Windows an executable in Vim's current working directory
|
||||||
is also normally found, but this can be disabled by setting
|
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:
|
The result is a Number:
|
||||||
1 exists
|
1 exists
|
||||||
|
|||||||
@@ -1291,3 +1291,19 @@ void vim_setenv_ext(const char *name, const char *val)
|
|||||||
didset_vimruntime = false;
|
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/message.h"
|
||||||
#include "nvim/option_vars.h"
|
#include "nvim/option_vars.h"
|
||||||
#include "nvim/os/fs.h"
|
#include "nvim/os/fs.h"
|
||||||
|
#include "nvim/os/os.h"
|
||||||
#include "nvim/os/os_defs.h"
|
#include "nvim/os/os_defs.h"
|
||||||
#include "nvim/os/shell.h"
|
#include "nvim/os/shell.h"
|
||||||
#include "nvim/os/signal.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,
|
static int do_os_system(char **argv, const char *input, size_t len, char **output, size_t *nread,
|
||||||
bool silent, bool forward_output)
|
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_decide_throttle(0); // Initialize throttle decider.
|
||||||
out_data_ring(NULL, 0); // Initialize output ring-buffer.
|
out_data_ring(NULL, 0); // Initialize output ring-buffer.
|
||||||
bool has_input = (input != NULL && len > 0);
|
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_outtrans(prog, 0, false);
|
||||||
msg_putchar('\n');
|
msg_putchar('\n');
|
||||||
}
|
}
|
||||||
multiqueue_free(events);
|
goto end;
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: unlike process events, stream events are not queued, as we want to
|
// 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)) {
|
if (!wstream_write(&proc->in, input_buffer)) {
|
||||||
// couldn't write, stop the process and tell the user about it
|
// couldn't write, stop the process and tell the user about it
|
||||||
proc_stop(proc);
|
proc_stop(proc);
|
||||||
return -1;
|
goto end;
|
||||||
}
|
}
|
||||||
// close the input stream after everything is written
|
// close the input stream after everything is written
|
||||||
wstream_set_write_cb(&proc->in, shell_write_cb, NULL);
|
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;
|
msg_no_more = true;
|
||||||
lines_left = -1;
|
lines_left = -1;
|
||||||
}
|
}
|
||||||
int exitcode = proc_wait(proc, -1, NULL);
|
exitcode = proc_wait(proc, -1, NULL);
|
||||||
if (!got_int && out_data_decide_throttle(0)) {
|
if (!got_int && out_data_decide_throttle(0)) {
|
||||||
// Last chunk of output was skipped; display it now.
|
// Last chunk of output was skipped; display it now.
|
||||||
out_data_ring(NULL, SIZE_MAX);
|
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));
|
assert(multiqueue_empty(events));
|
||||||
|
end:
|
||||||
multiqueue_free(events);
|
multiqueue_free(events);
|
||||||
|
|
||||||
|
#ifdef MSWIN
|
||||||
|
// Restore original value of NoDefaultCurrentDirectoryInExePath
|
||||||
|
restore_env_var("NoDefaultCurrentDirectoryInExePath", oldval, true);
|
||||||
|
#endif
|
||||||
|
|
||||||
return exitcode;
|
return exitcode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user