diff --git a/libavformat/http.c b/libavformat/http.c index 015a150..61a4d32 100644 --- a/libavformat/http.c +++ b/libavformat/http.c @@ -25,6 +25,7 @@ #include "config_components.h" #include +#include #include #if CONFIG_ZLIB #include @@ -399,6 +400,40 @@ static int redirect_cache_set(HTTPContext *s, const char *source, const char *de return 0; } +/* KCPhone: enforce the same HTTPS host allowlist on every HLS child request + * and every redirect, including when a playlist changes after Swift preflight. + * The wrapper sets this variable only for a serialized foreground export. */ +static int kc_https_host_allowed(const char *url) +{ + const char *allowed = getenv("KC_FFMPEG_ALLOWED_HOSTS"); + const char *entry; + char proto[16] = {0}, auth[256] = {0}, hostname[1024] = {0}; + int port = -1; + size_t host_len; + + if (!allowed || !*allowed || !url) + return 0; + av_url_split(proto, sizeof(proto), auth, sizeof(auth), + hostname, sizeof(hostname), &port, NULL, 0, url); + if (av_strcasecmp(proto, "https") || !hostname[0] || auth[0] || + (port > 0 && port != 443)) + return 0; + host_len = strlen(hostname); + entry = allowed; + while (*entry) { + const char *end = strchr(entry, ','); + size_t len = end ? (size_t)(end - entry) : strlen(entry); + if (len && ((host_len == len && !av_strncasecmp(hostname, entry, len)) || + (host_len > len && hostname[host_len - len - 1] == '.' && + !av_strncasecmp(hostname + host_len - len, entry, len)))) + return 1; + if (!end) + break; + entry = end + 1; + } + return 0; +} + /* return non zero if error */ static int http_open_cnx(URLContext *h, AVDictionary **options) { @@ -412,6 +447,9 @@ static int http_open_cnx(URLContext *h, AVDictionary **options) redo: + if (!kc_https_host_allowed(s->location)) + return AVERROR(EACCES); + cached = redirect_cache_get(s); if (cached) { if (redirects++ >= s->max_redirects)