Commit message: None
CVE: CVE-2016-8602
CWE: CWE-704
Vulnerability description: The .sethalftone5 function in psi/zht2.c in Ghostscript before 9.21 allows remote attackers to cause a denial of service (application crash) or possibly execute arbitrary code via a crafted Postscript document that calls .sethalftone5 with an empty operand stack.

Project: ghostscript
File: zht2.c

dict_real_result(i_ctx_t *i_ctx_p, ref * pdict, const char *kstr, double val)
{
    int code = 0;
    ref *ignore;

    if (dict_find_string(pdict, kstr, &ignore) > 0) {
        ref rval;

        check_dict_write(*pdict);
        make_real(&rval, val);
        code = idict_put_string(pdict, kstr, &rval);
    }
    return code;
}

Project: ghostscript
File: zht2.c

dict_spot_params(const ref * pdict, gs_spot_halftone * psp,
                 ref * psproc, ref * ptproc, gs_memory_t *mem)
{
    int code;

    check_dict_read(*pdict);
    if ((code = dict_float_param(pdict, "Frequency", 0.0,
                                 &psp->screen.frequency)) != 0 ||
        (code = dict_float_param(pdict, "Angle", 0.0,
                                 &psp->screen.angle)) != 0 ||
      (code = dict_proc_param(pdict, "SpotFunction", psproc, false)) != 0 ||
        (code = dict_bool_param(pdict, "AccurateScreens",
                                gs_currentaccuratescreens(mem),
                                &psp->accurate_screens)) < 0 ||
      (code = dict_proc_param(pdict, "TransferFunction", ptproc, false)) < 0
        )
        return (code < 0 ? code : gs_error_undefined);
    psp->transfer = (code > 0 ? (gs_mapping_proc) 0 : gs_mapped_transfer);
    psp->transfer_closure.proc = 0;
    psp->transfer_closure.data = 0;
    return 0;
}

Project: ghostscript
File: zht2.c

dict_spot_results(i_ctx_t *i_ctx_p, ref * pdict, const gs_spot_halftone * psp)
{
    int code;

    code = dict_real_result(i_ctx_p, pdict, "ActualFrequency",
                            psp->screen.actual_frequency);
    if (code < 0)
        return code;
    return dict_real_result(i_ctx_p, pdict, "ActualAngle",
                            psp->screen.actual_angle);
}

Project: ghostscript
File: zht2.c

dict_threshold2_params(const ref * pdict, gs_threshold2_halftone * ptp,
                       ref * ptproc, gs_memory_t *mem)
{
    ref *tstring;
    int code =
        dict_threshold_common_params(pdict,
                                     (gs_threshold_halftone_common *)ptp,
                                     &tstring, ptproc);
    int bps;
    uint size;
    int cw2, ch2;

    if (code < 0 ||
        (code = cw2 = dict_int_param(pdict, "Width2", 0, 0x7fff, 0,
                                     &ptp->width2)) < 0 ||
        (code = ch2 = dict_int_param(pdict, "Height2", 0, 0x7fff, 0,
                                     &ptp->height2)) < 0 ||
        (code = dict_int_param(pdict, "BitsPerSample", 8, 16, -1, &bps)) < 0
        )
        return code;
    if ((bps != 8 && bps != 16) || cw2 != ch2 ||
        (!cw2 && (ptp->width2 == 0 || ptp->height2 == 0))
        )
        return_error(gs_error_rangecheck);
    ptp->bytes_per_sample = bps / 8;
    switch (r_type(tstring)) {
    case t_string:
        size = r_size(tstring);
        gs_bytestring_from_string(&ptp->thresholds, tstring->value.const_bytes,
                                  size);
        break;
    case t_astruct:
        if (gs_object_type(mem, tstring->value.pstruct) != &st_bytes)
            return_error(gs_error_typecheck);
        size = gs_object_size(mem, tstring->value.pstruct);
        gs_bytestring_from_bytes(&ptp->thresholds, r_ptr(tstring, byte),
                                 0, size);
        break;
    default:
        return_error(gs_error_typecheck);
    }
    check_read(*tstring);
    if (size != (ptp->width * ptp->height + ptp->width2 * ptp->height2) *
        ptp->bytes_per_sample)
        return_error(gs_error_rangecheck);
    return 0;
}

Project: ghostscript
File: zht2.c

dict_threshold_common_params(const ref * pdict,
                             gs_threshold_halftone_common * ptp,
                             ref **pptstring, ref *ptproc)
{
    int code;

    check_dict_read(*pdict);
    if ((code = dict_int_param(pdict, "Width", 1, 0x7fff, -1,
                               &ptp->width)) < 0 ||
        (code = dict_int_param(pdict, "Height", 1, 0x7fff, -1,
                               &ptp->height)) < 0 ||
        (code = dict_find_string(pdict, "Thresholds", pptstring)) <= 0 ||
      (code = dict_proc_param(pdict, "TransferFunction", ptproc, false)) < 0
        )
        return (code < 0 ? code : gs_error_undefined);
    ptp->transfer_closure.proc = 0;
    ptp->transfer_closure.data = 0;
    return code;
}

Project: ghostscript
File: zht2.c

dict_threshold_params(const ref * pdict, gs_threshold_halftone * ptp,
                      ref * ptproc)
{
    ref *tstring;
    int code =
        dict_threshold_common_params(pdict,
                                     (gs_threshold_halftone_common *)ptp,
                                     &tstring, ptproc);

    if (code < 0)
        return code;
    check_read_type_only(*tstring, t_string);
    if (r_size(tstring) != (long)ptp->width * ptp->height)
        return_error(gs_error_rangecheck);
    ptp->thresholds.data = tstring->value.const_bytes;
    ptp->thresholds.size = r_size(tstring);
    ptp->transfer = (code > 0 ? (gs_mapping_proc) 0 : gs_mapped_transfer);
    return 0;
}

Project: ghostscript
File: zht2.c

gs_get_colorname_string(const gs_memory_t *mem, gs_separation_name colorname_index,
                        unsigned char **ppstr, unsigned int *pname_size)
{
    ref nref;

    name_index_ref(mem, colorname_index, &nref);
    name_string_ref(mem, &nref, &nref);
    return obj_string_data(mem, &nref, (const unsigned char**) ppstr, pname_size);
}

Project: ghostscript
File: zht2.c

sethalftone_cleanup(i_ctx_t *i_ctx_p)
{
    gx_device_halftone *pdht = r_ptr(&esp[4], gx_device_halftone);
    gs_halftone *pht = r_ptr(&esp[3], gs_halftone);

    gs_free_object(pdht->rc.memory, pdht,
                   "sethalftone_cleanup(device halftone)");
    gs_free_object(pht->rc.memory, pht,
                   "sethalftone_cleanup(halftone)");
    return 0;
}