[libdvbpsi-devel] PSI: multiple free
Gauthier Lamaison
gauthier.lamaison at gmail.com
Tue Jul 17 14:44:03 CEST 2012
Hi,
I found some potentials multiple frees in the function Gather*Sections
of each PSI tables.
When a table is complete the process is to save the current information,
chain the sections, decode the sections, delete the sections (by calling
dvbpsi_DeletePSISections), signal the new table, and reinitialize the
structures.
The problem is that dvpsi_ReInit* will call dvbpsi_ReInitDecoder which
will delete any none null sections.
The multiple free will only occur if you have multiple sections in your
table because when Gather*Sections calls dvbpsi_DeletePSISections it
will reset the first section (p_*_decoder->ap_sections[0] = NULL;) but
it will not reset the other sections which may have been freed by
calling dvbpsi_DeletePSISections.
Here is a example with the NIT table, let's say we have two sections for
the nit (with section number 0 et and section number 1).
When the table is completed, we'll call dvbpsi_ChainSectionsDecoder
which will link p_nit_decoder->ap_sections[0] and
p_nit_decoder->ap_sections[1].
Then we'll call dvbpsi_DeletePSISections (
dvbpsi_DeletePSISections(p_nit_decoder->ap_sections[0]) ) and free the
two sections (because p_nit_decoder->ap_sections[0] and
p_nit_decoder->ap_sections[1] are linked). But we'll only reset the
first section (p_nit_decoder->ap_sections[0] = NULL) which means that
the second section will point to a freed memory area.
But when we called dvpsi_ReInitNIT, dvbpsi_DeletePSISections will be
called again on each section:
for (unsigned int i = 0; i <= 255; i++)
{
if (p_decoder->ap_sections[i])
dvbpsi_DeletePSISections(p_decoder->ap_sections[i]);
p_decoder->ap_sections[i] = NULL;
}
There is no problem when i == 0 because we had reset that pointer but
when i == 1 the pointer is not null but points to a freed memory area
which will cause the double free.
But the main problem is that dvbpsi_DeletePSISections will delete the
section passed as a parameter and all the sections linked to that
section (and after dvbpsi_ChainSectionsDecoder all the section are
linked as a single linked list) and when dvpsi_ReInitNIT is called, it
will call dvbpsi_DeletePSISections on each non null section so if we
have 3 section we'll get:
dvbpsi_DeletePSISections(p_decoder->ap_sections[0]) : free(sections[0])
-> free(sections[1]) -> free(sections[2])
dvbpsi_DeletePSISections(p_decoder->ap_sections[1]) : free(sections[1])
-> free(sections[2])
dvbpsi_DeletePSISections(p_decoder->ap_sections[2]) : free(sections[2])
Here is what I propose:
First, remove the direct call to dvbpsi_DeletePSISections from
Gather*Sections, then add a boolean to dvbpsi_ReInitDecoder which will
indicate if the sections are chained or not so we'll know if we need to
call dvbpsi_DeletePSISections for each section or if we just need to
reset the pointers in the loop.
I will send you the different patch if my solution is right for you.
Regards,
Gauthier
More information about the libdvbpsi-devel
mailing list