Commit message: wildmidi_lib.c (WildMidi_Open, WildMidi_OpenBuffer): refuse to proceed if less then 18 bytes of input

Fixes bug #178.
CVE: CVE-2017-1000418
CWE: CWE-119
Vulnerability description: The WildMidi_Open function in WildMIDI since commit d8a466829c67cacbb1700beded25c448d99514e5 allows remote attackers to cause a denial of service (heap-based buffer overflow and application crash) or possibly have unspecified other impact via a crafted file.

Project: wildmidi
File: wildmidi_lib.c

static void WM_InitPatches(void) {
    int i;
    for (i = 0; i < 128; i++) {
        _WM_patch[i] = NULL;
    }
}

Project: wildmidi
File: wildmidi_lib.c

WM_SYMBOL int WildMidi_ConvertBufferToMidi (uint8_t *in, uint32_t insize,
                                            uint8_t **out, uint32_t *outsize) {
    if (!in || !out || !outsize) {
        _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL params)", 0);
        return (-1);
    }

    if (!memcmp(in, "FORM", 4)) {
        if (_WM_xmi2midi(in, insize, out, outsize,
                _cvt_get_option(WM_CO_XMI_TYPE)) < 0) {
            return (-1);
        }
    }
    else if (!memcmp(in, "MUS", 3)) {
        if (_WM_mus2midi(in, insize, out, outsize,
                _cvt_get_option(WM_CO_FREQUENCY)) < 0) {
            return (-1);
        }
    }
    else if (!memcmp(in, "MThd", 4)) {
        _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, 0, "Already a midi file", 0);
        return (-1);
    }
    else {
        _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, NULL, 0);
        return (-1);
    }

    return (0);
}

Project: wildmidi
File: wildmidi_lib.c

WM_SYMBOL int WildMidi_Init(const char *config_file, uint16_t rate, uint16_t mixer_options) {
    if (WM_Initialized) {
        _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_ALR_INIT, NULL, 0);
        return (-1);
    }

    if (config_file == NULL) {
        _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG,
                "(NULL config file pointer)", 0);
        return (-1);
    }
    WM_InitPatches();
    if (WM_LoadConfig(config_file) == -1) {
        return (-1);
    }

    if (mixer_options & 0x0FF0) {
        _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(invalid option)",
                0);
        WM_FreePatches();
        return (-1);
    }
    _WM_MixerOptions = mixer_options;

    if (rate < 11025) {
        _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG,
                "(rate out of bounds, range is 11025 - 65535)", 0);
        WM_FreePatches();
        return (-1);
    }
    _WM_SampleRate = rate;

    gauss_lock = 0;
    _WM_patch_lock = 0;
    _WM_MasterVolume = 948;
    WM_Initialized = 1;

    return (0);
}

Project: wildmidi
File: wildmidi_lib.c

WM_SYMBOL int WildMidi_SongSeek (midi * handle, int8_t nextsong) {
    struct _mdi *mdi;
    struct _event *event;
    struct _event *event_new;
    struct _note *note_data;

    if (!WM_Initialized) {
        _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0);
        return (-1);
    }
    if (handle == NULL) {
        _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL handle)", 0);
        return (-1);
    }
    mdi = (struct _mdi *) handle;
    _WM_Lock(&mdi->lock);

    if ((!mdi->is_type2) && (nextsong != 0)) {
        _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(Illegal use. Only usable with files detected to be type 2 compatible.", 0);
        _WM_Unlock(&mdi->lock);
        return (-1);
    }
    if ((nextsong > 1) || (nextsong < -1)) {
        _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(Invalid nextsong setting. -1 is previous song, 0 start of current song, 1 is next song)", 0);
        _WM_Unlock(&mdi->lock);
        return (-1);
    }

    event = mdi->current_event;

    if (nextsong == -1) {
        /* goto start of previous song */
        /*
         * So with this one we have to go back 2 eof's
         * then forward 1 event to get to the start of
         * the previous song.
         * NOTE: We will automatically stop at the start 
         * of the data.
         */
        uint8_t eof_cnt = 1;
        while (event != mdi->events) {
            if (event[-1].do_event == _WM_do_meta_endoftrack) {
                if (eof_cnt == 0) {
                    break;
                }
                eof_cnt = 0;
            }
            event--;
        }
        event_new = event;
        event = mdi->events;
        _WM_ResetToStart(handle);

    } else if (nextsong == 1) {
        /* goto start of next song */
        while (event->do_event != NULL) {
            if (event->do_event == _WM_do_meta_endoftrack) {
                event++;
                if (event->do_event == NULL) {
                    event--;
                    goto START_THIS_SONG;
                } else {
                    break;
                }
            }
            event++;
        }
        event_new = event;
        event = mdi->current_event;

    } else {
    START_THIS_SONG:
        /* goto start of this song */
        /* first find the offset */
        while (event != mdi->events) {
            if (event[-1].do_event == _WM_do_meta_endoftrack) {
                break;
            }
            event--;
        }
        event_new = event;
        event = mdi->events;
        _WM_ResetToStart(handle);
    }

    while (event != event_new) {
        event->do_event(mdi, &event->event_data);
        mdi->extra_info.current_sample += event->samples_to_next;
        event++;
    }

    mdi->current_event = event;

    note_data = mdi->note;
    if (note_data) {
        do {
            note_data->active = 0;
            if (note_data->replay) {
                note_data->replay = NULL;
            }
            note_data = note_data->next;
        } while (note_data);
    }
    mdi->note = NULL;

    _WM_Unlock(&mdi->lock);
    return (0);
}

Project: wildmidi
File: wildmidi_lib.c

void _cvt_reset_options (void) {
    _WM_Lock(&WM_ConvertOptions.lock);
    WM_ConvertOptions.xmi_convert_type = 0;
    WM_ConvertOptions.frequency = 0;
    _WM_Unlock(&WM_ConvertOptions.lock);
}