From patchwork Sat Jun 3 13:00:08 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michael Niedermayer X-Patchwork-Id: 3818 Delivered-To: ffmpegpatchwork@gmail.com Received: by 10.103.10.2 with SMTP id 2csp609831vsk; Sat, 3 Jun 2017 06:00:25 -0700 (PDT) X-Received: by 10.28.64.67 with SMTP id n64mr1538529wma.93.1496494824957; Sat, 03 Jun 2017 06:00:24 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1496494824; cv=none; d=google.com; s=arc-20160816; b=k/jxjjBMC1W5ZREoY3F0Hp8FEPOLLLW3ipzTpObMWC+qZOrUlkWJS9SkQjiYjVrG7b DMRGbQp6tLIzYksxs1X95W+eoO1SIYCNKWuTYNJ6nrTlHD1GlQTQ9oyFYfRPRrRamjVJ qpR8gKeECvw0Hgd/ralKoxksNjRSnKJ4qpqX2SbqRoAnAQNfbsqqxfb64YLBLBLYz6Ff NXAxL7/CcFxtCotpi89c+diyqN+YWtd30QhaBRt1K/17iloKyO0YMoNPOnNTk+LL8zoh FGOJ6cISXBPnUjNweEioXzbNC371x0d3SuStpNClLtbBZjklhTHfTzoaLF4YSGgVEkMx n38A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version:reply-to :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:message-id:date:to:from:delivered-to :arc-authentication-results; bh=ff7L6oY3Lra66qfDJbYH4Ko+ioy9jIXQkwcqfoNvRvA=; b=UPcHHlfUBfDvfFNOlWjTJI+AQW89zwwBhNduQlIiZO53lcfbrqBZ9tcEQ10YpiiwTJ KPfb0rvV3K2pzQXX1/DY5GoO5VZw3VSrPhUHiwL/XEWGC9m2iBgMr2d2ImezAeH31A2I 2xMyniO/rObhuICQCgTfFePEojW6HtCKzjABM5fbwTSzt/6IGb/T4jRVHtg9oGAVDuwK CY6HiTxzSL61Ssztc9it2DOS7CZo/OU/DG3ea4b5b/nbqtMT8o5FgtOYPpktLboE9InF 81XRyo7cSnTQYGcj8GsmFtaEqKb4sCTEfX0g0ubPn81NmU9CVrOAc3OJxYKVDu0WIZdr d1tQ== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id d103si5925576wma.32.2017.06.03.06.00.23; Sat, 03 Jun 2017 06:00:24 -0700 (PDT) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 374E7689D29; Sat, 3 Jun 2017 16:00:15 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from vie01a-dmta-pe05-1.mx.upcmail.net (vie01a-dmta-pe06-1.mx.upcmail.net [84.116.36.14]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 6EAD9689CBC for ; Sat, 3 Jun 2017 16:00:09 +0300 (EEST) Received: from [172.31.216.43] (helo=vie01a-pemc-psmtp-pe01) by vie01a-dmta-pe06.mx.upcmail.net with esmtp (Exim 4.88) (envelope-from ) id 1dH8f8-0001Xu-OO for ffmpeg-devel@ffmpeg.org; Sat, 03 Jun 2017 15:00:14 +0200 Received: from localhost ([213.47.41.20]) by vie01a-pemc-psmtp-pe01 with SMTP @ mailcloud.upcmail.net id UD081v00t0S5wYM01D09pL; Sat, 03 Jun 2017 15:00:09 +0200 X-SourceIP: 213.47.41.20 From: Michael Niedermayer To: FFmpeg development discussions and patches Date: Sat, 3 Jun 2017 15:00:08 +0200 Message-Id: <20170603130008.16979-1-michael@niedermayer.cc> X-Mailer: git-send-email 2.13.0 Subject: [FFmpeg-devel] [PATCH] avformat/hls: Check file extensions X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches MIME-Version: 1.0 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" This reduces the attack surface of local file-system and local network information leaking. It prevents the existing exploit leading to an information leak. As well as similar hypothetical attacks. Leaks of information from files and symlinks ending in common multimedia extensions are still possible. But files with sensitive information like private keys and passwords generally do not use common multimedia filename extensions. The existing exploit depends on a specific decoder as well. It does appear though that the exploit should be possible with any decoder. The problem is that as long as sensitive information gets into the decoder, the output of the decoder becomes sensitive as well. The only obvious solution is to prevent access to sensitive information. Or to disable hls or possibly some of its feature. More complex solutions like checking the path to limit access to only subdirectories of the hls path may work as an alternative. But such solutions are fragile and tricky to implement portably and would not stop every possible attack nor would they work with all valid hls files. Developers have expressed their dislike / objected to disabling hls by default as well as disabling hls with local files. This here is a less robust but also lower inconvenience solution. It can be applied stand alone or together with other solutions. Found-by: Emil Lerner and Pavel Cheremushkin Reported-by: Thierry Foucu Signed-off-by: Michael Niedermayer --- libavformat/hls.c | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/libavformat/hls.c b/libavformat/hls.c index 4b8fb19a52..9a26b2a3bd 100644 --- a/libavformat/hls.c +++ b/libavformat/hls.c @@ -204,6 +204,7 @@ typedef struct HLSContext { char *http_proxy; ///< holds the address of the HTTP proxy server AVDictionary *avio_opts; int strict_std_compliance; + char *allowed_extensions; } HLSContext; static int read_chomp_line(AVIOContext *s, char *buf, int maxlen) @@ -602,6 +603,8 @@ static int open_url(AVFormatContext *s, AVIOContext **pb, const char *url, AVDictionary *tmp = NULL; const char *proto_name = NULL; int ret; + char filename_buffer[1024]; + const char *filename; av_dict_copy(&tmp, opts, 0); av_dict_copy(&tmp, opts2, 0); @@ -618,8 +621,30 @@ static int open_url(AVFormatContext *s, AVIOContext **pb, const char *url, return AVERROR_INVALIDDATA; // only http(s) & file are allowed - if (!av_strstart(proto_name, "http", NULL) && !av_strstart(proto_name, "file", NULL)) + if (av_strstart(proto_name, "file", NULL)) { + filename = url; + } else if (av_strstart(proto_name, "http", NULL)) { + char *queryp; + filename = filename_buffer; + av_url_split(NULL, 0, NULL, 0, NULL, 0,NULL, + filename_buffer, sizeof(filename_buffer), + url); + if (strlen(filename_buffer) + 1 >= sizeof(filename_buffer)) + return AVERROR_INVALIDDATA; + queryp = strchr(filename_buffer, '?'); + if (queryp) + *queryp = 0; + } else + return AVERROR_INVALIDDATA; + + if (strcmp(c->allowed_extensions, "ALL") && !av_match_ext(filename, c->allowed_extensions)) { + av_log(s, AV_LOG_ERROR, + "Filename extension of \'%s\' is not a common multimedia extension, blocked for security reasons.\n" + "If you wish to override this adjust allowed_extensions, you can set it to \'ALL\' to allow all\n", + filename); return AVERROR_INVALIDDATA; + } + if (!strncmp(proto_name, url, strlen(proto_name)) && url[strlen(proto_name)] == ':') ; else if (av_strstart(url, "crypto", NULL) && !strncmp(proto_name, url + 7, strlen(proto_name)) && url[7 + strlen(proto_name)] == ':') @@ -2134,6 +2159,10 @@ static int hls_probe(AVProbeData *p) static const AVOption hls_options[] = { {"live_start_index", "segment index to start live streams at (negative values are from the end)", OFFSET(live_start_index), AV_OPT_TYPE_INT, {.i64 = -3}, INT_MIN, INT_MAX, FLAGS}, + {"allowed_extensions", "List of file extensions that hls is allowed to access", + OFFSET(allowed_extensions), AV_OPT_TYPE_STRING, + {.str = "3gp,aac,avi,flac,mkv,m3u8,m4a,m4s,m4v,mpg,mov,mp2,mp3,mp4,mpeg,mpegts,ogg,ogv,oga,ts,vob,wav"}, + INT_MIN, INT_MAX, FLAGS}, {NULL} };