From 3ba143533d74d4caf59a192de6cab4a130140ce7 Mon Sep 17 00:00:00 2001 From: lu4nx Date: Tue, 6 Dec 2022 15:42:40 +0800 Subject: [PATCH] Fix etags local command injection vulnerability * lib-src/etags.c: (escape_shell_arg_string): New function. --- lib-src/etags.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 56 insertions(+), 2 deletions(-) diff --git a/lib-src/etags.c b/lib-src/etags.c index d1d20858cd..c3ecbc2221 100644 --- a/lib-src/etags.c +++ b/lib-src/etags.c @@ -401,6 +401,7 @@ #define xrnew(op, n, m) ((op) = xnrealloc (op, n, (m) * sizeof *(op))) 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 *); @@ -1716,8 +1717,12 @@ process_file_name (char *file, language *lang) char *cmd1 = concat (compr->command, " \"", real_name); char *cmd = concat (cmd1, "\" > ", 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); + char *cmd1 = concat (compr->command, " ", new_real_name); + char *cmd = concat (cmd1, " > ", new_tmp_name); + free (new_real_name); + free (new_tmp_name); #endif free (cmd1); inf = (system (cmd) == -1 @@ -7707,6 +7712,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) { -- 2.38.1