Commit tterribe's port of Tremor r17541:
authorMonty <xiphmont@xiph.org>
Sat, 23 Oct 2010 10:34:24 +0000 (10:34 +0000)
committerMonty <xiphmont@xiph.org>
Sat, 23 Oct 2010 10:34:24 +0000 (10:34 +0000)
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.

Also, fix/eliminate two printf warnings in seeking_example extension.

svn path=/trunk/vorbis/; revision=17561

examples/seeking_example.c
lib/block.c

index 6355359..cbd5a9b 100644 (file)
@@ -61,13 +61,13 @@ void _verify(OggVorbis_File *ov,
   bread=ov_read(ov,buffer,4096,1,1,1,&dummy);
   for(j=0;j<bread;j++){
     if(buffer[j]!=bigassbuffer[j+((pos>>hs)*2)]){
-      fprintf(stderr,"data after seek doesn't match declared pcm position %lld\n",pos);
+      fprintf(stderr,"data after seek doesn't match declared pcm position %ld\n",(long)pos);
 
       for(i=0;i<(pcmlength>>hs)*2-bread;i++){
         for(j=0;j<bread;j++)
           if(buffer[j] != bigassbuffer[i+j])break;
         if(j==bread){
-          fprintf(stderr,"data after seek appears to match position %lld\n",(i/2)<<hs);
+          fprintf(stderr,"data after seek appears to match position %ld\n",(long)((i/2)<<hs));
         }
       }
       {
index c409515..2dc28c2 100644 (file)
@@ -860,6 +860,15 @@ 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 preceding granulepos; assume we started at zero (we'd
@@ -867,10 +876,16 @@ int vorbis_synthesis_blockin(vorbis_dsp_state *v,vorbis_block *vb){
           /* granulepos could be -1 due to a seek, but that would result
              in a long count, not short count */
 
-          v->pcm_current-=(b->sample_count-v->granulepos)>>hs;
+          /* 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)<<hs)
+            extra = (v->pcm_current - v->pcm_returned)<<hs;
+
+          v->pcm_current-=extra>>hs;
         }else{
           /* trim the beginning */
-          v->pcm_returned+=(b->sample_count-v->granulepos)>>hs;
+          v->pcm_returned+=extra>>hs;
           if(v->pcm_returned>v->pcm_current)
             v->pcm_returned=v->pcm_current;
         }
@@ -888,6 +903,20 @@ int vorbis_synthesis_blockin(vorbis_dsp_state *v,vorbis_block *vb){
         if(extra)
           if(vb->eofflag){
             /* partial last frame.  Strip the extra samples off */
+
+            /* 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)<<hs)
+              extra = (v->pcm_current - v->pcm_returned)<<hs;
+
+            /* 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>>hs;
           } /* else {Shouldn't happen *unless* the bitstream is out of
                spec.  Either way, believe the bitstream } */