Commit message: None
CVE: CVE-2018-16513
CWE: CWE-704
Vulnerability description: In Artifex Ghostscript before 9.24, attackers able to supply crafted PostScript files could use a type confusion in the setcolor function to crash the interpreter or possibly have unspecified other impact.

Project: ghostscript
File: zcolor.c

static int checkGamma(i_ctx_t * i_ctx_p, ref *CIEdict, int numvalues)
{
    int code = 0, i;
    float value[3];
    ref *tempref, valref;

    code = dict_find_string(CIEdict, "Gamma", &tempref);
    if (code > 0 && !r_has_type(tempref, t_null)) {
        if (numvalues > 1) {
            /* Array of gammas (RGB) */
            if (!r_is_array(tempref))
                return_error(gs_error_typecheck);
            if (r_size(tempref) != numvalues)
                return_error(gs_error_rangecheck);
            for (i=0;i<numvalues;i++) {
                code = array_get(imemory, tempref, i, &valref);
                if (code < 0)
                    return code;
                if (r_has_type(&valref, t_integer))
                    value[i] = (float)valref.value.intval;
                else if (r_has_type(&valref, t_real))
                    value[i] = (float)valref.value.realval;
                else
                    return_error(gs_error_typecheck);
                if (value[i] <= 0) return_error(gs_error_rangecheck);
            }
        } else {
            /* Single gamma (gray) */
            if (r_has_type(tempref, t_real))
                value[0] = (float)(tempref->value.realval);
            else if (r_has_type(tempref, t_integer))
                    value[0] = (float)(tempref->value.intval);
            else
                return_error(gs_error_typecheck);
            if (value[0] <= 0) return_error(gs_error_rangecheck);
        }
    }
    return 0;
}

Project: ghostscript
File: zcolor.c

static int cieadomain(i_ctx_t * i_ctx_p, ref *space, float *ptr)
{
    int code;
    ref CIEdict, *tempref;

    code = array_get(imemory, space, 1, &CIEdict);
    if (code < 0)
        return code;

    /* If we have a RangeA entry in the dictionary, get the
     * values from that
     */
    code = dict_find_string(&CIEdict, "RangeA", &tempref);
    if (code > 0 && !r_has_type(tempref, t_null)) {
        code = get_cie_param_array(imemory, tempref, 2, ptr);
        if (code < 0)
            return code;
    } else {
        /* Default values for CIEBasedA */
        ptr[0] = 0;
        ptr[1] = 1;
    }
    return 0;
}

Project: ghostscript
File: zcolor.c

static int ciearange(i_ctx_t * i_ctx_p, ref *space, float *ptr)
{
    int code;
    ref CIEdict, *tempref;

    code = array_get(imemory, space, 1, &CIEdict);
    if (code < 0)
        return code;

    /* If we have a RangeA entry in the dictionary, get the
     * values from that
     */
    code = dict_find_string(&CIEdict, "RangeA", &tempref);
    if (code > 0 && !r_has_type(tempref, t_null)) {
        code = get_cie_param_array(imemory, tempref, 2, ptr);
        if (code < 0)
            return code;
    } else {
        /* Default values for CIEBasedA */
        ptr[0] = 0;
        ptr[1] = 1;
    }
    return 0;
}

Project: ghostscript
File: zcolor.c

static int ciedefcompareproc(i_ctx_t *i_ctx_p, ref *space, ref *testspace)
{
    int code = 0;
    ref CIEdict1, CIEdict2;

    code = array_get(imemory, space, 1, &CIEdict1);
    if (code < 0)
        return 0;
    code = array_get(imemory, testspace, 1, &CIEdict2);
    if (code < 0)
        return 0;
    if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"WhitePoint"))
        return 0;
    if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"BlackPoint"))
        return 0;
    if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"RangeABC"))
        return 0;
    if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"DecodeABC"))
        return 0;
    if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"MatrixABC"))
        return 0;
    if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"RangeLMN"))
        return 0;
    if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"DecodeLMN"))
        return 0;
    if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"MatrixMN"))
        return 0;
    if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"RangeDEF"))
        return 0;
    if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"DecodeDEF"))
        return 0;
    if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"RangeHIJ"))
        return 0;
    if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"Table"))
        return 0;
    return 1;
}

Project: ghostscript
File: zcolor.c

static int ciedefvalidate(i_ctx_t *i_ctx_p, ref *space, float *values, int num_comps)
{
    os_ptr op = osp;
    int i;

    if (num_comps < 3)
        return_error(gs_error_stackunderflow);

    op -= 2;
    for (i=0;i<3;i++) {
        if (!r_has_type(op, t_integer) && !r_has_type(op, t_real))
            return_error(gs_error_typecheck);
        op++;
    }

    return 0;
}

Project: ghostscript
File: zcolor.c

static int deviceninitialproc(i_ctx_t *i_ctx_p, ref *space)
{
    gs_client_color cc;
    int i, num_components, code;
    ref namesarray;

    code = array_get(imemory, space, 1, &namesarray);
    if (code < 0)
        return code;
    num_components = r_size(&namesarray);
    cc.pattern = 0x00;
    for (i=0;i<num_components;i++)
        cc.paint.values[i] = 1.0;
    return gs_setcolor(igs, &cc);
}

Project: ghostscript
File: zcolor.c

static int dummyrange(i_ctx_t * i_ctx_p, ref *space, float *ptr)
{
    return 0;
}

Project: ghostscript
File: zcolor.c

static int hashcieabcspace(i_ctx_t * i_ctx_p, ref *space, gs_md5_state_t *md5)
{
    int code = 0;
    ref CIEdict1, spacename;

    code = array_get(imemory, space, 0, &spacename);
    if (code < 0)
        return 0;
    gs_md5_append(md5, (const gs_md5_byte_t *)&spacename.value.pname, sizeof(spacename.value.pname));

    code = array_get(imemory, space, 1, &CIEdict1);
    if (code < 0)
        return 0;
    if (!hashdictkey(i_ctx_p, &CIEdict1, (char *)"WhitePoint", md5))
        return 0;
    if (!hashdictkey(i_ctx_p, &CIEdict1, (char *)"BlackPoint", md5))
        return 0;
    if (!hashdictkey(i_ctx_p, &CIEdict1, (char *)"RangeABC", md5))
        return 0;
    if (!hashdictkey(i_ctx_p, &CIEdict1, (char *)"DecodeABC", md5))
        return 0;
    if (!hashdictkey(i_ctx_p, &CIEdict1, (char *)"MatrixABC", md5))
        return 0;
    if (!hashdictkey(i_ctx_p, &CIEdict1, (char *)"RangeLMN", md5))
        return 0;
    if (!hashdictkey(i_ctx_p, &CIEdict1, (char *)"DecodeLMN", md5))
        return 0;
    if (!hashdictkey(i_ctx_p, &CIEdict1, (char *)"MatrixMN", md5))
        return 0;
    return 1;
}

Project: ghostscript
File: zcolor.c

static int iccbasecolor(i_ctx_t * i_ctx_p, ref *space, int base, int *stage, int *cont, int *stack_depth)
{
    *stage = 0;
    *cont = 1;
    return 0;
}

Project: ghostscript
File: zcolor.c

static int icccomponents(i_ctx_t * i_ctx_p, ref *space, int *n)
{
    int code = 0;
    ref *tempref, ICCdict;

    code = array_get(imemory, space, 1, &ICCdict);
    if (code < 0)
        return code;

    code = dict_find_string(&ICCdict, "N", &tempref);
    if (code < 0)
        return code;
    if (code == 0)
        return gs_note_error(gs_error_undefined);
    *n = tempref->value.intval;
    return 0;
}

Project: ghostscript
File: zcolor.c

static int indexedrange(i_ctx_t * i_ctx_p, ref *space, float *ptr)
{
    ref hival;
    int code;

    code = array_get(imemory, space, 2, &hival);
    if (code < 0)
        return code;
    ptr[0] = 0;
    ptr[1] = (float)hival.value.intval;
    return 0;
}

Project: ghostscript
File: zcolor.c

static int patternalternatespace(i_ctx_t * i_ctx_p, ref *space, ref **r, int *CIESubst)
{
    ref tref;
    int code;

    if (!r_has_type(*r, t_name)) {
        if (r_is_array(*r)) {
            if (r_size(*r) > 1) {
                code = array_get(imemory, space, 1, &tref);
                if (code < 0)
                    return code;
                ref_assign(*r, &tref);
            } else
                *r = 0;
        } else
            return_error(gs_error_typecheck);
    } else
        *r = 0;
    return 0;
}

Project: ghostscript
File: zcolor.c

static int setcalrgbspace(i_ctx_t * i_ctx_p, ref *r, int *stage, int *cont, int CIESubst)
{
    ref rgbdict;
    int code = 0;
    float                   gamma[3], white[3], black[3], matrix[9];
    static const float      dflt_gamma[3] = { 1.0, 1.0, 1.0 };
    static const float      dflt_black[3] = {0,0,0}, dflt_white[3] = {0,0,0};
    static const float      dflt_matrix[9] = {1,0,0,0,1,0,0,0,1};
    int i;
    gs_client_color cc;

    *cont = 0;
    code = array_get(imemory, r, 1, &rgbdict);
    if (code < 0)
        return code;
/* Get all the parts */
    code = dict_floats_param( imemory,
                              &rgbdict,
                              "Gamma",
                              3,
                              gamma,
                              dflt_gamma );
    if (code < 0)
        return code;
    if (gamma[0] <= 0 || gamma[1] <= 0 || gamma[2] <= 0)
        return_error(gs_error_rangecheck);
    code = dict_floats_param( imemory,
                              &rgbdict,
                              "BlackPoint",
                              3,
                              black,
                              dflt_black );
    if (code < 0)
        return code;
    code = dict_floats_param( imemory,
                              &rgbdict,
                              "WhitePoint",
                              3,
                              white,
                              dflt_white );
    if (code < 0)
        return code;
    if (white[0] <= 0 || white[1] != 1.0 || white[2] <= 0)
        return_error(gs_error_rangecheck);
    code = dict_floats_param( imemory,
                              &rgbdict,
                              "Matrix",
                              9,
                              matrix,
                              dflt_matrix );
    if (code < 0)
        return code;
    code = seticc_cal(i_ctx_p, white, black, gamma, matrix, 3, rgbdict.value.saveid);
    if ( code < 0)
        return gs_rethrow(code, "setting CalRGB  color space");
    cc.pattern = 0x00;
    for (i=0;i<3;i++)
        cc.paint.values[i] = 0;
    code = gs_setcolor(igs, &cc);
    return code;
}

Project: ghostscript
File: zcolor.c

static int truecompareproc(i_ctx_t *i_ctx_p, ref *space, ref *testspace)
{
    return 1;
}

Project: ghostscript
File: zcolor.c

static int validatecalgrayspace(i_ctx_t * i_ctx_p, ref **r)
{
    int code=0;
    ref *space, calgraydict;

    space = *r;
    if (!r_is_array(space))
        return_error(gs_error_typecheck);
    /* Validate parameters, check we have enough operands */
    if (r_size(space) < 2)
        return_error(gs_error_rangecheck);
    code = array_get(imemory, space, 1, &calgraydict);
    if (code < 0)
        return code;
    check_type(calgraydict, t_dictionary);
    /* Check the white point, which is required */
    /* We have to have a white point */
    /* Check white point exists, and is an array of three numbers */
    code = checkWhitePoint(i_ctx_p, &calgraydict);
    if (code != 0)
        return code;
    /* The rest are optional.  Need to validate though */
    code = checkBlackPoint(i_ctx_p, &calgraydict);
    if (code < 0)
        return code;
    /* Check Gamma values */
    code = checkGamma(i_ctx_p, &calgraydict, 1);
    if (code < 0)
        return code;
    *r = 0;  /* No nested space */
    return 0;
}

Project: ghostscript
File: zcolor.c

zcolor_remap_one(
    i_ctx_t *           i_ctx_p,
    const ref *         pproc,
    gx_transfer_map *   pmap,
    const gs_gstate *    pgs,
    op_proc_t           finish_proc )
{
    os_ptr              op;

    /*
     * Detect the identity function, which is a common value for one or
     * more of these functions.
     */
    if (r_size(pproc) == 0) {
        gx_set_identity_transfer(pmap);
        /*
         * Even though we don't actually push anything on the e-stack, all
         * clients do, so we return o_push_estack in this case.  This is
         * needed so that clients' finishing procedures will get run.
         */
        return o_push_estack;
    }
    op = osp += 4;
    make_real(op - 3, 0);
    make_int(op - 2, transfer_map_size - 1);
    make_real(op - 1, 1);
    *op = *pproc;
    ++esp;
    make_struct(esp, imemory_space((gs_ref_memory_t *) pgs->memory),
                pmap);
    push_op_estack(finish_proc);
    push_op_estack(zfor_samples);
    return o_push_estack;
}

Project: ghostscript
File: zcolor.c

zcurrenthsbcolor(i_ctx_t * i_ctx_p)
{
    int code, depth;

    code = validate_spaces(i_ctx_p, &istate->colorspace[0].array, &depth);
    if (code < 0)
        return code;

    code = zcurrentcolor(i_ctx_p);
    if (code < 0)
        return code;
    /* Set up for the continuation procedure which will do the work */
    /* Make sure the exec stack has enough space */
    check_estack(7);
    push_mark_estack(es_other, colour_cleanup);
    esp++;
    /* variable to hold stack depth for tint transform */
    make_int(&esp[0], 0);
    esp++;
    /* Store the 'base' type color wanted, in this case HSB */
    make_int(&esp[0], 1);
    make_int(&esp[1], 1);
    /* Store the 'stage' of processing (initially 0) */
    make_int(&esp[2], 0);
    /* Store a pointer to the color space stored on the operand stack
     * as the stack may grow unpredictably making further access
     * to the space difficult
     */
    esp[3] = istate->colorspace[0].array;
    esp += 3; /* The push_op_estack macro increments esp before using it */
    /* Finally, the actual continuation routine */
    push_op_estack(currentbasecolor_cont);
    return o_push_estack;
}

Project: ghostscript
File: zcolor.c

zcurrenttransfer(i_ctx_t *i_ctx_p)
{
    os_ptr  op = osp;

    push(1);
    *op = istate->transfer_procs.gray;
    return 0;
}