diff --git a/SOURCES/cups-filters-CVE-2014-4337.patch b/SOURCES/cups-filters-CVE-2014-4337.patch new file mode 100644 index 0000000..b3b5d43 --- /dev/null +++ b/SOURCES/cups-filters-CVE-2014-4337.patch @@ -0,0 +1,254 @@ +diff -up cups-filters-1.0.35/NEWS.CVE-2014-4337 cups-filters-1.0.35/NEWS +diff -up cups-filters-1.0.35/utils/cups-browsed.c.CVE-2014-4337 cups-filters-1.0.35/utils/cups-browsed.c +--- cups-filters-1.0.35/utils/cups-browsed.c.CVE-2014-4337 2014-10-08 13:33:12.192067445 +0100 ++++ cups-filters-1.0.35/utils/cups-browsed.c 2014-10-08 13:54:45.742569979 +0100 +@@ -298,6 +298,75 @@ create_local_queue (const char *name, + return p; + } + ++/* ++ * Remove all illegal characters and replace each group of such characters ++ * by a single dash, return a free()-able string. ++ * ++ * mode = 0: Only allow letters, numbers, and dashes, for turning make/model ++ * info into a valid print queue name or into a string which can ++ * be supplied as option value in a filter command line without ++ * need of quoting ++ * mode = 1: Allow also '/', '.', ',', '_', for cleaning up MIME type ++ * strings (here available Page Description Languages, PDLs) to ++ * supply them on a filter command line without quoting ++ * ++ * Especially this prevents from arbitrary code execution by interface scripts ++ * generated for print queues to native IPP printers when a malicious IPP ++ * print service with forged PDL and/or make/model info gets broadcasted into ++ * the local network. ++ */ ++ ++char * /* O - Cleaned string */ ++remove_bad_chars(const char *str_orig, /* I - Original string */ ++ int mode) /* I - 0: Make/Model, queue name */ ++ /* 1: MIME types/PDLs */ ++{ ++ int i, j; ++ int havedash = 0; ++ char *str; ++ ++ if (str_orig == NULL) ++ return NULL; ++ ++ str = strdup(str_orig); ++ ++ /* for later str[strlen(str)-1] access */ ++ if (strlen(str) < 1) ++ return str; ++ ++ for (i = 0, j = 0; i < strlen(str); i++, j++) { ++ if (((str[i] >= 'A') && (str[i] <= 'Z')) || ++ ((str[i] >= 'a') && (str[i] <= 'z')) || ++ ((str[i] >= '0') && (str[i] <= '9')) || ++ (mode == 1 && (str[i] == '/' || str[i] == '_' || ++ str[i] == '.' || str[i] == ','))) { ++ /* Letter or number, keep it */ ++ havedash = 0; ++ } else { ++ /* Replace all other characters by a single '-' */ ++ if (havedash == 1) ++ j --; ++ else { ++ havedash = 1; ++ str[j] = '-'; ++ } ++ } ++ } ++ /* Add terminating zero */ ++ str[j] = '\0'; ++ /* Cut off trailing dashes */ ++ while (str[strlen(str)-1] == '-') ++ str[strlen(str)-1] = '\0'; ++ ++ /* Cut off leading dashes */ ++ i = 0; ++ while (str[i] == '-') ++ ++i; ++ ++ /* keep a free()-able string. +1 for trailing \0 */ ++ return memmove(str, str + i, strlen(str) - i + 1); ++} ++ + gboolean handle_cups_queues(gpointer unused) { + remote_printer_t *p; + http_t *http; +@@ -392,7 +461,7 @@ gboolean handle_cups_queues(gpointer unu + } + if (default_printer_name) + break; +- } ++ } + } + if (default_printer_name && + !strcasecmp(default_printer_name, p->name)) { +@@ -572,19 +641,30 @@ void generate_local_queue(const char *ho + const char *name, + const char *type, + const char *domain) { +- char *remote_queue, *remote_host; ++ char *remote_queue = NULL, *remote_host = NULL; + remote_printer_t *p; +- char *backup_queue_name, *local_queue_name = NULL; +- cups_dest_t *dests, *dest; ++ char *backup_queue_name = NULL, *local_queue_name = NULL; ++ cups_dest_t *dests = NULL, *dest = NULL; + int i, num_dests; +- const char *val; ++ size_t hl = 0; ++ const char *val = NULL; + + /* This is a remote CUPS queue, find queue name and host name */ +- remote_queue = resource + 9; +- remote_host = strdup(host); +- if (!strcmp(remote_host + strlen(remote_host) - 6, ".local")) ++ if (strncasecmp(resource, "printers/", 9)) { ++ debug_printf("cups-browsed: resource does not begin 'printers/'\n"); ++ return; ++ } ++ ++ remote_queue = remove_bad_chars(resource + 9, 0); ++ /* Find the remote host name. ++ * Used in constructing backup_queue_name, so need to sanitize. ++ * strdup() is called inside remove_bad_chars() and result is free()-able. ++ */ ++ remote_host = remove_bad_chars(host, 1); ++ hl = strlen(remote_host); ++ if (hl > 6 && !strcmp(remote_host + strlen(remote_host) - 6, ".local")) + remote_host[strlen(remote_host) - 6] = '\0'; +- if (!strcmp(remote_host + strlen(remote_host) - 7, ".local.")) ++ if (hl > 7 && !strcmp(remote_host + strlen(remote_host) - 7, ".local.")) + remote_host[strlen(remote_host) - 7] = '\0'; + debug_printf("cups-browsed: Found CUPS queue: %s on host %s.\n", + remote_queue, remote_host); +@@ -592,7 +672,7 @@ void generate_local_queue(const char *ho + /* Check if there exists already a CUPS queue with the + requested name Try name@host in such a case and if + this is also taken, ignore the printer */ +- if ((backup_queue_name = malloc((strlen(remote_queue) + ++ if ((backup_queue_name = malloc((strlen(remote_queue) + + strlen(remote_host) + 2) * + sizeof(char))) == NULL) { + debug_printf("cups-browsed: ERROR: Unable to allocate memory.\n"); +@@ -639,6 +719,7 @@ void generate_local_queue(const char *ho + local_queue_name); + free (backup_queue_name); + free (remote_host); ++ free (remote_queue); + cupsFreeDests(num_dests, dests); + return; + } +@@ -724,6 +805,7 @@ void generate_local_queue(const char *ho + + free (backup_queue_name); + free (remote_host); ++ free (remote_queue); + + if (p) + debug_printf("cups-browsed: Bonjour IDs: Service name: \"%s\", " +@@ -958,12 +1040,18 @@ found_cups_printer (const char *remote_h + char local_resource[HTTP_MAX_URI]; + char *c; + ++ memset(scheme, 0, sizeof(scheme)); ++ memset(username, 0, sizeof(username)); ++ memset(host, 0, sizeof(host)); ++ memset(resource, 0, sizeof(resource)); ++ memset(local_resource, 0, sizeof(local_resource)); ++ + httpSeparateURI (HTTP_URI_CODING_ALL, uri, +- scheme, sizeof(scheme), +- username, sizeof(username), +- host, sizeof(host), ++ scheme, sizeof(scheme) - 1, ++ username, sizeof(username) - 1, ++ host, sizeof(host) - 1, + &port, +- resource, sizeof(resource)); ++ resource, sizeof(resource)- 1); + + /* Check this isn't one of our own broadcasts */ + for (iface = cupsArrayFirst (netifs); +@@ -1071,7 +1159,12 @@ process_browse_data (GIOChannel *source, + char remote_host[256]; + char uri[1024]; + char info[1024]; +- char *c; ++ char *c = NULL, *end = NULL; ++ ++ memset(packet, 0, sizeof(packet)); ++ memset(remote_host, 0, sizeof(remote_host)); ++ memset(uri, 0, sizeof(uri)); ++ memset(info, 0, sizeof(info)); + + srclen = sizeof (srcaddr); + got = recvfrom (browsesocket, packet, sizeof (packet) - 1, 0, +@@ -1084,7 +1177,7 @@ process_browse_data (GIOChannel *source, + } + + packet[got] = '\0'; +- httpAddrString (&srcaddr, remote_host, sizeof (remote_host)); ++ httpAddrString (&srcaddr, remote_host, sizeof (remote_host) - 1); + + /* Check this packet is allowed */ + if (!allowed ((struct sockaddr *) &srcaddr)) { +@@ -1102,28 +1195,42 @@ process_browse_data (GIOChannel *source, + } + + info[0] = '\0'; ++ ++ /* do not read OOB */ ++ end = packet + sizeof(packet); + c = strchr (packet, '\"'); ++ if (c >= end) ++ return TRUE; ++ + if (c) { + /* Skip location field */ +- for (c++; *c != '\"'; c++) ++ for (c++; c < end && *c != '\"'; c++) + ; + ++ if (c >= end) ++ return TRUE; ++ + if (*c == '\"') { +- for (c++; isspace(*c); c++) ++ for (c++; c < end && isspace(*c); c++) + ; + } + ++ if (c >= end) ++ return TRUE; ++ + /* Is there an info field? */ + if (*c == '\"') { + int i; + c++; + for (i = 0; +- i < sizeof (info) - 1 && *c != '\"'; ++ i < sizeof (info) - 1 && *c != '\"' && c < end; + i++, c++) + info[i] = *c; + info[i] = '\0'; + } + } ++ if (c >= end) ++ return TRUE; + + found_cups_printer (remote_host, uri, info); + recheck_timer (); +@@ -1332,7 +1439,7 @@ send_browse_data (gpointer data) + while (attr && ippGetGroupTag(attr) == IPP_TAG_PRINTER) { + const char *attrname = ippGetName(attr); + int value_tag = ippGetValueTag(attr); +- ++ + if (!strcmp(attrname, "printer-type") && + value_tag == IPP_TAG_ENUM) { + type = ippGetInteger(attr, 0); diff --git a/SOURCES/cups-filters-CVE-2014-4338.patch b/SOURCES/cups-filters-CVE-2014-4338.patch new file mode 100644 index 0000000..108427e --- /dev/null +++ b/SOURCES/cups-filters-CVE-2014-4338.patch @@ -0,0 +1,51 @@ +diff -up cups-filters-1.0.35/utils/cups-browsed.c.CVE-2014-4338 cups-filters-1.0.35/utils/cups-browsed.c +--- cups-filters-1.0.35/utils/cups-browsed.c.CVE-2014-4338 2014-10-08 14:10:19.389201254 +0100 ++++ cups-filters-1.0.35/utils/cups-browsed.c 2014-10-08 16:24:09.648892671 +0100 +@@ -91,7 +91,8 @@ typedef struct netif_s { + /* Data structure for browse allow/deny rules */ + typedef enum allow_type_e { + ALLOW_IP, +- ALLOW_NET ++ ALLOW_NET, ++ ALLOW_INVALID + } allow_type_t; + typedef struct allow_s { + allow_type_t type; +@@ -1094,6 +1095,9 @@ allowed (struct sockaddr *srcaddr) + allow; + allow = cupsArrayNext (browseallow)) { + switch (allow->type) { ++ case ALLOW_INVALID: ++ break; ++ + case ALLOW_IP: + switch (srcaddr->sa_family) { + case AF_INET: +@@ -1699,6 +1703,8 @@ read_browseallow_value (const char *valu + char *p; + struct in_addr addr; + allow_t *allow = calloc (1, sizeof (allow_t)); ++ if (value == NULL) ++ goto fail; + p = strchr (value, '/'); + if (p) { + char *s = strdup (value); +@@ -1741,7 +1747,8 @@ read_browseallow_value (const char *valu + return 0; + + fail: +- free (allow); ++ allow->type = ALLOW_INVALID; ++ cupsArrayAdd (browseallow, allow); + return 1; + } + +@@ -1798,7 +1805,7 @@ read_configuration (const char *filename + debug_printf("cups-browsed: Adding BrowsePoll server: %s\n", value); + BrowsePoll[NumBrowsePoll++] = strdup (value); + } +- } else if (!strcasecmp(line, "BrowseAllow") && value) ++ } else if (!strcasecmp(line, "BrowseAllow")) + if (read_browseallow_value (value)) + debug_printf ("cups-browsed: BrowseAllow value \"%s\" not understood\n", + value); diff --git a/SPECS/cups-filters.spec b/SPECS/cups-filters.spec index 3c1f90d..b782f0c 100644 --- a/SPECS/cups-filters.spec +++ b/SPECS/cups-filters.spec @@ -4,7 +4,7 @@ Summary: OpenPrinting CUPS filters and backends Name: cups-filters Version: 1.0.35 -Release: 15%{?dist} +Release: 15%{?dist}.1 # For a breakdown of the licensing, see COPYING file # GPLv2: filters: commandto*, imagetoraster, pdftops, rasterto*, @@ -31,6 +31,8 @@ Patch6: cups-filters-format-mismatch.patch Patch7: cups-filters-pdf-landscape.patch Patch8: cups-filters-pdftoopvp.patch Patch9: cups-filters-CVE-2013-6475.patch +Patch10: cups-filters-CVE-2014-4337.patch +Patch11: cups-filters-CVE-2014-4338.patch Requires: cups-filters-libs%{?_isa} = %{version}-%{release} @@ -134,6 +136,15 @@ This is the development package for OpenPrinting CUPS filters and backends. # (bug #1052741). %patch9 -p1 -b .CVE-2013-6475 +# Applied upstream patch for cups-browsed DoS via +# process_browse_data() out-of-bounds read (CVE-2014-4337, +# bug #1111510). +%patch10 -p1 -b .CVE-2014-4337 + +# Applied upstream patch to fix BrowseAllow parsing issue +# (CVE-2014-4338, bug #1091568). +%patch11 -p1 -b .CVE-2014-4338 + %build # work-around Rpath ./autogen.sh @@ -240,6 +251,13 @@ fi %{_libdir}/libfontembed.so %changelog +* Wed Oct 8 2014 Tim Waugh - 1.0.35-15:.1 +- Applied upstream patch to fix BrowseAllow parsing issue + (CVE-2014-4338, bug #1091568). +- Applied upstream patch for cups-browsed DoS via + process_browse_data() out-of-bounds read (CVE-2014-4337, + bug #1111510). + * Fri Mar 28 2014 Tim Waugh - 1.0.35-15 - The texttopdf filter requires a TrueType monospaced font (bug #1070729).