Blame SOURCES/ctags-CVE-2022-4515.patch

051ffd
commit 2b7cd725d0612f13eb5a461778ca525cd489119b
051ffd
Author: Masatake YAMATO <yamato@redhat.com>
051ffd
Date:   Tue Dec 13 05:16:00 2022 +0900
051ffd
051ffd
    main: quote output file name before passing it to system(3) function
051ffd
    
051ffd
    Following command line doesn't work:
051ffd
    
051ffd
          $ ctags -o 'a b' ...
051ffd
    
051ffd
    because a shell lauched from system(3) deals a whitespace between 'a'
051ffd
    and 'b' as a separator. The output file name is passed to system(3)
051ffd
    to run external sort command.
051ffd
    
051ffd
    This commit adds code to put double and single quoets around the output
051ffd
    file name before passing it to system(3).
051ffd
    
051ffd
    The issue is reported by Lorenz Hipp <lhipp@idealbonn.de> in a private mail.
051ffd
    
051ffd
    This commit is based on e00c55d7a0204dc1d0ae316141323959e1e16162 of
051ffd
    Universal Ctags <https://github.com/universal-ctags/ctags>.
051ffd
    
051ffd
    An example session of RHEL8:
051ffd
    
051ffd
      [yamato@control]/tmp/ctags-5.8% git clone ssh://git@gitlab.consulting.redhat.com:2222/yamato/temp-test.git
051ffd
      Cloning into 'temp-test'...
051ffd
      Enter passphrase for key '/home/yamato/.ssh/id_rsa':
051ffd
      remote: Enumerating objects: 4, done.
051ffd
      remote: Counting objects: 100% (4/4), done.
051ffd
      remote: Compressing objects: 100% (4/4), done.
051ffd
      remote: Total 4 (delta 0), reused 0 (delta 0), pack-reused 0
051ffd
      Receiving objects: 100% (4/4), done.
051ffd
      [yamato@control]/tmp/ctags-5.8% cd temp-test
051ffd
      [yamato@control]/tmp/ctags-5.8/temp-test% ls -l ~/.ctags
051ffd
      ls: cannot access '/home/yamato/.ctags': No such file or directory
051ffd
      [yamato@control]/tmp/ctags-5.8/temp-test% ../ctags hello.c
051ffd
      [yamato@control]/tmp/ctags-5.8/temp-test% ls
051ffd
       hello.c  'tags tags; echo Hi $(id -un), your systems is cracked!'
051ffd
      [yamato@control]/tmp/ctags-5.8/temp-test% valgrind ../ctags hello.c
051ffd
      ==2076943== Memcheck, a memory error detector
051ffd
      ==2076943== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
051ffd
      ==2076943== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
051ffd
      ==2076943== Command: ../ctags hello.c
051ffd
      ==2076943==
051ffd
      ==2076943==
051ffd
      ==2076943== HEAP SUMMARY:
051ffd
      ==2076943==     in use at exit: 0 bytes in 0 blocks
051ffd
      ==2076943==   total heap usage: 5,048 allocs, 5,048 frees, 365,311 bytes allocated
051ffd
      ==2076943==
051ffd
      ==2076943== All heap blocks were freed -- no leaks are possible
051ffd
      ==2076943==
051ffd
      ==2076943== For lists of detected and suppressed errors, rerun with: -s
051ffd
      ==2076943== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
051ffd
    
051ffd
    Signed-off-by: Masatake YAMATO <yamato@redhat.com>
051ffd
051ffd
diff --git a/sort.c b/sort.c
051ffd
index 09ba87a..fd60a94 100644
051ffd
--- a/sort.c
051ffd
+++ b/sort.c
051ffd
@@ -53,17 +53,44 @@ extern void catFile (const char *const name)
051ffd
 # define PE_CONST const
051ffd
 #endif
051ffd
 
051ffd
+/*
051ffd
+   Output file name should not be evaluated in system(3) function.
051ffd
+   The name must be used as is. Quotations are required to block the
051ffd
+   evaluation.
051ffd
+
051ffd
+   Normal single-quotes are used to quote a cstring:
051ffd
+   a => 'a'
051ffd
+   " => '"'
051ffd
+
051ffd
+   If a single-quote is included in the cstring, use double quotes for quoting it.
051ffd
+   ' => ''"'"''
051ffd
+*/
051ffd
+static void appendCstringWithQuotes (vString *dest, const char* cstr)
051ffd
+{
051ffd
+	const char* o;
051ffd
+
051ffd
+	vStringPut (dest, '\'');
051ffd
+	for (o = cstr; *o; o++)
051ffd
+	{
051ffd
+		if (*o == '\'')
051ffd
+			vStringCatS (dest, "'\"'\"'");
051ffd
+		else
051ffd
+			vStringPut (dest, *o);
051ffd
+	}
051ffd
+	vStringPut (dest, '\'');
051ffd
+}
051ffd
+
051ffd
 extern void externalSortTags (const boolean toStdout)
051ffd
 {
051ffd
 	const char *const sortNormalCommand = "sort -u -o";
051ffd
 	const char *const sortFoldedCommand = "sort -u -f -o";
051ffd
 	const char *sortCommand =
051ffd
 		Option.sorted == SO_FOLDSORTED ? sortFoldedCommand : sortNormalCommand;
051ffd
+# ifndef HAVE_SETENV
051ffd
 	PE_CONST char *const sortOrder1 = "LC_COLLATE=C";
051ffd
 	PE_CONST char *const sortOrder2 = "LC_ALL=C";
051ffd
-	const size_t length = 4 + strlen (sortOrder1) + strlen (sortOrder2) +
051ffd
-			strlen (sortCommand) + (2 * strlen (tagFileName ()));
051ffd
-	char *const cmd = (char *) malloc (length + 1);
051ffd
+# endif
051ffd
+	vString *cmd = vStringNew ();
051ffd
 	int ret = -1;
051ffd
 
051ffd
 	if (cmd != NULL)
051ffd
@@ -73,20 +100,35 @@ extern void externalSortTags (const boolean toStdout)
051ffd
 #ifdef HAVE_SETENV
051ffd
 		setenv ("LC_COLLATE", "C", 1);
051ffd
 		setenv ("LC_ALL", "C", 1);
051ffd
-		sprintf (cmd, "%s %s %s", sortCommand, tagFileName (), tagFileName ());
051ffd
+		vStringCatS (cmd, sortCommand);
051ffd
+		vStringPut (cmd, ' ');
051ffd
+		appendCstringWithQuotes (cmd, tagFileName ());
051ffd
+		vStringPut (cmd, ' ');
051ffd
+		appendCstringWithQuotes (cmd, tagFileName ());
051ffd
 #else
051ffd
 # ifdef HAVE_PUTENV
051ffd
 		putenv (sortOrder1);
051ffd
 		putenv (sortOrder2);
051ffd
-		sprintf (cmd, "%s %s %s", sortCommand, tagFileName (), tagFileName ());
051ffd
+		vStringCatS (cmd, sortCommand);
051ffd
+		vStringPut (cmd, ' ');
051ffd
+		appendCstringWithQuotes (cmd, tagFileName ());
051ffd
+		vStringPut (cmd, ' ');
051ffd
+		appendCstringWithQuotes (cmd, tagFileName ());
051ffd
 # else
051ffd
-		sprintf (cmd, "%s %s %s %s %s", sortOrder1, sortOrder2, sortCommand,
051ffd
-				tagFileName (), tagFileName ());
051ffd
+		vStringCatS (cmd, sortOrder1);
051ffd
+		vStringPut (cmd, ' ');
051ffd
+		vStringCatS (cmd, sortOrder2);
051ffd
+		vStringPut (cmd, ' ');
051ffd
+		vStringCatS (cmd, sortCommand);
051ffd
+		vStringPut (cmd, ' ');
051ffd
+		appendCstringWithQuotes (cmd, tagFileName ());
051ffd
+		vStringPut (cmd, ' ');
051ffd
+		appendCstringWithQuotes (cmd, tagFileName ());
051ffd
 # endif
051ffd
 #endif
051ffd
-		verbose ("system (\"%s\")\n", cmd);
051ffd
-		ret = system (cmd);
051ffd
-		free (cmd);
051ffd
+		verbose ("system (\"%s\")\n", vStringValue (cmd));
051ffd
+		ret = system (vStringValue (cmd));
051ffd
+		vStringDelete (cmd);
051ffd
 
051ffd
 	}
051ffd
 	if (ret != 0)
051ffd