Skip to content

Commit

Permalink
Fix etags local command injection vulnerability
Browse files Browse the repository at this point in the history
* lib-src/etags.c: (escape_shell_arg_string): New function.
(process_file_name): Use it to quote file names passed to the
shell.  (Bug#59817)
  • Loading branch information
lu4nx authored and Eli-Zaretskii committed Dec 6, 2022
1 parent ed47344 commit 01a4035
Showing 1 changed file with 58 additions and 5 deletions.
63 changes: 58 additions & 5 deletions lib-src/etags.c
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,7 @@ static void invalidate_nodes (fdesc *, node **);
static void put_entries (node *);
static void cleanup_tags_file (char const * const, char const * const);

static char *escape_shell_arg_string (char *);
static void do_move_file (const char *, const char *);
static char *concat (const char *, const char *, const char *);
static char *skip_spaces (char *);
Expand Down Expand Up @@ -1713,13 +1714,16 @@ process_file_name (char *file, language *lang)
else
{
#if MSDOS || defined (DOS_NT)
char *cmd1 = concat (compr->command, " \"", real_name);
char *cmd = concat (cmd1, "\" > ", tmp_name);
int buf_len = strlen (compr->command) + strlen (" \"\" > \"\"") + strlen (real_name) + strlen (tmp_name) + 1;
char *cmd = xmalloc (buf_len);
snprintf (cmd, buf_len, "%s \"%s\" > \"%s\"", compr->command, real_name, tmp_name);
#else
char *cmd1 = concat (compr->command, " '", real_name);
char *cmd = concat (cmd1, "' > ", tmp_name);
char *new_real_name = escape_shell_arg_string (real_name);
char *new_tmp_name = escape_shell_arg_string (tmp_name);
int buf_len = strlen (compr->command) + strlen (" > ") + strlen (new_real_name) + strlen (new_tmp_name) + 1;
char *cmd = xmalloc (buf_len);
snprintf (cmd, buf_len, "%s %s > %s", compr->command, new_real_name, new_tmp_name);
#endif
free (cmd1);
inf = (system (cmd) == -1
? NULL
: fopen (tmp_name, "r" FOPEN_BINARY));
Expand Down Expand Up @@ -7707,6 +7711,55 @@ etags_mktmp (void)
return templt;
}

/*
* Adds single quotes around a string, if found single quotes, escaped it.
* Return a newly-allocated string.
*
* For example:
* escape_shell_arg_string("test.txt") => 'test.txt'
* escape_shell_arg_string("'test.txt") => ''\''test.txt'
*/
static char *
escape_shell_arg_string (char *str)
{
char *p = str;
int need_space = 2; /* ' at begin and end */

while (*p != '\0')
{
if (*p == '\'')
need_space += 4; /* ' to '\'', length is 4 */
else
need_space++;

p++;
}

char *new_str = xnew (need_space + 1, char);
new_str[0] = '\'';
new_str[need_space-1] = '\'';

int i = 1; /* skip first byte */
p = str;
while (*p != '\0')
{
new_str[i] = *p;
if (*p == '\'')
{
new_str[i+1] = '\\';
new_str[i+2] = '\'';
new_str[i+3] = '\'';
i += 3;
}

i++;
p++;
}

new_str[need_space] = '\0';
return new_str;
}

static void
do_move_file(const char *src_file, const char *dst_file)
{
Expand Down

0 comments on commit 01a4035

Please sign in to comment.