Commit message: None
CVE: CVE-2018-16541
CWE: CWE-416
Vulnerability description: In Artifex Ghostscript before 9.24, attackers able to supply crafted PostScript files could use incorrect free logic in pagedevice replacement to crash the interpreter.

Project: ghostscript
File: imain.c

get_op_array(const gs_memory_t *mem, int size)
{
    gs_main_instance *minst = get_minst_from_memory(mem);
    return op_index_op_array_table(minst->i_ctx_p,size);
}

Project: ghostscript
File: imain.c

gs_main_add_lib_path(gs_main_instance * minst, const char *lpath)
{
    /* Account for the possibility that the first element */
    /* is gp_current_directory name added by set_lib_paths. */
    int first_is_here =
        (r_size(&minst->lib_path.list) != 0 &&
         minst->lib_path.container.value.refs[0].value.bytes ==
         (const byte *)gp_current_directory_name ? 1 : 0);
    int code;

    r_set_size(&minst->lib_path.list, minst->lib_path.count +
               first_is_here);
    code = file_path_add(minst, &minst->lib_path, lpath);
    minst->lib_path.count = r_size(&minst->lib_path.list) - first_is_here;
    if (code < 0)
        return code;
    return gs_main_set_lib_paths(minst);
}

Project: ghostscript
File: imain.c

gs_main_dump_stack(gs_main_instance *minst, int code, ref * perror_object)
{
    i_ctx_t *i_ctx_p = minst->i_ctx_p;

    zflush(i_ctx_p);            /* force out buffered output */
    dmprintf1(minst->heap, "\nUnexpected interpreter error %d.\n", code);
    if (perror_object != 0) {
        dmputs(minst->heap, "Error object: ");
        debug_print_ref(minst->heap, perror_object);
        dmputc(minst->heap, '\n');
    }
    debug_dump_stack(minst->heap, &o_stack, "Operand stack");
    debug_dump_stack(minst->heap, &e_stack, "Execution stack");
    debug_dump_stack(minst->heap, &d_stack, "Dictionary stack");
}

Project: ghostscript
File: imain.c

int gs_main_init2aux(gs_main_instance * minst) {
    i_ctx_t * i_ctx_p = minst->i_ctx_p;

    if (minst->init_done < 2) {
        int code, exit_code;
        ref error_object, ifa;

        /* Set up enough so that we can safely be garbage collected */
        i_ctx_p->op_array_table_global = empty_table;
        i_ctx_p->op_array_table_local = empty_table;

        code = zop_init(i_ctx_p);
        if (code < 0)
            return code;
        code = op_init(i_ctx_p);        /* requires obj_init */
        if (code < 0)
            return code;

        /* Set up the array of additional initialization files. */
        make_const_string(&ifa, a_readonly | avm_foreign, gs_init_files_sizeof - 2, gs_init_files);
        code = initial_enter_name("INITFILES", &ifa);
        if (code < 0)
            return code;

        /* Set up the array of emulator names. */
        make_const_string(&ifa, a_readonly | avm_foreign, gs_emulators_sizeof - 2, gs_emulators);
        code = initial_enter_name("EMULATORS", &ifa);
        if (code < 0)
            return code;

        /* Pass the search path. */
        code = initial_enter_name("LIBPATH", &minst->lib_path.list);
        if (code < 0)
            return code;

        /* Execute the standard initialization file. */
        code = gs_run_init_file(minst, &exit_code, &error_object);
        if (code < 0)
            return code;
        minst->init_done = 2;
        /* NB this is to be done with device parameters
         * both minst->display and  display_set_callback() are going away
        */
        if (minst->display)
        if ((code = display_set_callback(minst, minst->display)) < 0)
            return code;

        if ((code = gs_main_run_string(minst,
                "JOBSERVER "
                " { false 0 .startnewjob } "
                " { NOOUTERSAVE not { save pop } if } "
                "ifelse", 0, &exit_code,
                &error_object)) < 0)
           return code;
    }
    return 0;
}

Project: ghostscript
File: imain.c

gs_main_lib_open(gs_main_instance * minst, const char *file_name, ref * pfile)
{
    /* This is a separate procedure only to avoid tying up */
    /* extra stack space while running the file. */
    i_ctx_t *i_ctx_p = minst->i_ctx_p;
#define maxfn 2048
    char fn[maxfn];
    uint len;

    return lib_file_open(&minst->lib_path, imemory,
                         NULL, /* Don't check permissions here, because permlist
                                  isn't ready running init files. */
                          file_name, strlen(file_name), fn, maxfn, &len, pfile);
}

Project: ghostscript
File: imain.c

gs_main_run_string_begin(gs_main_instance * minst, int user_errors,
                         int *pexit_code, ref * perror_object)
{
    const char *setup = ".runstringbegin";
    ref rstr;
    int code;

    gs_main_set_lib_paths(minst);
    make_const_string(&rstr, avm_foreign | a_readonly | a_executable,
                      strlen(setup), (const byte *)setup);
    code = gs_main_interpret(minst, &rstr, user_errors, pexit_code,
                        perror_object);
    return (code == gs_error_NeedInput ? 0 : code == 0 ? gs_error_Fatal : code);
}

Project: ghostscript
File: imain.c

gs_push_real(gs_main_instance * minst, double value)
{
    ref vref;

    make_real(&vref, value);
    return push_value(minst, &vref);
}

Project: ghostscript
File: imain.c

gs_to_exit_with_code(const gs_memory_t *mem, int exit_status, int code)
{
    return gs_main_finit(get_minst_from_memory(mem), exit_status, code);
}

Project: ghostscript
File: imain.c

pop_value(i_ctx_t *i_ctx_p, ref * pvalue)
{
    if (!ref_stack_count(&o_stack))
        return_error(gs_error_stackunderflow);
    *pvalue = *ref_stack_index(&o_stack, 0L);
    return 0;
}