From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from ffbox0-bg.ffmpeg.org (ffbox0-bg.ffmpeg.org [79.124.17.100]) by master.gitmailbox.com (Postfix) with ESMTPS id 510954E6CA for ; Tue, 27 Jan 2026 03:12:42 +0000 (UTC) Authentication-Results: ffbox; dkim=fail (body hash mismatch (got b'GQ+6dfqvIcChS2tL5C7SKqWwsWMFDDtBECkcjCJms64=', expected b'wt+UJTfklWnRLDf/urS7xX5RI5LGhpRAfshpvfrTYjs=')) header.d=ffmpeg.org header.i=@ffmpeg.org header.a=rsa-sha256 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ffmpeg.org; i=@ffmpeg.org; q=dns/txt; s=mail; t=1769483539; h=mime-version : to : date : message-id : reply-to : subject : list-id : list-archive : list-archive : list-help : list-owner : list-post : list-subscribe : list-unsubscribe : from : cc : content-type : content-transfer-encoding : from; bh=GQ+6dfqvIcChS2tL5C7SKqWwsWMFDDtBECkcjCJms64=; b=3YTsUuprJbmSkIQ5prx+p5vXgJmlCEB4gvppSW2kU6P+1FKVbTPA5ueaYirYkM8NP3Itp 91An64R9PUXuJvtn4yvMsl0WGpB0IqgXr5VO95BKd29nRfVeQiFCgGZKC3+6attK4n3FXi2 9KbsmziCCi0UM9BuTfjO2+7gAKM9Q6RuBztiq/ItJDu+vUwB18AMhF0lJVpDcooZgJJSBX5 VvJHnZSgm2WQtSMGox6QyexqC5JzAcKrd2o/ziwsJGUG9r6n/32rO5w9znif3x3RjIcIzig A3MJLG0YRCzXHc4jISuIWiy1/1GgLJ0e/Ny7VU/DETvV5gl4WLGhBKKa7cCA== Received: from [172.20.0.4] (unknown [172.20.0.4]) by ffbox0-bg.ffmpeg.org (Postfix) with ESMTP id 84E5C690F14; Tue, 27 Jan 2026 05:12:19 +0200 (EET) ARC-Seal: i=1; cv=none; a=rsa-sha256; d=ffmpeg.org; s=arc; t=1769483519; b=eZRb7tIUnzkuVj5/IGd8Fy7ZP75R0tR0vIjSjexCKahWiR1iSGIkdTZcLww7hRePhM8bs h+1CtFL/CEl86Fw0asC+k0hlEHjrNOMWqwElrbHGF2nBK9ctyREZFkkMgYQA7AZrJyVFPnL JsTlt2nJ+Ytopgj6d7NlbPzTty0ep2tMENSiAwi1CnlQEg5USGC8OsVJl6iO3t3EGaxZDVy 8QQ21pJg3BXtZitQRPn8F15aY3+gUl2xIsGL0nVNPXALLVImx/0FV4OnQo/Ky7vhG1Mw3Eo 2r9ktXcPm+a+F5TU9L+m1H3m8SEKewoZamwROr4ScLhctB6avk03gPe7wo8Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=ffmpeg.org; s=arc; t=1769483519; h=from : sender : reply-to : subject : date : message-id : to : cc : mime-version : content-type : content-transfer-encoding : content-id : content-description : resent-date : resent-from : resent-sender : resent-to : resent-cc : resent-message-id : in-reply-to : references : list-id : list-help : list-unsubscribe : list-subscribe : list-post : list-owner : list-archive; bh=EFKxdqf5Lk3FRLKZN0rQWTPJxpUNOJwgNerLjXnV1wk=; b=Ybctczwd7QpVR+mwakfFVS/RKJSgzMtHl4AXKJFAojQG0z8i5fULUbRjvZE7Vd8p5Kqkp EDIJy+0istPcdGcI9pUvVAJdIjEqNotCzNoQbG42VdRYtuamZIZqb3gOhhXvo4Mz0cSptBd 1ZbjevRn9yob7H1dDSYZHNrSTtGzIq4mqNhnpLxGLCPTyHO805u+nRIryc0xEIZ0F4r3XEM DgxKNk4ofR/CNA8zh+Xe1eXdewRe39i1Ujjj4cIT+kw7cSSOhoz6MM6eyp0ao2AJw/1dQNz ytgkjbssk52O+jWO0+1SCjngiixb8Ot8r5gUvDjyxnQC6LIfXj64Vx1hYXXw== ARC-Authentication-Results: i=1; ffmpeg.org; dkim=pass header.d=ffmpeg.org header.i=@ffmpeg.org; arc=none; dmarc=pass header.from=ffmpeg.org policy.dmarc=quarantine Authentication-Results: ffmpeg.org; dkim=pass header.d=ffmpeg.org header.i=@ffmpeg.org; arc=none (Message is not ARC signed); dmarc=pass (Used From Domain Record) header.from=ffmpeg.org policy.dmarc=quarantine DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ffmpeg.org; i=@ffmpeg.org; q=dns/txt; s=mail; t=1769483511; h=content-type : mime-version : content-transfer-encoding : from : to : reply-to : subject : date : from; bh=wt+UJTfklWnRLDf/urS7xX5RI5LGhpRAfshpvfrTYjs=; b=ejdwyYtIaz8TFl3a+UzQv+LgZUD+vC/xe8B9E/4nNdPgMxu9bvRIJd1BdW7eyLiMBEF7g 5brUE7liwDnr4z0ESxe+yAqETeACmv/XobmstK1pR/HtwXkP1etUxZKTrBAGT8dAOVJwrMl G3LobeluJdqzDIygX1dp8+zQYacf802eHu19HuwyURx/MKBvPI1A9II0H5IduaRZPi6mKeu EIuinbVth259nm/PAE5HjhWHTZvDdvACTSLcosit+0EZLZhtI+ws7SZzu9J08UNL7JqeIzu +2SU7SXPdFRa+pLsKN3OO6VM9C1I42DwwwRL7m+4ZihXOHJwm+EWfAI/I6PQ== Received: from 69dab402ede7 (code.ffmpeg.org [188.245.149.3]) by ffbox0-bg.ffmpeg.org (Postfix) with ESMTPS id DBF0A690E65 for ; Tue, 27 Jan 2026 05:11:51 +0200 (EET) MIME-Version: 1.0 To: ffmpeg-devel@ffmpeg.org Date: Tue, 27 Jan 2026 03:11:51 -0000 Message-ID: <176948351205.25.12031576060316920207@4457048688e7> Message-ID-Hash: XN3YZ2DOODVIXAAQ5IEGMWHAUQ4W7ZRJ X-Message-ID-Hash: XN3YZ2DOODVIXAAQ5IEGMWHAUQ4W7ZRJ X-MailFrom: code@ffmpeg.org X-Mailman-Rule-Hits: nonmember-moderation X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; header-match-ffmpeg-devel.ffmpeg.org-0; header-match-ffmpeg-devel.ffmpeg.org-1; header-match-ffmpeg-devel.ffmpeg.org-2; header-match-ffmpeg-devel.ffmpeg.org-3; emergency; member-moderation X-Mailman-Version: 3.3.10 Precedence: list Reply-To: FFmpeg development discussions and patches Subject: [FFmpeg-devel] [PR] avformat/hlsenc: fix format string vulnerability in parse_playlist (PR #21597) List-Id: FFmpeg development discussions and patches Archived-At: Archived-At: List-Archive: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: From: kingroryg via ffmpeg-devel Cc: kingroryg Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Archived-At: List-Archive: List-Post: PR #21597 opened by kingroryg URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/21597 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/21597.patch The vtt_basename variable, derived from user-provided output filename concatenated with "%d.vtt", was used directly as a format string in snprintf(). If the user provides a filename containing format specifiers (e.g., "output_%s_test.m3u8"), these specifiers are interpreted by snprintf(), causing stack memory to be read. This could lead to: - Information disclosure via %x, %p, %s reading stack memory - Denial of service via %s reading invalid pointers - Potential code execution via %n (if not blocked by system) Fix by using %.*s to safely copy the base portion of the filename without interpreting any format specifiers it may contain. Add unit test to verify format string safety. Reproduction steps for the vuln: 1. Create a test video with subtitles: ```bash ffmpeg -f lavfi -i "color=c=red:s=64x64:d=1" -f lavfi -i "sine=f=440:d=1" \ -c:v mpeg4 -c:a aac -shortest test_input.mp4 echo -e "1\n00:00:00,000 --> 00:00:01,000\nTest" > test.srt ``` 2. Create initial HLS playlist with format specifiers in filename: ```bash ffmpeg -i test_input.mp4 -i test.srt -c:v copy -c:a copy -c:s webvtt \ -f hls "test_%s_INJECT.m3u8" ``` 3. Trigger vulnerable code path with `append_list`: ```bash ffmpeg -i test_input.mp4 -i test.srt -c:v copy -c:a copy -c:s webvtt \ -f hls -hls_flags append_list "test_%s_INJECT.m3u8" ``` Signed-off-by: Sarthak Munshi >>From 197d073bcd0cf97caed20f2db941077facbe0e73 Mon Sep 17 00:00:00 2001 From: Sarthak Munshi Date: Mon, 26 Jan 2026 19:05:17 -0800 Subject: [PATCH] avformat/hlsenc: fix format string vulnerability in parse_playlist The vtt_basename variable, derived from user-provided output filename concatenated with "%d.vtt", was used directly as a format string in snprintf(). If the user provides a filename containing format specifiers (e.g., "output_%s_test.m3u8"), these specifiers are interpreted by snprintf(), causing stack memory to be read. This could lead to: - Information disclosure via %x, %p, %s reading stack memory - Denial of service via %s reading invalid pointers - Potential code execution via %n (if not blocked by system) Fix by using %.*s to safely copy the base portion of the filename without interpreting any format specifiers it may contain. Add unit test to verify format string safety. Signed-off-by: Sarthak Munshi --- libavformat/Makefile | 1 + libavformat/hlsenc.c | 7 +++- libavformat/tests/hlsenc.c | 79 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 85 insertions(+), 2 deletions(-) create mode 100644 libavformat/tests/hlsenc.c diff --git a/libavformat/Makefile b/libavformat/Makefile index 5fd3f7252a..848610d2aa 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -782,6 +782,7 @@ TESTPROGS-$(CONFIG_MOV_MUXER) += movenc TESTPROGS-$(CONFIG_NETWORK) += noproxy TESTPROGS-$(CONFIG_SRTP) += srtp TESTPROGS-$(CONFIG_IMF_DEMUXER) += imf +TESTPROGS-$(CONFIG_HLS_MUXER) += hlsenc TOOLS = aviocat \ ismindex \ diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c index 7105404d1e..5996a52218 100644 --- a/libavformat/hlsenc.c +++ b/libavformat/hlsenc.c @@ -1242,13 +1242,16 @@ static int parse_playlist(AVFormatContext *s, const char *url, VariantStream *vs if (vs->has_subtitle) { int vtt_index = extract_segment_number(line); const char *vtt_basename = av_basename(vs->vtt_basename); - int len = strlen(vtt_basename) + 11; + const char *fmt = strstr(vtt_basename, "%d"); + int base_len = fmt ? (int)(fmt - vtt_basename) : strlen(vtt_basename); + int len = base_len + 25; char *vtt_file = av_mallocz(len); if (!vtt_file) { ret = AVERROR(ENOMEM); goto fail; } - snprintf(vtt_file, len, vtt_basename, vtt_index); + /* Use %.*s to safely copy base without format string interpretation */ + snprintf(vtt_file, len, "%.*s%d.vtt", base_len, vtt_basename, vtt_index); ff_format_set_url(vs->vtt_avf, vtt_file); } diff --git a/libavformat/tests/hlsenc.c b/libavformat/tests/hlsenc.c new file mode 100644 index 0000000000..181ae0de47 --- /dev/null +++ b/libavformat/tests/hlsenc.c @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2025 FFmpeg developers + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include + +static int test_vtt_filename_fmtstr(void) +{ + int ret = 0; + struct { + const char *vtt_basename; + int vtt_index; + const char *expected; + } tests[] = { + { "normal%d.vtt", 5, "normal5.vtt" }, + { "test_%s_file%d.vtt", 10, "test_%s_file10.vtt" }, + { "leak%x%x%d.vtt", 0, "leak%x%x0.vtt" }, + { "%p%n%d.vtt", 1, "%p%n1.vtt" }, + { "safe_name%d.vtt", 123, "safe_name123.vtt" }, + }; + int i; + + printf("Testing VTT filename format string safety:\n"); + + for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { + const char *vtt_basename = tests[i].vtt_basename; + int vtt_index = tests[i].vtt_index; + const char *expected = tests[i].expected; + const char *fmt; + int base_len, len; + char vtt_file[256]; + + fmt = strstr(vtt_basename, "%d"); + base_len = fmt ? (int)(fmt - vtt_basename) : strlen(vtt_basename); + len = base_len + 25; + + if (len > sizeof(vtt_file)) + len = sizeof(vtt_file); + + snprintf(vtt_file, len, "%.*s%d.vtt", base_len, vtt_basename, vtt_index); + + if (strcmp(vtt_file, expected) != 0) { + printf(" FAIL: input='%s' idx=%d => '%s' (expected '%s')\n", + vtt_basename, vtt_index, vtt_file, expected); + ret = 1; + } else { + printf(" PASS: input='%s' idx=%d => '%s'\n", + vtt_basename, vtt_index, vtt_file); + } + } + + return ret; +} + +int main(void) +{ + int ret = 0; + + ret |= test_vtt_filename_fmtstr(); + + return ret; +} -- 2.52.0 _______________________________________________ ffmpeg-devel mailing list -- ffmpeg-devel@ffmpeg.org To unsubscribe send an email to ffmpeg-devel-leave@ffmpeg.org