mpv: Add patch-player_lua_ytdl__hook.lua to address CVE-2018-6360 Sync player/lua/ytdl_hook.lua with upstream commit 2a0f9fc1588d8bda51a6340197c54285f3f62755 minus hunks that need `on_load_fail' hook introduced after mpv-0.27. Bump PKGREVISION.diff -r1.62 -r1.63 pkgsrc/multimedia/mpv/Makefile
(leot)
@@ -1,73 +1,73 @@ | @@ -1,73 +1,73 @@ | |||
1 | # $NetBSD: Makefile,v 1.62 2018/01/28 20:10:57 wiz Exp $ | 1 | # $NetBSD: Makefile,v 1.63 2018/01/29 21:54:22 leot Exp $ | |
2 | 2 | |||
3 | DISTNAME= mpv-0.27.0 | 3 | DISTNAME= mpv-0.27.0 | |
4 | PKGREVISION= 1 | 4 | PKGREVISION= 2 | |
5 | CATEGORIES= multimedia | 5 | CATEGORIES= multimedia | |
6 | MASTER_SITES= ${MASTER_SITE_GITHUB:=mpv-player/} | 6 | MASTER_SITES= ${MASTER_SITE_GITHUB:=mpv-player/} | |
7 | GITHUB_TAG= v${PKGVERSION_NOREV} | 7 | GITHUB_TAG= v${PKGVERSION_NOREV} | |
8 | 8 | |||
9 | MAINTAINER= leot@NetBSD.org | 9 | MAINTAINER= leot@NetBSD.org | |
10 | HOMEPAGE= https://mpv.io/ | 10 | HOMEPAGE= https://mpv.io/ | |
11 | COMMENT= Video player based on MPlayer and mplayer2 | 11 | COMMENT= Video player based on MPlayer and mplayer2 | |
12 | LICENSE= gnu-gpl-v2 AND gnu-lgpl-v2.1 | 12 | LICENSE= gnu-gpl-v2 AND gnu-lgpl-v2.1 | |
13 | 13 | |||
14 | # needs sem_timedwait(3) | 14 | # needs sem_timedwait(3) | |
15 | NOT_FOR_PLATFORM= NetBSD-[1-6]*-* | 15 | NOT_FOR_PLATFORM= NetBSD-[1-6]*-* | |
16 | 16 | |||
17 | NOT_PAX_MPROTECT_SAFE+= bin/mpv | 17 | NOT_PAX_MPROTECT_SAFE+= bin/mpv | |
18 | 18 | |||
19 | BUILD_DEPENDS+= ${PYPKGPREFIX}-docutils>=0.12:../../textproc/py-docutils | 19 | BUILD_DEPENDS+= ${PYPKGPREFIX}-docutils>=0.12:../../textproc/py-docutils | |
20 | # ${WRKSRC}/bootstrap.py mentions needed version | 20 | # ${WRKSRC}/bootstrap.py mentions needed version | |
21 | BUILD_DEPENDS+= waf>=1.8.12:../../devel/waf | 21 | BUILD_DEPENDS+= waf>=1.8.12:../../devel/waf | |
22 | 22 | |||
23 | WAF_CONFIGURE_ARGS+= --bindir=${PREFIX}/bin | 23 | WAF_CONFIGURE_ARGS+= --bindir=${PREFIX}/bin | |
24 | 24 | |||
25 | PYTHON_FOR_BUILD_ONLY= yes | 25 | PYTHON_FOR_BUILD_ONLY= yes | |
26 | 26 | |||
27 | USE_TOOLS+= perl pkg-config | 27 | USE_TOOLS+= perl pkg-config | |
28 | 28 | |||
29 | MAKE_DIRS= ${PKG_SYSCONFDIR}/mpv | 29 | MAKE_DIRS= ${PKG_SYSCONFDIR}/mpv | |
30 | INSTALLATION_DIRS= share/examples/mpv | 30 | INSTALLATION_DIRS= share/examples/mpv | |
31 | CONF_FILES+= share/examples/mpv/encoding-profiles.conf ${PKG_SYSCONFDIR}/mpv/encoding-profiles.conf | 31 | CONF_FILES+= share/examples/mpv/encoding-profiles.conf ${PKG_SYSCONFDIR}/mpv/encoding-profiles.conf | |
32 | 32 | |||
33 | SUBST_CLASSES+= audio | 33 | SUBST_CLASSES+= audio | |
34 | SUBST_SED.audio+= -e "s,/dev/dsp,${DEVOSSAUDIO}," | 34 | SUBST_SED.audio+= -e "s,/dev/dsp,${DEVOSSAUDIO}," | |
35 | SUBST_FILES.audio+= audio/out/ao_oss.c stream/ai_oss.c | 35 | SUBST_FILES.audio+= audio/out/ao_oss.c stream/ai_oss.c | |
36 | SUBST_STAGE.audio= pre-configure | 36 | SUBST_STAGE.audio= pre-configure | |
37 | SUBST_MESSAGE.audio= Fixing path to audio device. | 37 | SUBST_MESSAGE.audio= Fixing path to audio device. | |
38 | 38 | |||
39 | SUBST_CLASSES+= python | 39 | SUBST_CLASSES+= python | |
40 | SUBST_SED.python+= -e "s,python,python${PYVERSSUFFIX}," | 40 | SUBST_SED.python+= -e "s,python,python${PYVERSSUFFIX}," | |
41 | SUBST_SED.python+= -e "s,rst2man,rst2man-${PYVERSSUFFIX}," | 41 | SUBST_SED.python+= -e "s,rst2man,rst2man-${PYVERSSUFFIX}," | |
42 | SUBST_FILES.python+= wscript | 42 | SUBST_FILES.python+= wscript | |
43 | SUBST_STAGE.python= pre-configure | 43 | SUBST_STAGE.python= pre-configure | |
44 | SUBST_MESSAGE.python= Fix Python command names. | 44 | SUBST_MESSAGE.python= Fix Python command names. | |
45 | 45 | |||
46 | post-install: | 46 | post-install: | |
47 | cd ${DESTDIR}${PREFIX} && ${MV} etc/mpv/encoding-profiles.conf share/examples/mpv | 47 | cd ${DESTDIR}${PREFIX} && ${MV} etc/mpv/encoding-profiles.conf share/examples/mpv | |
48 | 48 | |||
49 | .include "options.mk" | 49 | .include "options.mk" | |
50 | 50 | |||
51 | .include "../../mk/bsd.prefs.mk" | 51 | .include "../../mk/bsd.prefs.mk" | |
52 | .if ${OPSYS} != "Darwin" | 52 | .if ${OPSYS} != "Darwin" | |
53 | .include "../../graphics/MesaLib/buildlink3.mk" | 53 | .include "../../graphics/MesaLib/buildlink3.mk" | |
54 | .include "../../x11/libXinerama/buildlink3.mk" | 54 | .include "../../x11/libXinerama/buildlink3.mk" | |
55 | .include "../../x11/libXrandr/buildlink3.mk" | 55 | .include "../../x11/libXrandr/buildlink3.mk" | |
56 | .include "../../x11/libXScrnSaver/buildlink3.mk" | 56 | .include "../../x11/libXScrnSaver/buildlink3.mk" | |
57 | .include "../../x11/libXv/buildlink3.mk" | 57 | .include "../../x11/libXv/buildlink3.mk" | |
58 | .include "../../x11/libXxf86vm/buildlink3.mk" | 58 | .include "../../x11/libXxf86vm/buildlink3.mk" | |
59 | .include "../../mk/oss.buildlink3.mk" | 59 | .include "../../mk/oss.buildlink3.mk" | |
60 | .endif | 60 | .endif | |
61 | 61 | |||
62 | .include "../../converters/libiconv/buildlink3.mk" | 62 | .include "../../converters/libiconv/buildlink3.mk" | |
63 | .include "../../devel/waf/waf.mk" | 63 | .include "../../devel/waf/waf.mk" | |
64 | .include "../../devel/zlib/buildlink3.mk" | 64 | .include "../../devel/zlib/buildlink3.mk" | |
65 | .include "../../lang/python/application.mk" | 65 | .include "../../lang/python/application.mk" | |
66 | .include "../../multimedia/libdvdnav/buildlink3.mk" | 66 | .include "../../multimedia/libdvdnav/buildlink3.mk" | |
67 | .include "../../multimedia/libdvdread/buildlink3.mk" | 67 | .include "../../multimedia/libdvdread/buildlink3.mk" | |
68 | BUILDLINK_API_DEPENDS.ffmpeg3+= ffmpeg3>=3.2.2 | 68 | BUILDLINK_API_DEPENDS.ffmpeg3+= ffmpeg3>=3.2.2 | |
69 | .include "../../multimedia/ffmpeg3/buildlink3.mk" | 69 | .include "../../multimedia/ffmpeg3/buildlink3.mk" | |
70 | .include "../../graphics/hicolor-icon-theme/buildlink3.mk" | 70 | .include "../../graphics/hicolor-icon-theme/buildlink3.mk" | |
71 | .include "../../sysutils/desktop-file-utils/desktopdb.mk" | 71 | .include "../../sysutils/desktop-file-utils/desktopdb.mk" | |
72 | .include "../../mk/jpeg.buildlink3.mk" | 72 | .include "../../mk/jpeg.buildlink3.mk" | |
73 | .include "../../mk/bsd.pkg.mk" | 73 | .include "../../mk/bsd.pkg.mk" |
@@ -1,8 +1,9 @@ | @@ -1,8 +1,9 @@ | |||
1 | $NetBSD: distinfo,v 1.37 2017/09/13 10:35:58 leot Exp $ | 1 | $NetBSD: distinfo,v 1.38 2018/01/29 21:54:22 leot Exp $ | |
2 | 2 | |||
3 | SHA1 (mpv-0.27.0.tar.gz) = d4bddb88cf7a112a295a130a091181acbe25605b | 3 | SHA1 (mpv-0.27.0.tar.gz) = d4bddb88cf7a112a295a130a091181acbe25605b | |
4 | RMD160 (mpv-0.27.0.tar.gz) = d2edbdfdc6fdf3a0c210536ac3966e99113c83ad | 4 | RMD160 (mpv-0.27.0.tar.gz) = d2edbdfdc6fdf3a0c210536ac3966e99113c83ad | |
5 | SHA512 (mpv-0.27.0.tar.gz) = 22738f907d84d362095773972f685e3b03ab4c8172a22ddede290fc221a83ab9135b96f8b18191dabe842b2963f68983929cf065097287fc1a054a7d5f1d0ae4 | 5 | SHA512 (mpv-0.27.0.tar.gz) = 22738f907d84d362095773972f685e3b03ab4c8172a22ddede290fc221a83ab9135b96f8b18191dabe842b2963f68983929cf065097287fc1a054a7d5f1d0ae4 | |
6 | Size (mpv-0.27.0.tar.gz) = 2956816 bytes | 6 | Size (mpv-0.27.0.tar.gz) = 2956816 bytes | |
7 | SHA1 (patch-audio_out_ao__oss.c) = d7f3a75ab43efe396ce536fb54e6207a7ded3510 | 7 | SHA1 (patch-audio_out_ao__oss.c) = d7f3a75ab43efe396ce536fb54e6207a7ded3510 | |
8 | SHA1 (patch-player_lua_ytdl__hook.lua) = 450a6f2640c76b5db0c0cd585674ccd689712f78 | |||
8 | SHA1 (patch-player_main.c) = 842432e448526a9d170e7efd2b01276e36072e16 | 9 | SHA1 (patch-player_main.c) = 842432e448526a9d170e7efd2b01276e36072e16 |
$NetBSD: patch-player_lua_ytdl__hook.lua,v 1.1 2018/01/29 21:54:22 leot Exp $
Sync ytdl_hook.lua script with commit 2a0f9fc1588d8bda51a6340197c54285f3f62755
in order to fix CVE-2018-6360.
Please note that this completely omits hunks that need `on_load_fail' hook that
was implemented post-0.27.
--- player/lua/ytdl_hook.lua.orig 2018-01-28 10:58:02.151884824 +0000
+++ player/lua/ytdl_hook.lua
@@ -15,6 +16,18 @@ local ytdl = {
local chapter_list = {}
+function Set (t)
+ local set = {}
+ for _, v in pairs(t) do set[v] = true end
+ return set
+end
+
+local safe_protos = Set {
+ "http", "https", "ftp", "ftps",
+ "rtmp", "rtmps", "rtmpe", "rtmpt", "rtmpts", "rtmpte",
+ "data"
+}
+
local function exec(args)
local ret = utils.subprocess({args = args})
return ret.status, ret.stdout, ret
@@ -71,6 +84,15 @@ local function edl_escape(url)
return "%" .. string.len(url) .. "%" .. url
end
+local function url_is_safe(url)
+ local proto = type(url) == "string" and url:match("^(.+)://") or nil
+ local safe = proto and safe_protos[proto]
+ if not safe then
+ msg.error(("Ignoring potentially unsafe url: '%s'"):format(url))
+ end
+ return safe
+end
+
local function time_to_secs(time_string)
local ret
@@ -182,6 +204,9 @@ local function edl_track_joined(fragment
for i = offset, #fragments do
local fragment = fragments[i]
+ if not url_is_safe(join_url(base, fragment)) then
+ return nil
+ end
table.insert(parts, edl_escape(join_url(base, fragment)))
if fragment.duration then
parts[#parts] =
@@ -191,16 +216,63 @@ local function edl_track_joined(fragment
return edl .. table.concat(parts, ";") .. ";"
end
+local function has_native_dash_demuxer()
+ local demuxers = mp.get_property_native("demuxer-lavf-list")
+ for _,v in ipairs(demuxers) do
+ if v == "dash" then
+ return true
+ end
+ end
+ return false
+end
+
+local function valid_manifest(json)
+ local reqfmt = json["requested_formats"] and json["requested_formats"][1] or {}
+ if not reqfmt["manifest_url"] and not json["manifest_url"] then
+ return false
+ end
+ local proto = reqfmt["protocol"] or json["protocol"] or ""
+ return (has_native_dash_demuxer() and proto == "http_dash_segments") or
+ proto:find("^m3u8")
+end
+
local function add_single_video(json)
local streamurl = ""
+ local max_bitrate = 0
+ local reqfmts = json["requested_formats"]
+
+ -- prefer manifest_url if present
+ if valid_manifest(json) then
+ local mpd_url = reqfmts and reqfmts[1]["manifest_url"] or
+ json["manifest_url"]
+ if not mpd_url then
+ msg.error("No manifest URL found in JSON data.")
+ return
+ elseif not url_is_safe(mpd_url) then
+ return
+ end
+
+ streamurl = mpd_url
+
+ if reqfmts then
+ for _, track in pairs(reqfmts) do
+ max_bitrate = track.tbr > max_bitrate and
+ track.tbr or max_bitrate
+ end
+ elseif json.tbr then
+ max_bitrate = json.tbr > max_bitrate and json.tbr or max_bitrate
+ end
-- DASH/split tracks
- if not (json["requested_formats"] == nil) then
- for _, track in pairs(json.requested_formats) do
+ elseif reqfmts then
+ for _, track in pairs(reqfmts) do
local edl_track = nil
edl_track = edl_track_joined(track.fragments,
track.protocol, json.is_live,
track.fragment_base_url)
+ if not edl_track and not url_is_safe(track.url) then
+ return
+ end
if track.acodec and track.acodec ~= "none" then
-- audio track
mp.commandv("audio-add",
@@ -217,6 +289,9 @@ local function add_single_video(json)
edl_track = edl_track_joined(json.fragments, json.protocol,
json.is_live, json.fragment_base_url)
+ if not edl_track and not url_is_safe(json.url) then
+ return
+ end
-- normal video or single track
streamurl = edl_track or json.url
set_http_headers(json.http_headers)
@@ -231,6 +306,13 @@ local function add_single_video(json)
mp.set_property("file-local-options/force-media-title", json.title)
+ -- set hls-bitrate for dash track selection
+ if max_bitrate > 0 and
+ not option_was_set("hls-bitrate") and
+ not option_was_set_locally("hls-bitrate") then
+ mp.set_property_native('file-local-options/hls-bitrate', max_bitrate*1000)
+ end
+
-- add subtitles
if not (json.requested_subtitles == nil) then
for lang, sub_info in pairs(json.requested_subtitles) do
@@ -309,7 +391,8 @@ mp.add_hook("on_load", 10, function ()
-- check for youtube-dl in mpv's config dir
if not (ytdl.searched) then
- local ytdl_mcd = mp.find_config_file("youtube-dl")
+ local exesuf = (package.config:sub(1,1) == '\\') and '.exe' or ''
+ local ytdl_mcd = mp.find_config_file("youtube-dl" .. exesuf)
if not (ytdl_mcd == nil) then
msg.verbose("found youtube-dl at: " .. ytdl_mcd)
ytdl.path = ytdl_mcd
@@ -365,9 +448,15 @@ mp.add_hook("on_load", 10, function ()
local es, json, result = exec(command)
if (es < 0) or (json == nil) or (json == "") then
- if not result.killed_by_us then
- msg.warn("youtube-dl failed, trying to play URL directly ...")
+ local err = "youtube-dl failed: "
+ if result.error and result.error == "init" then
+ err = err .. "not found or not enough permissions"
+ elseif not result.killed_by_us then
+ err = err .. "unexpected error ocurred"
+ else
+ err = string.format("%s returned '%d'", err, es)
end
+ msg.error(err)
return
end
@@ -396,18 +485,26 @@ mp.add_hook("on_load", 10, function ()
return
end
+ local self_redirecting_url =
+ json.entries[1]["_type"] ~= "url_transparent" and
+ json.entries[1]["webpage_url"] and
+ json.entries[1]["webpage_url"] == json["webpage_url"]
+
-- some funky guessing to detect multi-arc videos
- if (not (json.entries[1]["_type"] == "url_transparent")) and
- (not (json.entries[1]["webpage_url"] == nil)
- and (json.entries[1]["webpage_url"] == json["webpage_url"]))
- and not (json.entries[1].url == nil) then
+ if self_redirecting_url and #json.entries > 1
+ and json.entries[1].protocol == "m3u8_native"
+ and json.entries[1].url then
msg.verbose("multi-arc video detected, building EDL")
local playlist = edl_track_joined(json.entries)
msg.debug("EDL: " .. playlist)
+ if not playlist then
+ return
+ end
+
-- can't change the http headers for each entry, so use the 1st
if json.entries[1] then
set_http_headers(json.entries[1].http_headers)
@@ -446,39 +543,43 @@ mp.add_hook("on_load", 10, function ()
end
end
- elseif (not (json.entries[1]["_type"] == "url_transparent")) and
- (not (json.entries[1]["webpage_url"] == nil)
- and (json.entries[1]["webpage_url"] == json["webpage_url"]))
- and (#json.entries == 1) then
-
+ elseif self_redirecting_url and #json.entries == 1 then
msg.verbose("Playlist with single entry detected.")
add_single_video(json.entries[1])
else
-
- local playlist = "#EXTM3U\n"
+ local playlist = {"#EXTM3U"}
for i, entry in pairs(json.entries) do
local site = entry.url
local title = entry.title
if not (title == nil) then
title = string.gsub(title, '%s+', ' ')
- playlist = playlist .. "#EXTINF:0," .. title .. "\n"
+ table.insert(playlist, "#EXTINF:0," .. title)
end
- -- some extractors will still return the full info for
- -- all clips in the playlist and the URL will point
- -- directly to the file in that case, which we don't
- -- want so get the webpage URL instead, which is what
- -- we want
- if not (json.entries[1]["_type"] == "url_transparent")
- and not (entry["webpage_url"] == nil) then
+ --[[ some extractors will still return the full info for
+ all clips in the playlist and the URL will point
+ directly to the file in that case, which we don't
+ want so get the webpage URL instead, which is what
+ we want, but only if we aren't going to trigger an
+ infinite loop
+ --]]
+ if entry["webpage_url"] and not self_redirecting_url then
site = entry["webpage_url"]
end
- playlist = playlist .. "ytdl://" .. site .. "\n"
+ -- links with only youtube id as returned by --flat-playlist
+ if not site:find("://") then
+ table.insert(playlist, "ytdl://" .. site)
+ elseif url_is_safe(site) then
+ table.insert(playlist, site)
+ end
+
end
- mp.set_property("stream-open-filename", "memory://" .. playlist)
+ if #playlist > 0 then
+ mp.set_property("stream-open-filename", "memory://" .. table.concat(playlist, "\n"))
+ end
end
else -- probably a video