[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

ctags(1) command execution vulnerability



On Tue, May 04, 2004 at 09:49:09AM +0400, Roman Bogorodskiy wrote:
> Hello,
> 
> 	ctags(1) uses external application sort(1) for sorting the tags file.
> It calls it via system(3) function. 
[snip]
> This code will be executed when "-u" arg was given. So, if we'll execute 
> ctags in a such way:
> 
> ctags -u -f ';echo hi' *.c
[snip]
> -					    "mv %s OTAGS; fgrep -v '\t%s\t' OTAGS >%s; rm OTAGS",
> +					    "mv '%s' OTAGS; fgrep -v '\t%s\t' OTAGS >'%s'; rm OTAGS",
[snip]
> -				(void)asprintf(&cmd, "sort -o %s %s",
> +				(void)asprintf(&cmd, "sort -o '%s' '%s'",

Unfortunately, this is still not a complete solution; the following
still works, at least for me:

  ctags -u -f "'; echo hi; '" *.c

Filtering the filename characters would be a better idea; possibly
something like the attached patch.

G'luck,
Peter

-- 
Peter Pentchev	roam_(_at_)_ringlet_(_dot_)_net    roam_(_at_)_sbnd_(_dot_)_net    roam_(_at_)_FreeBSD_(_dot_)_org
PGP key:	http://people.FreeBSD.org/~roam/roam.key.asc
Key fingerprint	FDBA FD79 C26F 3C51 C95E  DF9E ED18 B68D 1619 4553
This sentence contradicts itself - or rather - well, no, actually it doesn't!

Index: src/usr.bin/ctags/ctags.c
===================================================================
RCS file: /home/ncvs/src/usr.bin/ctags/ctags.c,v
retrieving revision 1.18
diff -u -r1.18 ctags.c
--- src/usr.bin/ctags/ctags.c	28 Jul 2002 15:50:38 -0000	1.18
+++ src/usr.bin/ctags/ctags.c	4 May 2004 06:27:23 -0000
@@ -46,6 +46,7 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD: src/usr.bin/ctags/ctags.c,v 1.18 2002/07/28 15:50:38 dwmalone Exp $");
 
+#include <ctype.h>
 #include <err.h>
 #include <limits.h>
 #include <locale.h>
@@ -84,6 +85,7 @@
 void	init(void);
 void	find_entries(char *);
 static void usage(void);
+static char	*validatename(const char *);
 
 int
 main(int argc, char **argv)
@@ -118,7 +120,7 @@
 			dflag++;
 			break;
 		case 'f':
-			outfile = optarg;
+			outfile = validatename(optarg);
 			break;
 		case 't':
 			tflag = YES;
@@ -201,6 +203,25 @@
 	exit(1);
 }
 
+static char *
+validatename(const char *fname)
+{
+	char *n, *q;
+	const char *p, *end;
+	size_t len;
+
+	len = strlen(fname);
+	n = malloc(len + 1);
+	if (n == NULL)
+		errx(1, "out of memory");
+	end = n + len;
+	for (p = fname, q = n; *p != '\0' && q != end; p++)
+		if (isalnum(*p) || strchr("-_./", *p) != NULL)
+			*q++ = *p;
+	*q = '\0';
+	return (n);
+}
+
 /*
  * init --
  *	this routine sets up the boolean pseudo-functions which work by
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 187 bytes
Desc: not available
Url : http://lists.freebsd.org/pipermail/freebsd-security/attachments/20040504/6c3d5a0c/attachment.bin