[Buildroot] [git commit branch/2021.02.x] package/janus-gateway: fix CVE-2021-4020
From: Peter Korsgaard <peter@korsgaard.com>
Date: 2021-12-12 22:25:11
Subsystem:
the rest · Maintainer:
Linus Torvalds
commit: https://git.buildroot.net/buildroot/commit/?id=2436f0d75c14b7d8a2490a715f140472e152626a branch: https://git.buildroot.net/buildroot/commit/?id=refs/heads/2021.02.x Fix CVE-2021-4020: janus-gateway is vulnerable to Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') Signed-off-by: Fabrice Fontaine <redacted> Signed-off-by: Yann E. MORIN <redacted> (cherry picked from commit 99d2826e039858b749504cb53e713e8b53664b39) Signed-off-by: Peter Korsgaard <peter@korsgaard.com> --- ...ross-site-Scripting-XSS-exploits-in-demos.patch | 357 +++++++++++++++++++++ package/janus-gateway/janus-gateway.mk | 3 + 2 files changed, 360 insertions(+)
diff --git a/package/janus-gateway/0003-Fix-potential-Cross-site-Scripting-XSS-exploits-in-demos.patch b/package/janus-gateway/0003-Fix-potential-Cross-site-Scripting-XSS-exploits-in-demos.patch
new file mode 100644
index 0000000000..9f3adfcc8e
--- /dev/null
+++ b/package/janus-gateway/0003-Fix-potential-Cross-site-Scripting-XSS-exploits-in-demos.patch@@ -0,0 +1,357 @@ +From ba166e9adebfe5343f826c6a9e02299d35414ffd Mon Sep 17 00:00:00 2001 +From: Lorenzo Miniero <lminiero@gmail.com> +Date: Thu, 25 Nov 2021 17:20:53 +0100 +Subject: [PATCH] Fix potential Cross-site Scripting (XSS) exploits in demos + (#2817) + +[Retrieved (and backported) from: +https://github.com/meetecho/janus-gateway/commit/ba166e9adebfe5343f826c6a9e02299d35414ffd] +Signed-off-by: Fabrice Fontaine <fontaine.fabrice@gmail.com> +--- + html/audiobridgetest.js | 17 +++++++++++++---- + html/recordplaytest.js | 13 +++++++++++-- + html/screensharingtest.js | 11 ++++++++++- + html/streamingtest.js | 13 +++++++++++-- + html/textroomtest.js | 23 ++++++++++++++--------- + html/videocalltest.js | 15 ++++++++++++--- + html/videoroomtest.js | 13 +++++++++++-- + html/vp9svctest.js | 13 +++++++++++-- + 8 files changed, 93 insertions(+), 25 deletions(-) + +diff --git a/html/audiobridgetest.js b/html/audiobridgetest.js +index 18e1cc1839..f757789708 100644 +--- a/html/audiobridgetest.js ++++ b/html/audiobridgetest.js +@@ -178,7 +178,7 @@ $(document).ready(function() { + Janus.debug("Got a list of participants:", list); + for(var f in list) { + var id = list[f]["id"]; +- var display = list[f]["display"]; ++ var display = escapeXmlTags(list[f]["display"]); + var setup = list[f]["setup"]; + var muted = list[f]["muted"]; + var spatial = list[f]["spatial_position"]; +@@ -222,7 +222,7 @@ $(document).ready(function() { + Janus.debug("Got a list of participants:", list); + for(var f in list) { + var id = list[f]["id"]; +- var display = list[f]["display"]; ++ var display = escapeXmlTags(list[f]["display"]); + var setup = list[f]["setup"]; + var muted = list[f]["muted"]; + var spatial = list[f]["spatial_position"]; +@@ -267,7 +267,7 @@ $(document).ready(function() { + Janus.debug("Got a list of participants:", list); + for(var f in list) { + var id = list[f]["id"]; +- var display = list[f]["display"]; ++ var display = escapeXmlTags(list[f]["display"]); + var setup = list[f]["setup"]; + var muted = list[f]["muted"]; + var spatial = list[f]["spatial_position"]; +@@ -429,7 +429,7 @@ function registerUsername() { + return; + } + var register = { request: "join", room: myroom, display: username }; +- myusername = username; ++ myusername = escapeXmlTags(username); + mixertest.send({ message: register}); + } + } +@@ -448,3 +448,12 @@ function getQueryStringValue(name) { + results = regex.exec(location.search); + return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " ")); + } ++ ++// Helper to escape XML tags ++function escapeXmlTags(value) { ++ if(value) { ++ var escapedValue = value.replace(new RegExp('<', 'g'), '<'); ++ escapedValue = escapedValue.replace(new RegExp('>', 'g'), '>'); ++ return escapedValue; ++ } ++} +diff --git a/html/recordplaytest.js b/html/recordplaytest.js +index 74ee7bed95..52b5ccbc4c 100644 +--- a/html/recordplaytest.js ++++ b/html/recordplaytest.js +@@ -423,11 +423,11 @@ function updateRecsList() { + Janus.debug("Got a list of available recordings:", list); + for(var mp in list) { + Janus.debug(" >> [" + list[mp]["id"] + "] " + list[mp]["name"] + " (" + list[mp]["date"] + ")"); +- $('#recslist').append("<li><a href='#' id='" + list[mp]["id"] + "'>" + list[mp]["name"] + " [" + list[mp]["date"] + "]" + "</a></li>"); ++ $('#recslist').append("<li><a href='#' id='" + list[mp]["id"] + "'>" + escapeXmlTags(list[mp]["name"]) + " [" + list[mp]["date"] + "]" + "</a></li>"); + } + $('#recslist a').unbind('click').click(function() { + selectedRecording = $(this).attr("id"); +- selectedRecordingInfo = $(this).text(); ++ selectedRecordingInfo = escapeXmlTags($(this).text()); + $('#recset').html($(this).html()).parent().removeClass('open'); + $('#play').removeAttr('disabled').click(startPlayout); + return false; +@@ -545,3 +545,12 @@ function getQueryStringValue(name) { + results = regex.exec(location.search); + return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " ")); + } ++ ++// Helper to escape XML tags ++function escapeXmlTags(value) { ++ if(value) { ++ var escapedValue = value.replace(new RegExp('<', 'g'), '<'); ++ escapedValue = escapedValue.replace(new RegExp('>', 'g'), '>'); ++ return escapedValue; ++ } ++} +diff --git a/html/screensharingtest.js b/html/screensharingtest.js +index 61eac70f43..c64d8dbd67 100644 +--- a/html/screensharingtest.js ++++ b/html/screensharingtest.js +@@ -161,7 +161,7 @@ $(document).ready(function() { + if(event === "joined") { + myid = msg["id"]; + $('#session').html(room); +- $('#title').html(msg["description"]); ++ $('#title').html(escapeXmlTags(msg["description"])); + Janus.log("Successfully joined room " + msg["room"] + " with ID " + myid); + if(role === "publisher") { + // This is our session, publish our stream +@@ -514,3 +514,12 @@ function newRemoteFeed(id, display) { + } + }); + } ++ ++// Helper to escape XML tags ++function escapeXmlTags(value) { ++ if(value) { ++ var escapedValue = value.replace(new RegExp('<', 'g'), '<'); ++ escapedValue = escapedValue.replace(new RegExp('>', 'g'), '>'); ++ return escapedValue; ++ } ++} +diff --git a/html/streamingtest.js b/html/streamingtest.js +index 7dd2e1f681..3f9937f11c 100644 +--- a/html/streamingtest.js ++++ b/html/streamingtest.js +@@ -323,7 +323,7 @@ function updateStreamsList() { + Janus.debug(list); + for(var mp in list) { + Janus.debug(" >> [" + list[mp]["id"] + "] " + list[mp]["description"] + " (" + list[mp]["type"] + ")"); +- $('#streamslist').append("<li><a href='#' id='" + list[mp]["id"] + "'>" + list[mp]["description"] + " (" + list[mp]["type"] + ")" + "</a></li>"); ++ $('#streamslist').append("<li><a href='#' id='" + list[mp]["id"] + "'>" + escapeXmlTags(list[mp]["description"]) + " (" + list[mp]["type"] + ")" + "</a></li>"); + } + $('#streamslist a').unbind('click').click(function() { + selectedStream = $(this).attr("id"); +@@ -345,7 +345,7 @@ function getStreamInfo() { + var body = { request: "info", id: parseInt(selectedStream) || selectedStream }; + streaming.send({ message: body, success: function(result) { + if(result && result.info && result.info.metadata) { +- $('#metadata').html(result.info.metadata); ++ $('#metadata').html(escapeXmlTags(result.info.metadata)); + $('#info').removeClass('hide').show(); + } + }}); +@@ -394,6 +394,15 @@ function stopStream() { + simulcastStarted = false; + } + ++// Helper to escape XML tags ++function escapeXmlTags(value) { ++ if(value) { ++ var escapedValue = value.replace(new RegExp('<', 'g'), '<'); ++ escapedValue = escapedValue.replace(new RegExp('>', 'g'), '>'); ++ return escapedValue; ++ } ++} ++ + // Helpers to create Simulcast-related UI, if enabled + function addSimulcastButtons() { + $('#curres').parent().append( +diff --git a/html/textroomtest.js b/html/textroomtest.js +index 082ae44905..3d0697e35a 100644 +--- a/html/textroomtest.js ++++ b/html/textroomtest.js +@@ -153,9 +153,7 @@ $(document).ready(function() { + var what = json["textroom"]; + if(what === "message") { + // Incoming message: public or private? +- var msg = json["text"]; +- msg = msg.replace(new RegExp('<', 'g'), '<'); +- msg = msg.replace(new RegExp('>', 'g'), '>'); ++ var msg = escapeXmlTags(json["text"]); + var from = json["from"]; + var dateString = getDateString(json["date"]); + var whisper = json["whisper"]; +@@ -170,9 +168,7 @@ $(document).ready(function() { + } + } else if(what === "announcement") { + // Room announcement +- var msg = json["text"]; +- msg = msg.replace(new RegExp('<', 'g'), '<'); +- msg = msg.replace(new RegExp('>', 'g'), '>'); ++ var msg = escapeXmlTags(json["text"]); + var dateString = getDateString(json["date"]); + $('#chatroom').append('<p style="color: purple;">[' + dateString + '] <i>' + msg + '</i>'); + $('#chatroom').get(0).scrollTop = $('#chatroom').get(0).scrollHeight; +@@ -180,7 +176,7 @@ $(document).ready(function() { + // Somebody joined + var username = json["username"]; + var display = json["display"]; +- participants[username] = display ? display : username; ++ participants[username] = escapeXmlTags(display ? display : username); + if(username !== myid && $('#rp' + username).length === 0) { + // Add to the participants list + $('#list').append('<li id="rp' + username + '" class="list-group-item">' + participants[username] + '</li>'); +@@ -282,7 +278,7 @@ function registerUsername() { + username: myid, + display: username + }; +- myusername = username; ++ myusername = escapeXmlTags(username); + transactions[transaction] = function(response) { + if(response["textroom"] === "error") { + // Something went wrong +@@ -312,7 +308,7 @@ function registerUsername() { + if(response.participants && response.participants.length > 0) { + for(var i in response.participants) { + var p = response.participants[i]; +- participants[p.username] = p.display ? p.display : p.username; ++ participants[p.username] = escapeXmlTags(p.display ? p.display : p.username); + if(p.username !== myid && $('#rp' + p.username).length === 0) { + // Add to the participants list + $('#list').append('<li id="rp' + p.username + '" class="list-group-item">' + participants[p.username] + '</li>'); +@@ -418,3 +414,12 @@ function getQueryStringValue(name) { + results = regex.exec(location.search); + return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " ")); + } ++ ++// Helper to escape XML tags ++function escapeXmlTags(value) { ++ if(value) { ++ var escapedValue = value.replace(new RegExp('<', 'g'), '<'); ++ escapedValue = escapedValue.replace(new RegExp('>', 'g'), '>'); ++ return escapedValue; ++ } ++} +diff --git a/html/videocalltest.js b/html/videocalltest.js +index d1c1ab8d07..18ccbc2c47 100644 +--- a/html/videocalltest.js ++++ b/html/videocalltest.js +@@ -148,7 +148,7 @@ $(document).ready(function() { + } else if(result["event"]) { + var event = result["event"]; + if(event === 'registered') { +- myusername = result["username"]; ++ myusername = escapeXmlTags(result["username"]); + Janus.log("Successfully registered as " + myusername + "!"); + $('#youok').removeClass('hide').show().html("Registered as '" + myusername + "'"); + // Get a list of available peers, just for fun +@@ -163,7 +163,7 @@ $(document).ready(function() { + bootbox.alert("Waiting for the peer to answer..."); + } else if(event === 'incomingcall') { + Janus.log("Incoming call from " + result["username"] + "!"); +- yourusername = result["username"]; ++ yourusername = escapeXmlTags(result["username"]); + // Notify user + bootbox.hideAll(); + incoming = bootbox.dialog({ +@@ -213,7 +213,7 @@ $(document).ready(function() { + }); + } else if(event === 'accepted') { + bootbox.hideAll(); +- var peer = result["username"]; ++ var peer = escapeXmlTags(result["username"]); + if(!peer) { + Janus.log("Call started!"); + } else { +@@ -598,6 +598,15 @@ function getQueryStringValue(name) { + return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " ")); + } + ++// Helper to escape XML tags ++function escapeXmlTags(value) { ++ if(value) { ++ var escapedValue = value.replace(new RegExp('<', 'g'), '<'); ++ escapedValue = escapedValue.replace(new RegExp('>', 'g'), '>'); ++ return escapedValue; ++ } ++} ++ + // Helpers to create Simulcast-related UI, if enabled + function addSimulcastButtons(temporal) { + $('#curres').parent().append( +diff --git a/html/videoroomtest.js b/html/videoroomtest.js +index 6a566891d8..5a3ade9be9 100644 +--- a/html/videoroomtest.js ++++ b/html/videoroomtest.js +@@ -400,7 +400,7 @@ function registerUsername() { + ptype: "publisher", + display: username + }; +- myusername = username; ++ myusername = escapeXmlTags(username); + sfutest.send({ message: register }); + } + } +@@ -530,7 +530,7 @@ function newRemoteFeed(id, display, audio, video) { + } + } + remoteFeed.rfid = msg["id"]; +- remoteFeed.rfdisplay = msg["display"]; ++ remoteFeed.rfdisplay = escapeXmlTags(msg["display"]); + if(!remoteFeed.spinner) { + var target = document.getElementById('videoremote'+remoteFeed.rfindex); + remoteFeed.spinner = new Spinner({top:100}).spin(target); +@@ -685,6 +685,15 @@ function getQueryStringValue(name) { + return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " ")); + } + ++// Helper to escape XML tags ++function escapeXmlTags(value) { ++ if(value) { ++ var escapedValue = value.replace(new RegExp('<', 'g'), '<'); ++ escapedValue = escapedValue.replace(new RegExp('>', 'g'), '>'); ++ return escapedValue; ++ } ++} ++ + // Helpers to create Simulcast-related UI, if enabled + function addSimulcastButtons(feed, temporal) { + var index = feed; +diff --git a/html/vp9svctest.js b/html/vp9svctest.js +index eca0239c32..b22ccf3340 100644 +--- a/html/vp9svctest.js ++++ b/html/vp9svctest.js +@@ -387,7 +387,7 @@ function registerUsername() { + ptype: "publisher", + display: username + }; +- myusername = username; ++ myusername = escapeXmlTags(username); + sfutest.send({ message: register }); + } + } +@@ -486,7 +486,7 @@ function newRemoteFeed(id, display, audio, video) { + } + } + remoteFeed.rfid = msg["id"]; +- remoteFeed.rfdisplay = msg["display"]; ++ remoteFeed.rfdisplay = escapeXmlTags(msg["display"]); + if(!remoteFeed.spinner) { + var target = document.getElementById('videoremote'+remoteFeed.rfindex); + remoteFeed.spinner = new Spinner({top:100}).spin(target); +@@ -630,6 +630,15 @@ function newRemoteFeed(id, display, audio, video) { + }); + } + ++// Helper to escape XML tags ++function escapeXmlTags(value) { ++ if(value) { ++ var escapedValue = value.replace(new RegExp('<', 'g'), '<'); ++ escapedValue = escapedValue.replace(new RegExp('>', 'g'), '>'); ++ return escapedValue; ++ } ++} ++ + // Helpers to create SVC-related UI for a new viewer + function addSvcButtons(feed) { + var index = feed;
diff --git a/package/janus-gateway/janus-gateway.mk b/package/janus-gateway/janus-gateway.mk
index 40652d802a..98e00aeeb8 100644
--- a/package/janus-gateway/janus-gateway.mk
+++ b/package/janus-gateway/janus-gateway.mk@@ -11,6 +11,9 @@ JANUS_GATEWAY_LICENSE_FILES = COPYING JANUS_GATEWAY_CPE_ID_VENDOR = meetecho JANUS_GATEWAY_CPE_ID_PRODUCT = janus +# 0003-Fix-potential-Cross-site-Scripting-XSS-exploits-in-demos.patch +JANUS_GATEWAY_IGNORE_CVES += CVE-2021-4020 + # ding-libs provides the ini_config library JANUS_GATEWAY_DEPENDENCIES = host-pkgconf jansson libnice \ libsrtp host-gengetopt libglib2 openssl libconfig \
_______________________________________________ buildroot mailing list buildroot@buildroot.org https://lists.buildroot.org/mailman/listinfo/buildroot