
Un archivo AVI puede tener múltiples pistas. Por ejemplo, una pista de audio y una pista de video.
Para analizar un número arbitrario de pistas, VLC primero debe determinar si una pista determinada está completa y es reproducible. Con este propósito se configuran dos variables. Ambas denominadas i_track.
La variable p_sys representa el archivo AVI para nuestros propósitos. Por lo tanto, la variable i_track "oficial", que se utilizará para hacer referencia a las pistas que se determinan como completas y reproducibles, es p_sys->i_track. Se inicializa con una macro aquí:
```
TAB_INIT(p_sys->i_track, p_sys->track);
//#define TAB_INIT( count, tab ) do {(count) = 0; (tab) = NULL; } while(0)
```
Mientras tanto, se configura una segunda variable i_track para contar TODAS las pistas, independientemente de si están completas o son reproducibles.
```
i_track = AVI_ChunkCount( p_hdrl, AVIFOURCC_strl, true );
```
La segunda i_track representa todos los chunks que comienzan con 'strl'. Controla un bucle 'for' que establece la variable p_sys->i_track solo si pasa una serie de comprobaciones:
```
for( unsigned i = 0 ; i < i_track; i++ )
{
...
TAB_APPEND( p_sys->i_track, p_sys->track, tk );
//#define TAB_APPEND( count, tab, p ) {TAB_APPEND_CAST( , count, tab, p )}
//TAB_APPEND_CAST( ,p_sys->i_track, p_sys->track, tk)
//if( (count) > 0 ) (tab) = cast realloc( tab, sizeof( *(tab) ) * ( (count) + 1 ) );
//else (tab) = cast malloc( sizeof( *(tab) ) );
//if( !(tab) ) abort();
//(tab)[count] = (p);
//(count)++; //p_sys->i_track incremented here
}
```
Durante un bucle 'for' posterior, la variable p_sys->i_track se utiliza como el número de chunk en una llamada a AVI_ChunkFind, que devuelve el enésimo chunk que coincide con un valor de chunk FOURCC dado, en nuestro caso 'strl':
```
for( unsigned i = 0 ; i < p_sys->i_track; i++ )
{
avi_track_t *tk = p_sys->track[i];
if( tk->fmt.i_cat != AUDIO_ES ||
tk->idx.i_size < 1 ||
tk->i_scale != 1 ||
tk->i_samplesize != 0 )
continue;
//CVE-2021-25804
avi_chunk_list_t *p_strl = AVI_ChunkFind( p_hdrl, AVIFOURCC_strl, i, true );
//subsequently changed to: avi_chunk_list_t *p_strl = AVI_ChunkFind( p_hdrl, AVIFOURCC_strl, tk->fmt.i_id, true );
avi_chunk_strf_t *p_strf = AVI_ChunkFind( p_strl, AVIFOURCC_strf, 0, false );
if( !p_strf || p_strf->i_cat != AUDIO_ES )
continue;
const WAVEFORMATEX *p_wf = p_strf->u.p_wf;
```
Si bien p_sys->i_track cuenta el número correcto de pistas completadas, no lleva la cuenta de a qué número de chunk se asignó. Esto significa que si hay un chunk strl no válido antes del chunk strl válido, el primer chunk se ignorará correctamente al configurar el objeto de pista, pero cuando se llame a ChunkFind, aún seleccionará el primer chunk no válido.
Después de que se creara CVE-2021-25804, el problema se corrigió cambiando la variable de número de chunk de ChunkFind de i a tk->fmt.i_id. tk->fmt.i_id se establece por primera vez justo encima de la llamada a TAB_APPEND() que vimos anteriormente:
```
tk->fmt.i_id = i;
if( p_strn && p_strn->p_str )
tk->fmt.psz_description = FromACP( p_strn->p_str );
//see es_format_truncated.c
tk->p_es = es_out_Add( p_demux->out, &tk->fmt );
TAB_APPEND( p_sys->i_track, p_sys->track, tk );
```
Esto parece solucionar el problema, ya que tk->fmt.i_id se establece en i y, por lo tanto, el chunk completado debería ser el seleccionado por ChunkFind(). Sin embargo, las pruebas revelan que, de hecho, el valor de tk->fmt.i_id se establece en -1 en el momento de la llamada problemática a ChunkFind(). Este es el valor de inicialización establecido durante una llamada a es_format_Init().
```
void es_format_Init( es_format_t *fmt,
int i_cat, vlc_fourcc_t i_codec )
{
memset(fmt, 0, sizeof (*fmt));
fmt->i_cat = i_cat;
fmt->i_codec = i_codec;
fmt->i_profile = -1;
fmt->i_level = -1;
fmt->i_id = -1;
fmt->i_priority = ES_PRIORITY_SELECTABLE_MIN;
fmt->psz_language = NULL;
fmt->psz_description = NULL;
fmt->p_extra_languages = NULL;
if (fmt->i_cat == VIDEO_ES)
video_format_Init(&fmt->video, 0);
fmt->b_packetized = true;
fmt->p_extra = NULL;
}
```
Esta inicialización ocurre en el mismo bucle 'for' en el que fmt->i_id se establece en i.
```
for( unsigned i = 0 ; i < i_track; i++ )
{
...
switch( p_strh->i_type )
{
case( AVIFOURCC_auds ):
{
es_format_Init( &tk->fmt, AUDIO_ES, 0 );
...
}
...
}
tk->fmt.i_id = i;
if( p_strn && p_strn->p_str )
tk->fmt.psz_description = FromACP( p_strn->p_str );
tk->p_es = es_out_Add( p_demux->out, &tk->fmt );
TAB_APPEND( p_sys->i_track, p_sys->track, tk );
}
```