[FFmpeg-trac] #8226(avfilter:new): A use-after-free bug in formats.c
FFmpeg
trac at avcodec.org
Mon Oct 7 14:36:55 EEST 2019
#8226: A use-after-free bug in formats.c
-----------------------------------+--------------------------------------
Reporter: wurongxin | Type: defect
Status: new | Priority: normal
Component: avfilter | Version: git-master
Keywords: | Blocked By:
Blocking: | Reproduced by developer: 0
Analyzed by developer: 0 |
-----------------------------------+--------------------------------------
Summary of the bug:
How to reproduce:
{{{
% ffmpeg -i input ... output
ffmpeg version
built on ...
}}}
Patches should be submitted to the ffmpeg-devel mailing list and not this
bug tracker.
In the source file libavfilter/formats.c, in the function
"ff_set_common_samplerates", there is a potential double free bug. The
variable "samplerates->formats" has been freed twice.
{{{#!C++
556. int ff_set_common_samplerates(AVFilterContext *ctx,
557. AVFilterFormats *samplerates)
558. {
559. SET_COMMON_FORMATS(ctx, samplerates, in_samplerates,
out_samplerates,
560. ff_formats_ref, ff_formats_unref, formats);
561. }
}}}
The macro definition is as follows:
{{{#!C++
510. #define SET_COMMON_FORMATS(ctx, fmts, in_fmts, out_fmts, ref_fn,
unref_fn, list) \
511. int count = 0, i;
\
512.
\
513. if (!fmts)
\
514. return AVERROR(ENOMEM);
\
515.
\
516. for (i = 0; i < ctx->nb_inputs; i++) {
\
517. if (ctx->inputs[i] && !ctx->inputs[i]->out_fmts) {
\
518. int ret = ref_fn(fmts, &ctx->inputs[i]->out_fmts);
\
519. if (ret < 0) {
\
520. unref_fn(&fmts);
\
521. av_freep(&fmts->list);
\
522. av_freep(&fmts);
\
523. return ret;
\
524. }
\
525. count++;
\
526. }
\
527. }
\
528. for (i = 0; i < ctx->nb_outputs; i++) {
\
529. if (ctx->outputs[i] && !ctx->outputs[i]->in_fmts) {
\
530. int ret = ref_fn(fmts, &ctx->outputs[i]->in_fmts);
\
531. if (ret < 0) {
\
532. unref_fn(&fmts);
\
533. av_freep(&fmts->list);
\
534. av_freep(&fmts);
\
535. return ret;
\
536. }
\
537. count++;
\
538. }
\
539. }
\
540.
\
541. if (!count) {
\
542. av_freep(&fmts->list);
\
543. av_freep(&fmts->refs);
\
544. av_freep(&fmts);
\
545. }
\
546.
\
547. return 0;
}}}
As shown in the above definition, at Line 518, it will invoke the function
"ff_formats_ref", and the variable fmts->formats will be freed. At Line
520, it will invoke the function "ff_formats_unref", and the variable
fmts->formats will again be freed. This would lead to a double free bug.
To see how fmts->formats will be freed in the function "ff_formats_ref",
please see the following code snippet. At Line 427, it will invoke the
function "ff_formats_unref" and free the variable f->formats. It should
be very important to be noted that, after the return of the function
ff_formats_ref, the parameter "AVFilterFormats *f" will still point to the
original memory location, although the "f" has been changed at Line 427.
{{{#!C++
440. int ff_formats_ref(AVFilterFormats *f, AVFilterFormats **ref)
441. {
442. FORMATS_REF(f, ref, ff_formats_unref);
443. }
...
419. #define FORMATS_REF(f, ref, unref_fn)
\
420. void *tmp;
\
421.
\
422. if (!f || !ref)
\
423. return AVERROR(ENOMEM);
\
424.
\
425. tmp = av_realloc_array(f->refs, sizeof(*f->refs), f->refcount
+ 1); \
426. if (!tmp) {
\
427. unref_fn(&f);
\
428. return AVERROR(ENOMEM);
\
429. }
\
430. f->refs = tmp;
\
431. f->refs[f->refcount++] = ref;
\
432. *ref = f;
\
433. return 0
...
}}}
To see how the function "ff_formats_unref" frees the f->formats, please
see the following code snippet. As we can see, at Line 469, according to
the macro definition, "list" is "formats", and ref->formats will be freed
at Line 469.
{{{#!C++
476. void ff_formats_unref(AVFilterFormats **ref)
477. {
478. FORMATS_UNREF(ref, formats);
479. }
...
455. #define FORMATS_UNREF(ref, list)
\
456. do {
\
457. int idx = -1;
\
458.
\
459. if (!*ref || !(*ref)->refs)
\
460. return;
\
461.
\
462. FIND_REF_INDEX(ref, idx);
\
463.
\
464. if (idx >= 0)
\
465. memmove((*ref)->refs + idx, (*ref)->refs + idx + 1,
\
466. sizeof(*(*ref)->refs) * ((*ref)->refcount - idx - 1));
\
467.
\
468. if(!--(*ref)->refcount) {
\
469. av_free((*ref)->list);
\
470. av_free((*ref)->refs);
\
471. av_free(*ref);
\
472. }
\
473. *ref = NULL;
\
474. } while (0)
}}}
--
Ticket URL: <https://trac.ffmpeg.org/ticket/8226>
FFmpeg <https://ffmpeg.org>
FFmpeg issue tracker
More information about the FFmpeg-trac
mailing list