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

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