diff options
author | Monty <xiphmont@xiph.org> | 2010-10-18 09:49:20 +0000 |
---|---|---|
committer | Monty <xiphmont@xiph.org> | 2010-10-18 09:49:20 +0000 |
commit | bbe63bb1e8faf60e1b89d2e9ca2aa9872f47ffe7 (patch) | |
tree | 4e0710334a60f1d737222545240f6c13cfcb920d | |
parent | ef651239baad50bff0d1a9ee755aa92f48481c23 (diff) | |
download | tremor-bbe63bb1e8faf60e1b89d2e9ca2aa9872f47ffe7.tar.gz |
Harden the code that trims the last packet of a stream; it was
possible to game the granpos such that the trim code would try to
rewind more samples than were actually available in storage.
git-svn-id: https://svn.xiph.org/trunk/Tremor@17541 0101bb08-14d6-0310-b084-bc0e0c8e3800
-rw-r--r-- | block.c | 38 |
1 files changed, 34 insertions, 4 deletions
@@ -401,17 +401,32 @@ int vorbis_synthesis_blockin(vorbis_dsp_state *v,vorbis_block *vb){ if(b->sample_count>v->granulepos){ /* corner case; if this is both the first and last audio page, then spec says the end is cut, not beginning */ + long extra=b->sample_count-vb->granulepos; + + /* we use ogg_int64_t for granule positions because a + uint64 isn't universally available. Unfortunately, + that means granposes can be 'negative' and result in + extra being negative */ + if(extra<0) + extra=0; + if(vb->eofflag){ /* trim the end */ /* no preceeding granulepos; assume we started at zero (we'd have to in a short single-page stream) */ /* granulepos could be -1 due to a seek, but that would result in a long coun`t, not short count */ - - v->pcm_current-=(b->sample_count-v->granulepos); + + /* Guard against corrupt/malicious frames that set EOP and + a backdated granpos; don't rewind more samples than we + actually have */ + if(extra > v->pcm_current - v->pcm_returned) + extra = v->pcm_current - v->pcm_returned; + + v->pcm_current-=extra; }else{ /* trim the beginning */ - v->pcm_returned+=(b->sample_count-v->granulepos); + v->pcm_returned+=extra; if(v->pcm_returned>v->pcm_current) v->pcm_returned=v->pcm_current; } @@ -429,7 +444,22 @@ int vorbis_synthesis_blockin(vorbis_dsp_state *v,vorbis_block *vb){ if(extra) if(vb->eofflag){ /* partial last frame. Strip the extra samples off */ - v->pcm_current-=extra; + + /* Guard against corrupt/malicious frames that set EOP and + a backdated granpos; don't rewind more samples than we + actually have */ + if(extra > v->pcm_current - v->pcm_returned) + extra = v->pcm_current - v->pcm_returned; + + /* we use ogg_int64_t for granule positions because a + uint64 isn't universally available. Unfortunately, + that means granposes can be 'negative' and result in + extra being negative */ + if(extra<0) + extra=0; + + v->pcm_current-=extra; + } /* else {Shouldn't happen *unless* the bitstream is out of spec. Either way, believe the bitstream } */ } /* else {Shouldn't happen *unless* the bitstream is out of |