Skip to content

OCU-01-001 WP2: Crash via Wrong-Tag *-Supported Attributes (Medium) #149

@tapatiohaxx

Description

@tapatiohaxx

libcupsfilters validates enum-like job options against printer-reported *-supported
capability attributes on supported driverless and helper paths. In the audited code,
cfIPPAttrEnumValForPrinter() resolves the matching printer capability attribute by name
using IPP_TAG_ZERO, then iterates through its values and feeds ippGetString() results
directly into strcasecmp(). Despite the helper name, cfIPPAttrEnumValForPrinter()
returns the selected attribute value as a string.
This creates a crashable semantic type-confusion during the processing of untrusted
printer capability data. While network daemons like cups-browsed may validate
attributes via ippValidateAttributes() prior to ingestion, local parsing of malformed IPP
files or bypassed network validation will trigger the flaw. As confirmed by the
OpenPrinting maintainers, because libcupsfilters is a library and the caller provides the
attributes, this manifests as a local application crash rather than a service-level DoS.

Affected File:

https://github.com/OpenPrinting/libcupsfilters/blob/3ee9507/cupsfilters/ipp.c

Affected Code:

const char *
cfIPPAttrEnumValForPrinter(
    ipp_t *printer_attrs,  // I - Printer attributes (from get-printer-attributes or NULL)
    ipp_t *job_attrs,      // I - Job attributes
    const char *attr_name) // I - Attribute name
// O - Attribute value as string
{
    ipp_attribute_t *attr;
    char printer_attr_name[256];
    int i;
    const char *res;

    // Validate input parameters
    if ((printer_attrs == NULL && job_attrs == NULL) || attr_name == NULL)
        return NULL;

    // Check if job has the named attribute and get its value as string
    if (job_attrs == NULL ||
        (attr = ippFindAttribute(job_attrs, attr_name, IPP_TAG_ZERO)) == NULL) {
        res = NULL;
    } else {
        res = ippGetString(attr, 0, NULL);
    }

    if (printer_attrs) {
        if (res && res[0]) {
            // Check if value is valid according to printer attributes
            snprintf(printer_attr_name, sizeof(printer_attr_name) - 1,
                     "%s-supported", attr_name);

            if ((attr = ippFindAttribute(printer_attrs, printer_attr_name,
                                        IPP_TAG_ZERO)) != NULL) {
                for (i = 0; i < ippGetCount(attr); i++) {
                    if (strcasecmp(res, ippGetString(attr, i, NULL)) == 0)
                        break;  // Job attribute value is valid
                }

                if (i == ippGetCount(attr))
                    res = NULL;  // Job attribute value is not valid
            }
        }

        if (!res || !res[0]) {
            // Use default value if no valid value found
            snprintf(printer_attr_name, sizeof(printer_attr_name) - 1,
                     "%s-default", attr_name);

            if ((attr = ippFindAttribute(printer_attrs, printer_attr_name,
                                        IPP_TAG_ZERO)) != NULL)
                res = ippGetString(attr, 0, NULL);
        }
    }

    return res;
}

To mitigate this issue, it is recommended to request the expected string-compatible tag
or tags explicitly for *-supported attributes instead of using IPP_TAG_ZERO where
feasible. Every ippGetString() result should be checked before it is passed into
strcasecmp() or similar string-only logic, and wrong-tag capability attributes should be
treated as invalid printer data

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions