From 98fdfc6df88b1e34a736d5e126e6c8139c8de1a6 Mon Sep 17 00:00:00 2001 From: Sean Barrett Date: Fri, 9 Aug 2019 04:05:22 -0700 Subject: [PATCH] Fix seven bugs discovered and fixed by ForAllSecure: CVE-2019-13217: heap buffer overflow in start_decoder() CVE-2019-13218: stack buffer overflow in compute_codewords() CVE-2019-13219: uninitialized memory in vorbis_decode_packet_rest() CVE-2019-13220: out-of-range read in draw_line() CVE-2019-13221: issue with large 1D codebooks in lookup1_values() CVE-2019-13222: unchecked NULL returned by get_window() CVE-2019-13223: division by zero in predict_point() --- stb_vorbis.c | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/stb_vorbis.c b/stb_vorbis.c index ff117abe6f..aa48137976 100644 --- a/stb_vorbis.c +++ b/stb_vorbis.c @@ -33,6 +33,7 @@ // Timur Gagiev // // Partial history: +// 1.17 - 2019-07-08 - fix CVE-2019-13217..CVE-2019-13223 (by ForAllSecure) // 1.16 - 2019-03-04 - fix warnings // 1.15 - 2019-02-07 - explicit failure if Ogg Skeleton data is found // 1.14 - 2018-02-11 - delete bogus dealloca usage @@ -1202,8 +1203,10 @@ static int lookup1_values(int entries, int dim) int r = (int) floor(exp((float) log((float) entries) / dim)); if ((int) floor(pow((float) r+1, dim)) <= entries) // (int) cast for MinGW warning; ++r; // floor() to avoid _ftol() when non-CRT - assert(pow((float) r+1, dim) > entries); - assert((int) floor(pow((float) r, dim)) <= entries); // (int),floor() as above + if (pow((float) r+1, dim) <= entries) + return -1; + if ((int) floor(pow((float) r, dim)) > entries) + return -1; return r; } @@ -2013,7 +2016,7 @@ static __forceinline void draw_line(float *output, int x0, int y0, int x1, int y ady -= abs(base) * adx; if (x1 > n) x1 = n; if (x < x1) { - LINE_OP(output[x], inverse_db_table[y]); + LINE_OP(output[x], inverse_db_table[y&255]); for (++x; x < x1; ++x) { err += ady; if (err >= adx) { @@ -2021,7 +2024,7 @@ static __forceinline void draw_line(float *output, int x0, int y0, int x1, int y y += sy; } else y += base; - LINE_OP(output[x], inverse_db_table[y]); + LINE_OP(output[x], inverse_db_table[y&255]); } } } @@ -3048,7 +3051,6 @@ static float *get_window(vorb *f, int len) len <<= 1; if (len == f->blocksize_0) return f->window[0]; if (len == f->blocksize_1) return f->window[1]; - assert(0); return NULL; } @@ -3454,6 +3456,7 @@ static int vorbis_finish_frame(stb_vorbis *f, int len, int left, int right) if (f->previous_length) { int i,j, n = f->previous_length; float *w = get_window(f, n); + if (w == NULL) return 0; for (i=0; i < f->channels; ++i) { for (j=0; j < n; ++j) f->channel_buffers[i][left+j] = @@ -3695,6 +3698,7 @@ static int start_decoder(vorb *f) while (current_entry < c->entries) { int limit = c->entries - current_entry; int n = get_bits(f, ilog(limit)); + if (current_length >= 32) return error(f, VORBIS_invalid_setup); if (current_entry + n > (int) c->entries) { return error(f, VORBIS_invalid_setup); } memset(lengths + current_entry, current_length, n); current_entry += n; @@ -3798,7 +3802,9 @@ static int start_decoder(vorb *f) c->value_bits = get_bits(f, 4)+1; c->sequence_p = get_bits(f,1); if (c->lookup_type == 1) { - c->lookup_values = lookup1_values(c->entries, c->dimensions); + int values = lookup1_values(c->entries, c->dimensions); + if (values < 0) return error(f, VORBIS_invalid_setup); + c->lookup_values = (uint32) values; } else { c->lookup_values = c->entries * c->dimensions; } @@ -3934,6 +3940,9 @@ static int start_decoder(vorb *f) p[j].id = j; } qsort(p, g->values, sizeof(p[0]), point_compare); + for (j=0; j < g->values-1; ++j) + if (p[j].x == p[j+1].x) + return error(f, VORBIS_invalid_setup); for (j=0; j < g->values; ++j) g->sorted_order[j] = (uint8) p[j].id; // precompute the neighbors @@ -4020,6 +4029,7 @@ static int start_decoder(vorb *f) max_submaps = m->submaps; if (get_bits(f,1)) { m->coupling_steps = get_bits(f,8)+1; + if (m->coupling_steps > f->channels) return error(f, VORBIS_invalid_setup); for (k=0; k < m->coupling_steps; ++k) { m->chan[k].magnitude = get_bits(f, ilog(f->channels-1)); m->chan[k].angle = get_bits(f, ilog(f->channels-1)); @@ -5386,6 +5396,12 @@ int stb_vorbis_get_samples_float(stb_vorbis *f, int channels, float **buffer, in #endif // STB_VORBIS_NO_PULLDATA_API /* Version history + 1.17 - 2019-07-08 - fix CVE-2019-13217, -13218, -13219, -13220, -13221, -13223, -13223 + found with Mayhem by ForAllSecure + 1.16 - 2019-03-04 - fix warnings + 1.15 - 2019-02-07 - explicit failure if Ogg Skeleton data is found + 1.14 - 2018-02-11 - delete bogus dealloca usage + 1.13 - 2018-01-29 - fix truncation of last frame (hopefully) 1.12 - 2017-11-21 - limit residue begin/end to blocksize/2 to avoid large temp allocs in bad/corrupt files 1.11 - 2017-07-23 - fix MinGW compilation 1.10 - 2017-03-03 - more robust seeking; fix negative ilog(); clear error in open_memory