ports/70618: print/a2ps-* using "file -L %s" as shell argument --> dangerous to use it in world-writable directories
Rudolf Polzer
freebsd-dr at durchnull.de
Wed Aug 18 15:20:27 UTC 2004
>Number: 70618
>Category: ports
>Synopsis: print/a2ps-* using "file -L %s" as shell argument --> dangerous to use it in world-writable directories
>Confidential: no
>Severity: critical
>Priority: high
>Responsible: freebsd-ports-bugs
>State: open
>Quarter:
>Keywords:
>Date-Required:
>Class: sw-bug
>Submitter-Id: current-users
>Arrival-Date: Wed Aug 18 15:20:26 GMT 2004
>Closed-Date:
>Last-Modified:
>Originator: Rudolf Polzer
>Release: FreeBSD 5.2.1-RELEASE-p9 i386
>Organization:
>Environment:
System: FreeBSD katsuragi.durchnull.ath.cx 5.2.1-RELEASE-p9 FreeBSD 5.2.1-RELEASE-p9 #19: Thu Jul 1 11:20:21 CEST 2004 root at katsuragi.durchnull.ath.cx:/usr/src/sys/i386/compile/DIV0_KERNEL i386
>Description:
a2ps builds a command line for file() containing an unescaped version of
the file name, thus might call external programs described by the file name.
Running a cronjob over a public writable directory a2ps-ing all files in it
- or simply typing "a2ps *.txt" in /tmp - is therefore dangerous.
>How-To-Repeat:
rpolzer:/tmp 7> touch 'x`echo>&2 42`'
rpolzer:/tmp 8> a2ps -o /dev/null 'x`echo>&2 42`'
42
[x`echo>&2 42` (plain): 0 pages on 0 sheets]
[Total: 0 pages on 0 sheets] saved into the file `/dev/null'
>Fix:
Apply this patch (can be directly put into files/):
diff -ru ../a2ps-4.13.orig/src/select.c ./src/select.c
--- ../a2ps-4.13.orig/src/select.c Wed Aug 18 16:32:09 2004
+++ ./src/select.c Wed Aug 18 16:49:12 2004
@@ -131,6 +131,36 @@
return 1;
}
+/* escapes the name of a file so that the shell groks it in 'single' q.marks.
+ The resulting pointer has to be free()ed when not longer used. */
+char *
+shell_escape(const char *fn)
+{
+ size_t len = 0;
+ const char *inp;
+ char *retval, *outp;
+
+ for(inp = fn; *inp; ++inp)
+ switch(*inp)
+ {
+ case '\'': len += 4; break;
+ default: len += 1; break;
+ }
+
+ outp = retval = malloc(len + 1);
+ if(!outp)
+ return ""; /* perhaps one should do better error handling here */
+ for(inp = fn; *inp; ++inp)
+ switch(*inp)
+ {
+ case '\'': *outp++ = '\''; *outp++ = '\\'; *outp++ = '\'', *outp++ = '\''; break;
+ default: *outp++ = *inp; break;
+ }
+ *outp = 0;
+
+ return retval;
+}
+
/* What says file about the type of a file (result is malloc'd). NULL
if could not be run. */
@@ -144,11 +174,13 @@
if (IS_EMPTY (job->file_command))
return NULL;
+ filename = shell_escape(filename);
/* Call file(1) with the correct option */
- command = ALLOCA (char, (2
+ command = ALLOCA (char, (4
+ strlen (job->file_command)
+ ustrlen (filename)));
- sprintf (command, "%s %s", job->file_command, (const char *) filename);
+ sprintf (command, "%s '%s'", job->file_command, (const char *) filename);
+ free(filename);
message (msg_tool, (stderr, "Reading pipe: `%s'\n", command));
file_out = popen (command, "r");
>Release-Note:
>Audit-Trail:
>Unformatted:
More information about the freebsd-ports-bugs
mailing list