apple / cups

Apple CUPS Sources
https://www.cups.org
Apache License 2.0
1.93k stars 464 forks source link

cups should not create large chunks of memory on the stack #2388

Closed michaelrsweet closed 16 years ago

michaelrsweet commented 17 years ago

Version: 1.4-feature CUPS.org User: mcknight

The problem showed up specifically in cups/ipp.c in both ippWriteIO() and ippReadIO(). There, cups creates a buffer of 32 K on the stack. This sounds little in a world with a few gigs of RAM but there are stack limits and some operating systems set them to quite conservative values. Worse even with pthreads where every thread has another (normally significantly smaller) stack limit.

We noticed that on a gnome application on OpenBSD that was linked against the cups library. Clicking the print button made the application crash.

The pthreads stack limits were set to 64k per thread and with quite some stack backtrace of previous function calls and all their local variables, cups touched the limit requesting another 32k and the process got killed by the operating system.

Especially a library does not know in which circumstances it is executed later and should be conservative about its expectations regarding system ressources.

I append the patch that fixed that very problem but this bug report is rather meant as a general advice to not put large data structures on the stack.

michaelrsweet commented 17 years ago

CUPS.org User: mike

I'm re-flagging this as a request for enhancement. At this point, it is doubtful we will incorporate this change before CUPS 1.4, and it will certainly need some cleanup and serious testing.

michaelrsweet commented 17 years ago

CUPS.org User: mike

Considering for 1.4...

michaelrsweet commented 16 years ago

CUPS.org User: mike

Fixed in Subversion repository.

The actual implementation maintains a linked list of buffers so we don't allocate memory every time.

michaelrsweet commented 16 years ago

"patch-cups_ipp_c":

$OpenBSD$ --- cups/ipp.c.orig Mon Jan 3 20:29:45 2005 +++ cups/ipp.c Fri May 18 16:05:29 2007 @@ -856,6 +856,12 @@ ippReadFile(int fd, /* I - HTTP dat

/*

@@ -867,11 +873,12 @@ ippReadIO(void src, / I - Data ipp_t ipp) / I - IPP data / { int n; / Length of data */

@@ -1023,11 +1035,11 @@ ippReadIO(void src, / I - Data

      if (tag != IPP_TAG_STRING &&
          (tag < IPP_TAG_TEXTLANG || tag > IPP_TAG_MIMETYPE))

@@ -1262,12 +1274,13 @@ ippReadIO(void src, / I - Data if (n > 0) { DEBUG_puts("ippReadIO: endCollection tag with value length > 0!");

@@ -1406,6 +1428,12 @@ ippWriteFile(int fd, /* I - HTTP da

/*

@@ -1418,7 +1446,7 @@ ippWriteIO(void dst, / I - Des { int i; /* Looping var / int n; / Length of data */

@@ -1530,8 +1562,8 @@ ippWriteIO(void dst, / I - Des * overflow the buffer... */

@@ -2069,12 +2101,12 @@ ippWriteIO(void dst, / I - Des * values with a zero-length name... */

michaelrsweet commented 16 years ago

"str2388.patch":

Index: cups/ipp.c

--- cups/ipp.c (revision 7988) +++ cups/ipp.c (working copy) @@ -75,6 +75,8 @@

+static unsigned char _ipp_buffer_get(void); +static void ipp_buffer_release(unsigned char b); static size_t ipp_length(ipp_t ipp, int collection); static ssize_t ipp_read_http(http_t http, ipp_uchar_t buffer, size_t length); @@ -1064,8 +1066,7 @@ ippt *ipp) / I - IPP data / { int n; / Length of data */

@@ -1108,6 +1116,7 @@ { DEBUG_printf(("ippReadIO: version number (%d.%d) is bad.\n", buffer[0], buffer[1]));

@@ -1144,7 +1153,11 @@ for (;;) { if ((*cb)(src, buffer, 1) < 1)

@@ -1215,7 +1230,11 @@ */

         if (ipp->current == NULL)

@@ -1279,7 +1300,11 @@ if ((temp = realloc(attr, sizeof(ipp_attribute_t) + (attr->num_values + IPP_MAX_VALUES - 1) * sizeof(ipp_value_t))) == NULL)

@@ -1329,6 +1355,7 @@ if ((*cb)(src, buffer, n) < n) { DEBUG_puts("ippReadIO: unable to read name!");

@@ -1340,6 +1367,7 @@ if ((attr = ipp->current = _ippAddAttr(ipp, 1)) == NULL) { DEBUG_puts("ippReadIO: unable to allocate attribute!");

@@ -1362,6 +1390,7 @@ if ((*cb)(src, buffer, 2) < 2) { DEBUG_puts("ippReadIO: unable to read value length!");

@@ -1375,12 +1404,14 @@ if (n != 4) { DEBUG_printf(("ippReadIO: bad value length %d!\n", n));

@@ -1394,12 +1425,14 @@ if (n != 1) { DEBUG_printf(("ippReadIO: bad value length %d!\n", n));

@@ -1423,15 +1456,17 @@ case IPP_TAG_CHARSET : case IPP_TAG_LANGUAGE : case IPP_TAG_MIMETYPE :

@@ -1445,12 +1480,14 @@ if (n != 11) { DEBUG_printf(("ippReadIO: bad value length %d!\n", n));

@@ -1482,12 +1521,14 @@ if (n != 8) { DEBUG_printf(("ippReadIO: bad value length %d!\n", n));

@@ -1501,15 +1542,17 @@

    case IPP_TAG_TEXTLANG :
    case IPP_TAG_NAMELANG :

@@ -1527,10 +1570,11 @@

    n = (bufptr[0] << 8) | bufptr[1];

@@ -1542,9 +1586,10 @@ bufptr += 2 + n; n = (bufptr[0] << 8) | bufptr[1];

@@ -1563,17 +1608,21 @@ { DEBUG_puts("ippReadIO: begCollection tag with value length " "> 0!");

@@ -1621,12 +1671,14 @@ if (n > IPP_MAX_LENGTH) { DEBUG_printf(("ippReadIO: bad value length %d!\n", n));

@@ -1636,12 +1688,14 @@ if ((value->unknown.data = malloc(n)) == NULL) { DEBUG_puts("ippReadIO: Unable to allocate value");

@@ -2002,12 +2072,13 @@ i < attr->num_values; i ++, value ++) {

@@ -2062,12 +2133,13 @@ ippTagString(attr->value_tag))); DEBUG_printf(("ippWriteIO: writing name=0,\"\"\n"));

@@ -2084,18 +2156,23 @@ else n = 0;

@@ -2128,12 +2205,13 @@ i < attr->num_values; i ++, value ++) {

@@ -2172,13 +2250,14 @@ i < attr->num_values; i ++, value ++) {

@@ -2282,12 +2362,13 @@ * values with a zero-length name... */

@@ -2317,15 +2398,21 @@ if (value->string.text != NULL) n += (int)strlen(value->string.text);

@@ -2382,12 +2469,13 @@ * value... */

@@ -2417,6 +2505,7 @@ { DEBUG_puts("ippWriteIO: Could not write IPP " "attribute...");

@@ -2428,8 +2517,13 @@

               value->collection->state = IPP_IDLE;

@@ -2445,12 +2539,13 @@ * values with a zero-length name... */

@@ -2471,15 +2566,21 @@

               n = value->unknown.length;

@@ -2507,6 +2608,7 @@ if ((*cb)(dst, buffer, (int)(bufptr - buffer)) < 0) { DEBUG_puts("ippWriteIO: Could not write IPP attribute...");

@@ -2546,6 +2648,7 @@ if ((*cb)(dst, buffer, n) < 0) { DEBUG_puts("ippWriteIO: Could not write IPP end-tag...");

@@ -2560,6 +2663,8 @@ break; /* anti-compiler-warning-code */ }

@@ -2684,6 +2789,47 @@

/*

Index: cups/ipp-private.h

--- cups/ipp-private.h (revision 7988) +++ cups/ipp-private.h (working copy) @@ -35,9 +35,24 @@

/*

+typedef struct _ipp_buffer_s /\ Read/write buffer **/ +{

@@ -159,6 +161,12 @@

cupsFreeOptions(cg->cupsd_num_settings, cg->cupsd_settings);

Index: cups/globals.h

--- cups/globals.h (revision 7988) +++ cups/globals.h (working copy) @@ -85,6 +85,7 @@

/* ipp.c _/ ipp_uchar_t ippdate[11]; / RFC-1903 date/time data */