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(">", out);
+ else if (*s == '\"')
+ fputs(""", out);
++ else if (*s == '\'')
++ fputs("'", out);
+ else if (*s == '&')
+ fputs("&", 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: