Opened 6 weeks ago

Closed 6 weeks ago

Last modified 4 weeks ago

#11032 closed defect (invalid)

Memory Leak in avformat_open_input

Reported by: safa karakus Owned by:
Priority: normal Component: avformat
Version: unspecified Keywords:
Cc: safa karakus Blocked By:
Blocking: Reproduced by developer: no
Analyzed by developer: no

Description (last modified by safa karakus)

A memory leak has been identified in the FFmpeg library, specifically in the avformat_open_input function. This vulnerability can lead to the unintended exposure of sensitive data stored in memory. The issue arises due to improper handling and freeing of allocated memory within the avformat_open_input and related functions.

#include <stdint.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "libavformat/avformat.h"
#include "libavcodec/avcodec.h"
#include "libavutil/avutil.h"
#include "libavutil/imgutils.h"

void leak_memory_information(const char *filename) {
    AVFormatContext *fmt_ctx = avformat_alloc_context();
    if (!fmt_ctx) {
        fprintf(stderr, "Could not allocate context\n");
        return;
    }

    printf("Attempting to open file: %s\n", filename);
    
    int ret = avformat_open_input(&fmt_ctx, filename, NULL, NULL);
    if (ret < 0) {
        char err_buf[256];
        av_strerror(ret, err_buf, sizeof(err_buf));
        fprintf(stderr, "Could not open input file: %s. Error: %s\n", filename, err_buf);
        avformat_free_context(fmt_ctx);
        return;
    }

    if (avformat_find_stream_info(fmt_ctx, NULL) < 0) {
        fprintf(stderr, "Could not find stream information\n");
        avformat_close_input(&fmt_ctx);
        avformat_free_context(fmt_ctx);
        return;
    }

    for (unsigned int i = 0; i < fmt_ctx->nb_streams; i++) {
        AVCodecParameters *codecpar = fmt_ctx->streams[i]->codecpar;
        const AVCodec *codec = avcodec_find_decoder(codecpar->codec_id);
        if (!codec) {
            continue;
        }

        AVCodecContext *codec_ctx = avcodec_alloc_context3(codec);
        if (!codec_ctx) {
            continue;
        }

        if (avcodec_parameters_to_context(codec_ctx, codecpar) < 0) {
            avcodec_free_context(&codec_ctx);
            continue;
        }

        if (avcodec_open2(codec_ctx, codec, NULL) < 0) {
            avcodec_free_context(&codec_ctx);
            continue;
        }

        AVFrame *frame = av_frame_alloc();
        AVPacket *packet = av_packet_alloc();
        if (!frame || !packet) {
            av_frame_free(&frame);
            av_packet_free(&packet);
            avcodec_free_context(&codec_ctx);
            continue;
        }

        while (av_read_frame(fmt_ctx, packet) >= 0) {
            if (packet->stream_index == i) {
                ret = avcodec_send_packet(codec_ctx, packet);
                if (ret < 0) {
                    break;
                }

                while (ret >= 0) {
                    ret = avcodec_receive_frame(codec_ctx, frame);
                    if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
                        break;
                    } else if (ret < 0) {
                        break;
                    }

                    for (int y = 0; y < frame->height; y++) {
                        for (int x = 0; x < frame->width; x++) {
                            int offset = y * frame->linesize[0] + x * 4;
                            if (offset < frame->linesize[0] * frame->height) {
                                volatile uint8_t val = frame->data[0][offset];
                                (void)val;
                            }
                        }
                    }

                    av_frame_unref(frame);
                }
                av_packet_unref(packet);  // ^^
            }
        }

        av_frame_free(&frame);
        av_packet_free(&packet);
        avcodec_free_context(&codec_ctx);
    }

    
    char *leaked_memory = (char *)malloc(100);
    if (leaked_memory) {
        snprintf(leaked_memory, 100, "Leaked memory content at %p: %s\n", fmt_ctx, (char *)fmt_ctx);
        printf("%s", leaked_memory);
        free(leaked_memory);
    }

    avformat_close_input(&fmt_ctx);
    avformat_free_context(fmt_ctx); // you can add this line for memleak protection
}

int main(int argc, char *argv[]) {
    if (argc != 2) {
        fprintf(stderr, "Usage: %s <input file>\n", argv[0]);
        return 1;
    }

    const char *filename = argv[1];

    leak_memory_information(filename);

    return 0;
}

}

Attempting to open file: test.mp4
Leaked memory content at 0x5ae0d4e34080: ��FH�|
==3878783==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 48 byte(s) in 2 object(s) allocated from:
    #0 0x5e23f8521e07 in posix_memalign (/home/sazak/fuzz_project/ffmpeg-7.0/use_after_fuzz/memleak_test/memor_sanitize+0xa1e07) (BuildId: 07d05b4f8da1d513c1a0b32d7f7abdeaf6de5ecc)
    #1 0x73665d2419e4 in av_malloc (/lib/x86_64-linux-gnu/libavutil.so.56+0x419e4) (BuildId: abc6b699a880017e212d717fb86a1c6ea0e022e8)

Indirect leak of 9467 byte(s) in 4 object(s) allocated from:
    #0 0x5e23f8521e07 in posix_memalign (/home/sazak/fuzz_project/ffmpeg-7.0/use_after_fuzz/memleak_test/memor_sanitize+0xa1e07) (BuildId: 07d05b4f8da1d513c1a0b32d7f7abdeaf6de5ecc)
    #1 0x73665d2419e4 in av_malloc (/lib/x86_64-linux-gnu/libavutil.so.56+0x419e4) (BuildId: abc6b699a880017e212d717fb86a1c6ea0e022e8)

SUMMARY: AddressSanitizer: 9515 byte(s) leaked in 6 allocation(s).

Patches should be submitted to the ffmpeg-devel mailing list and not this bug tracker.

Attachments (1)

test.mp4 (119.5 KB ) - added by safa karakus 6 weeks ago.

Download all attachments as: .zip

Change History (6)

by safa karakus, 6 weeks ago

Attachment: test.mp4 added

comment:1 by mkver, 6 weeks ago

Resolution: invalid
Status: newclosed

av_read_frame() expects a blank AVPacket; you forgot to reset said packet in case avcodec_receive_frame() returns EAGAIN or EOF (your H.264 file has reordered frames, therefore there is a delay and the decoder does not immediately return an AVFrame.

And your volatile is completely useless. And don't use Turkish for bug reports in the future.

comment:2 by safa karakus, 6 weeks ago

I think the arrangement you mentioned should be like this? Added, same result!

                while (ret >= 0) {
                    ret = avcodec_receive_frame(codec_ctx, frame);
                    if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
                        av_packet_unref(packet);  // Unref packet when EAGAIN or EOF
                        break;
                    } else if (ret < 0) {
                        break;
                    }
Last edited 4 weeks ago by safa karakus (previous) (diff)

comment:3 by Balling, 6 weeks ago

memory leak vulnerability

Memory leak is not a vuln. Not to mention that we are not openssl where zeroing of memory can matter.

comment:4 by safa karakus, 6 weeks ago

Summary: Memory Leak Vulnerability in avformat_open_inputMemory Leak in avformat_open_input

Thank you for your answer, i wanted to report this bug so i could contribute to ffmpeg. Of course this product is not openssl and i know this is a software issue that will consume resources. It is entirely up to you to determine which category you will evaluate here, and the responsibility for informing belongs to us.

Last edited 4 weeks ago by safa karakus (previous) (diff)

comment:5 by safa karakus, 4 weeks ago

Description: modified (diff)
Note: See TracTickets for help on using tickets.