aboutsummaryrefslogtreecommitdiffstats
path: root/lib-src
diff options
context:
space:
mode:
authorlu4nx2022-12-06 15:42:40 +0800
committerEli Zaretskii2022-12-06 18:07:45 +0200
commit01a4035c869b91c153af9a9132c87adb7669ea1c (patch)
tree16fc8c5c285a51e3b360de5955c76d437486a4e3 /lib-src
parented4734405dfbe26d3da7cedc4e4cd599618bf6ee (diff)
downloademacs-01a4035c869b91c153af9a9132c87adb7669ea1c.tar.gz
emacs-01a4035c869b91c153af9a9132c87adb7669ea1c.zip
Fix etags local command injection vulnerability
* 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)
Diffstat (limited to 'lib-src')
-rw-r--r--lib-src/etags.c63
1 files changed, 58 insertions, 5 deletions
diff --git a/lib-src/etags.c b/lib-src/etags.c
index d1d20858cdd..ba0092cc637 100644
--- a/lib-src/etags.c
+++ b/lib-src/etags.c
@@ -401,6 +401,7 @@ static void invalidate_nodes (fdesc *, node **);
401static void put_entries (node *); 401static void put_entries (node *);
402static void cleanup_tags_file (char const * const, char const * const); 402static void cleanup_tags_file (char const * const, char const * const);
403 403
404static char *escape_shell_arg_string (char *);
404static void do_move_file (const char *, const char *); 405static void do_move_file (const char *, const char *);
405static char *concat (const char *, const char *, const char *); 406static char *concat (const char *, const char *, const char *);
406static char *skip_spaces (char *); 407static char *skip_spaces (char *);
@@ -1713,13 +1714,16 @@ process_file_name (char *file, language *lang)
1713 else 1714 else
1714 { 1715 {
1715#if MSDOS || defined (DOS_NT) 1716#if MSDOS || defined (DOS_NT)
1716 char *cmd1 = concat (compr->command, " \"", real_name); 1717 int buf_len = strlen (compr->command) + strlen (" \"\" > \"\"") + strlen (real_name) + strlen (tmp_name) + 1;
1717 char *cmd = concat (cmd1, "\" > ", tmp_name); 1718 char *cmd = xmalloc (buf_len);
1719 snprintf (cmd, buf_len, "%s \"%s\" > \"%s\"", compr->command, real_name, tmp_name);
1718#else 1720#else
1719 char *cmd1 = concat (compr->command, " '", real_name); 1721 char *new_real_name = escape_shell_arg_string (real_name);
1720 char *cmd = concat (cmd1, "' > ", tmp_name); 1722 char *new_tmp_name = escape_shell_arg_string (tmp_name);
1723 int buf_len = strlen (compr->command) + strlen (" > ") + strlen (new_real_name) + strlen (new_tmp_name) + 1;
1724 char *cmd = xmalloc (buf_len);
1725 snprintf (cmd, buf_len, "%s %s > %s", compr->command, new_real_name, new_tmp_name);
1721#endif 1726#endif
1722 free (cmd1);
1723 inf = (system (cmd) == -1 1727 inf = (system (cmd) == -1
1724 ? NULL 1728 ? NULL
1725 : fopen (tmp_name, "r" FOPEN_BINARY)); 1729 : fopen (tmp_name, "r" FOPEN_BINARY));
@@ -7707,6 +7711,55 @@ etags_mktmp (void)
7707 return templt; 7711 return templt;
7708} 7712}
7709 7713
7714/*
7715 * Adds single quotes around a string, if found single quotes, escaped it.
7716 * Return a newly-allocated string.
7717 *
7718 * For example:
7719 * escape_shell_arg_string("test.txt") => 'test.txt'
7720 * escape_shell_arg_string("'test.txt") => ''\''test.txt'
7721 */
7722static char *
7723escape_shell_arg_string (char *str)
7724{
7725 char *p = str;
7726 int need_space = 2; /* ' at begin and end */
7727
7728 while (*p != '\0')
7729 {
7730 if (*p == '\'')
7731 need_space += 4; /* ' to '\'', length is 4 */
7732 else
7733 need_space++;
7734
7735 p++;
7736 }
7737
7738 char *new_str = xnew (need_space + 1, char);
7739 new_str[0] = '\'';
7740 new_str[need_space-1] = '\'';
7741
7742 int i = 1; /* skip first byte */
7743 p = str;
7744 while (*p != '\0')
7745 {
7746 new_str[i] = *p;
7747 if (*p == '\'')
7748 {
7749 new_str[i+1] = '\\';
7750 new_str[i+2] = '\'';
7751 new_str[i+3] = '\'';
7752 i += 3;
7753 }
7754
7755 i++;
7756 p++;
7757 }
7758
7759 new_str[need_space] = '\0';
7760 return new_str;
7761}
7762
7710static void 7763static void
7711do_move_file(const char *src_file, const char *dst_file) 7764do_move_file(const char *src_file, const char *dst_file)
7712{ 7765{