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

Bug#555666: CVE-2009-2820: XSS issues



Package: cups
Version: 1.4.1-5
Severity: grave
Tags: security patch

Hi Martin

The recent DSA (DSA-1933-1) fixed a few cross-site scripting issues.
Please include the patch in the unstable/testing distribution.

Cheers
Steffen
diff -u cupsys-1.2.2/debian/changelog cupsys-1.2.2/debian/changelog
--- cupsys-1.2.2/debian/changelog
+++ cupsys-1.2.2/debian/changelog
@@ -1,3 +1,15 @@
+cupsys (1.2.2-0ubuntu0.6.06.15) dapper-security; urgency=low
+
+  * SECURITY UPDATE: XSS and CRLF injection in headers
+    - debian/patches/83_CVE-2009-2820.dpatch: Introduce cgiClearVariables()
+      in cgi-bin/{var.c,cgi.h}. Clear out variables in
+      cgi-bin/{classes,help,ipp-var,jobs,printers}.c. Encode URL string and
+      clear out variables in cgi-bin/admin.c. Filter more characters in
+      cgi-bin/template.c.
+    - CVE-2009-2820
+
+ -- Marc Deslauriers <marc.deslauriers@ubuntu.com>  Fri, 30 Oct 2009 21:40:07 -0400
+
 cupsys (1.2.2-0ubuntu0.6.06.14) dapper-security; urgency=low
 
   * SECURITY UPDATE: Remote denial-of-service via IPP_TAG_UNSUPPORTED tags.
diff -u cupsys-1.2.2/debian/patches/00list cupsys-1.2.2/debian/patches/00list
--- cupsys-1.2.2/debian/patches/00list
+++ cupsys-1.2.2/debian/patches/00list
@@ -39,0 +40 @@
+83_CVE-2009-2820
only in patch2:
unchanged:
--- cupsys-1.2.2.orig/debian/patches/83_CVE-2009-2820.dpatch
+++ cupsys-1.2.2/debian/patches/83_CVE-2009-2820.dpatch
@@ -0,0 +1,409 @@
+#! /bin/sh /usr/share/dpatch/dpatch-run
+## 83_CVE-2009-2820.dpatch by Marc Deslauriers <marc.deslauriers@ubuntu.com>
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: Description: fix XSS and CRLF injection in headers
+## DP: Patch: backported from Aaron Sigel's patch
+
+@DPATCH@
+diff -urNad cupsys-1.2.2~/cgi-bin/admin.c cupsys-1.2.2/cgi-bin/admin.c
+--- cupsys-1.2.2~/cgi-bin/admin.c	2006-05-22 14:47:09.000000000 -0400
++++ cupsys-1.2.2/cgi-bin/admin.c	2009-10-30 21:39:59.000000000 -0400
+@@ -107,6 +107,7 @@
+   */
+ 
+   cgiSetVariable("SECTION", "admin");
++  cgiSetVariable("REFRESH_PAGE", "");
+ 
+  /*
+   * See if we have form data...
+@@ -137,16 +138,61 @@
+ 
+ 
+       if (getenv("HTTPS"))
+-        snprintf(prefix, sizeof(prefix), "https://%s:%s";,
+-	         getenv("SERVER_NAME"), getenv("SERVER_PORT"));
++	snprintf(prefix, sizeof(prefix), "https://%s:%s";,
++		 getenv("SERVER_NAME"), getenv("SERVER_PORT"));
+       else
+-        snprintf(prefix, sizeof(prefix), "http://%s:%s";,
+-	         getenv("SERVER_NAME"), getenv("SERVER_PORT"));
++	snprintf(prefix, sizeof(prefix), "http://%s:%s";,
++		 getenv("SERVER_NAME"), getenv("SERVER_PORT"));
++
++      fprintf(stderr, "DEBUG: redirecting with prefix %s!\n", prefix);
+ 
+       if ((url = cgiGetVariable("URL")) != NULL)
+-        printf("Location: %s%s\n\n", prefix, url);
++      {
++	char	encoded[1024],		/* Encoded URL string */
++		*ptr;			/* Pointer into encoded string */
++
++
++	ptr = encoded;
++	if (*url != '/')
++	  *ptr++ = '/';
++
++	for (; *url && ptr < (encoded + sizeof(encoded) - 4); url ++)
++	{
++	  if (strchr("%@&+ <>#=", *url) || *url < ' ' || *url & 128)
++	  {
++	   /*
++	    * Percent-encode this character; safe because we have at least 4
++	    * bytes left in the array...
++	    */
++
++	    sprintf(ptr, "%%%02X", *url & 255);
++	    ptr += 3;
++	  }
++	  else
++	    *ptr++ = *url;
++	}
++
++	*ptr = '\0';
++
++	if (*url)
++	{
++	 /*
++	  * URL was too long, just redirect to the admin page...
++	  */
++
++	  printf("Location: %s/admin\n\n", prefix);
++	}
++	else
++	{
++	 /*
++	  * URL is OK, redirect there...
++	  */
++
++	  printf("Location: %s%s\n\n", prefix, encoded);
++	}
++      }
+       else
+-        printf("Location: %s/admin\n\n", prefix);
++	printf("Location: %s/admin\n\n", prefix);
+     }
+     else if (!strcmp(op, "start-printer"))
+       do_printer_op(http, IPP_RESUME_PRINTER, cgiText(_("Start Printer")));
+@@ -238,6 +284,7 @@
+   ipp_attribute_t *attr;		/* member-uris attribute */
+   char		uri[HTTP_MAX_URI];	/* Device or printer URI */
+   const char	*name,			/* Pointer to class name */
++		*op,			/* Operation name */
+ 		*ptr;			/* Pointer to CGI variable */
+   const char	*title;			/* Title of page */
+   static const char * const pattrs[] =	/* Requested printer attributes */
+@@ -249,6 +296,7 @@
+ 
+ 
+   title = cgiText(modify ? _("Modify Class") : _("Add Class"));
++  op    = cgiGetVariable("OP");
+   name  = cgiGetVariable("PRINTER_NAME");
+ 
+   if (cgiGetVariable("PRINTER_LOCATION") == NULL)
+@@ -271,6 +319,12 @@
+     * Do the request and get back a response...
+     */
+ 
++    cgiClearVariables();
++    if (op)
++      cgiSetVariable("OP", op);
++    if (name)
++      cgiSetVariable("PRINTER_NAME", name);
++
+     if ((response = cupsDoRequest(http, request, "/")) != NULL)
+     {
+      /*
+diff -urNad cupsys-1.2.2~/cgi-bin/cgi.h cupsys-1.2.2/cgi-bin/cgi.h
+--- cupsys-1.2.2~/cgi-bin/cgi.h	2006-01-14 15:37:40.000000000 -0500
++++ cupsys-1.2.2/cgi-bin/cgi.h	2009-10-30 21:39:46.000000000 -0400
+@@ -63,6 +63,7 @@
+ extern void		cgiAbort(const char *title, const char *stylesheet,
+ 			         const char *format, ...);
+ extern int		cgiCheckVariables(const char *names);
++extern void		cgiClearVariables(void);
+ extern void		*cgiCompileSearch(const char *query);
+ extern void		cgiCopyTemplateFile(FILE *out, const char *tmpl);
+ extern void		cgiCopyTemplateLang(const char *tmpl);
+diff -urNad cupsys-1.2.2~/cgi-bin/classes.c cupsys-1.2.2/cgi-bin/classes.c
+--- cupsys-1.2.2~/cgi-bin/classes.c	2006-05-22 14:47:09.000000000 -0400
++++ cupsys-1.2.2/cgi-bin/classes.c	2009-10-30 21:39:46.000000000 -0400
+@@ -78,6 +78,7 @@
+   */
+ 
+   cgiSetVariable("SECTION", "classes");
++  cgiSetVariable("REFRESH_PAGE", "");
+ 
+  /*
+   * See if we are displaying a printer or all classes...
+diff -urNad cupsys-1.2.2~/cgi-bin/help.c cupsys-1.2.2/cgi-bin/help.c
+--- cupsys-1.2.2~/cgi-bin/help.c	2006-05-19 15:39:28.000000000 -0400
++++ cupsys-1.2.2/cgi-bin/help.c	2009-10-30 21:39:46.000000000 -0400
+@@ -72,6 +72,7 @@
+   */
+ 
+   cgiSetVariable("SECTION", "help");
++  cgiSetVariable("REFRESH_PAGE", "");
+ 
+  /*
+   * Load the help index...
+@@ -111,7 +112,7 @@
+   */
+ 
+   for (i = 0; i < argc; i ++)
+-    fprintf(stderr, "argv[%d]=\"%s\"\n", i, argv[i]);
++    fprintf(stderr, "DEBUG: argv[%d]=\"%s\"\n", i, argv[i]);
+ 
+   if ((helpfile = getenv("PATH_INFO")) != NULL)
+   {
+@@ -187,6 +188,12 @@
+   topic = cgiGetVariable("TOPIC");
+   si    = helpSearchIndex(hi, query, topic, helpfile);
+ 
++  cgiClearVariables();
++  if (query)
++    cgiSetVariable("QUERY", query);
++  if (topic)
++    cgiSetVariable("TOPIC", topic);
++
+   fprintf(stderr, "DEBUG: query=\"%s\", topic=\"%s\"\n",
+           query ? query : "(null)", topic ? topic : "(null)");
+ 
+diff -urNad cupsys-1.2.2~/cgi-bin/ipp-var.c cupsys-1.2.2/cgi-bin/ipp-var.c
+--- cupsys-1.2.2~/cgi-bin/ipp-var.c	2006-05-22 14:47:09.000000000 -0400
++++ cupsys-1.2.2/cgi-bin/ipp-var.c	2009-10-30 21:39:46.000000000 -0400
+@@ -1075,7 +1075,9 @@
+   int			ascending,	/* Order of jobs (0 = descending) */
+ 			first,		/* First job to show */
+ 			count;		/* Number of jobs */
+-  const char		*var;		/* Form variable */
++  const char		*var,		/* Form variable */
++			*query,		/* Query string */
++			*section;	/* Section in web interface */
+   void			*search;	/* Search data */
+   char			url[1024],	/* URL for prev/next/this */
+ 			*urlptr,	/* Position in URL */
+@@ -1120,10 +1122,13 @@
+     * Get a list of matching job objects.
+     */
+ 
+-    if ((var = cgiGetVariable("QUERY")) != NULL)
+-      search = cgiCompileSearch(var);
++    if ((query = cgiGetVariable("QUERY")) != NULL)
++      search = cgiCompileSearch(query);
+     else
++    {
++      query  = NULL;
+       search = NULL;
++    }
+ 
+     jobs  = cgiGetIPPObjects(response, search);
+     count = cupsArrayCount(jobs);
+@@ -1148,16 +1153,27 @@
+     if (first < 0)
+       first = 0;
+ 
+-    sprintf(url, "%d", count);
+-    cgiSetVariable("TOTAL", url);
+-
+     if ((var = cgiGetVariable("ORDER")) != NULL)
+       ascending = !strcasecmp(var, "asc");
+     else
+-    {
+       ascending = !which_jobs || !strcasecmp(which_jobs, "not-completed");
+-      cgiSetVariable("ORDER", ascending ? "asc" : "dec");
+-    }
++
++    section = cgiGetVariable("SECTION");
++
++    cgiClearVariables();
++
++    if (query)
++      cgiSetVariable("QUERY", query);
++
++    cgiSetVariable("ORDER", ascending ? "asc" : "dec");
++
++    cgiSetVariable("SECTION", section);
++
++    sprintf(url, "%d", count);
++    cgiSetVariable("TOTAL", url);
++
++    if (which_jobs)
++      cgiSetVariable("WHICH_JOBS", which_jobs);
+ 
+     if (ascending)
+     {
+@@ -1180,11 +1196,10 @@
+ 
+     urlend = url + sizeof(url);
+ 
+-    if ((var = cgiGetVariable("QUERY")) != NULL)
++    if (query != NULL)
+     {
+       if (dest)
+-        snprintf(url, sizeof(url), "/%s/%s?QUERY=", cgiGetVariable("SECTION"),
+-	         dest);
++        snprintf(url, sizeof(url), "/%s/%s?QUERY=", section, dest);
+       else
+         strlcpy(url, "/jobs/?QUERY=", sizeof(url));
+ 
+@@ -1199,7 +1214,7 @@
+     else
+     {
+       if (dest)
+-        snprintf(url, sizeof(url), "/%s/%s?", cgiGetVariable("SECTION"), dest);
++        snprintf(url, sizeof(url), "/%s/%s?", section, dest);
+       else
+         strlcpy(url, "/jobs/?", sizeof(url));
+ 
+diff -urNad cupsys-1.2.2~/cgi-bin/jobs.c cupsys-1.2.2/cgi-bin/jobs.c
+--- cupsys-1.2.2~/cgi-bin/jobs.c	2006-02-14 22:21:04.000000000 -0500
++++ cupsys-1.2.2/cgi-bin/jobs.c	2009-10-30 21:39:46.000000000 -0400
+@@ -66,6 +66,7 @@
+   */
+ 
+   cgiSetVariable("SECTION", "jobs");
++  cgiSetVariable("REFRESH_PAGE", "");
+ 
+  /*
+   * Connect to the HTTP server...
+diff -urNad cupsys-1.2.2~/cgi-bin/printers.c cupsys-1.2.2/cgi-bin/printers.c
+--- cupsys-1.2.2~/cgi-bin/printers.c	2006-05-22 14:47:09.000000000 -0400
++++ cupsys-1.2.2/cgi-bin/printers.c	2009-10-30 21:39:46.000000000 -0400
+@@ -81,6 +81,7 @@
+   */
+ 
+   cgiSetVariable("SECTION", "printers");
++  cgiSetVariable("REFRESH_PAGE", "");
+ 
+  /*
+   * See if we are displaying a printer or all printers...
+diff -urNad cupsys-1.2.2~/cgi-bin/template.c cupsys-1.2.2/cgi-bin/template.c
+--- cupsys-1.2.2~/cgi-bin/template.c	2006-05-19 15:39:28.000000000 -0400
++++ cupsys-1.2.2/cgi-bin/template.c	2009-10-30 21:39:46.000000000 -0400
+@@ -639,6 +639,8 @@
+       fputs("&gt;", out);
+     else if (*s == '\"')
+       fputs("&quot;", out);
++    else if (*s == '\'')
++      fputs("&#39;", out);
+     else if (*s == '&')
+       fputs("&amp;", out);
+     else
+@@ -659,7 +661,7 @@
+ {
+   while (*s)
+   {
+-    if (strchr("%&+ <>#=", *s) || *s & 128)
++    if (strchr("%@&+ <>#=", *s) || *s < ' ' || *s & 128)
+       fprintf(out, "%%%02X", *s & 255);
+     else
+       putc(*s, out);
+diff -urNad cupsys-1.2.2~/cgi-bin/var.c cupsys-1.2.2/cgi-bin/var.c
+--- cupsys-1.2.2~/cgi-bin/var.c	2006-05-19 15:39:28.000000000 -0400
++++ cupsys-1.2.2/cgi-bin/var.c	2009-10-30 21:39:46.000000000 -0400
+@@ -24,6 +24,7 @@
+  * Contents:
+  *
+  *   cgiCheckVariables()        - Check for the presence of "required" variables.
++ *   cgiClearVariables()        - Clear all form variables.
+  *   cgiGetArray()              - Get an element from a form array...
+  *   cgiGetFile()               - Get the file (if any) that was submitted in the form.
+  *   cgiGetSize()               - Get the size of a form array value.
+@@ -144,6 +145,31 @@
+ 
+ 
+ /*
++ * 'cgiClearVariables()' - Clear all form variables.
++ */
++
++void
++cgiClearVariables(void)
++{
++  int		i, j;			/* Looping vars */
++  _cgi_var_t	*v;			/* Current variable */
++
++
++  for (v = form_vars, i = form_count; i > 0; v ++, i --)
++  {
++    _cupsStrFree(v->name);
++    for (j = 0; j < v->nvalues; j ++)
++      if (v->values[j])
++        _cupsStrFree(v->values[j]);
++  }
++
++  form_count = 0;
++
++  cgi_unlink_file();
++}
++
++
++/*
+  * 'cgiGetArray()' - Get an element from a form array...
+  */
+ 
+@@ -163,7 +189,7 @@
+   if (element < 0 || element >= var->nvalues)
+     return (NULL);
+ 
+-  return (var->values[element]);
++  return (_cupsStrAlloc(var->values[element]));
+ }
+ 
+ 
+@@ -218,7 +244,7 @@
+            var->values[var->nvalues - 1]);
+ #endif /* DEBUG */
+ 
+-  return ((var == NULL) ? NULL : var->values[var->nvalues - 1]);
++  return ((var == NULL) ? NULL : _cupsStrAlloc(var->values[var->nvalues - 1]));
+ }
+ 
+ 
+@@ -344,9 +370,9 @@
+       var->nvalues = element + 1;
+     }
+     else if (var->values[element])
+-      free((char *)var->values[element]);
++      _cupsStrFree((char *)var->values[element]);
+ 
+-    var->values[element] = strdup(value);
++    var->values[element] = _cupsStrAlloc(value);
+   }
+ }
+ 
+@@ -385,7 +411,7 @@
+   {
+     for (i = size; i < var->nvalues; i ++)
+       if (var->values[i])
+-        free((void *)(var->values[i]));
++        _cupsStrFree((void *)(var->values[i]));
+   }
+ 
+   var->nvalues = size;
+@@ -418,9 +444,9 @@
+   {
+     for (i = 0; i < var->nvalues; i ++)
+       if (var->values[i])
+-        free((char *)var->values[i]);
++        _cupsStrFree((char *)var->values[i]);
+ 
+-    var->values[0] = strdup(value);
++    var->values[0] = _cupsStrAlloc(value);
+     var->nvalues   = 1;
+   }
+ }
+@@ -456,11 +482,11 @@
+   }
+ 
+   var                  = form_vars + form_count;
+-  var->name            = strdup(name);
++  var->name            = _cupsStrAlloc(name);
+   var->nvalues         = element + 1;
+   var->avalues         = element + 1;
+   var->values          = calloc(element + 1, sizeof(char *));
+-  var->values[element] = strdup(value);
++  var->values[element] = _cupsStrAlloc(value);
+ 
+   form_count ++;
+ }

Reply to: