mirror of
https://github.com/vim/vim.git
synced 2026-05-28 00:21:37 +02:00
patch 9.2.0434: cscope: filename interpreted by /bin/sh
Problem: cs_create_connection() builds the cscope command by
interpolating csinfo[i].fname (and ppath, flags) into a
string and lets the shell parse it. Shell metacharacters
in a database filename are therefore evaluated by /bin/sh
before cscope is exec'd, rather than being passed through as a
literal path (q1uf3ng)
Solution: Build argv directly and execvp() the cscope binary
without an intervening shell.
closes: #20119
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
+91
-34
@@ -829,11 +829,11 @@ cs_create_connection(int i)
|
||||
int to_cs[2], from_cs[2];
|
||||
# endif
|
||||
int cmdlen;
|
||||
int len;
|
||||
char *prog, *cmd, *ppath = NULL;
|
||||
size_t proglen;
|
||||
# ifdef MSWIN
|
||||
int fd;
|
||||
int len;
|
||||
SECURITY_ATTRIBUTES sa;
|
||||
PROCESS_INFORMATION pi;
|
||||
STARTUPINFO si;
|
||||
@@ -872,7 +872,6 @@ err_closing:
|
||||
else if (csinfo[i].pid == 0) // child: run cscope.
|
||||
{
|
||||
char **argv = NULL;
|
||||
int argc = 0;
|
||||
|
||||
if (dup2(to_cs[0], STDIN_FILENO) == -1)
|
||||
PERROR("cs_create_connection 1");
|
||||
@@ -956,48 +955,93 @@ err_closing:
|
||||
|
||||
// run the cscope command
|
||||
# ifdef UNIX
|
||||
vim_snprintf(cmd, cmdlen, "/bin/sh -c \"exec %s -dl -f %s",
|
||||
prog, csinfo[i].fname);
|
||||
# else
|
||||
vim_snprintf(cmd, cmdlen, "%s -dl -f %s", prog, csinfo[i].fname);
|
||||
# endif
|
||||
if (csinfo[i].ppath != NULL)
|
||||
{
|
||||
len = (int)STRLEN(cmd);
|
||||
vim_snprintf(cmd + len, cmdlen - len, " -P%s", csinfo[i].ppath);
|
||||
}
|
||||
if (csinfo[i].flags != NULL)
|
||||
{
|
||||
len = (int)STRLEN(cmd);
|
||||
vim_snprintf(cmd + len, cmdlen - len, " %s", csinfo[i].flags);
|
||||
}
|
||||
# ifdef UNIX
|
||||
// terminate the -c command argument
|
||||
STRCAT(cmd, "\"");
|
||||
garray_T ga_argv;
|
||||
char **tok = NULL;
|
||||
int tokc = 0;
|
||||
|
||||
// on Win32 we still need prog
|
||||
vim_free(prog);
|
||||
# endif
|
||||
vim_free(ppath);
|
||||
ga_init2(&ga_argv, sizeof(char *), 8);
|
||||
|
||||
// 'cscopeprg' may be multi-word (e.g. "cscope --foo");
|
||||
// split it into separate argv entries.
|
||||
if (build_argv_from_string((char_u *)prog, &tok, &tokc) == FAIL)
|
||||
exit(EXIT_FAILURE);
|
||||
for (int k = 0; k < tokc; ++k)
|
||||
{
|
||||
if (ga_grow(&ga_argv, 1) == FAIL)
|
||||
exit(EXIT_FAILURE);
|
||||
((char **)ga_argv.ga_data)[ga_argv.ga_len++] = tok[k];
|
||||
}
|
||||
VIM_CLEAR(tok);
|
||||
|
||||
// Literal arguments: "-dl", "-f", fname.
|
||||
if (ga_grow(&ga_argv, 3) == FAIL)
|
||||
exit(EXIT_FAILURE);
|
||||
((char **)ga_argv.ga_data)[ga_argv.ga_len++] =
|
||||
(char *)vim_strsave((char_u *)"-dl");
|
||||
((char **)ga_argv.ga_data)[ga_argv.ga_len++] =
|
||||
(char *)vim_strsave((char_u *)"-f");
|
||||
((char **)ga_argv.ga_data)[ga_argv.ga_len++] =
|
||||
(char *)vim_strsave((char_u *)csinfo[i].fname);
|
||||
|
||||
// "-P<ppath>" as a single argv entry, if set.
|
||||
if (ppath != NULL)
|
||||
{
|
||||
size_t plen = STRLEN(ppath) + 3;
|
||||
char *parg = alloc(plen);
|
||||
|
||||
if (parg == NULL || ga_grow(&ga_argv, 1) == FAIL)
|
||||
exit(EXIT_FAILURE);
|
||||
vim_snprintf(parg, plen, "-P%s", ppath);
|
||||
((char **)ga_argv.ga_data)[ga_argv.ga_len++] = parg;
|
||||
}
|
||||
|
||||
// 'flags' is intended to be a sequence of cscope tokens
|
||||
// like "-q -i somefile"; split it the same way as prog.
|
||||
if (csinfo[i].flags != NULL)
|
||||
{
|
||||
if (build_argv_from_string((char_u *)csinfo[i].flags,
|
||||
&tok, &tokc) == FAIL)
|
||||
exit(EXIT_FAILURE);
|
||||
for (int k = 0; k < tokc; ++k)
|
||||
{
|
||||
if (ga_grow(&ga_argv, 1) == FAIL)
|
||||
exit(EXIT_FAILURE);
|
||||
((char **)ga_argv.ga_data)[ga_argv.ga_len++] = tok[k];
|
||||
}
|
||||
vim_free(tok);
|
||||
}
|
||||
|
||||
// NULL-terminate argv.
|
||||
if (ga_grow(&ga_argv, 1) == FAIL)
|
||||
exit(EXIT_FAILURE);
|
||||
((char **)ga_argv.ga_data)[ga_argv.ga_len] = NULL;
|
||||
|
||||
vim_free(prog);
|
||||
vim_free(ppath);
|
||||
vim_free(cmd);
|
||||
|
||||
# if defined(UNIX)
|
||||
# if defined(HAVE_SETSID) || defined(HAVE_SETPGID)
|
||||
// Change our process group to avoid cscope receiving SIGWINCH.
|
||||
// Change our process group to avoid cscope receiving SIGWINCH.
|
||||
# if defined(HAVE_SETSID)
|
||||
(void)setsid();
|
||||
(void)setsid();
|
||||
# else
|
||||
if (setpgid(0, 0) == -1)
|
||||
PERROR(_("cs_create_connection setpgid failed"));
|
||||
if (setpgid(0, 0) == -1)
|
||||
PERROR(_("cs_create_connection setpgid failed"));
|
||||
# endif
|
||||
# endif
|
||||
if (build_argv_from_string((char_u *)cmd, &argv, &argc) == FAIL)
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
if (execvp(argv[0], argv) == -1)
|
||||
PERROR(_("cs_create_connection exec failed"));
|
||||
argv = (char **)ga_argv.ga_data;
|
||||
if (argv[0] == NULL || execvp(argv[0], argv) == -1)
|
||||
{
|
||||
fprintf(stderr, "%s\n",
|
||||
_("cs_create_connection exec failed"));
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
exit(127);
|
||||
// NOTREACHED
|
||||
exit(127);
|
||||
// NOTREACHED
|
||||
}
|
||||
}
|
||||
else // parent.
|
||||
{
|
||||
@@ -1016,6 +1060,19 @@ err_closing:
|
||||
}
|
||||
# else
|
||||
// MSWIN
|
||||
vim_snprintf(cmd, cmdlen, "%s -dl -f %s", prog, csinfo[i].fname);
|
||||
if (csinfo[i].ppath != NULL)
|
||||
{
|
||||
len = (int)STRLEN(cmd);
|
||||
vim_snprintf(cmd + len, cmdlen - len, " -P%s", csinfo[i].ppath);
|
||||
}
|
||||
if (csinfo[i].flags != NULL)
|
||||
{
|
||||
len = (int)STRLEN(cmd);
|
||||
vim_snprintf(cmd + len, cmdlen - len, " %s", csinfo[i].flags);
|
||||
}
|
||||
vim_free(ppath);
|
||||
|
||||
// Create a new process to run cscope and use pipes to talk with it
|
||||
GetStartupInfo(&si);
|
||||
si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
|
||||
|
||||
@@ -288,6 +288,13 @@ func Test_cscopeWithCscopeConnections()
|
||||
|
||||
call assert_equal(cscope_connection(5, 'out'), 0)
|
||||
call assert_equal(cscope_connection(-1, 'out'), 0)
|
||||
cscope kill -1
|
||||
|
||||
" Test: cscope file with shell meta chars
|
||||
call writefile([], 'Xcscope2.out`id>Xid`', 'D')
|
||||
call assert_fails('cscope add Xcscope2.out`id>Xid`', 'E609:')
|
||||
call assert_false(filereadable('Xid'))
|
||||
cscope kill -1
|
||||
|
||||
call CscopeSetupOrClean(0)
|
||||
endfunc
|
||||
|
||||
@@ -729,6 +729,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
434,
|
||||
/**/
|
||||
433,
|
||||
/**/
|
||||
|
||||
Reference in New Issue
Block a user