diff --git a/backport-CVE-2022-45939.patch b/backport-CVE-2022-45939.patch new file mode 100644 index 0000000000000000000000000000000000000000..1287403a8bab2960904338374b9a728d5ebb0a0e --- /dev/null +++ b/backport-CVE-2022-45939.patch @@ -0,0 +1,272 @@ +From d48bb4874bc6cd3e69c7a15fc3c91cc141025c51 Mon Sep 17 00:00:00 2001 +From: lu4nx +Date: Fri, 25 Nov 2022 14:38:29 +0800 +Subject: Fixed ctags local command execute vulnerability + +* lib-src/etags.c: + +(clean_matched_file_tag): New function +(do_move_file): New function +(readline_internal): +Add `leave_cr` parameter, if true, include the \r character + +* test/manual/etags/CTAGS.good_crlf: New file +* test/manual/etags/CTAGS.good_update: New file +* test/manual/etags/crlf: New file +* test/manual/etags/Makefile: Add `ctags -u` test cases + +Conflict:Removed test case related code, so the patch is over 9000 lines, it's too big +Reference:https://git.savannah.gnu.org/cgit/emacs.git/commit/?id=d48bb4874bc6cd3e69c7a15fc3c91cc141025c51 +--- + lib-src/etags.c | 149 +- + 1 files changed, 113 insertions(+), 36 deletions(-) + +diff --git a/lib-src/etags.c b/lib-src/etags.c +index 3107c7b..b6f51df 100644 +--- a/lib-src/etags.c ++++ b/lib-src/etags.c +@@ -375,7 +375,7 @@ static void just_read_file (FILE *); + + static language *get_language_from_langname (const char *); + static void readline (linebuffer *, FILE *); +-static ptrdiff_t readline_internal (linebuffer *, FILE *, char const *); ++static ptrdiff_t readline_internal (linebuffer *, FILE *, char const *, const bool); + static bool nocase_tail (const char *); + static void get_tag (char *, char **); + static void get_lispy_tag (char *); +@@ -399,7 +399,9 @@ static void free_fdesc (fdesc *); + static void pfnote (char *, bool, char *, ptrdiff_t, intmax_t, intmax_t); + static void invalidate_nodes (fdesc *, node **); + static void put_entries (node *); ++static void clean_matched_file_tag (char const * const, char const * const); + ++static void do_move_file (const char *, const char *); + static char *concat (const char *, const char *, const char *); + static char *skip_spaces (char *); + static char *skip_non_spaces (char *); +@@ -1332,7 +1334,7 @@ main (int argc, char **argv) + if (parsing_stdin) + fatal ("cannot parse standard input " + "AND read file names from it"); +- while (readline_internal (&filename_lb, stdin, "-") > 0) ++ while (readline_internal (&filename_lb, stdin, "-", false) > 0) + process_file_name (filename_lb.buffer, lang); + } + else +@@ -1380,9 +1382,6 @@ main (int argc, char **argv) + /* From here on, we are in (CTAGS && !cxref_style) */ + if (update) + { +- char *cmd = +- xmalloc (strlen (tagfile) + whatlen_max + +- sizeof "mv..OTAGS;grep -Fv '\t\t' OTAGS >;rm OTAGS"); + for (i = 0; i < current_arg; ++i) + { + switch (argbuffer[i].arg_type) +@@ -1393,17 +1392,8 @@ main (int argc, char **argv) + default: + continue; /* the for loop */ + } +- char *z = stpcpy (cmd, "mv "); +- z = stpcpy (z, tagfile); +- z = stpcpy (z, " OTAGS;grep -Fv '\t"); +- z = stpcpy (z, argbuffer[i].what); +- z = stpcpy (z, "\t' OTAGS >"); +- z = stpcpy (z, tagfile); +- strcpy (z, ";rm OTAGS"); +- if (system (cmd) != EXIT_SUCCESS) +- fatal ("failed to execute shell command"); ++ clean_matched_file_tag (tagfile, argbuffer[i].what); + } +- free (cmd); + append_to_tagfile = true; + } + +@@ -1448,6 +1438,51 @@ main (int argc, char **argv) + return EXIT_SUCCESS; + } + ++/* ++ * Equivalent to: mv tags OTAGS;grep -Fv ' filename ' OTAGS >tags;rm OTAGS ++ */ ++static void ++clean_matched_file_tag (const char* tagfile, const char* match_file_name) ++{ ++ FILE *otags_f = fopen ("OTAGS", "wb"); ++ FILE *tag_f = fopen (tagfile, "rb"); ++ ++ if (otags_f == NULL) ++ pfatal ("OTAGS"); ++ ++ if (tag_f == NULL) ++ pfatal (tagfile); ++ ++ int buf_len = strlen (match_file_name) + sizeof ("\t\t ") + 1; ++ char *buf = xmalloc (buf_len); ++ snprintf (buf, buf_len, "\t%s\t", match_file_name); ++ ++ linebuffer line; ++ linebuffer_init (&line); ++ while (readline_internal (&line, tag_f, tagfile, true) > 0) ++ { ++ if (ferror (tag_f)) ++ pfatal (tagfile); ++ ++ if (strstr (line.buffer, buf) == NULL) ++ { ++ fprintf (otags_f, "%s\n", line.buffer); ++ if (ferror (tag_f)) ++ pfatal (tagfile); ++ } ++ } ++ free (buf); ++ free (line.buffer); ++ ++ if (fclose (otags_f) == EOF) ++ pfatal ("OTAGS"); ++ ++ if (fclose (tag_f) == EOF) ++ pfatal (tagfile); ++ ++ do_move_file ("OTAGS", tagfile); ++ return; ++} + + /* + * Return a compressor given the file name. If EXTPTR is non-zero, +@@ -1831,7 +1866,7 @@ find_entries (FILE *inf) + + /* Else look for sharp-bang as the first two characters. */ + if (parser == NULL +- && readline_internal (&lb, inf, infilename) > 0 ++ && readline_internal (&lb, inf, infilename, false) > 0 + && lb.len >= 2 + && lb.buffer[0] == '#' + && lb.buffer[1] == '!') +@@ -6878,7 +6913,7 @@ analyze_regex (char *regex_arg) + if (regexfp == NULL) + pfatal (regexfile); + linebuffer_init (®exbuf); +- while (readline_internal (®exbuf, regexfp, regexfile) > 0) ++ while (readline_internal (®exbuf, regexfp, regexfile, false) > 0) + analyze_regex (regexbuf.buffer); + free (regexbuf.buffer); + if (fclose (regexfp) != 0) +@@ -7226,11 +7261,13 @@ get_lispy_tag (register char *bp) + + /* + * Read a line of text from `stream' into `lbp', excluding the +- * newline or CR-NL, if any. Return the number of characters read from +- * `stream', which is the length of the line including the newline. ++ * newline or CR-NL (if `leave_cr` is false), if any. Return the ++ * number of characters read from `stream', which is the length ++ * of the line including the newline. + * +- * On DOS or Windows we do not count the CR character, if any before the +- * NL, in the returned length; this mirrors the behavior of Emacs on those ++ * On DOS or Windows, if `leave_cr` is false, we do not count the ++ * CR character, if any before the NL, in the returned length; ++ * this mirrors the behavior of Emacs on those + * platforms (for text files, it translates CR-NL to NL as it reads in the + * file). + * +@@ -7238,7 +7275,7 @@ get_lispy_tag (register char *bp) + * appended to `filebuf'. + */ + static ptrdiff_t +-readline_internal (linebuffer *lbp, FILE *stream, char const *filename) ++readline_internal (linebuffer *lbp, FILE *stream, char const *filename, const bool leave_cr) + { + char *buffer = lbp->buffer; + char *p = lbp->buffer; +@@ -7268,19 +7305,19 @@ readline_internal (linebuffer *lbp, FILE *stream, char const *filename) + break; + } + if (c == '\n') +- { +- if (p > buffer && p[-1] == '\r') +- { +- p -= 1; +- chars_deleted = 2; +- } +- else +- { +- chars_deleted = 1; +- } +- *p = '\0'; +- break; +- } ++ { ++ if (!leave_cr && p > buffer && p[-1] == '\r') ++ { ++ p -= 1; ++ chars_deleted = 2; ++ } ++ else ++ { ++ chars_deleted = 1; ++ } ++ *p = '\0'; ++ break; ++ } + *p++ = c; + } + lbp->len = p - buffer; +@@ -7311,7 +7348,7 @@ static void + readline (linebuffer *lbp, FILE *stream) + { + linecharno = charno; /* update global char number of line start */ +- ptrdiff_t result = readline_internal (lbp, stream, infilename); ++ ptrdiff_t result = readline_internal (lbp, stream, infilename, false); + lineno += 1; /* increment global line number */ + charno += result; /* increment global char number */ + +@@ -7669,6 +7706,46 @@ etags_mktmp (void) + return templt; + } + ++static void ++do_move_file(const char *src_file, const char *dst_file) ++{ ++ if (rename (src_file, dst_file) == 0) ++ return; ++ ++ FILE *src_f = fopen (src_file, "rb"); ++ FILE *dst_f = fopen (dst_file, "wb"); ++ ++ if (src_f == NULL) ++ pfatal (src_file); ++ ++ if (dst_f == NULL) ++ pfatal (dst_file); ++ ++ int c; ++ while ((c = fgetc (src_f)) != EOF) ++ { ++ if (ferror (src_f)) ++ pfatal (src_file); ++ ++ if (ferror (dst_f)) ++ pfatal (dst_file); ++ ++ if (fputc (c, dst_f) == EOF) ++ pfatal ("cannot write"); ++ } ++ ++ if (fclose (src_f) == EOF) ++ pfatal (src_file); ++ ++ if (fclose (dst_f) == EOF) ++ pfatal (dst_file); ++ ++ if (unlink (src_file) == -1) ++ pfatal ("unlink error"); ++ ++ return; ++} ++ + /* Return a newly allocated string containing the file name of FILE + relative to the absolute directory DIR (which should end with a slash). */ + static char * +-- +cgit v1.1 diff --git a/emacs.spec b/emacs.spec index 6fe8250422afa988131422009f344095d890583b..76b559c0d0d006ac5c34b580b94771cfd4eb3ff0 100644 --- a/emacs.spec +++ b/emacs.spec @@ -4,7 +4,7 @@ Name: emacs Epoch: 1 Version: 27.1 -Release: 6 +Release: 7 Summary: An extensible GNU text editor License: GPLv3+ and CC0-1.0 URL: http://www.gnu.org/software/emacs @@ -20,6 +20,7 @@ Source8: %{name}.appdata.xml Patch1: emacs-spellchecker.patch Patch2: emacs-system-crypto-policies.patch +Patch6000: backport-CVE-2022-45939.patch BuildRequires: gcc atk-devel cairo-devel freetype-devel fontconfig-devel dbus-devel giflib-devel BuildRequires: glibc-devel zlib-devel gnutls-devel libselinux-devel GConf2-devel alsa-lib-devel @@ -397,6 +398,9 @@ fi %{_mandir}/*/* %changelog +* Thu Dec 01 2022 wangkerong - 1:27.1-7 +- fix CVE-2022-45939 + * Mon Aug 9 2021 yangcheng - 1:27.1-6 - fixed the upgrade error caused by the info file in the emacs-common software package being repackaged