diff options
| author | lu4nx | 2022-12-06 15:42:40 +0800 |
|---|---|---|
| committer | Eli Zaretskii | 2022-12-06 18:07:45 +0200 |
| commit | 01a4035c869b91c153af9a9132c87adb7669ea1c (patch) | |
| tree | 16fc8c5c285a51e3b360de5955c76d437486a4e3 /lib-src | |
| parent | ed4734405dfbe26d3da7cedc4e4cd599618bf6ee (diff) | |
| download | emacs-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.c | 63 |
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 **); | |||
| 401 | static void put_entries (node *); | 401 | static void put_entries (node *); |
| 402 | static void cleanup_tags_file (char const * const, char const * const); | 402 | static void cleanup_tags_file (char const * const, char const * const); |
| 403 | 403 | ||
| 404 | static char *escape_shell_arg_string (char *); | ||
| 404 | static void do_move_file (const char *, const char *); | 405 | static void do_move_file (const char *, const char *); |
| 405 | static char *concat (const char *, const char *, const char *); | 406 | static char *concat (const char *, const char *, const char *); |
| 406 | static char *skip_spaces (char *); | 407 | static 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 | */ | ||
| 7722 | static char * | ||
| 7723 | escape_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 | |||
| 7710 | static void | 7763 | static void |
| 7711 | do_move_file(const char *src_file, const char *dst_file) | 7764 | do_move_file(const char *src_file, const char *dst_file) |
| 7712 | { | 7765 | { |