summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael R Sweet <msweet@msweet.org>2021-07-16 07:32:45 -0400
committerMichael R Sweet <msweet@msweet.org>2021-07-16 07:32:45 -0400
commitab83aeec841831b8b17b2efb9004f77c32027bc6 (patch)
treee238898ed3ee9cd34d7d07b47a1526eed2ddfecc
parent5708fbb59c7f43277dffe12c283854cd565d7113 (diff)
downloadcups-ab83aeec841831b8b17b2efb9004f77c32027bc6.tar.gz
Mirror IPP fuzzing fixes from OpenPrinting CUPS.
-rw-r--r--cups/ipp.c169
1 files changed, 74 insertions, 95 deletions
diff --git a/cups/ipp.c b/cups/ipp.c
index 94a2264a6..42cf2fcaf 100644
--- a/cups/ipp.c
+++ b/cups/ipp.c
@@ -2868,7 +2868,7 @@ ippReadIO(void *src, /* I - Data source */
/* Small string buffer */
*bufptr, /* Pointer into buffer */
*bufend; /* End of buffer */
- ipp_attribute_t *attr; /* Current attribute */
+ ipp_attribute_t *attr = NULL; /* Current attribute */
ipp_tag_t tag; /* Current tag */
ipp_tag_t value_tag; /* Current value tag */
_ipp_value_t *value; /* Current value */
@@ -2901,8 +2901,7 @@ ippReadIO(void *src, /* I - Data source */
if ((*cb)(src, buffer, 8) < 8)
{
DEBUG_puts("1ippReadIO: Unable to read header.");
- _cupsBufferRelease((char *)buffer);
- return (IPP_STATE_ERROR);
+ goto rollback;
}
/*
@@ -2940,8 +2939,7 @@ ippReadIO(void *src, /* I - Data source */
if ((*cb)(src, buffer, 1) < 1)
{
DEBUG_puts("1ippReadIO: Callback returned EOF/error");
- _cupsBufferRelease((char *)buffer);
- return (IPP_STATE_ERROR);
+ goto rollback;
}
DEBUG_printf(("2ippReadIO: ipp->current=%p, ipp->prev=%p", (void *)ipp->current, (void *)ipp->prev));
@@ -2960,8 +2958,7 @@ ippReadIO(void *src, /* I - Data source */
if ((*cb)(src, buffer, 4) < 4)
{
DEBUG_puts("1ippReadIO: Callback returned EOF/error");
- _cupsBufferRelease((char *)buffer);
- return (IPP_STATE_ERROR);
+ goto rollback;
}
tag = (ipp_tag_t)((((((buffer[0] << 8) | buffer[1]) << 8) |
@@ -2975,8 +2972,7 @@ ippReadIO(void *src, /* I - Data source */
_cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP extension tag larger than 0x7FFFFFFF."), 1);
DEBUG_printf(("1ippReadIO: bad tag 0x%x.", tag));
- _cupsBufferRelease((char *)buffer);
- return (IPP_STATE_ERROR);
+ goto rollback;
}
}
@@ -2995,8 +2991,7 @@ ippReadIO(void *src, /* I - Data source */
{
_cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Invalid group tag."), 1);
DEBUG_printf(("1ippReadIO: bad tag 0x%02x.", tag));
- _cupsBufferRelease((char *)buffer);
- return (IPP_STATE_ERROR);
+ goto rollback;
}
else if (tag < IPP_TAG_UNSUPPORTED_VALUE)
{
@@ -3004,13 +2999,20 @@ ippReadIO(void *src, /* I - Data source */
* Group tag... Set the current group and continue...
*/
- if (ipp->curtag == tag)
+ if (parent)
+ {
+ _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Invalid group tag."), 1);
+ DEBUG_printf(("1ippReadIO: bad tag 0x%02x.", tag));
+ goto rollback;
+ }
+ else if (ipp->curtag == tag)
ipp->prev = ippAddSeparator(ipp);
else if (ipp->current)
ipp->prev = ipp->current;
ipp->curtag = tag;
ipp->current = NULL;
+ attr = NULL;
DEBUG_printf(("2ippReadIO: group tag=%x(%s), ipp->prev=%p", tag, ippTagString(tag), (void *)ipp->prev));
continue;
}
@@ -3025,8 +3027,7 @@ ippReadIO(void *src, /* I - Data source */
if ((*cb)(src, buffer, 2) < 2)
{
DEBUG_puts("1ippReadIO: unable to read name length.");
- _cupsBufferRelease((char *)buffer);
- return (IPP_STATE_ERROR);
+ goto rollback;
}
n = (buffer[0] << 8) | buffer[1];
@@ -3035,8 +3036,7 @@ ippReadIO(void *src, /* I - Data source */
{
_cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP name larger than 32767 bytes."), 1);
DEBUG_printf(("1ippReadIO: bad name length %d.", n));
- _cupsBufferRelease((char *)buffer);
- return (IPP_STATE_ERROR);
+ goto rollback;
}
DEBUG_printf(("2ippReadIO: name length=%d", n));
@@ -3045,7 +3045,7 @@ ippReadIO(void *src, /* I - Data source */
{
_cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Invalid named IPP attribute in collection."), 1);
DEBUG_puts("1ippReadIO: bad attribute name in collection.");
- return (IPP_STATE_ERROR);
+ goto rollback;
}
else if (n == 0 && tag != IPP_TAG_MEMBERNAME && tag != IPP_TAG_END_COLLECTION)
{
@@ -3057,8 +3057,7 @@ ippReadIO(void *src, /* I - Data source */
{
_cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP attribute has no name."), 1);
DEBUG_puts("1ippReadIO: Attribute without name and no current.");
- _cupsBufferRelease((char *)buffer);
- return (IPP_STATE_ERROR);
+ goto rollback;
}
attr = ipp->current;
@@ -3097,8 +3096,7 @@ ippReadIO(void *src, /* I - Data source */
DEBUG_printf(("1ippReadIO: 1setOf value tag %x(%s) != %x(%s)",
value_tag, ippTagString(value_tag), tag,
ippTagString(tag)));
- _cupsBufferRelease((char *)buffer);
- return (IPP_STATE_ERROR);
+ goto rollback;
}
if (value_tag != tag)
@@ -3124,8 +3122,7 @@ ippReadIO(void *src, /* I - Data source */
DEBUG_printf(("1ippReadIO: 1setOf value tag %x(%s) != %x(%s)",
value_tag, ippTagString(value_tag), tag,
ippTagString(tag)));
- _cupsBufferRelease((char *)buffer);
- return (IPP_STATE_ERROR);
+ goto rollback;
}
if (value_tag == IPP_TAG_INTEGER && tag == IPP_TAG_RANGE)
@@ -3147,8 +3144,7 @@ ippReadIO(void *src, /* I - Data source */
DEBUG_printf(("1ippReadIO: value tag %x(%s) != %x(%s)",
value_tag, ippTagString(value_tag), tag,
ippTagString(tag)));
- _cupsBufferRelease((char *)buffer);
- return (IPP_STATE_ERROR);
+ goto rollback;
}
/*
@@ -3156,10 +3152,7 @@ ippReadIO(void *src, /* I - Data source */
*/
if ((value = ipp_set_value(ipp, &attr, attr->num_values)) == NULL)
- {
- _cupsBufferRelease((char *)buffer);
- return (IPP_STATE_ERROR);
- }
+ goto rollback;
}
else if (tag == IPP_TAG_MEMBERNAME)
{
@@ -3171,8 +3164,13 @@ ippReadIO(void *src, /* I - Data source */
{
_cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP member name is not empty."), 1);
DEBUG_puts("1ippReadIO: member name not empty.");
- _cupsBufferRelease((char *)buffer);
- return (IPP_STATE_ERROR);
+ goto rollback;
+ }
+ else if (!parent)
+ {
+ _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP member attribute outside of collection."), 1);
+ DEBUG_puts("1ippReadIO: member attribute outside of collection.");
+ goto rollback;
}
if (ipp->current)
@@ -3183,8 +3181,7 @@ ippReadIO(void *src, /* I - Data source */
{
_cupsSetHTTPError(HTTP_STATUS_ERROR);
DEBUG_puts("1ippReadIO: unable to allocate attribute.");
- _cupsBufferRelease((char *)buffer);
- return (IPP_STATE_ERROR);
+ goto rollback;
}
DEBUG_printf(("2ippReadIO: membername, ipp->current=%p, ipp->prev=%p", (void *)ipp->current, (void *)ipp->prev));
@@ -3200,8 +3197,7 @@ ippReadIO(void *src, /* I - Data source */
if ((*cb)(src, buffer, (size_t)n) < n)
{
DEBUG_puts("1ippReadIO: unable to read name.");
- _cupsBufferRelease((char *)buffer);
- return (IPP_STATE_ERROR);
+ goto rollback;
}
buffer[n] = '\0';
@@ -3214,8 +3210,7 @@ ippReadIO(void *src, /* I - Data source */
{
_cupsSetHTTPError(HTTP_STATUS_ERROR);
DEBUG_puts("1ippReadIO: unable to allocate attribute.");
- _cupsBufferRelease((char *)buffer);
- return (IPP_STATE_ERROR);
+ goto rollback;
}
DEBUG_printf(("2ippReadIO: name=\"%s\", ipp->current=%p, ipp->prev=%p", buffer, (void *)ipp->current, (void *)ipp->prev));
@@ -3231,8 +3226,7 @@ ippReadIO(void *src, /* I - Data source */
if ((*cb)(src, buffer, 2) < 2)
{
DEBUG_puts("1ippReadIO: unable to read value length.");
- _cupsBufferRelease((char *)buffer);
- return (IPP_STATE_ERROR);
+ goto rollback;
}
n = (buffer[0] << 8) | buffer[1];
@@ -3243,8 +3237,7 @@ ippReadIO(void *src, /* I - Data source */
_cupsSetError(IPP_STATUS_ERROR_INTERNAL,
_("IPP value larger than 32767 bytes."), 1);
DEBUG_printf(("1ippReadIO: bad value length %d.", n));
- _cupsBufferRelease((char *)buffer);
- return (IPP_STATE_ERROR);
+ goto rollback;
}
switch (tag)
@@ -3260,15 +3253,13 @@ ippReadIO(void *src, /* I - Data source */
_cupsSetError(IPP_STATUS_ERROR_INTERNAL,
_("IPP enum value not 4 bytes."), 1);
DEBUG_printf(("1ippReadIO: bad integer value length %d.", n));
- _cupsBufferRelease((char *)buffer);
- return (IPP_STATE_ERROR);
+ goto rollback;
}
if ((*cb)(src, buffer, 4) < 4)
{
DEBUG_puts("1ippReadIO: Unable to read integer value.");
- _cupsBufferRelease((char *)buffer);
- return (IPP_STATE_ERROR);
+ goto rollback;
}
n = (((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) |
@@ -3286,15 +3277,13 @@ ippReadIO(void *src, /* I - Data source */
_cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP boolean value not 1 byte."),
1);
DEBUG_printf(("1ippReadIO: bad boolean value length %d.", n));
- _cupsBufferRelease((char *)buffer);
- return (IPP_STATE_ERROR);
+ goto rollback;
}
if ((*cb)(src, buffer, 1) < 1)
{
DEBUG_puts("1ippReadIO: Unable to read boolean value.");
- _cupsBufferRelease((char *)buffer);
- return (IPP_STATE_ERROR);
+ goto rollback;
}
value->boolean = (char)buffer[0];
@@ -3335,8 +3324,7 @@ ippReadIO(void *src, /* I - Data source */
if ((*cb)(src, buffer, (size_t)n) < n)
{
DEBUG_puts("1ippReadIO: unable to read string value.");
- _cupsBufferRelease((char *)buffer);
- return (IPP_STATE_ERROR);
+ goto rollback;
}
}
@@ -3350,15 +3338,13 @@ ippReadIO(void *src, /* I - Data source */
{
_cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP date value not 11 bytes."), 1);
DEBUG_printf(("1ippReadIO: bad date value length %d.", n));
- _cupsBufferRelease((char *)buffer);
- return (IPP_STATE_ERROR);
+ goto rollback;
}
if ((*cb)(src, value->date, 11) < 11)
{
DEBUG_puts("1ippReadIO: Unable to read date value.");
- _cupsBufferRelease((char *)buffer);
- return (IPP_STATE_ERROR);
+ goto rollback;
}
break;
@@ -3368,15 +3354,13 @@ ippReadIO(void *src, /* I - Data source */
_cupsSetError(IPP_STATUS_ERROR_INTERNAL,
_("IPP resolution value not 9 bytes."), 1);
DEBUG_printf(("1ippReadIO: bad resolution value length %d.", n));
- _cupsBufferRelease((char *)buffer);
- return (IPP_STATE_ERROR);
+ goto rollback;
}
if ((*cb)(src, buffer, 9) < 9)
{
DEBUG_puts("1ippReadIO: Unable to read resolution value.");
- _cupsBufferRelease((char *)buffer);
- return (IPP_STATE_ERROR);
+ goto rollback;
}
value->resolution.xres =
@@ -3396,15 +3380,13 @@ ippReadIO(void *src, /* I - Data source */
_("IPP rangeOfInteger value not 8 bytes."), 1);
DEBUG_printf(("1ippReadIO: bad rangeOfInteger value length "
"%d.", n));
- _cupsBufferRelease((char *)buffer);
- return (IPP_STATE_ERROR);
+ goto rollback;
}
if ((*cb)(src, buffer, 8) < 8)
{
DEBUG_puts("1ippReadIO: Unable to read range value.");
- _cupsBufferRelease((char *)buffer);
- return (IPP_STATE_ERROR);
+ goto rollback;
}
value->range.lower =
@@ -3429,22 +3411,19 @@ ippReadIO(void *src, /* I - Data source */
"minimum 4 bytes."), 1);
DEBUG_printf(("1ippReadIO: bad stringWithLanguage value "
"length %d.", n));
- _cupsBufferRelease((char *)buffer);
- return (IPP_STATE_ERROR);
+ goto rollback;
}
if ((*cb)(src, buffer, (size_t)n) < n)
{
DEBUG_puts("1ippReadIO: Unable to read string w/language "
"value.");
- _cupsBufferRelease((char *)buffer);
- return (IPP_STATE_ERROR);
+ goto rollback;
}
bufptr = buffer;
bufend = buffer + n;
-
/*
* text-with-language and name-with-language are composite
* values:
@@ -3457,14 +3436,13 @@ ippReadIO(void *src, /* I - Data source */
n = (bufptr[0] << 8) | bufptr[1];
- if ((bufptr + 2 + n) >= bufend || n >= (int)sizeof(string))
+ if ((bufptr + 2 + n + 2) > bufend || n >= (int)sizeof(string))
{
_cupsSetError(IPP_STATUS_ERROR_INTERNAL,
_("IPP language length overflows value."), 1);
DEBUG_printf(("1ippReadIO: bad language value length %d.",
n));
- _cupsBufferRelease((char *)buffer);
- return (IPP_STATE_ERROR);
+ goto rollback;
}
else if (n >= IPP_MAX_LANGUAGE)
{
@@ -3472,8 +3450,7 @@ ippReadIO(void *src, /* I - Data source */
_("IPP language length too large."), 1);
DEBUG_printf(("1ippReadIO: bad language value length %d.",
n));
- _cupsBufferRelease((char *)buffer);
- return (IPP_STATE_ERROR);
+ goto rollback;
}
memcpy(string, bufptr + 2, (size_t)n);
@@ -3481,7 +3458,7 @@ ippReadIO(void *src, /* I - Data source */
value->string.language = _cupsStrAlloc((char *)string);
- bufptr += 2 + n;
+ bufptr += 2 + n;
n = (bufptr[0] << 8) | bufptr[1];
if ((bufptr + 2 + n) > bufend)
@@ -3489,8 +3466,7 @@ ippReadIO(void *src, /* I - Data source */
_cupsSetError(IPP_STATUS_ERROR_INTERNAL,
_("IPP string length overflows value."), 1);
DEBUG_printf(("1ippReadIO: bad string value length %d.", n));
- _cupsBufferRelease((char *)buffer);
- return (IPP_STATE_ERROR);
+ goto rollback;
}
bufptr[2 + n] = '\0';
@@ -3510,30 +3486,28 @@ ippReadIO(void *src, /* I - Data source */
_("IPP begCollection value not 0 bytes."), 1);
DEBUG_puts("1ippReadIO: begCollection tag with value length "
"> 0.");
- _cupsBufferRelease((char *)buffer);
- return (IPP_STATE_ERROR);
+ goto rollback;
}
if (ippReadIO(src, cb, 1, ipp, value->collection) == IPP_STATE_ERROR)
{
DEBUG_puts("1ippReadIO: Unable to read collection value.");
- _cupsBufferRelease((char *)buffer);
- return (IPP_STATE_ERROR);
+ goto rollback;
}
break;
case IPP_TAG_END_COLLECTION :
- _cupsBufferRelease((char *)buffer);
-
if (n > 0)
{
_cupsSetError(IPP_STATUS_ERROR_INTERNAL,
_("IPP endCollection value not 0 bytes."), 1);
DEBUG_puts("1ippReadIO: endCollection tag with value length "
"> 0.");
- return (IPP_STATE_ERROR);
+ goto rollback;
}
+ _cupsBufferRelease((char *)buffer);
+
DEBUG_puts("1ippReadIO: endCollection tag...");
return (ipp->state = IPP_STATE_DATA);
@@ -3548,22 +3522,19 @@ ippReadIO(void *src, /* I - Data source */
_cupsSetError(IPP_STATUS_ERROR_INTERNAL,
_("IPP memberName with no attribute."), 1);
DEBUG_puts("1ippReadIO: Member name without attribute.");
- _cupsBufferRelease((char *)buffer);
- return (IPP_STATE_ERROR);
+ goto rollback;
}
else if (n == 0)
{
_cupsSetError(IPP_STATUS_ERROR_INTERNAL,
_("IPP memberName value is empty."), 1);
DEBUG_puts("1ippReadIO: Empty member name value.");
- _cupsBufferRelease((char *)buffer);
- return (IPP_STATE_ERROR);
+ goto rollback;
}
else if ((*cb)(src, buffer, (size_t)n) < n)
{
DEBUG_puts("1ippReadIO: Unable to read member name value.");
- _cupsBufferRelease((char *)buffer);
- return (IPP_STATE_ERROR);
+ goto rollback;
}
buffer[n] = '\0';
@@ -3588,8 +3559,7 @@ ippReadIO(void *src, /* I - Data source */
_("IPP octetString length too large."), 1);
DEBUG_printf(("1ippReadIO: bad octetString value length %d.",
n));
- _cupsBufferRelease((char *)buffer);
- return (IPP_STATE_ERROR);
+ goto rollback;
}
value->unknown.length = n;
@@ -3600,15 +3570,13 @@ ippReadIO(void *src, /* I - Data source */
{
_cupsSetHTTPError(HTTP_STATUS_ERROR);
DEBUG_puts("1ippReadIO: Unable to allocate value");
- _cupsBufferRelease((char *)buffer);
- return (IPP_STATE_ERROR);
+ goto rollback;
}
if ((*cb)(src, value->unknown.data, (size_t)n) < n)
{
DEBUG_puts("1ippReadIO: Unable to read unsupported value.");
- _cupsBufferRelease((char *)buffer);
- return (IPP_STATE_ERROR);
+ goto rollback;
}
}
else
@@ -3636,6 +3604,17 @@ ippReadIO(void *src, /* I - Data source */
_cupsBufferRelease((char *)buffer);
return (ipp->state);
+
+ // If we get here, there was an error that required us to roll back the last
+ // attribute read in order to keep the IPP message valid...
+ rollback:
+
+ _cupsBufferRelease((char *)buffer);
+
+ if (attr)
+ ippDeleteAttribute(ipp, attr);
+
+ return (IPP_STATE_ERROR);
}