image_render_color_thresh(gx_image_enum *penum_orig, const byte *buffer, int data_x,
                          uint w, int h, gx_device * dev)
{
    gx_image_enum *penum = penum_orig; /* const within proc */
    image_posture posture = penum->posture;
    int vdi;  /* amounts to replicate */
    fixed xrun = 0;
    byte *thresh_align;
    byte *devc_contone[GX_DEVICE_COLOR_MAX_COMPONENTS];
    byte *psrc_plane[GX_DEVICE_COLOR_MAX_COMPONENTS];
    byte *devc_contone_gray;
    const byte *psrc = buffer + data_x;
    int dest_width, dest_height, data_length;
    int spp_out = dev->color_info.num_components;
    int position, i, j, k;
    int offset_bits = penum->ht_offset_bits;
    int contone_stride = 0;  /* Not used in landscape case */
    fixed offset;
    int src_size;
    bool flush_buff = false;
    byte *psrc_temp;
    int offset_contone[GX_DEVICE_COLOR_MAX_COMPONENTS];    /* to ensure 128 bit boundary */
    int offset_threshold;  /* to ensure 128 bit boundary */
    gx_dda_fixed dda_ht;
    int xn, xr;		/* destination position (pixel, not contone buffer offset) */
    int code = 0;
    int spp_cm = 0;
    byte *psrc_cm = NULL, *psrc_cm_start = NULL;
    byte *bufend = NULL;
    int psrc_planestride = w/penum->spp;

    if (h != 0 && penum->line_size != 0) {      /* line_size == 0, nothing to do */
        /* Get the buffer into the device color space */
        code = image_color_icc_prep(penum, psrc, w, dev, &spp_cm, &psrc_cm,
                                    &psrc_cm_start,  &bufend, true);
        if (code < 0)
            return code;
    } else {
        if (penum->ht_landscape.count == 0 || posture == image_portrait) {
            return 0;
        } else {
            /* Need to flush the buffer */
            offset_bits = penum->ht_landscape.count;
            penum->ht_offset_bits = offset_bits;
            penum->ht_landscape.offset_set = true;
            flush_buff = true;
        }
    }
    /* Data is now in the proper destination color space.  Now we want
       to go ahead and get the data into the proper spatial setting and then
       threshold.  First get the data spatially sampled correctly */
    src_size = penum->rect.w;

    /* Set up the dda.  We could move this out but the cost is pretty small */
    dda_ht = (posture == image_portrait) ? penum->dda.pixel0.x : penum->dda.pixel0.y;
    if (penum->dxx > 0)
        dda_translate(dda_ht, -fixed_epsilon);      /* to match rounding in non-fast code */

    switch (posture) {
        case image_portrait:
            /* Figure out our offset in the contone and threshold data
               buffers so that we ensure that we are on the 128bit
               memory boundaries when we get offset_bits into the data. */
            /* Can't do this earlier, as GC might move the buffers. */
            xrun = dda_current(dda_ht);
            dest_width = gxht_dda_length(&dda_ht, src_size);
            if (penum->x_extent.x < 0)
                xrun += penum->x_extent.x;
            vdi = penum->hci;
            contone_stride = penum->line_size;
            offset_threshold = (- (((long)(penum->thresh_buffer)) +
                                      penum->ht_offset_bits)) & 15;
            for (k = 0; k < spp_out; k ++) {
                offset_contone[k]   = (- (((long)(penum->line)) +
                                          contone_stride * k +
                                          penum->ht_offset_bits)) & 15;
            }
            data_length = dest_width;
            dest_height = fixed2int_var_rounded(any_abs(penum->y_extent.y));
#ifdef DEBUG
            /* Help in spotting problems */
            memset(penum->ht_buffer, 0x00, penum->ht_stride * vdi * spp_out);
#endif
            break;
        case image_landscape:
        default:
            /* Figure out our offset in the contone and threshold data buffers
               so that we ensure that we are on the 128bit memory boundaries.
               Can't do this earlier as GC may move the buffers.
             */
            vdi = penum->wci;
            contone_stride = penum->line_size;
            dest_width = fixed2int_var_rounded(any_abs(penum->y_extent.x));
            /* match height in gxht_thresh.c dev_width calculation */
            xrun = dda_current(dda_ht);            /* really yrun, but just used here for landscape */
            dest_height = gxht_dda_length(&dda_ht, src_size);
            data_length = dest_height;
            offset_threshold = (-(long)(penum->thresh_buffer)) & 15;
            for (k = 0; k < spp_out; k ++) {
                offset_contone[k]   = (- ((long)(penum->line) +
                                          contone_stride * k)) & 15;
            }
            /* In the landscaped case, we want to accumulate multiple columns
               of data before sending to the device.  We want to have a full
               byte of HT data in one write.  This may not be possible at the
               left or right and for those and for those we have so send partial
               chunks */
            /* Initialize our xstart and compute our partial bit chunk so
               that we get in sync with the 1 bit mem device 16 bit positions
               for the rest of the chunks */
            if (penum->ht_landscape.count == 0) {
                /* In the landscape case, the size depends upon
                   if we are moving left to right or right to left with
                   the image data.  This offset is to ensure that we  get
                   aligned in our chunks along 16 bit boundaries */
                penum->ht_landscape.offset_set = true;
                if (penum->ht_landscape.index < 0) {
                    penum->ht_landscape.xstart = penum->xci + vdi - 1;
                    offset_bits = (penum->ht_landscape.xstart % 16) + 1;
                    /* xci can be negative, so allow for that */
                    if (offset_bits <= 0) offset_bits += 16;
                } else {
                    penum->ht_landscape.xstart = penum->xci;
                    /* xci can be negative, see Bug 692569. */
                    offset_bits = 16 - penum->xci % 16;
                    if (offset_bits >= 16) offset_bits -= 16;
                }
                if (offset_bits == 0 || offset_bits == 16) {
                    penum->ht_landscape.offset_set = false;
                    penum->ht_offset_bits = 0;
                } else {
                    penum->ht_offset_bits = offset_bits;
                }
            }
            break;
    }
    if (flush_buff)
        goto flush;  /* All done */

    /* Get the pointers to our buffers */
    for (k = 0; k < spp_out; k++) {
        if (posture == image_portrait) {
            devc_contone[k] = penum->line + contone_stride * k +
                              offset_contone[k];
        } else {
            devc_contone[k] = penum->line + offset_contone[k] +
                              LAND_BITS * k * contone_stride;
        }
        psrc_plane[k] = psrc_cm + psrc_planestride * k;
    }
    xr = fixed2int_var_rounded(dda_current(dda_ht));	/* indexes in the destination (contone) */

    /* Do conversion to device resolution in quick small loops. */
    /* For now we have 3 cases.  A CMYK (4 channel), gray, or other case
       the latter of which is not yet implemented */
    switch (spp_out)
    {
        /* Monochrome output case */
        case 1:
            devc_contone_gray = devc_contone[0];
            switch (posture) {
                /* Monochrome portrait */
                case image_portrait:
                    if (penum->dst_width > 0) {
                        if (src_size == dest_width) {
                            memcpy(devc_contone_gray, psrc_cm, data_length);
                        } else if (src_size * 2 == dest_width) {
                            psrc_temp = psrc_cm;
                            for (k = 0; k < data_length; k+=2,
                                 devc_contone_gray+=2, psrc_temp++) {
                                *devc_contone_gray =
                                    *(devc_contone_gray+1) = *psrc_temp;
                            }
                        } else {
                            /* Mono case, forward */
                            psrc_temp = psrc_cm;
                            for (k=0; k<src_size; k++) {
                                dda_next(dda_ht);
                                xn = fixed2int_var_rounded(dda_current(dda_ht));
                                while (xr < xn) {
                                    *devc_contone_gray++ = *psrc_temp;
                                    xr++;
                                }           /* at loop exit xn will be >= xr */
                                psrc_temp++;
                            }
                        }
                    } else {
                        /* Mono case, backwards */
                        devc_contone_gray += (data_length - 1);
                        psrc_temp = psrc_cm;
                        for (k=0; k<src_size; k++) {
                            dda_next(dda_ht);
                            xn = fixed2int_var_rounded(dda_current(dda_ht));
                            while (xr > xn) {
                                *devc_contone_gray-- = *psrc_temp;
                                xr--;
                            }           /* at loop exit xn will be >= xr */
                            psrc_temp++;
                        }
                    }
                    break;
                /* Monochrome landscape */
                case image_landscape:
                    /* We store the data at this point into a column. Depending
                       upon our landscape direction we may be going left to right
                       or right to left. */
                    if (penum->ht_landscape.flipy) {
                        position = penum->ht_landscape.curr_pos +
                                    LAND_BITS * (data_length - 1);
                        psrc_temp = psrc_cm;
                        for (k=0; k<src_size; k++) {
                            dda_next(dda_ht);
                            xn = fixed2int_var_rounded(dda_current(dda_ht));
                            while (xr > xn) {
                                devc_contone_gray[position] = *psrc_temp;
                                position -= LAND_BITS;
                                xr--;
                            }           /* at loop exit xn will be <= xr */
                            psrc_temp++;
                        }
                    } else {
                        position = penum->ht_landscape.curr_pos;
                        /* Code up special cases for when we have no scaling
                           and 2x scaling which we will run into in 300 and
                           600dpi devices and content */
                        if (src_size == dest_height) {
                            for (k = 0; k < data_length; k++) {
                                devc_contone_gray[position] = psrc_cm[k];
                                position += LAND_BITS;
                            }
                        } else if (src_size*2 == dest_height) {
                            for (k = 0; k < data_length; k+=2) {
                                offset = fixed2int_var_rounded(fixed_half * k);
                                devc_contone_gray[position] =
                                    devc_contone_gray[position + LAND_BITS] =
                                    psrc_cm[offset];
                                position += 2*LAND_BITS;
                            }
                        } else {
                            /* use dda */
                            psrc_temp = psrc_cm;
                            for (k=0; k<src_size; k++) {
                                dda_next(dda_ht);
                                xn = fixed2int_var_rounded(dda_current(dda_ht));
                                while (xr < xn) {
                                    devc_contone_gray[position] = *psrc_temp;
                                    position += LAND_BITS;
                                    xr++;
                                }           /* at loop exit xn will be >= xr */
                                psrc_temp++;
                            }
                        }
                    }
                    /* Store the width information and update our counts */
                    penum->ht_landscape.count += vdi;
                    penum->ht_landscape.widths[penum->ht_landscape.curr_pos] = vdi;
                    penum->ht_landscape.curr_pos += penum->ht_landscape.index;
                    penum->ht_landscape.num_contones++;
                    break;
                default:
                    /* error not allowed */
                    break;
            }
        break;

        /* CMYK case */
        case 4:
            switch (posture) {
                /* CMYK portrait */
                case image_portrait:
                    if (penum->dst_width > 0) {
                        if (src_size == dest_width) {
                            memcpy(devc_contone[0], psrc_plane[0], data_length);
                            memcpy(devc_contone[1], psrc_plane[1], data_length);
                            memcpy(devc_contone[2], psrc_plane[2], data_length);
                            memcpy(devc_contone[3], psrc_plane[3], data_length);
                        } else if (src_size * 2 == dest_width) {
                            for (k = 0; k < data_length; k+=2) {
                                *(devc_contone[0]) = *(devc_contone[0]+1) =
                                    *psrc_plane[0]++;
                                *(devc_contone[1]) = *(devc_contone[1]+1) =
                                    *psrc_plane[1]++;
                                *(devc_contone[2]) = *(devc_contone[2]+1) =
                                    *psrc_plane[2]++;
                                *(devc_contone[3]) = *(devc_contone[3]+1) =
                                    *psrc_plane[3]++;
                                devc_contone[0] += 2;
                                devc_contone[1] += 2;
                                devc_contone[2] += 2;
                                devc_contone[3] += 2;
                            }
                        } else {
                        /* CMYK case, forward */
                            for (k=0, j=0; k<src_size; k++) {
                                dda_next(dda_ht);
                                xn = fixed2int_var_rounded(dda_current(dda_ht));
                                while (xr < xn) {
                                    *(devc_contone[0])++ = (psrc_plane[0])[j];
                                    *(devc_contone[1])++ = (psrc_plane[1])[j];
                                    *(devc_contone[2])++ = (psrc_plane[2])[j];
                                    *(devc_contone[3])++ = (psrc_plane[3])[j];
                                    xr++;
                                }           /* at loop exit xn will be >= xr */
                                j++;
                            }
                        }
                    } else {
                        /* CMYK case, backwards */
                        /* Move to the other end and we will decrement */
                        devc_contone[0] += (data_length - 1);
                        devc_contone[1] += (data_length - 1);
                        devc_contone[2] += (data_length - 1);
                        devc_contone[3] += (data_length - 1);
                        for (k=0, j=0; k<src_size; k++) {
                            dda_next(dda_ht);
                            xn = fixed2int_var_rounded(dda_current(dda_ht));
                            while (xr > xn) {
                                *(devc_contone[0])-- = (psrc_plane[0])[j];
                                *(devc_contone[1])-- = (psrc_plane[1])[j];
                                *(devc_contone[2])-- = (psrc_plane[2])[j];
                                *(devc_contone[3])-- = (psrc_plane[3])[j];
                                xr--;
                            }           /* at loop exit xn will be <= xr */
                            j++;
                        }
                    }
                    break;
                /* CMYK landscape */
                case image_landscape:
                    /* Data is already color managed. */
                    /* We store the data at this point into columns in
                       seperate planes. Depending upon our landscape direction
                       we may be going left to right or right to left. */
                    if (penum->ht_landscape.flipy) {
                        position = penum->ht_landscape.curr_pos +
                                    LAND_BITS * (data_length - 1);
                        /* use dda */
                        for (k=0, i=0; k<src_size; k++) {
                            dda_next(dda_ht);
                            xn = fixed2int_var_rounded(dda_current(dda_ht));
                            while (xr > xn) {
                                for (j = 0; j < spp_out; j++)
                                    *(devc_contone[j] + position) = (psrc_plane[j])[i];
                                position -= LAND_BITS;
                                xr--;
                            }           /* at loop exit xn will be <= xr */
                            i++;
                        }
                    } else {
                        position = penum->ht_landscape.curr_pos;
                        /* Code up special cases for when we have no scaling
                           and 2x scaling which we will run into in 300 and
                           600dpi devices and content */
                        /* Apply initial offset */
                        for (k = 0; k < spp_out; k++)
                            devc_contone[k] = devc_contone[k] + position;
                        if (src_size == dest_height) {
                            for (k = 0; k < data_length; k++) {
                                /* Is it better to unwind this?  We know it is 4 */
                                for (j = 0; j < spp_out; j++) {
                                    *(devc_contone[j]) = (psrc_plane[j])[k];
                                    devc_contone[j] += LAND_BITS;
                                }
                            }
                        } else if (src_size*2 == dest_height) {
                            for (k = 0; k < data_length; k+=2) {
                                offset = fixed2int_var_rounded(fixed_half * k);
                                /* Is it better to unwind this?  We know it is 4 */
                                for (j = 0; j < spp_out; j++) {
                                    *(devc_contone[j]) =
                                      *(devc_contone[j] + LAND_BITS) =
                                      (psrc_plane[j])[offset];
                                    devc_contone[j] += 2 * LAND_BITS;
                                }
                            }
                        } else {
                            /* use dda */
                            for (k=0, i=0; k<src_size; k++) {
                                dda_next(dda_ht);
                                xn = fixed2int_var_rounded(dda_current(dda_ht));
                                while (xr > xn) {
                                    for (j = 0; j < spp_out; j++)
                                        *(devc_contone[j] + position) = (psrc_plane[j])[i];
                                    position -= LAND_BITS;
                                    xr--;
                                }           /* at loop exit xn will be <= xr */
                                i++;
                            }
                        }
                    }
                    /* Store the width information and update our counts */
                    penum->ht_landscape.count += vdi;
                    penum->ht_landscape.widths[penum->ht_landscape.curr_pos] = vdi;
                    penum->ht_landscape.curr_pos += penum->ht_landscape.index;
                    penum->ht_landscape.num_contones++;
                    break;
                default:
                    /* error not allowed */
                    break;
            }
        break;
        default:
            /* Not yet handled (e.g. CMY case) */
        break;
    }
    /* Apply threshold array to image data. It may be neccessary to invert
       depnding upon the polarity of the device */
flush:
    thresh_align = penum->thresh_buffer + offset_threshold;
    code = gxht_thresh_planes(penum, xrun, dest_width, dest_height,
                              thresh_align, dev, offset_contone,
                              contone_stride);
    /* Free cm buffer, if it was used */
    if (psrc_cm_start != NULL) {
        gs_free_object(penum->pgs->memory, (byte *)psrc_cm_start,
                       "image_render_color_thresh");
    }
    return code;
}


Fixes old bug(which could result in Denial of Service)
due to a missing check before reading the 8 bytes of a DW_FORM_ref_sig8.
DW202206-001
	modified:   src/lib/libdwarf/dwarf_form.c

dwarf_global_formref_b(Dwarf_Attribute attr,
    Dwarf_Off * ret_offset,
    Dwarf_Bool * offset_is_info,
    Dwarf_Error * error)
{
    Dwarf_Debug dbg = 0;
    Dwarf_Unsigned offset = 0;
    Dwarf_CU_Context cu_context = 0;
    Dwarf_Half context_version = 0;
    Dwarf_Byte_Ptr section_end = 0;
    Dwarf_Bool is_info = TRUE;

    int res  = get_attr_dbg(&dbg,&cu_context,attr,error);
    if (res != DW_DLV_OK) {
        return res;
    }
    section_end =
        _dwarf_calculate_info_section_end_ptr(cu_context);
    context_version = cu_context->cc_version_stamp;
    is_info = cu_context->cc_is_info;
    switch (attr->ar_attribute_form) {

    case DW_FORM_ref1:
        offset = *(Dwarf_Small *) attr->ar_debug_ptr;
        goto fixoffset;

    case DW_FORM_ref2:
        READ_UNALIGNED_CK(dbg, offset, Dwarf_Unsigned,
            attr->ar_debug_ptr, DWARF_HALF_SIZE,
            error,section_end);
        goto fixoffset;

    case DW_FORM_ref4:
        READ_UNALIGNED_CK(dbg, offset, Dwarf_Unsigned,
            attr->ar_debug_ptr, DWARF_32BIT_SIZE,
            error,section_end);
        goto fixoffset;

    case DW_FORM_ref8:
        READ_UNALIGNED_CK(dbg, offset, Dwarf_Unsigned,
            attr->ar_debug_ptr, DWARF_64BIT_SIZE,
            error,section_end);
        goto fixoffset;

    case DW_FORM_ref_udata:
        {
        Dwarf_Byte_Ptr ptr = attr->ar_debug_ptr;
        Dwarf_Unsigned localoffset = 0;

        DECODE_LEB128_UWORD_CK(ptr,localoffset,
            dbg,error,section_end);
        offset = localoffset;

        fixoffset: /* we have a local offset, make it global */

        /* check legality of offset */
        if (offset >= cu_context->cc_length +
            cu_context->cc_length_size +
            cu_context->cc_extension_size) {
            _dwarf_error(dbg, error, DW_DLE_ATTR_FORM_OFFSET_BAD);
            return DW_DLV_ERROR;
        }

        /* globalize the offset */
        offset += cu_context->cc_debug_offset;
        }
        break;

    /*  The DWARF2 document did not make clear that
        DW_FORM_data4( and 8) were references with
        global offsets to some section.
        That was first clearly documented in DWARF3.
        In DWARF4 these two forms are no longer references. */
    case DW_FORM_data4:
        if (context_version >= DW_CU_VERSION4) {
            _dwarf_error(dbg, error, DW_DLE_NOT_REF_FORM);
            return DW_DLV_ERROR;
        }
        READ_UNALIGNED_CK(dbg, offset, Dwarf_Unsigned,
            attr->ar_debug_ptr, DWARF_32BIT_SIZE,
            error, section_end);
        /* The offset is global. */
        break;
    case DW_FORM_data8:
        if (context_version >= DW_CU_VERSION4) {
            _dwarf_error(dbg, error, DW_DLE_NOT_REF_FORM);
            return DW_DLV_ERROR;
        }
        READ_UNALIGNED_CK(dbg, offset, Dwarf_Unsigned,
            attr->ar_debug_ptr, DWARF_64BIT_SIZE,
            error,section_end);
        /* The offset is global. */
        break;
    case DW_FORM_ref_addr:
        {
            /*  In Dwarf V2 DW_FORM_ref_addr was defined
                as address-size even though it is a .debug_info
                offset.  Fixed in Dwarf V3 to be offset-size.
                */
            unsigned length_size = 0;
            if (context_version == 2) {
                length_size = cu_context->cc_address_size;
            } else {
                length_size = cu_context->cc_length_size;
            }
            if (length_size == 4) {
                READ_UNALIGNED_CK(dbg, offset, Dwarf_Unsigned,
                    attr->ar_debug_ptr, DWARF_32BIT_SIZE,
                    error,section_end);
            } else if (length_size == 8) {
                READ_UNALIGNED_CK(dbg, offset, Dwarf_Unsigned,
                    attr->ar_debug_ptr, DWARF_64BIT_SIZE,
                    error,section_end);
            } else {
                _dwarf_error(dbg, error,
                    DW_DLE_FORM_SEC_OFFSET_LENGTH_BAD);
                return DW_DLV_ERROR;
            }
        }
        break;
    /*  Index into .debug_rnglists/.debug_loclists section.
        Return the index itself. */
    case DW_FORM_loclistx:
    case DW_FORM_rnglistx: {
        unsigned length_size = cu_context->cc_length_size;
        READ_UNALIGNED_CK(dbg, offset, Dwarf_Unsigned,
            attr->ar_debug_ptr, length_size,
            error,section_end);
        }
        break;
    case DW_FORM_sec_offset:
    case DW_FORM_GNU_ref_alt:  /* 2013 GNU extension */
    case DW_FORM_GNU_strp_alt: /* 2013 GNU extension */
    case DW_FORM_strp_sup:     /* DWARF5, sup string section */
    case DW_FORM_line_strp:    /* DWARF5, .debug_line_str section */
        {
            /*  DW_FORM_sec_offset first exists in DWARF4.*/
            /*  It is up to the caller to know what the offset
                of DW_FORM_sec_offset, DW_FORM_strp_sup
                or DW_FORM_GNU_strp_alt etc refer to,
                the offset is not going to refer to .debug_info! */
            unsigned length_size = cu_context->cc_length_size;
            if (length_size == 4) {
                READ_UNALIGNED_CK(dbg, offset, Dwarf_Unsigned,
                    attr->ar_debug_ptr, DWARF_32BIT_SIZE,
                    error,section_end);
            } else if (length_size == 8) {
                READ_UNALIGNED_CK(dbg, offset, Dwarf_Unsigned,
                    attr->ar_debug_ptr, DWARF_64BIT_SIZE,
                    error,section_end);
            } else {
                _dwarf_error(dbg, error,
                    DW_DLE_FORM_SEC_OFFSET_LENGTH_BAD);
                return DW_DLV_ERROR;
            }
        }
        break;
    case DW_FORM_ref_sig8: {
        /*  This, in DWARF4, is how
            .debug_info refers to .debug_types. */
        Dwarf_Sig8 sig8;
        Dwarf_Bool t_is_info = TRUE;
        Dwarf_Unsigned t_offset = 0;

        memcpy(&sig8,attr->ar_debug_ptr,sizeof(Dwarf_Sig8));
        res = find_sig8_target_as_global_offset(attr,
            &sig8,&t_is_info,&t_offset,error);
        if (res == DW_DLV_ERROR) {
            _dwarf_error_string(dbg, error,
                DW_DLE_REF_SIG8_NOT_HANDLED,
                "DW_DLE_REF_SIG8_NOT_HANDLED: "
                " problem finding target");
            return DW_DLV_ERROR;
        }
        if (res == DW_DLV_NO_ENTRY) {
            return res;
        }
        is_info = t_is_info;
        offset = t_offset;
        break;
    }
    default: {
        dwarfstring m;
        int formcode = attr->ar_attribute_form;
        int fcres = 0;
        const char *name = 0;

        dwarfstring_constructor(&m);
        dwarfstring_append_printf_u(&m,
            "DW_DLE_BAD_REF_FORM: The form code is 0x%x ",
            formcode);
        fcres  = dwarf_get_FORM_name (formcode,&name);
        if (fcres != DW_DLV_OK) {
            name="<UnknownFormCode>";
        }
        dwarfstring_append_printf_s(&m,
            " %s.",(char *)name);
        _dwarf_error_string(dbg, error, DW_DLE_BAD_REF_FORM,
            dwarfstring_string(&m));
        dwarfstring_destructor(&m);
        return DW_DLV_ERROR;
        }
    }

    *offset_is_info = is_info;
    *ret_offset = offset;
    return DW_DLV_OK;
}

There is a heap-based buffer over-read in libdwarf 0.4.0. This issue is related to dwarf_global_formref_b.


dwarf_global_formref_b(Dwarf_Attribute attr,
    Dwarf_Off * ret_offset,
    Dwarf_Bool * offset_is_info,
    Dwarf_Error * error)
{
    Dwarf_Debug dbg = 0;
    Dwarf_Unsigned offset = 0;
    Dwarf_CU_Context cu_context = 0;
    Dwarf_Half context_version = 0;
    Dwarf_Byte_Ptr section_end = 0;
    Dwarf_Bool is_info = TRUE;

    int res  = get_attr_dbg(&dbg,&cu_context,attr,error);
    if (res != DW_DLV_OK) {
        return res;
    }
    section_end =
        _dwarf_calculate_info_section_end_ptr(cu_context);
    context_version = cu_context->cc_version_stamp;
    is_info = cu_context->cc_is_info;
    switch (attr->ar_attribute_form) {

    case DW_FORM_ref1:
        offset = *(Dwarf_Small *) attr->ar_debug_ptr;
        goto fixoffset;

    case DW_FORM_ref2:
        READ_UNALIGNED_CK(dbg, offset, Dwarf_Unsigned,
            attr->ar_debug_ptr, DWARF_HALF_SIZE,
            error,section_end);
        goto fixoffset;

    case DW_FORM_ref4:
        READ_UNALIGNED_CK(dbg, offset, Dwarf_Unsigned,
            attr->ar_debug_ptr, DWARF_32BIT_SIZE,
            error,section_end);
        goto fixoffset;

    case DW_FORM_ref8:
        READ_UNALIGNED_CK(dbg, offset, Dwarf_Unsigned,
            attr->ar_debug_ptr, DWARF_64BIT_SIZE,
            error,section_end);
        goto fixoffset;

    case DW_FORM_ref_udata:
        {
        Dwarf_Byte_Ptr ptr = attr->ar_debug_ptr;
        Dwarf_Unsigned localoffset = 0;

        DECODE_LEB128_UWORD_CK(ptr,localoffset,
            dbg,error,section_end);
        offset = localoffset;

        fixoffset: /* we have a local offset, make it global */

        /* check legality of offset */
        if (offset >= cu_context->cc_length +
            cu_context->cc_length_size +
            cu_context->cc_extension_size) {
            _dwarf_error(dbg, error, DW_DLE_ATTR_FORM_OFFSET_BAD);
            return DW_DLV_ERROR;
        }

        /* globalize the offset */
        offset += cu_context->cc_debug_offset;
        }
        break;

    /*  The DWARF2 document did not make clear that
        DW_FORM_data4( and 8) were references with
        global offsets to some section.
        That was first clearly documented in DWARF3.
        In DWARF4 these two forms are no longer references. */
    case DW_FORM_data4:
        if (context_version >= DW_CU_VERSION4) {
            _dwarf_error(dbg, error, DW_DLE_NOT_REF_FORM);
            return DW_DLV_ERROR;
        }
        READ_UNALIGNED_CK(dbg, offset, Dwarf_Unsigned,
            attr->ar_debug_ptr, DWARF_32BIT_SIZE,
            error, section_end);
        /* The offset is global. */
        break;
    case DW_FORM_data8:
        if (context_version >= DW_CU_VERSION4) {
            _dwarf_error(dbg, error, DW_DLE_NOT_REF_FORM);
            return DW_DLV_ERROR;
        }
        READ_UNALIGNED_CK(dbg, offset, Dwarf_Unsigned,
            attr->ar_debug_ptr, DWARF_64BIT_SIZE,
            error,section_end);
        /* The offset is global. */
        break;
    case DW_FORM_ref_addr:
        {
            /*  In Dwarf V2 DW_FORM_ref_addr was defined
                as address-size even though it is a .debug_info
                offset.  Fixed in Dwarf V3 to be offset-size.
                */
            unsigned length_size = 0;
            if (context_version == 2) {
                length_size = cu_context->cc_address_size;
            } else {
                length_size = cu_context->cc_length_size;
            }
            if (length_size == 4) {
                READ_UNALIGNED_CK(dbg, offset, Dwarf_Unsigned,
                    attr->ar_debug_ptr, DWARF_32BIT_SIZE,
                    error,section_end);
            } else if (length_size == 8) {
                READ_UNALIGNED_CK(dbg, offset, Dwarf_Unsigned,
                    attr->ar_debug_ptr, DWARF_64BIT_SIZE,
                    error,section_end);
            } else {
                _dwarf_error(dbg, error,
                    DW_DLE_FORM_SEC_OFFSET_LENGTH_BAD);
                return DW_DLV_ERROR;
            }
        }
        break;
    /*  Index into .debug_rnglists/.debug_loclists section.
        Return the index itself. */
    case DW_FORM_loclistx:
    case DW_FORM_rnglistx: {
        unsigned length_size = cu_context->cc_length_size;
        READ_UNALIGNED_CK(dbg, offset, Dwarf_Unsigned,
            attr->ar_debug_ptr, length_size,
            error,section_end);
        }
        break;
    case DW_FORM_sec_offset:
    case DW_FORM_GNU_ref_alt:  /* 2013 GNU extension */
    case DW_FORM_GNU_strp_alt: /* 2013 GNU extension */
    case DW_FORM_strp_sup:     /* DWARF5, sup string section */
    case DW_FORM_line_strp:    /* DWARF5, .debug_line_str section */
        {
            /*  DW_FORM_sec_offset first exists in DWARF4.*/
            /*  It is up to the caller to know what the offset
                of DW_FORM_sec_offset, DW_FORM_strp_sup
                or DW_FORM_GNU_strp_alt etc refer to,
                the offset is not going to refer to .debug_info! */
            unsigned length_size = cu_context->cc_length_size;
            if (length_size == 4) {
                READ_UNALIGNED_CK(dbg, offset, Dwarf_Unsigned,
                    attr->ar_debug_ptr, DWARF_32BIT_SIZE,
                    error,section_end);
            } else if (length_size == 8) {
                READ_UNALIGNED_CK(dbg, offset, Dwarf_Unsigned,
                    attr->ar_debug_ptr, DWARF_64BIT_SIZE,
                    error,section_end);
            } else {
                _dwarf_error(dbg, error,
                    DW_DLE_FORM_SEC_OFFSET_LENGTH_BAD);
                return DW_DLV_ERROR;
            }
        }
        break;
    case DW_FORM_ref_sig8: {
        /*  This, in DWARF4, is how
            .debug_info refers to .debug_types. */
        Dwarf_Sig8 sig8;
        Dwarf_Bool t_is_info = TRUE;
        Dwarf_Unsigned t_offset = 0;

        if ((attr->ar_debug_ptr + sizeof(Dwarf_Sig8)) > section_end) {
            _dwarf_error_string(dbg, error,
                DW_DLE_REF_SIG8_NOT_HANDLED,
                "DW_DLE_REF_SIG8_NOT_HANDLED: "
                " Dwarf_Sig8 content runs off the end of its section");
            return DW_DLV_ERROR;
        }
        memcpy(&sig8,attr->ar_debug_ptr,sizeof(Dwarf_Sig8));
        res = find_sig8_target_as_global_offset(attr,
            &sig8,&t_is_info,&t_offset,error);
        if (res == DW_DLV_ERROR) {
            _dwarf_error_string(dbg, error,
                DW_DLE_REF_SIG8_NOT_HANDLED,
                "DW_DLE_REF_SIG8_NOT_HANDLED: "
                " problem finding target");
            return DW_DLV_ERROR;
        }
        if (res == DW_DLV_NO_ENTRY) {
            return res;
        }
        is_info = t_is_info;
        offset = t_offset;
        break;
    }
    default: {
        dwarfstring m;
        int formcode = attr->ar_attribute_form;
        int fcres = 0;
        const char *name = 0;

        dwarfstring_constructor(&m);
        dwarfstring_append_printf_u(&m,
            "DW_DLE_BAD_REF_FORM: The form code is 0x%x ",
            formcode);
        fcres  = dwarf_get_FORM_name (formcode,&name);
        if (fcres != DW_DLV_OK) {
            name="<UnknownFormCode>";
        }
        dwarfstring_append_printf_s(&m,
            " %s.",(char *)name);
        _dwarf_error_string(dbg, error, DW_DLE_BAD_REF_FORM,
            dwarfstring_string(&m));
        dwarfstring_destructor(&m);
        return DW_DLV_ERROR;
        }
    }

    *offset_is_info = is_info;
    *ret_offset = offset;
    return DW_DLV_OK;
}


lib/vsprintf: Replace space with '_' before crng is ready

Before crng is ready, output of "%p" composes of "(ptrval)" and
left padding spaces for alignment as no random address can be
generated. This seems a little strange when default string width
is larger than strlen("(ptrval)").

For example, when irq domain names are built with "%p", the nodes
under /sys/kernel/debug/irq/domains like this on AArch64 system,

[root@y irq]# ls domains/
default                   irqchip@        (ptrval)-2
irqchip@        (ptrval)-4  \_SB_.TCS0.QIC1  \_SB_.TCS0.QIC3
irqchip@        (ptrval)  irqchip@        (ptrval)-3
\_SB_.TCS0.QIC0             \_SB_.TCS0.QIC2

The name "irqchip@        (ptrval)-2" is not so readable in console
output.

This patch replaces space with readable "_" when output needs padding.
Following is the output after applying the patch,

[root@y domains]# ls
default                   irqchip@(____ptrval____)-2
irqchip@(____ptrval____)-4  \_SB_.TCS0.QIC1  \_SB_.TCS0.QIC3
irqchip@(____ptrval____)  irqchip@(____ptrval____)-3  \_SB_.TCS0.QIC0
\_SB_.TCS0.QIC2

There is same problem in some subsystem's dmesg output. Moreover,
someone may call "%p" in a similar case. In addition, the timing of
crng initialization done may vary on different system. So, the change
is made in vsprintf.c.

Suggested-by: Rasmus Villemoes <linux@rasmusvillemoes.dk>
Link: http://lkml.kernel.org/r/20180216210711.79901-7-andriy.shevchenko@linux.intel.com
To: "Tobin C . Harding" <me@tobin.cc>
To: linux@rasmusvillemoes.dk
To: Joe Perches <joe@perches.com>
To: linux-kernel@vger.kernel.org
To: Andrew Morton <akpm@linux-foundation.org>
Cc: Joey Zheng <yu.zheng@hxt-semitech.com>
Signed-off-by: Shunyong Yang <shunyong.yang@hxt-semitech.com>
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Petr Mladek <pmladek@suse.com>

static char *ptr_to_id(char *buf, char *end, void *ptr, struct printf_spec spec)
{
	unsigned long hashval;

	if (unlikely(!have_filled_random_ptr_key)) {
		spec.field_width = 2 * sizeof(ptr);
		/* string length must be less than default_width */
		return string(buf, end, "(ptrval)", spec);
	}

#ifdef CONFIG_64BIT
	hashval = (unsigned long)siphash_1u64((u64)ptr, &ptr_key);
	/*
	 * Mask off the first 32 bits, this makes explicit that we have
	 * modified the address (and 32 bits is plenty for a unique ID).
	 */
	hashval = hashval & 0xffffffff;
#else
	hashval = (unsigned long)siphash_1u32((u32)ptr, &ptr_key);
#endif
	return pointer_string(buf, end, (const void *)hashval, spec);
}

The hidma_chan_stats function in drivers/dma/qcom/hidma_dbg.c in the Linux kernel 4.14.90 allows local users to obtain sensitive address information by reading "callback=" lines in a debugfs file.


static char *ptr_to_id(char *buf, char *end, void *ptr, struct printf_spec spec)
{
	const char *str = sizeof(ptr) == 8 ? "(____ptrval____)" : "(ptrval)";
	unsigned long hashval;

	if (unlikely(!have_filled_random_ptr_key)) {
		spec.field_width = 2 * sizeof(ptr);
		/* string length must be less than default_width */
		return string(buf, end, str, spec);
	}

#ifdef CONFIG_64BIT
	hashval = (unsigned long)siphash_1u64((u64)ptr, &ptr_key);
	/*
	 * Mask off the first 32 bits, this makes explicit that we have
	 * modified the address (and 32 bits is plenty for a unique ID).
	 */
	hashval = hashval & 0xffffffff;
#else
	hashval = (unsigned long)siphash_1u32((u32)ptr, &ptr_key);
#endif
	return pointer_string(buf, end, (const void *)hashval, spec);
}


Fix DCTStream::getChars we're reading past the buffer check

I wonder how this had never crashed before :S

Fixes #1011

int DCTStream::getChars(int nChars, unsigned char *buffer)
{
    for (int i = 0; i < nChars;) {
        if (current == limit) {
            if (!readLine())
                return i;
        }
        int left = limit - current;
        if (nChars < left)
            left = nChars;
        memcpy(buffer + i, current, left);
        current += left;
        i += left;
    }
    return nChars;
}

DCTStream::getChars in DCTStream.cc in Poppler 20.12.1 has a heap-based buffer overflow via a crafted PDF document. NOTE: later reports indicate that this only affects builds from Poppler git clones in late December 2020, not the 20.12.1 release. In this situation, it should NOT be considered a Poppler vulnerability. However, several third-party Open Source projects directly rely on Poppler git clones made at arbitrary times, and therefore the CVE remains useful to users of those projects


int DCTStream::getChars(int nChars, unsigned char *buffer)
{
    for (int i = 0; i < nChars;) {
        if (current == limit) {
            if (!readLine())
                return i;
        }
        int left = limit - current;
        if (left + i > nChars)
            left = nChars - i;
        memcpy(buffer + i, current, left);
        current += left;
        i += left;
    }
    return nChars;
}


wildcardmatch: fix heap buffer overflow in setcharset

The code would previous read beyond the end of the pattern string if the
match pattern ends with an open bracket when the default pattern
matching function is used.

Detected by OSS-Fuzz:
https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=4161

CVE-2017-8817

Bug: https://curl.haxx.se/docs/adv_2017-ae72.html

static int setcharset(unsigned char **p, unsigned char *charset)
{
  setcharset_state state = CURLFNM_SCHS_DEFAULT;
  unsigned char rangestart = 0;
  unsigned char lastchar   = 0;
  bool something_found = FALSE;
  unsigned char c;
  for(;;) {
    c = **p;
    switch(state) {
    case CURLFNM_SCHS_DEFAULT:
      if(ISALNUM(c)) { /* ASCII value */
        rangestart = c;
        charset[c] = 1;
        (*p)++;
        state = CURLFNM_SCHS_MAYRANGE;
        something_found = TRUE;
      }
      else if(c == ']') {
        if(something_found)
          return SETCHARSET_OK;
        something_found = TRUE;
        state = CURLFNM_SCHS_RIGHTBR;
        charset[c] = 1;
        (*p)++;
      }
      else if(c == '[') {
        char c2 = *((*p) + 1);
        if(c2 == ':') { /* there has to be a keyword */
          (*p) += 2;
          if(parsekeyword(p, charset)) {
            state = CURLFNM_SCHS_DEFAULT;
          }
          else
            return SETCHARSET_FAIL;
        }
        else {
          charset[c] = 1;
          (*p)++;
        }
        something_found = TRUE;
      }
      else if(c == '?' || c == '*') {
        something_found = TRUE;
        charset[c] = 1;
        (*p)++;
      }
      else if(c == '^' || c == '!') {
        if(!something_found) {
          if(charset[CURLFNM_NEGATE]) {
            charset[c] = 1;
            something_found = TRUE;
          }
          else
            charset[CURLFNM_NEGATE] = 1; /* negate charset */
        }
        else
          charset[c] = 1;
        (*p)++;
      }
      else if(c == '\\') {
        c = *(++(*p));
        if(ISPRINT((c))) {
          something_found = TRUE;
          state = CURLFNM_SCHS_MAYRANGE;
          charset[c] = 1;
          rangestart = c;
          (*p)++;
        }
        else
          return SETCHARSET_FAIL;
      }
      else if(c == '\0') {
        return SETCHARSET_FAIL;
      }
      else {
        charset[c] = 1;
        (*p)++;
        something_found = TRUE;
      }
      break;
    case CURLFNM_SCHS_MAYRANGE:
      if(c == '-') {
        charset[c] = 1;
        (*p)++;
        lastchar = '-';
        state = CURLFNM_SCHS_MAYRANGE2;
      }
      else if(c == '[') {
        state = CURLFNM_SCHS_DEFAULT;
      }
      else if(ISALNUM(c)) {
        charset[c] = 1;
        (*p)++;
      }
      else if(c == '\\') {
        c = *(++(*p));
        if(ISPRINT(c)) {
          charset[c] = 1;
          (*p)++;
        }
        else
          return SETCHARSET_FAIL;
      }
      else if(c == ']') {
        return SETCHARSET_OK;
      }
      else
        return SETCHARSET_FAIL;
      break;
    case CURLFNM_SCHS_MAYRANGE2:
      if(c == ']') {
        return SETCHARSET_OK;
      }
      else if(c == '\\') {
        c = *(++(*p));
        if(ISPRINT(c)) {
          charset[c] = 1;
          state = CURLFNM_SCHS_DEFAULT;
          (*p)++;
        }
        else
          return SETCHARSET_FAIL;
      }
      else if(c >= rangestart) {
        if((ISLOWER(c) && ISLOWER(rangestart)) ||
           (ISDIGIT(c) && ISDIGIT(rangestart)) ||
           (ISUPPER(c) && ISUPPER(rangestart))) {
          charset[lastchar] = 0;
          rangestart++;
          while(rangestart++ <= c)
            charset[rangestart-1] = 1;
          (*p)++;
          state = CURLFNM_SCHS_DEFAULT;
        }
        else
          return SETCHARSET_FAIL;
      }
      else
        return SETCHARSET_FAIL;
      break;
    case CURLFNM_SCHS_RIGHTBR:
      if(c == '[') {
        state = CURLFNM_SCHS_RIGHTBRLEFTBR;
        charset[c] = 1;
        (*p)++;
      }
      else if(c == ']') {
        return SETCHARSET_OK;
      }
      else if(c == '\0') {
        return SETCHARSET_FAIL;
      }
      else if(ISPRINT(c)) {
        charset[c] = 1;
        (*p)++;
        state = CURLFNM_SCHS_DEFAULT;
      }
      else
        /* used 'goto fail' instead of 'return SETCHARSET_FAIL' to avoid a
         * nonsense warning 'statement not reached' at end of the fnc when
         * compiling on Solaris */
        goto fail;
      break;
    case CURLFNM_SCHS_RIGHTBRLEFTBR:
      if(c == ']') {
        return SETCHARSET_OK;
      }
      else {
        state  = CURLFNM_SCHS_DEFAULT;
        charset[c] = 1;
        (*p)++;
      }
      break;
    }
  }
fail:
  return SETCHARSET_FAIL;
}

The FTP wildcard function in curl and libcurl before 7.57.0 allows remote attackers to cause a denial of service (out-of-bounds read and application crash) or possibly have unspecified other impact via a string that ends with an '[' character.


static int setcharset(unsigned char **p, unsigned char *charset)
{
  setcharset_state state = CURLFNM_SCHS_DEFAULT;
  unsigned char rangestart = 0;
  unsigned char lastchar   = 0;
  bool something_found = FALSE;
  unsigned char c;
  for(;;) {
    c = **p;
    if(!c)
      return SETCHARSET_FAIL;

    switch(state) {
    case CURLFNM_SCHS_DEFAULT:
      if(ISALNUM(c)) { /* ASCII value */
        rangestart = c;
        charset[c] = 1;
        (*p)++;
        state = CURLFNM_SCHS_MAYRANGE;
        something_found = TRUE;
      }
      else if(c == ']') {
        if(something_found)
          return SETCHARSET_OK;
        something_found = TRUE;
        state = CURLFNM_SCHS_RIGHTBR;
        charset[c] = 1;
        (*p)++;
      }
      else if(c == '[') {
        char c2 = *((*p) + 1);
        if(c2 == ':') { /* there has to be a keyword */
          (*p) += 2;
          if(parsekeyword(p, charset)) {
            state = CURLFNM_SCHS_DEFAULT;
          }
          else
            return SETCHARSET_FAIL;
        }
        else {
          charset[c] = 1;
          (*p)++;
        }
        something_found = TRUE;
      }
      else if(c == '?' || c == '*') {
        something_found = TRUE;
        charset[c] = 1;
        (*p)++;
      }
      else if(c == '^' || c == '!') {
        if(!something_found) {
          if(charset[CURLFNM_NEGATE]) {
            charset[c] = 1;
            something_found = TRUE;
          }
          else
            charset[CURLFNM_NEGATE] = 1; /* negate charset */
        }
        else
          charset[c] = 1;
        (*p)++;
      }
      else if(c == '\\') {
        c = *(++(*p));
        if(ISPRINT((c))) {
          something_found = TRUE;
          state = CURLFNM_SCHS_MAYRANGE;
          charset[c] = 1;
          rangestart = c;
          (*p)++;
        }
        else
          return SETCHARSET_FAIL;
      }
      else {
        charset[c] = 1;
        (*p)++;
        something_found = TRUE;
      }
      break;
    case CURLFNM_SCHS_MAYRANGE:
      if(c == '-') {
        charset[c] = 1;
        (*p)++;
        lastchar = '-';
        state = CURLFNM_SCHS_MAYRANGE2;
      }
      else if(c == '[') {
        state = CURLFNM_SCHS_DEFAULT;
      }
      else if(ISALNUM(c)) {
        charset[c] = 1;
        (*p)++;
      }
      else if(c == '\\') {
        c = *(++(*p));
        if(ISPRINT(c)) {
          charset[c] = 1;
          (*p)++;
        }
        else
          return SETCHARSET_FAIL;
      }
      else if(c == ']') {
        return SETCHARSET_OK;
      }
      else
        return SETCHARSET_FAIL;
      break;
    case CURLFNM_SCHS_MAYRANGE2:
      if(c == ']') {
        return SETCHARSET_OK;
      }
      else if(c == '\\') {
        c = *(++(*p));
        if(ISPRINT(c)) {
          charset[c] = 1;
          state = CURLFNM_SCHS_DEFAULT;
          (*p)++;
        }
        else
          return SETCHARSET_FAIL;
      }
      else if(c >= rangestart) {
        if((ISLOWER(c) && ISLOWER(rangestart)) ||
           (ISDIGIT(c) && ISDIGIT(rangestart)) ||
           (ISUPPER(c) && ISUPPER(rangestart))) {
          charset[lastchar] = 0;
          rangestart++;
          while(rangestart++ <= c)
            charset[rangestart-1] = 1;
          (*p)++;
          state = CURLFNM_SCHS_DEFAULT;
        }
        else
          return SETCHARSET_FAIL;
      }
      else
        return SETCHARSET_FAIL;
      break;
    case CURLFNM_SCHS_RIGHTBR:
      if(c == '[') {
        state = CURLFNM_SCHS_RIGHTBRLEFTBR;
        charset[c] = 1;
        (*p)++;
      }
      else if(c == ']') {
        return SETCHARSET_OK;
      }
      else if(ISPRINT(c)) {
        charset[c] = 1;
        (*p)++;
        state = CURLFNM_SCHS_DEFAULT;
      }
      else
        /* used 'goto fail' instead of 'return SETCHARSET_FAIL' to avoid a
         * nonsense warning 'statement not reached' at end of the fnc when
         * compiling on Solaris */
        goto fail;
      break;
    case CURLFNM_SCHS_RIGHTBRLEFTBR:
      if(c == ']') {
        return SETCHARSET_OK;
      }
      else {
        state  = CURLFNM_SCHS_DEFAULT;
        charset[c] = 1;
        (*p)++;
      }
      break;
    }
  }
fail:
  return SETCHARSET_FAIL;
}


gfile: Limit access to files when copying

file_copy_fallback creates new files with default permissions and
set the correct permissions after the operation is finished. This
might cause that the files can be accessible by more users during
the operation than expected. Use G_FILE_CREATE_PRIVATE for the new
files to limit access to those files.

file_copy_fallback (GFile                  *source,
                    GFile                  *destination,
                    GFileCopyFlags          flags,
                    GCancellable           *cancellable,
                    GFileProgressCallback   progress_callback,
                    gpointer                progress_callback_data,
                    GError                **error)
{
  gboolean ret = FALSE;
  GFileInputStream *file_in = NULL;
  GInputStream *in = NULL;
  GOutputStream *out = NULL;
  GFileInfo *info = NULL;
  const char *target;
  char *attrs_to_read;
  gboolean do_set_attributes = FALSE;

  /* need to know the file type */
  info = g_file_query_info (source,
                            G_FILE_ATTRIBUTE_STANDARD_TYPE "," G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET,
                            G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
                            cancellable,
                            error);
  if (!info)
    goto out;

  /* Maybe copy the symlink? */
  if ((flags & G_FILE_COPY_NOFOLLOW_SYMLINKS) &&
      g_file_info_get_file_type (info) == G_FILE_TYPE_SYMBOLIC_LINK)
    {
      target = g_file_info_get_symlink_target (info);
      if (target)
        {
          if (!copy_symlink (destination, flags, cancellable, target, error))
            goto out;

          ret = TRUE;
          goto out;
        }
        /* ... else fall back on a regular file copy */
    }
  /* Handle "special" files (pipes, device nodes, ...)? */
  else if (g_file_info_get_file_type (info) == G_FILE_TYPE_SPECIAL)
    {
      /* FIXME: could try to recreate device nodes and others? */
      g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
                           _("Can’t copy special file"));
      goto out;
    }

  /* Everything else should just fall back on a regular copy. */

  file_in = open_source_for_copy (source, destination, flags, cancellable, error);
  if (!file_in)
    goto out;
  in = G_INPUT_STREAM (file_in);

  if (!build_attribute_list_for_copy (destination, flags, &attrs_to_read,
                                      cancellable, error))
    goto out;

  if (attrs_to_read != NULL)
    {
      GError *tmp_error = NULL;

      /* Ok, ditch the previous lightweight info (on Unix we just
       * called lstat()); at this point we gather all the information
       * we need about the source from the opened file descriptor.
       */
      g_object_unref (info);

      info = g_file_input_stream_query_info (file_in, attrs_to_read,
                                             cancellable, &tmp_error);
      if (!info)
        {
          /* Not all gvfs backends implement query_info_on_read(), we
           * can just fall back to the pathname again.
           * https://bugzilla.gnome.org/706254
           */
          if (g_error_matches (tmp_error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED))
            {
              g_clear_error (&tmp_error);
              info = g_file_query_info (source, attrs_to_read, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
                                        cancellable, error);
            }
          else
            {
              g_free (attrs_to_read);
              g_propagate_error (error, tmp_error);
              goto out;
            }
        }
      g_free (attrs_to_read);
      if (!info)
        goto out;

      do_set_attributes = TRUE;
    }

  /* In the local file path, we pass down the source info which
   * includes things like unix::mode, to ensure that the target file
   * is not created with different permissions from the source file.
   *
   * If a future API like g_file_replace_with_info() is added, switch
   * this code to use that.
   */
  if (G_IS_LOCAL_FILE (destination))
    {
      if (flags & G_FILE_COPY_OVERWRITE)
        out = (GOutputStream*)_g_local_file_output_stream_replace (_g_local_file_get_filename (G_LOCAL_FILE (destination)),
                                                                   FALSE, NULL,
                                                                   flags & G_FILE_COPY_BACKUP,
                                                                   G_FILE_CREATE_REPLACE_DESTINATION,
                                                                   info,
                                                                   cancellable, error);
      else
        out = (GOutputStream*)_g_local_file_output_stream_create (_g_local_file_get_filename (G_LOCAL_FILE (destination)),
                                                                  FALSE, 0, info,
                                                                  cancellable, error);
    }
  else if (flags & G_FILE_COPY_OVERWRITE)
    {
      out = (GOutputStream *)g_file_replace (destination,
                                             NULL,
                                             flags & G_FILE_COPY_BACKUP,
                                             G_FILE_CREATE_REPLACE_DESTINATION,
                                             cancellable, error);
    }
  else
    {
      out = (GOutputStream *)g_file_create (destination, 0, cancellable, error);
    }

  if (!out)
    goto out;

#ifdef __linux__
  if (G_IS_FILE_DESCRIPTOR_BASED (in) && G_IS_FILE_DESCRIPTOR_BASED (out))
    {
      GError *reflink_err = NULL;

      if (!btrfs_reflink_with_progress (in, out, info, cancellable,
                                        progress_callback, progress_callback_data,
                                        &reflink_err))
        {
          if (g_error_matches (reflink_err, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED))
            {
              g_clear_error (&reflink_err);
            }
          else
            {
              g_propagate_error (error, reflink_err);
              goto out;
            }
        }
      else
        {
          ret = TRUE;
          goto out;
        }
    }
#endif

#ifdef HAVE_SPLICE
  if (G_IS_FILE_DESCRIPTOR_BASED (in) && G_IS_FILE_DESCRIPTOR_BASED (out))
    {
      GError *splice_err = NULL;

      if (!splice_stream_with_progress (in, out, cancellable,
                                        progress_callback, progress_callback_data,
                                        &splice_err))
        {
          if (g_error_matches (splice_err, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED))
            {
              g_clear_error (&splice_err);
            }
          else
            {
              g_propagate_error (error, splice_err);
              goto out;
            }
        }
      else
        {
          ret = TRUE;
          goto out;
        }
    }

#endif

  /* A plain read/write loop */
  if (!copy_stream_with_progress (in, out, source, cancellable,
                                  progress_callback, progress_callback_data,
                                  error))
    goto out;

  ret = TRUE;
 out:
  if (in)
    {
      /* Don't care about errors in source here */
      (void) g_input_stream_close (in, cancellable, NULL);
      g_object_unref (in);
    }

  if (out)
    {
      /* But write errors on close are bad! */
      if (!g_output_stream_close (out, cancellable, ret ? error : NULL))
        ret = FALSE;
      g_object_unref (out);
    }

  /* Ignore errors here. Failure to copy metadata is not a hard error */
  /* TODO: set these attributes /before/ we do the rename() on Unix */
  if (ret && do_set_attributes)
    {
      g_file_set_attributes_from_info (destination,
                                       info,
                                       G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
                                       cancellable,
                                       NULL);
    }

  g_clear_object (&info);

  return ret;
}

file_copy_fallback in gio/gfile.c in GNOME GLib 2.15.0 through 2.61.1 does not properly restrict file permissions while a copy operation is in progress. Instead, default permissions are used.


file_copy_fallback (GFile                  *source,
                    GFile                  *destination,
                    GFileCopyFlags          flags,
                    GCancellable           *cancellable,
                    GFileProgressCallback   progress_callback,
                    gpointer                progress_callback_data,
                    GError                **error)
{
  gboolean ret = FALSE;
  GFileInputStream *file_in = NULL;
  GInputStream *in = NULL;
  GOutputStream *out = NULL;
  GFileInfo *info = NULL;
  const char *target;
  char *attrs_to_read;
  gboolean do_set_attributes = FALSE;

  /* need to know the file type */
  info = g_file_query_info (source,
                            G_FILE_ATTRIBUTE_STANDARD_TYPE "," G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET,
                            G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
                            cancellable,
                            error);
  if (!info)
    goto out;

  /* Maybe copy the symlink? */
  if ((flags & G_FILE_COPY_NOFOLLOW_SYMLINKS) &&
      g_file_info_get_file_type (info) == G_FILE_TYPE_SYMBOLIC_LINK)
    {
      target = g_file_info_get_symlink_target (info);
      if (target)
        {
          if (!copy_symlink (destination, flags, cancellable, target, error))
            goto out;

          ret = TRUE;
          goto out;
        }
        /* ... else fall back on a regular file copy */
    }
  /* Handle "special" files (pipes, device nodes, ...)? */
  else if (g_file_info_get_file_type (info) == G_FILE_TYPE_SPECIAL)
    {
      /* FIXME: could try to recreate device nodes and others? */
      g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
                           _("Can’t copy special file"));
      goto out;
    }

  /* Everything else should just fall back on a regular copy. */

  file_in = open_source_for_copy (source, destination, flags, cancellable, error);
  if (!file_in)
    goto out;
  in = G_INPUT_STREAM (file_in);

  if (!build_attribute_list_for_copy (destination, flags, &attrs_to_read,
                                      cancellable, error))
    goto out;

  if (attrs_to_read != NULL)
    {
      GError *tmp_error = NULL;

      /* Ok, ditch the previous lightweight info (on Unix we just
       * called lstat()); at this point we gather all the information
       * we need about the source from the opened file descriptor.
       */
      g_object_unref (info);

      info = g_file_input_stream_query_info (file_in, attrs_to_read,
                                             cancellable, &tmp_error);
      if (!info)
        {
          /* Not all gvfs backends implement query_info_on_read(), we
           * can just fall back to the pathname again.
           * https://bugzilla.gnome.org/706254
           */
          if (g_error_matches (tmp_error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED))
            {
              g_clear_error (&tmp_error);
              info = g_file_query_info (source, attrs_to_read, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
                                        cancellable, error);
            }
          else
            {
              g_free (attrs_to_read);
              g_propagate_error (error, tmp_error);
              goto out;
            }
        }
      g_free (attrs_to_read);
      if (!info)
        goto out;

      do_set_attributes = TRUE;
    }

  /* In the local file path, we pass down the source info which
   * includes things like unix::mode, to ensure that the target file
   * is not created with different permissions from the source file.
   *
   * If a future API like g_file_replace_with_info() is added, switch
   * this code to use that.
   */
  if (G_IS_LOCAL_FILE (destination))
    {
      if (flags & G_FILE_COPY_OVERWRITE)
        out = (GOutputStream*)_g_local_file_output_stream_replace (_g_local_file_get_filename (G_LOCAL_FILE (destination)),
                                                                   FALSE, NULL,
                                                                   flags & G_FILE_COPY_BACKUP,
                                                                   G_FILE_CREATE_REPLACE_DESTINATION |
                                                                   G_FILE_CREATE_PRIVATE, info,
                                                                   cancellable, error);
      else
        out = (GOutputStream*)_g_local_file_output_stream_create (_g_local_file_get_filename (G_LOCAL_FILE (destination)),
                                                                  FALSE, G_FILE_CREATE_PRIVATE, info,
                                                                  cancellable, error);
    }
  else if (flags & G_FILE_COPY_OVERWRITE)
    {
      out = (GOutputStream *)g_file_replace (destination,
                                             NULL,
                                             flags & G_FILE_COPY_BACKUP,
                                             G_FILE_CREATE_REPLACE_DESTINATION |
                                             G_FILE_CREATE_PRIVATE,
                                             cancellable, error);
    }
  else
    {
      out = (GOutputStream *)g_file_create (destination, G_FILE_CREATE_PRIVATE, cancellable, error);
    }

  if (!out)
    goto out;

#ifdef __linux__
  if (G_IS_FILE_DESCRIPTOR_BASED (in) && G_IS_FILE_DESCRIPTOR_BASED (out))
    {
      GError *reflink_err = NULL;

      if (!btrfs_reflink_with_progress (in, out, info, cancellable,
                                        progress_callback, progress_callback_data,
                                        &reflink_err))
        {
          if (g_error_matches (reflink_err, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED))
            {
              g_clear_error (&reflink_err);
            }
          else
            {
              g_propagate_error (error, reflink_err);
              goto out;
            }
        }
      else
        {
          ret = TRUE;
          goto out;
        }
    }
#endif

#ifdef HAVE_SPLICE
  if (G_IS_FILE_DESCRIPTOR_BASED (in) && G_IS_FILE_DESCRIPTOR_BASED (out))
    {
      GError *splice_err = NULL;

      if (!splice_stream_with_progress (in, out, cancellable,
                                        progress_callback, progress_callback_data,
                                        &splice_err))
        {
          if (g_error_matches (splice_err, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED))
            {
              g_clear_error (&splice_err);
            }
          else
            {
              g_propagate_error (error, splice_err);
              goto out;
            }
        }
      else
        {
          ret = TRUE;
          goto out;
        }
    }

#endif

  /* A plain read/write loop */
  if (!copy_stream_with_progress (in, out, source, cancellable,
                                  progress_callback, progress_callback_data,
                                  error))
    goto out;

  ret = TRUE;
 out:
  if (in)
    {
      /* Don't care about errors in source here */
      (void) g_input_stream_close (in, cancellable, NULL);
      g_object_unref (in);
    }

  if (out)
    {
      /* But write errors on close are bad! */
      if (!g_output_stream_close (out, cancellable, ret ? error : NULL))
        ret = FALSE;
      g_object_unref (out);
    }

  /* Ignore errors here. Failure to copy metadata is not a hard error */
  /* TODO: set these attributes /before/ we do the rename() on Unix */
  if (ret && do_set_attributes)
    {
      g_file_set_attributes_from_info (destination,
                                       info,
                                       G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
                                       cancellable,
                                       NULL);
    }

  g_clear_object (&info);

  return ret;
}


datetime: fix potential out-of-bound read on malformed datetime string

https://bugzilla.gnome.org/show_bug.cgi?id=777263

gst_date_time_new_from_iso8601_string (const gchar * string)
{
  gint year = -1, month = -1, day = -1, hour = -1, minute = -1;
  gint gmt_offset_hour = -99, gmt_offset_min = -99;
  gdouble second = -1.0;
  gfloat tzoffset = 0.0;
  guint64 usecs;
  gint len, ret;

  g_return_val_if_fail (string != NULL, NULL);

  GST_DEBUG ("Parsing '%s' into a datetime", string);

  len = strlen (string);

  /* The input string is expected to start either with a year (4 digits) or
   * with an hour (2 digits). Hour must be followed by minute. In any case,
   * the string must be at least 4 characters long and start with 2 digits */
  if (len < 4 || !g_ascii_isdigit (string[0]) || !g_ascii_isdigit (string[1]))
    return NULL;

  if (g_ascii_isdigit (string[2]) && g_ascii_isdigit (string[3])) {
    ret = sscanf (string, "%04d-%02d-%02d", &year, &month, &day);

    if (ret == 0)
      return NULL;

    if (ret == 3 && day <= 0) {
      ret = 2;
      day = -1;
    }

    if (ret >= 2 && month <= 0) {
      ret = 1;
      month = day = -1;
    }

    if (ret >= 1 && (year <= 0 || year > 9999 || month > 12 || day > 31))
      return NULL;

    else if (ret >= 1 && len < 16)
      /* YMD is 10 chars. XMD + HM will be 16 chars. if it is less,
       * it make no sense to continue. We will stay with YMD. */
      goto ymd;

    string += 10;
    /* Exit if there is no expeceted value on this stage */
    if (!(*string == 'T' || *string == '-' || *string == ' '))
      goto ymd;

    string += 1;
  }
  /* if hour or minute fails, then we will use only ymd. */
  hour = g_ascii_strtoull (string, (gchar **) & string, 10);
  if (hour > 24 || *string != ':')
    goto ymd;

  /* minute */
  minute = g_ascii_strtoull (string + 1, (gchar **) & string, 10);
  if (minute > 59)
    goto ymd;

  /* second */
  if (*string == ':') {
    second = g_ascii_strtoull (string + 1, (gchar **) & string, 10);
    /* if we fail here, we still can reuse hour and minute. We
     * will still attempt to parse any timezone information */
    if (second > 59) {
      second = -1.0;
    } else {
      /* microseconds */
      if (*string == '.' || *string == ',') {
        const gchar *usec_start = string + 1;
        guint digits;

        usecs = g_ascii_strtoull (string + 1, (gchar **) & string, 10);
        if (usecs != G_MAXUINT64 && string > usec_start) {
          digits = (guint) (string - usec_start);
          second += (gdouble) usecs / pow (10.0, digits);
        }
      }
    }
  }

  if (*string == 'Z')
    goto ymd_hms;
  else {
    /* reuse some code from gst-plugins-base/gst-libs/gst/tag/gstxmptag.c */
    gint gmt_offset = -1;
    gchar *plus_pos = NULL;
    gchar *neg_pos = NULL;
    gchar *pos = NULL;

    GST_LOG ("Checking for timezone information");

    /* check if there is timezone info */
    plus_pos = strrchr (string, '+');
    neg_pos = strrchr (string, '-');
    if (plus_pos)
      pos = plus_pos + 1;
    else if (neg_pos)
      pos = neg_pos + 1;

    if (pos) {
      gint ret_tz;
      if (pos[2] == ':')
        ret_tz = sscanf (pos, "%d:%d", &gmt_offset_hour, &gmt_offset_min);
      else
        ret_tz = sscanf (pos, "%02d%02d", &gmt_offset_hour, &gmt_offset_min);

      GST_DEBUG ("Parsing timezone: %s", pos);

      if (ret_tz == 2) {
        if (neg_pos != NULL && neg_pos + 1 == pos) {
          gmt_offset_hour *= -1;
          gmt_offset_min *= -1;
        }
        gmt_offset = gmt_offset_hour * 60 + gmt_offset_min;

        tzoffset = gmt_offset / 60.0;

        GST_LOG ("Timezone offset: %f (%d minutes)", tzoffset, gmt_offset);
      } else
        GST_WARNING ("Failed to parse timezone information");
    }
  }

ymd_hms:
  if (year == -1 || month == -1 || day == -1) {
    GDateTime *now_utc, *now_in_given_tz;

    /* No date was supplied: make it today */
    now_utc = g_date_time_new_now_utc ();
    if (tzoffset != 0.0) {
      /* If a timezone offset was supplied, get the date of that timezone */
      g_assert (gmt_offset_min != -99);
      g_assert (gmt_offset_hour != -99);
      now_in_given_tz =
          g_date_time_add_minutes (now_utc,
          (60 * gmt_offset_hour) + gmt_offset_min);
      g_date_time_unref (now_utc);
    } else {
      now_in_given_tz = now_utc;
    }
    g_date_time_get_ymd (now_in_given_tz, &year, &month, &day);
    g_date_time_unref (now_in_given_tz);
  }
  return gst_date_time_new (tzoffset, year, month, day, hour, minute, second);
ymd:
  if (year == -1) {
    /* No date was supplied and time failed to parse */
    return NULL;
  }
  return gst_date_time_new_ymd (year, month, day);
}

The gst_date_time_new_from_iso8601_string function in gst/gstdatetime.c in GStreamer before 1.10.3 allows remote attackers to cause a denial of service (out-of-bounds heap read) via a malformed datetime string.


gst_date_time_new_from_iso8601_string (const gchar * string)
{
  gint year = -1, month = -1, day = -1, hour = -1, minute = -1;
  gint gmt_offset_hour = -99, gmt_offset_min = -99;
  gdouble second = -1.0;
  gfloat tzoffset = 0.0;
  guint64 usecs;
  gint len, ret;

  g_return_val_if_fail (string != NULL, NULL);

  GST_DEBUG ("Parsing '%s' into a datetime", string);

  len = strlen (string);

  /* The input string is expected to start either with a year (4 digits) or
   * with an hour (2 digits). Hour must be followed by minute. In any case,
   * the string must be at least 4 characters long and start with 2 digits */
  if (len < 4 || !g_ascii_isdigit (string[0]) || !g_ascii_isdigit (string[1]))
    return NULL;

  if (g_ascii_isdigit (string[2]) && g_ascii_isdigit (string[3])) {
    ret = sscanf (string, "%04d-%02d-%02d", &year, &month, &day);

    if (ret == 0)
      return NULL;

    if (ret == 3 && day <= 0) {
      ret = 2;
      day = -1;
    }

    if (ret >= 2 && month <= 0) {
      ret = 1;
      month = day = -1;
    }

    if (ret >= 1 && (year <= 0 || year > 9999 || month > 12 || day > 31))
      return NULL;

    else if (ret >= 1 && len < 16)
      /* YMD is 10 chars. XMD + HM will be 16 chars. if it is less,
       * it make no sense to continue. We will stay with YMD. */
      goto ymd;

    string += 10;
    /* Exit if there is no expeceted value on this stage */
    if (!(*string == 'T' || *string == '-' || *string == ' '))
      goto ymd;

    string += 1;
  }
  /* if hour or minute fails, then we will use only ymd. */
  hour = g_ascii_strtoull (string, (gchar **) & string, 10);
  if (hour > 24 || *string != ':')
    goto ymd;

  /* minute */
  minute = g_ascii_strtoull (string + 1, (gchar **) & string, 10);
  if (minute > 59)
    goto ymd;

  /* second */
  if (*string == ':') {
    second = g_ascii_strtoull (string + 1, (gchar **) & string, 10);
    /* if we fail here, we still can reuse hour and minute. We
     * will still attempt to parse any timezone information */
    if (second > 59) {
      second = -1.0;
    } else {
      /* microseconds */
      if (*string == '.' || *string == ',') {
        const gchar *usec_start = string + 1;
        guint digits;

        usecs = g_ascii_strtoull (string + 1, (gchar **) & string, 10);
        if (usecs != G_MAXUINT64 && string > usec_start) {
          digits = (guint) (string - usec_start);
          second += (gdouble) usecs / pow (10.0, digits);
        }
      }
    }
  }

  if (*string == 'Z')
    goto ymd_hms;
  else {
    /* reuse some code from gst-plugins-base/gst-libs/gst/tag/gstxmptag.c */
    gint gmt_offset = -1;
    gchar *plus_pos = NULL;
    gchar *neg_pos = NULL;
    gchar *pos = NULL;

    GST_LOG ("Checking for timezone information");

    /* check if there is timezone info */
    plus_pos = strrchr (string, '+');
    neg_pos = strrchr (string, '-');
    if (plus_pos)
      pos = plus_pos + 1;
    else if (neg_pos)
      pos = neg_pos + 1;

    if (pos && strlen (pos) >= 3) {
      gint ret_tz;
      if (pos[2] == ':')
        ret_tz = sscanf (pos, "%d:%d", &gmt_offset_hour, &gmt_offset_min);
      else
        ret_tz = sscanf (pos, "%02d%02d", &gmt_offset_hour, &gmt_offset_min);

      GST_DEBUG ("Parsing timezone: %s", pos);

      if (ret_tz == 2) {
        if (neg_pos != NULL && neg_pos + 1 == pos) {
          gmt_offset_hour *= -1;
          gmt_offset_min *= -1;
        }
        gmt_offset = gmt_offset_hour * 60 + gmt_offset_min;

        tzoffset = gmt_offset / 60.0;

        GST_LOG ("Timezone offset: %f (%d minutes)", tzoffset, gmt_offset);
      } else
        GST_WARNING ("Failed to parse timezone information");
    }
  }

ymd_hms:
  if (year == -1 || month == -1 || day == -1) {
    GDateTime *now_utc, *now_in_given_tz;

    /* No date was supplied: make it today */
    now_utc = g_date_time_new_now_utc ();
    if (tzoffset != 0.0) {
      /* If a timezone offset was supplied, get the date of that timezone */
      g_assert (gmt_offset_min != -99);
      g_assert (gmt_offset_hour != -99);
      now_in_given_tz =
          g_date_time_add_minutes (now_utc,
          (60 * gmt_offset_hour) + gmt_offset_min);
      g_date_time_unref (now_utc);
    } else {
      now_in_given_tz = now_utc;
    }
    g_date_time_get_ymd (now_in_given_tz, &year, &month, &day);
    g_date_time_unref (now_in_given_tz);
  }
  return gst_date_time_new (tzoffset, year, month, day, hour, minute, second);
ymd:
  if (year == -1) {
    /* No date was supplied and time failed to parse */
    return NULL;
  }
  return gst_date_time_new_ymd (year, month, day);
}


net: qlogic: Fix memory leak in ql_alloc_large_buffers

In ql_alloc_large_buffers, a new skb is allocated via netdev_alloc_skb.
This skb should be released if pci_dma_mapping_error fails.

Fixes: 0f8ab89e825f ("qla3xxx: Check return code from pci_map_single() in ql_release_to_lrg_buf_free_list(), ql_populate_free_queue(), ql_alloc_large_buffers(), and ql3xxx_send()")
Signed-off-by: Navid Emamdoost <navid.emamdoost@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

static int ql_alloc_large_buffers(struct ql3_adapter *qdev)
{
	int i;
	struct ql_rcv_buf_cb *lrg_buf_cb;
	struct sk_buff *skb;
	dma_addr_t map;
	int err;

	for (i = 0; i < qdev->num_large_buffers; i++) {
		skb = netdev_alloc_skb(qdev->ndev,
				       qdev->lrg_buffer_len);
		if (unlikely(!skb)) {
			/* Better luck next round */
			netdev_err(qdev->ndev,
				   "large buff alloc failed for %d bytes at index %d\n",
				   qdev->lrg_buffer_len * 2, i);
			ql_free_large_buffers(qdev);
			return -ENOMEM;
		} else {

			lrg_buf_cb = &qdev->lrg_buf[i];
			memset(lrg_buf_cb, 0, sizeof(struct ql_rcv_buf_cb));
			lrg_buf_cb->index = i;
			lrg_buf_cb->skb = skb;
			/*
			 * We save some space to copy the ethhdr from first
			 * buffer
			 */
			skb_reserve(skb, QL_HEADER_SPACE);
			map = pci_map_single(qdev->pdev,
					     skb->data,
					     qdev->lrg_buffer_len -
					     QL_HEADER_SPACE,
					     PCI_DMA_FROMDEVICE);

			err = pci_dma_mapping_error(qdev->pdev, map);
			if (err) {
				netdev_err(qdev->ndev,
					   "PCI mapping failed with error: %d\n",
					   err);
				ql_free_large_buffers(qdev);
				return -ENOMEM;
			}

			dma_unmap_addr_set(lrg_buf_cb, mapaddr, map);
			dma_unmap_len_set(lrg_buf_cb, maplen,
					  qdev->lrg_buffer_len -
					  QL_HEADER_SPACE);
			lrg_buf_cb->buf_phy_addr_low =
			    cpu_to_le32(LS_64BITS(map));
			lrg_buf_cb->buf_phy_addr_high =
			    cpu_to_le32(MS_64BITS(map));
		}
	}
	return 0;

A memory leak in the ql_alloc_large_buffers() function in drivers/net/ethernet/qlogic/qla3xxx.c in the Linux kernel before 5.3.5 allows local users to cause a denial of service (memory consumption) by triggering pci_dma_mapping_error() failures, aka CID-1acb8f2a7a9f.


static int ql_alloc_large_buffers(struct ql3_adapter *qdev)
{
	int i;
	struct ql_rcv_buf_cb *lrg_buf_cb;
	struct sk_buff *skb;
	dma_addr_t map;
	int err;

	for (i = 0; i < qdev->num_large_buffers; i++) {
		skb = netdev_alloc_skb(qdev->ndev,
				       qdev->lrg_buffer_len);
		if (unlikely(!skb)) {
			/* Better luck next round */
			netdev_err(qdev->ndev,
				   "large buff alloc failed for %d bytes at index %d\n",
				   qdev->lrg_buffer_len * 2, i);
			ql_free_large_buffers(qdev);
			return -ENOMEM;
		} else {

			lrg_buf_cb = &qdev->lrg_buf[i];
			memset(lrg_buf_cb, 0, sizeof(struct ql_rcv_buf_cb));
			lrg_buf_cb->index = i;
			lrg_buf_cb->skb = skb;
			/*
			 * We save some space to copy the ethhdr from first
			 * buffer
			 */
			skb_reserve(skb, QL_HEADER_SPACE);
			map = pci_map_single(qdev->pdev,
					     skb->data,
					     qdev->lrg_buffer_len -
					     QL_HEADER_SPACE,
					     PCI_DMA_FROMDEVICE);

			err = pci_dma_mapping_error(qdev->pdev, map);
			if (err) {
				netdev_err(qdev->ndev,
					   "PCI mapping failed with error: %d\n",
					   err);
				dev_kfree_skb_irq(skb);
				ql_free_large_buffers(qdev);
				return -ENOMEM;
			}

			dma_unmap_addr_set(lrg_buf_cb, mapaddr, map);
			dma_unmap_len_set(lrg_buf_cb, maplen,
					  qdev->lrg_buffer_len -
					  QL_HEADER_SPACE);
			lrg_buf_cb->buf_phy_addr_low =
			    cpu_to_le32(LS_64BITS(map));
			lrg_buf_cb->buf_phy_addr_high =
			    cpu_to_le32(MS_64BITS(map));
		}
	}
	return 0;


on certificate import check whether the two signature algorithms match

gnutls_x509_crt_import(gnutls_x509_crt_t cert,
		       const gnutls_datum_t * data,
		       gnutls_x509_crt_fmt_t format)
{
	int result = 0;
	int version;

	if (cert == NULL) {
		gnutls_assert();
		return GNUTLS_E_INVALID_REQUEST;
	}

	if (cert->der.data) {
		gnutls_free(cert->der.data);
		cert->der.data = NULL;
	}

	/* If the Certificate is in PEM format then decode it
	 */
	if (format == GNUTLS_X509_FMT_PEM) {
		/* Try the first header */
		result =
		    _gnutls_fbase64_decode(PEM_X509_CERT2, data->data,
					   data->size, &cert->der);

		if (result <= 0) {
			/* try for the second header */
			result =
			    _gnutls_fbase64_decode(PEM_X509_CERT,
						   data->data, data->size,
						   &cert->der);

			if (result < 0) {
				gnutls_assert();
				return result;
			}
		}
	} else {
		result = _gnutls_set_datum(&cert->der, data->data, data->size);
		if (result < 0) {
			gnutls_assert();
			return result;
		}
	}

	if (cert->expanded) {
		/* Any earlier asn1_der_decoding will modify the ASN.1
		   structure, so we need to replace it with a fresh
		   structure. */
		result = crt_reinit(cert);
		if (result < 0) {
			gnutls_assert();
			goto cleanup;
		}
	}

	cert->expanded = 1;

	result =
	    asn1_der_decoding(&cert->cert, cert->der.data, cert->der.size, NULL);
	if (result != ASN1_SUCCESS) {
		result = _gnutls_asn2err(result);
		gnutls_assert();
		goto cleanup;
	}

	result = _gnutls_x509_get_raw_field2(cert->cert, &cert->der,
					  "tbsCertificate.issuer.rdnSequence",
					  &cert->raw_issuer_dn);
	if (result < 0) {
		gnutls_assert();
		goto cleanup;
	}

	result = _gnutls_x509_get_raw_field2(cert->cert, &cert->der,
					  "tbsCertificate.subject.rdnSequence",
					  &cert->raw_dn);
	if (result < 0) {
		gnutls_assert();
		goto cleanup;
	}

	result = _gnutls_x509_get_raw_field2(cert->cert, &cert->der,
					  "tbsCertificate.subjectPublicKeyInfo",
					  &cert->raw_spki);
	if (result < 0) {
		gnutls_assert();
		goto cleanup;
	}

	/* enforce the rule that only version 3 certificates carry extensions */
	version = gnutls_x509_crt_get_version(cert);
	if (version < 3) {
		gnutls_datum_t exts;
		result = _gnutls_x509_get_raw_field2(cert->cert, &cert->der,
			"tbsCertificate.extensions", &exts);
		if (result >= 0 && exts.size > 0) {
			gnutls_assert();
			_gnutls_debug_log("error: extensions present in certificate with version %d\n", version);
			result = GNUTLS_E_X509_CERTIFICATE_ERROR;
			goto cleanup;
		}
	}

	/* Since we do not want to disable any extension
	 */
	cert->use_extensions = 1;

	return 0;

      cleanup:
	_gnutls_free_datum(&cert->der);
	return result;
}

GnuTLS before 3.3.13 does not validate that the signature algorithms match when importing a certificate.


gnutls_x509_crt_import(gnutls_x509_crt_t cert,
		       const gnutls_datum_t * data,
		       gnutls_x509_crt_fmt_t format)
{
	int result = 0;
	int version, s2;

	if (cert == NULL) {
		gnutls_assert();
		return GNUTLS_E_INVALID_REQUEST;
	}

	if (cert->der.data) {
		gnutls_free(cert->der.data);
		cert->der.data = NULL;
	}

	/* If the Certificate is in PEM format then decode it
	 */
	if (format == GNUTLS_X509_FMT_PEM) {
		/* Try the first header */
		result =
		    _gnutls_fbase64_decode(PEM_X509_CERT2, data->data,
					   data->size, &cert->der);

		if (result <= 0) {
			/* try for the second header */
			result =
			    _gnutls_fbase64_decode(PEM_X509_CERT,
						   data->data, data->size,
						   &cert->der);

			if (result < 0) {
				gnutls_assert();
				return result;
			}
		}
	} else {
		result = _gnutls_set_datum(&cert->der, data->data, data->size);
		if (result < 0) {
			gnutls_assert();
			return result;
		}
	}

	if (cert->expanded) {
		/* Any earlier asn1_der_decoding will modify the ASN.1
		   structure, so we need to replace it with a fresh
		   structure. */
		result = crt_reinit(cert);
		if (result < 0) {
			gnutls_assert();
			goto cleanup;
		}
	}

	cert->expanded = 1;

	result =
	    asn1_der_decoding(&cert->cert, cert->der.data, cert->der.size, NULL);
	if (result != ASN1_SUCCESS) {
		result = _gnutls_asn2err(result);
		gnutls_assert();
		goto cleanup;
	}

	result = _gnutls_x509_get_signature_algorithm(cert->cert,
						      "signatureAlgorithm.algorithm");
	if (result < 0) {
		gnutls_assert();
		goto cleanup;
	}

	s2 = _gnutls_x509_get_signature_algorithm(cert->cert,
						  "tbsCertificate.signature.algorithm");
	if (result != s2) {
		_gnutls_debug_log("signatureAlgorithm.algorithm differs from tbsCertificate.signature.algorithm: %s, %s\n",
			gnutls_sign_get_name(result), gnutls_sign_get_name(s2));
		gnutls_assert();
		result = GNUTLS_E_CERTIFICATE_ERROR;
		goto cleanup;
	}

	result = _gnutls_x509_get_raw_field2(cert->cert, &cert->der,
					  "tbsCertificate.issuer.rdnSequence",
					  &cert->raw_issuer_dn);
	if (result < 0) {
		gnutls_assert();
		goto cleanup;
	}

	result = _gnutls_x509_get_raw_field2(cert->cert, &cert->der,
					  "tbsCertificate.subject.rdnSequence",
					  &cert->raw_dn);
	if (result < 0) {
		gnutls_assert();
		goto cleanup;
	}

	result = _gnutls_x509_get_raw_field2(cert->cert, &cert->der,
					  "tbsCertificate.subjectPublicKeyInfo",
					  &cert->raw_spki);
	if (result < 0) {
		gnutls_assert();
		goto cleanup;
	}

	/* enforce the rule that only version 3 certificates carry extensions */
	version = gnutls_x509_crt_get_version(cert);
	if (version < 3) {
		gnutls_datum_t exts;
		result = _gnutls_x509_get_raw_field2(cert->cert, &cert->der,
			"tbsCertificate.extensions", &exts);
		if (result >= 0 && exts.size > 0) {
			gnutls_assert();
			_gnutls_debug_log("error: extensions present in certificate with version %d\n", version);
			result = GNUTLS_E_X509_CERTIFICATE_ERROR;
			goto cleanup;
		}
	}

	/* Since we do not want to disable any extension
	 */
	cert->use_extensions = 1;

	return 0;

      cleanup:
	_gnutls_free_datum(&cert->der);
	return result;
}


XBM coder leaves the hex image data uninitialized if hex value of the pixel is negative

static Image *ReadXBMImage(const ImageInfo *image_info,ExceptionInfo *exception)
{
  char
    buffer[MagickPathExtent],
    name[MagickPathExtent];

  Image
    *image;

  int
    c;

  MagickBooleanType
    status;

  register ssize_t
    i,
    x;

  register Quantum
    *q;

  register unsigned char
    *p;

  short int
    hex_digits[256];

  ssize_t
    y;

  unsigned char
    *data;

  unsigned int
    bit,
    byte,
    bytes_per_line,
    height,
    length,
    padding,
    version,
    width;

  /*
    Open image file.
  */
  assert(image_info != (const ImageInfo *) NULL);
  assert(image_info->signature == MagickCoreSignature);
  if (image_info->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
      image_info->filename);
  assert(exception != (ExceptionInfo *) NULL);
  assert(exception->signature == MagickCoreSignature);
  image=AcquireImage(image_info,exception);
  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
  if (status == MagickFalse)
    {
      image=DestroyImageList(image);
      return((Image *) NULL);
    }
  /*
    Read X bitmap header.
  */
  width=0;
  height=0;
  *name='\0';
  while (ReadBlobString(image,buffer) != (char *) NULL)
    if (sscanf(buffer,"#define %1024s %u",name,&width) == 2)
      if ((strlen(name) >= 6) &&
          (LocaleCompare(name+strlen(name)-6,"_width") == 0))
        break;
  while (ReadBlobString(image,buffer) != (char *) NULL)
    if (sscanf(buffer,"#define %1024s %u",name,&height) == 2)
      if ((strlen(name) >= 7) &&
          (LocaleCompare(name+strlen(name)-7,"_height") == 0))
        break;
  image->columns=width;
  image->rows=height;
  image->depth=8;
  image->storage_class=PseudoClass;
  image->colors=2;
  /*
    Scan until hex digits.
  */
  version=11;
  while (ReadBlobString(image,buffer) != (char *) NULL)
  {
    if (sscanf(buffer,"static short %1024s = {",name) == 1)
      version=10;
    else
      if (sscanf(buffer,"static unsigned char %1024s = {",name) == 1)
        version=11;
      else
        if (sscanf(buffer,"static char %1024s = {",name) == 1)
          version=11;
        else
          continue;
    p=(unsigned char *) strrchr(name,'_');
    if (p == (unsigned char *) NULL)
      p=(unsigned char *) name;
    else
      p++;
    if (LocaleCompare("bits[]",(char *) p) == 0)
      break;
  }
  if ((image->columns == 0) || (image->rows == 0) ||
      (EOFBlob(image) != MagickFalse))
    ThrowReaderException(CorruptImageError,"ImproperImageHeader");
  /*
    Initialize image structure.
  */
  if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
    ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
  /*
    Initialize colormap.
  */
  image->colormap[0].red=(MagickRealType) QuantumRange;
  image->colormap[0].green=(MagickRealType) QuantumRange;
  image->colormap[0].blue=(MagickRealType) QuantumRange;
  image->colormap[1].red=0.0;
  image->colormap[1].green=0.0;
  image->colormap[1].blue=0.0;
  if (image_info->ping != MagickFalse)
    {
      (void) CloseBlob(image);
      return(GetFirstImageInList(image));
    }
  status=SetImageExtent(image,image->columns,image->rows,exception);
  if (status == MagickFalse)
    return(DestroyImageList(image));
  /*
    Initialize hex values.
  */
  for (i=0; i < (ssize_t) (sizeof(hex_digits)/sizeof(*hex_digits)); i++)
    hex_digits[i]=(-1);
  hex_digits[(int) '0']=0;
  hex_digits[(int) '1']=1;
  hex_digits[(int) '2']=2;
  hex_digits[(int) '3']=3;
  hex_digits[(int) '4']=4;
  hex_digits[(int) '5']=5;
  hex_digits[(int) '6']=6;
  hex_digits[(int) '7']=7;
  hex_digits[(int) '8']=8;
  hex_digits[(int) '9']=9;
  hex_digits[(int) 'A']=10;
  hex_digits[(int) 'B']=11;
  hex_digits[(int) 'C']=12;
  hex_digits[(int) 'D']=13;
  hex_digits[(int) 'E']=14;
  hex_digits[(int) 'F']=15;
  hex_digits[(int) 'a']=10;
  hex_digits[(int) 'b']=11;
  hex_digits[(int) 'c']=12;
  hex_digits[(int) 'd']=13;
  hex_digits[(int) 'e']=14;
  hex_digits[(int) 'f']=15;
  hex_digits[(int) 'x']=0;
  hex_digits[(int) ' ']=(-1);
  hex_digits[(int) ',']=(-1);
  hex_digits[(int) '}']=(-1);
  hex_digits[(int) '\n']=(-1);
  hex_digits[(int) '\t']=(-1);
  /*
    Read hex image data.
  */
  padding=0;
  if (((image->columns % 16) != 0) && ((image->columns % 16) < 9) &&
      (version == 10))
    padding=1;
  bytes_per_line=(unsigned int) (image->columns+7)/8+padding;
  length=(unsigned int) image->rows;
  data=(unsigned char *) AcquireQuantumMemory(length,bytes_per_line*
    sizeof(*data));
  if (data == (unsigned char *) NULL)
    ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
  p=data;
  if (version == 10)
    for (i=0; i < (ssize_t) (bytes_per_line*image->rows); (i+=2))
    {
      c=XBMInteger(image,hex_digits);
      if (c < 0)
        break;
      *p++=(unsigned char) c;
      if ((padding == 0) || (((i+2) % bytes_per_line) != 0))
        *p++=(unsigned char) (c >> 8);
    }
  else
    for (i=0; i < (ssize_t) (bytes_per_line*image->rows); i++)
    {
      c=XBMInteger(image,hex_digits);
      if (c < 0)
        break;
      *p++=(unsigned char) c;
    }
  if (EOFBlob(image) != MagickFalse)
    {
      data=(unsigned char *) RelinquishMagickMemory(data);
      ThrowReaderException(CorruptImageError,"UnexpectedEndOfFile");
    }
  /*
    Convert X bitmap image to pixel packets.
  */
  p=data;
  for (y=0; y < (ssize_t) image->rows; y++)
  {
    q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
    if (q == (Quantum *) NULL)
      break;
    bit=0;
    byte=0;
    for (x=0; x < (ssize_t) image->columns; x++)
    {
      if (bit == 0)
        byte=(unsigned int) (*p++);
      SetPixelIndex(image,(Quantum) ((byte & 0x01) != 0 ? 0x01 : 0x00),q);
      bit++;
      byte>>=1;
      if (bit == 8)
        bit=0;
      q+=GetPixelChannels(image);
    }
    if (SyncAuthenticPixels(image,exception) == MagickFalse)
      break;
    status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
      image->rows);
    if (status == MagickFalse)
      break;
  }
  data=(unsigned char *) RelinquishMagickMemory(data);
  (void) SyncImage(image,exception);
  (void) CloseBlob(image);
  return(GetFirstImageInList(image));
}

ReadXBMImage in coders/xbm.c in ImageMagick before 7.0.8-9 leaves data uninitialized when processing an XBM file that has a negative pixel value. If the affected code is used as a library loaded into a process that includes sensitive information, that information sometimes can be leaked via the image data.


static Image *ReadXBMImage(const ImageInfo *image_info,ExceptionInfo *exception)
{
  char
    buffer[MagickPathExtent],
    name[MagickPathExtent];

  Image
    *image;

  int
    c;

  MagickBooleanType
    status;

  register ssize_t
    i,
    x;

  register Quantum
    *q;

  register unsigned char
    *p;

  short int
    hex_digits[256];

  ssize_t
    y;

  unsigned char
    *data;

  unsigned int
    bit,
    byte,
    bytes_per_line,
    height,
    length,
    padding,
    version,
    width;

  /*
    Open image file.
  */
  assert(image_info != (const ImageInfo *) NULL);
  assert(image_info->signature == MagickCoreSignature);
  if (image_info->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
      image_info->filename);
  assert(exception != (ExceptionInfo *) NULL);
  assert(exception->signature == MagickCoreSignature);
  image=AcquireImage(image_info,exception);
  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
  if (status == MagickFalse)
    {
      image=DestroyImageList(image);
      return((Image *) NULL);
    }
  /*
    Read X bitmap header.
  */
  width=0;
  height=0;
  *name='\0';
  while (ReadBlobString(image,buffer) != (char *) NULL)
    if (sscanf(buffer,"#define %1024s %u",name,&width) == 2)
      if ((strlen(name) >= 6) &&
          (LocaleCompare(name+strlen(name)-6,"_width") == 0))
        break;
  while (ReadBlobString(image,buffer) != (char *) NULL)
    if (sscanf(buffer,"#define %1024s %u",name,&height) == 2)
      if ((strlen(name) >= 7) &&
          (LocaleCompare(name+strlen(name)-7,"_height") == 0))
        break;
  image->columns=width;
  image->rows=height;
  image->depth=8;
  image->storage_class=PseudoClass;
  image->colors=2;
  /*
    Scan until hex digits.
  */
  version=11;
  while (ReadBlobString(image,buffer) != (char *) NULL)
  {
    if (sscanf(buffer,"static short %1024s = {",name) == 1)
      version=10;
    else
      if (sscanf(buffer,"static unsigned char %1024s = {",name) == 1)
        version=11;
      else
        if (sscanf(buffer,"static char %1024s = {",name) == 1)
          version=11;
        else
          continue;
    p=(unsigned char *) strrchr(name,'_');
    if (p == (unsigned char *) NULL)
      p=(unsigned char *) name;
    else
      p++;
    if (LocaleCompare("bits[]",(char *) p) == 0)
      break;
  }
  if ((image->columns == 0) || (image->rows == 0) ||
      (EOFBlob(image) != MagickFalse))
    ThrowReaderException(CorruptImageError,"ImproperImageHeader");
  /*
    Initialize image structure.
  */
  if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
    ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
  /*
    Initialize colormap.
  */
  image->colormap[0].red=(MagickRealType) QuantumRange;
  image->colormap[0].green=(MagickRealType) QuantumRange;
  image->colormap[0].blue=(MagickRealType) QuantumRange;
  image->colormap[1].red=0.0;
  image->colormap[1].green=0.0;
  image->colormap[1].blue=0.0;
  if (image_info->ping != MagickFalse)
    {
      (void) CloseBlob(image);
      return(GetFirstImageInList(image));
    }
  status=SetImageExtent(image,image->columns,image->rows,exception);
  if (status == MagickFalse)
    return(DestroyImageList(image));
  /*
    Initialize hex values.
  */
  for (i=0; i < (ssize_t) (sizeof(hex_digits)/sizeof(*hex_digits)); i++)
    hex_digits[i]=(-1);
  hex_digits[(int) '0']=0;
  hex_digits[(int) '1']=1;
  hex_digits[(int) '2']=2;
  hex_digits[(int) '3']=3;
  hex_digits[(int) '4']=4;
  hex_digits[(int) '5']=5;
  hex_digits[(int) '6']=6;
  hex_digits[(int) '7']=7;
  hex_digits[(int) '8']=8;
  hex_digits[(int) '9']=9;
  hex_digits[(int) 'A']=10;
  hex_digits[(int) 'B']=11;
  hex_digits[(int) 'C']=12;
  hex_digits[(int) 'D']=13;
  hex_digits[(int) 'E']=14;
  hex_digits[(int) 'F']=15;
  hex_digits[(int) 'a']=10;
  hex_digits[(int) 'b']=11;
  hex_digits[(int) 'c']=12;
  hex_digits[(int) 'd']=13;
  hex_digits[(int) 'e']=14;
  hex_digits[(int) 'f']=15;
  hex_digits[(int) 'x']=0;
  hex_digits[(int) ' ']=(-1);
  hex_digits[(int) ',']=(-1);
  hex_digits[(int) '}']=(-1);
  hex_digits[(int) '\n']=(-1);
  hex_digits[(int) '\t']=(-1);
  /*
    Read hex image data.
  */
  padding=0;
  if (((image->columns % 16) != 0) && ((image->columns % 16) < 9) &&
      (version == 10))
    padding=1;
  bytes_per_line=(unsigned int) (image->columns+7)/8+padding;
  length=(unsigned int) image->rows;
  data=(unsigned char *) AcquireQuantumMemory(length,bytes_per_line*
    sizeof(*data));
  if (data == (unsigned char *) NULL)
    ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
  p=data;
  if (version == 10)
    for (i=0; i < (ssize_t) (bytes_per_line*image->rows); (i+=2))
    {
      c=XBMInteger(image,hex_digits);
      if (c < 0)
        {
          data=(unsigned char *) RelinquishMagickMemory(data);
          ThrowReaderException(CorruptImageError,"ImproperImageHeader");
        }
      *p++=(unsigned char) c;
      if ((padding == 0) || (((i+2) % bytes_per_line) != 0))
        *p++=(unsigned char) (c >> 8);
    }
  else
    for (i=0; i < (ssize_t) (bytes_per_line*image->rows); i++)
    {
      c=XBMInteger(image,hex_digits);
      if (c < 0)
        {
          data=(unsigned char *) RelinquishMagickMemory(data);
          ThrowReaderException(CorruptImageError,"ImproperImageHeader");
        }
      *p++=(unsigned char) c;
    }
  if (EOFBlob(image) != MagickFalse)
    {
      data=(unsigned char *) RelinquishMagickMemory(data);
      ThrowReaderException(CorruptImageError,"UnexpectedEndOfFile");
    }
  /*
    Convert X bitmap image to pixel packets.
  */
  p=data;
  for (y=0; y < (ssize_t) image->rows; y++)
  {
    q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
    if (q == (Quantum *) NULL)
      break;
    bit=0;
    byte=0;
    for (x=0; x < (ssize_t) image->columns; x++)
    {
      if (bit == 0)
        byte=(unsigned int) (*p++);
      SetPixelIndex(image,(Quantum) ((byte & 0x01) != 0 ? 0x01 : 0x00),q);
      bit++;
      byte>>=1;
      if (bit == 8)
        bit=0;
      q+=GetPixelChannels(image);
    }
    if (SyncAuthenticPixels(image,exception) == MagickFalse)
      break;
    status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
      image->rows);
    if (status == MagickFalse)
      break;
  }
  data=(unsigned char *) RelinquishMagickMemory(data);
  (void) SyncImage(image,exception);
  (void) CloseBlob(image);
  return(GetFirstImageInList(image));
}