[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

squeeze update of mumble



Greetings.

I'd like to update the mumble package in squeeze for CVE-2014-3755 and
CVE-2014-3756, Debian bug #748189.  The upstream fixes for this:

    http://mumble.info/security/Mumble-SA-2014-005.txt
    http://mumble.info/security/Mumble-SA-2014-005.patch

    http://mumble.info/security/Mumble-SA-2014-006.txt
    http://mumble.info/security/Mumble-SA-2014-006.patch

... had to be backported somewhat to get them to apply for 1.2.2-squeeze1,
but I managed to do so.

A debdiff of the proposed changes is attached.

If this is okay to upload, let me know if the upload needs to go to a
specific queue or if 'dput <changes_file>' is all that's needed.

Thanks much.
   -- Chris

-- 
Chris Knadle
Chris.Knadle@coredump.us
diff -Nru mumble-1.2.2/debian/changelog mumble-1.2.2/debian/changelog
--- mumble-1.2.2/debian/changelog	2012-02-17 08:27:34.000000000 -0500
+++ mumble-1.2.2/debian/changelog	2015-12-25 23:39:07.000000000 -0500
@@ -1,3 +1,17 @@
+mumble (1.2.2-6+squeeze2) squeeze-lts; urgency=medium
+
+  * Add patch 0006-fix-CVE-2014-3755.patch (ported for mumble in squeeze)
+       http://mumble.info/security/Mumble-SA-2014-005.txt
+    SVG images with local file references could trigger client DoS
+    Closes: #748189, CVE-2014-3755
+  * Add patch 0007-fix-CVE-2014-3756.patch (ported for mumble in squeeze)
+       http://mumble.info/security/Mumble-SA-2014-006.txt
+    The Mumble client did not properly HTML-escape some external strings
+    before using them in a rich-text (HTML) context.
+    Closes: #748189, CVE-2014-3756
+
+ -- Christopher Knadle <Chris.Knadle@coredump.us>  Fri, 25 Dec 2015 03:06:55 -0500
+
 mumble (1.2.2-6+squeeze1) stable-security; urgency=high
 
   * Add patch 0005-set-file-permissions from Marc Deslauriers, which fixes the
diff -Nru mumble-1.2.2/debian/patches/0006-fix-CVE-2014-3755.patch mumble-1.2.2/debian/patches/0006-fix-CVE-2014-3755.patch
--- mumble-1.2.2/debian/patches/0006-fix-CVE-2014-3755.patch	1969-12-31 19:00:00.000000000 -0500
+++ mumble-1.2.2/debian/patches/0006-fix-CVE-2014-3755.patch	2015-12-27 04:15:10.000000000 -0500
@@ -0,0 +1,521 @@
+Description: patch to fix CVE-2014-3755
+ Patch ported by Chris Knadle <Chris.Knadle@coredump.us> from fix
+ for the same bug for mumble in  wheezy.
+commit c7aecb2956f214cd83b7a862a4fcf15cc76c4450
+Author: Mikkel Krautz <mikkel@krautz.dk>
+Date:   Tue May 13 20:23:05 2014 +0200
+Last-Updated: 2015-12-25
+
+    mumble: fix Mumble-SA-2014-005.
+    
+    Qt's SVG image plugin is not safe to use with potentially
+    unsafe SVGs, such as those downloaded over the network.
+    
+    More specifically, it is possible to trigger local file
+    access via Qt's SVG renderer using SVG features such as XML
+    stylesheets (XSL) and SVG image tags, and potentially other
+    features. This allows an attacker to have Qt read arbitrary
+    files into the memory space of the Mumble process.
+    
+    This makes it easy to perform a Denial of Service attack
+    against a Mumble client. A client DoS can be accomplished
+    by serving it an SVG file that refers to a filesystem path
+    that is un-ending or is known to block under certain
+    circumstances.
+    
+    Having arbitrary files read into the Mumble process could
+    potentially also be abused by an attacker to gain access
+    to the content of the files, if combined with an (as of
+    yet unknown) vulnerability that allows the attacker to
+    read Mumble's memory.
+    
+    To fix the issue, this change removes SVG as a supported
+    image format for all externally received images. This
+    includes things such as text messages, user comments,
+    channel comments and user textures/avatars. It also removes
+    the ability to transmit SVGs using any of the aforementioned
+    channels.
+    
+    This is accomplished by introducing a new class called
+    RichTextImage. The RichTextImage class is used, via its
+    isValidImage() method, to validate images before they are used
+    in a rich text context in Mumble. In its current form, the
+    isValidImage() method simply checks whether the image's format
+    is part of the set of image formats that are deemed safe
+    (PNG, JPG, GIF).
+    
+    The LogDocument class, which is the QTextDocument that backs
+    the Mumble log view, undergoes the following changes:
+    
+     - LogDocument now restricts images loaded via QNetworkRequest
+       and QNetworkReply to those that pass the
+       RichTextImage::isValidImage() check.
+     - Resources that use the data:// scheme are now loaded via
+       QNetworkRequest and QNetworkReply, just like http:// and
+       https:// URLs. This allows all resources to make use of
+       LogDocument's new image format restrictions.
+     - The functionality of the ValidDocument class, a subclass
+       of LogDocument that was used to validate HTML snippets,
+       is now part of LogDocument itself. The original
+       ValidDocument class has been removed.
+    
+    The RichTextEditor class is used to author text messages
+    and user comments. The RichTextEditor is changed to use
+    a LogDocument instead of a regular QTextDocument as its
+    backing document. This allows the RichTextEditor to benefit
+    from LogDocument's new image filtering functionality.
+    
+    The static method Log::validHtml is used to validate
+    HTML before using it in various contexts such as the Mumble
+    log view and tooltips. This method is modified to use the
+    LogDocument class instead of the ValidDocument class.
+    A call to documentLayout() on the LogDocument is also
+    added to the method. This ensures that image loading
+    (and thus validation) is performed.
+    
+    The MainWindow::openImageFile() method is re-worked to
+    sniff and validate a selected image using
+    RichTextImage::isValidImage to ensure that only valid
+    rich text images can be selected, regardless of file
+    extension.
+    
+    The Overlay::verifyTexture() method is used to verify and
+    set a ClientUser's texture and texture format, either by
+    reading it from the local cache, or by reqesting a new
+    texture from the server. This method is changed to only
+    verify and set textures that pass the
+    RichTextImage::isValidImage() check.
+    
+    The ServerHandler::setUserTexture() method (also known as
+    ServerHandler::setTexture() in some 1.2.x versions of Mumble)
+    is changed to only allow settings textures that pass the
+    RichTextImage::isValidImage() check.
+    
+    Thanks to Tim Cooper for reporting this issue, proposing an
+    initial patch and reviewing the final patch. This commit has
+    also been reviewed and iterated upon by Stefan Hacker.
+
+--- a/src/mumble/Log.cpp
++++ b/src/mumble/Log.cpp
+@@ -33,6 +33,7 @@
+ #include "TextToSpeech.h"
+ #include "MainWindow.h"
+ #include "Channel.h"
++#include "RichTextEditor.h"
+ #include "ServerHandler.h"
+ #include "Global.h"
+ 
+@@ -356,13 +357,23 @@
+ 
+ QString Log::validHtml(const QString &html, bool allowReplacement, QTextCursor *tc) {
+ 	QDesktopWidget dw;
+-	ValidDocument qtd(allowReplacement);
++	LogDocument qtd;
+ 	bool valid = false;
+ 
++	qtd.setAllowHTTPResources(allowReplacement);
++	qtd.setOnlyLoadDataURLs(true);
++
+ 	QRectF qr = dw.availableGeometry(dw.screenNumber(g.mw));
+ 	qtd.setTextWidth(qr.width() / 2);
+ 	qtd.setDefaultStyleSheet(qApp->styleSheet());
+ 
++	// Call documentLayout on our LogDocument to ensure
++	// it has a layout backing it. With a layout set on
++	// the document, it will attempt to load all the
++	// resources it contains as soon as we call setHtml(),
++	// allowing our validation checks for things such as
++	// data URL images to run.
++	(void) qtd.documentLayout();
+ 	qtd.setHtml(html);
+ 	valid = qtd.isValid();
+ 
+@@ -598,66 +609,86 @@
+ 		tts->say(terse);
+ }
+ 
+-ValidDocument::ValidDocument(bool allowhttp, QObject *p) : QTextDocument(p) {
+-	bValid = true;
+-	qslValidImage << QLatin1String("data");
+-	if (allowhttp) {
+-		qslValidImage << QLatin1String("http");
+-		qslValidImage << QLatin1String("https");
+-	}
+-}
+-
+-QVariant ValidDocument::loadResource(int type, const QUrl &url) {
+-	QVariant v = QLatin1String("PlaceHolder");
+-	if ((type == QTextDocument::ImageResource) && qslValidImage.contains(url.scheme()))
+-		return QTextDocument::loadResource(type, url);
+-	bValid = false;
+-	return v;
+-}
+-
+-bool ValidDocument::isValid() const {
+-	return bValid;
+-}
+-
+-LogDocument::LogDocument(QObject *p) : QTextDocument(p) {
++LogDocument::LogDocument(QObject *p)
++	: QTextDocument(p)
++	, m_valid(true)
++	, m_onlyLoadDataURLs(false)
++	, m_allowHTTPResources(true) {
+ }
+ 
+ QVariant LogDocument::loadResource(int type, const QUrl &url) {
+-	if (type != QTextDocument::ImageResource)
++	if (type != QTextDocument::ImageResource) {
++		m_valid = false;
+ 		return QLatin1String("No external resources allowed.");
+-	if (g.s.iMaxImageSize <= 0)
+-		return QLatin1String("Image download disabled.");
+-
+-	if (url.scheme() == QLatin1String("data")) {
+-		QVariant v = QTextDocument::loadResource(type, url);
+-		addResource(type, url, v);
+-		return v;
+ 	}
+ 
+-	qWarning() << "LogDocument::loadResource " << type << url.toString();
++	if (url.scheme() != QLatin1String("data") && g.s.iMaxImageSize <= 0) {
++		m_valid = false;
++		return QLatin1String("Image download disabled.");
++	}
+ 
+ 	QImage qi(1, 1, QImage::Format_Mono);
+ 	addResource(type, url, qi);
+ 
+-	if (! url.isValid() || url.isRelative())
++	if (! url.isValid() || url.isRelative()) {
++		m_valid = false;
+ 		return qi;
++	}
+ 
+-	if ((url.scheme() != QLatin1String("http")) && (url.scheme() != QLatin1String("https")))
++	QStringList allowedSchemes;
++	allowedSchemes << QLatin1String("data");
++	if (m_allowHTTPResources) {
++		allowedSchemes << QLatin1String("http");
++		allowedSchemes << QLatin1String("https");
++	}
++
++	if (!allowedSchemes.contains(url.scheme())) {
++		m_valid = false;
+ 		return qi;
++	}
++
++	bool shouldLoad = true;
++	if (m_onlyLoadDataURLs && url.scheme() != QLatin1String("data")) {
++		shouldLoad = false;
++	}
++
++	if (shouldLoad) {
++		QNetworkRequest req(url);
++		QNetworkReply *rep = g.nam->get(req);
++		connect(rep, SIGNAL(metaDataChanged()), this, SLOT(receivedHead()));
++		connect(rep, SIGNAL(finished()), this, SLOT(finished()));
++
++		// Handle data URLs immediately without a roundtrip to the event loop.
++		// We need this to perform proper validation for data URL images when
++		// a LogDocument is used inside Log::validHtml().
++		if (url.scheme() == QLatin1String("data")) {
++			QCoreApplication::sendPostedEvents(rep, 0);
++		}
++	}
+ 
+-	QNetworkRequest req(url);
+-	QNetworkReply *rep = g.nam->get(req);
+-	connect(rep, SIGNAL(metaDataChanged()), this, SLOT(receivedHead()));
+-	connect(rep, SIGNAL(finished()), this, SLOT(finished()));
+ 	return qi;
+ }
+ 
++void LogDocument::setAllowHTTPResources(bool allowHTTPResources) {
++	m_allowHTTPResources = allowHTTPResources;
++}
++
++void LogDocument::setOnlyLoadDataURLs(bool onlyLoadDataURLs) {
++	m_onlyLoadDataURLs = onlyLoadDataURLs;
++}
++
++bool LogDocument::isValid() {
++	return m_valid;
++}
++
+ void LogDocument::receivedHead() {
+ 	QNetworkReply *rep = qobject_cast<QNetworkReply *>(sender());
+-	QVariant length = rep->header(QNetworkRequest::ContentLengthHeader);
+-	if (length == QVariant::Invalid || length.toInt() > g.s.iMaxImageSize) {
+-		qWarning() << "Image "<< rep->url().toString() <<" (" << length.toInt() << " byte) to big, request aborted. ";
+-		rep->abort();
++	if (rep->url().scheme() != QLatin1String("data")) {
++		QVariant length = rep->header(QNetworkRequest::ContentLengthHeader);
++		if (length == QVariant::Invalid || length.toInt() > g.s.iMaxImageSize) {
++			m_valid = false;
++			rep->abort();
++		}
+ 	}
+ }
+ 
+@@ -665,14 +696,42 @@
+ 	QNetworkReply *rep = qobject_cast<QNetworkReply *>(sender());
+ 
+ 	if (rep->error() == QNetworkReply::NoError) {
+-		QVariant qv = rep->readAll();
++		QByteArray ba = rep->readAll();
++		QByteArray fmt;
+ 		QImage qi;
+ 
+-		if (qi.loadFromData(qv.toByteArray()) && qi.width() <= g.s.iMaxImageWidth && qi.height() <= g.s.iMaxImageHeight) {
+-			addResource(QTextDocument::ImageResource, rep->request().url(), qi);
+-			g.mw->qteLog->setDocument(this);
+-		} else qWarning() << "Image "<< rep->url().toString() <<" (" << qi.width() << "x" << qi.height() <<") to large.";
+-	} else qWarning() << "Image "<< rep->url().toString() << " download failed.";
++		// Sniff the format instead of relying on the MIME type.
++		// There are many misconfigured servers out there and
++		// Mumble has historically sniffed the received data
++		// instead of strictly requiring a correct Content-Type.
++		if (RichTextImage::isValidImage(ba, fmt)) {
++			if (qi.loadFromData(ba, fmt)) {
++				bool ok = true;
++				if (rep->url().scheme() != QLatin1String("data")) {
++					ok = (qi.width() <= g.s.iMaxImageWidth && qi.height() <= g.s.iMaxImageHeight);
++				}
++				if (ok) {
++					addResource(QTextDocument::ImageResource, rep->request().url(), qi);
++
++					// Force a re-layout of the QTextEdit the next
++					// time we enter the event loop.
++					// We must not trigger a re-layout immediately.
++					// Doing so can trigger crashes deep inside Qt
++					// if the QTextDocument has just been set on the
++					// text edit widget.
++					QTextEdit *qte = qobject_cast<QTextEdit *>(parent());
++					if (qte != NULL) {
++						QEvent *e = new QEvent(QEvent::FontChange);
++						QApplication::postEvent(qte, e);
++					}
++				} else {
++					m_valid = false;
++				}
++			}
++		} else {
++			m_valid = false;
++		}
++	}
+ 
+ 	rep->deleteLater();
+ }
+--- a/src/mumble/Log.h
++++ b/src/mumble/Log.h
+@@ -96,29 +96,23 @@
+ 		void log(MsgType t, const QString &console, const QString &terse=QString());
+ };
+ 
+-class ValidDocument : public QTextDocument {
+-	private:
+-		Q_OBJECT
+-		Q_DISABLE_COPY(ValidDocument)
+-	protected:
+-		QStringList qslValidImage;
+-		bool bValid;
+-		QVariant loadResource(int, const QUrl &);
+-	public:
+-		ValidDocument(bool httpimages, QObject *p = NULL);
+-		bool isValid() const;
+-};
+-
+ class LogDocument : public QTextDocument {
+ 	private:
+ 		Q_OBJECT
+ 		Q_DISABLE_COPY(LogDocument)
+ 	public:
+ 		LogDocument(QObject *p = NULL);
+-		QVariant loadResource(int, const QUrl &);
++		virtual QVariant loadResource(int, const QUrl &);
++		void setAllowHTTPResources(bool allowHttpResources);
++		void setOnlyLoadDataURLs(bool onlyLoadDataURLs);
++		bool isValid();
+ 	public slots:
+ 		void receivedHead();
+ 		void finished();
++	private:
++		bool m_allowHTTPResources;
++		bool m_valid;
++		bool m_onlyLoadDataURLs;
+ };
+ 
+ #else
+--- a/src/mumble/MainWindow.cpp
++++ b/src/mumble/MainWindow.cpp
+@@ -50,6 +50,7 @@
+ #include "Plugins.h"
+ #include "Log.h"
+ #include "Overlay.h"
++#include "RichTextEditor.h"
+ #include "Global.h"
+ #include "Database.h"
+ #include "ViewCert.h"
+@@ -2350,7 +2351,7 @@
+ 	if (g.s.qsImagePath.isEmpty() || ! QDir::root().exists(g.s.qsImagePath))
+ 		g.s.qsImagePath = QDesktopServices::storageLocation(QDesktopServices::PicturesLocation);
+ 
+-	QString fname = QFileDialog::getOpenFileName(this, tr("Choose image file"), g.s.qsImagePath, tr("Images (*.png *.jpg *.svg)"));
++	QString fname = QFileDialog::getOpenFileName(this, tr("Choose image file"), g.s.qsImagePath, tr("Images (*.png *.jpg *.jpeg)"));
+ 
+ 	if (fname.isNull())
+ 		return retval;
+@@ -2370,7 +2371,17 @@
+ 	QBuffer qb(&qba);
+ 	qb.open(QIODevice::ReadOnly);
+ 
+-	QImageReader qir(&qb, fi.suffix().toUtf8());
++	QImageReader qir;
++	qir.setAutoDetectImageFormat(false);
++
++	QByteArray fmt;
++	if (!RichTextImage::isValidImage(qba, fmt)) {
++		QMessageBox::warning(this, tr("Failed to load image"), tr("Image format not recognized."));
++		return retval;
++	}
++
++	qir.setFormat(fmt);
++	qir.setDevice(&qb);
+ 
+ 	QImage img = qir.read();
+ 	if (img.isNull()) {
+--- a/src/mumble/Overlay.cpp
++++ b/src/mumble/Overlay.cpp
+@@ -33,6 +33,7 @@
+ #include "Channel.h"
+ #include "Global.h"
+ #include "Message.h"
++#include "RichTextEditor.h"
+ #include "Database.h"
+ #include "ServerHandler.h"
+ 
+@@ -799,15 +800,23 @@
+ 			qb.open(QIODevice::ReadOnly);
+ 
+ 			QImageReader qir;
+-			if (cp->qbaTexture.startsWith("<?xml"))
+-				qir.setFormat("svg");
+-			qir.setDevice(&qb);
+-			if (! qir.canRead() || (qir.size().width() > 1024) || (qir.size().height() > 1024)) {
+-				valid = false;
++			qir.setAutoDetectImageFormat(false);
++
++			QByteArray fmt;
++			if (RichTextImage::isValidImage(cp->qbaTexture, fmt)) {
++				qir.setFormat(fmt);
++				qir.setDevice(&qb);
++				if (! qir.canRead() || (qir.size().width() > 1024) || (qir.size().height() > 1024)) {
++					valid = false;
++				} else {
++					cp->qbaTextureFormat = qir.format();
++					QImage qi = qir.read();
++					valid = ! qi.isNull();
++				}
+ 			} else {
+ 				cp->qbaTextureFormat = qir.format();
+ 				QImage qi = qir.read();
+-				valid = ! qi.isNull();
++				valid = false;
+ 			}
+ 		}
+ 		if (! valid) {
+--- a/src/mumble/RichTextEditor.cpp
++++ b/src/mumble/RichTextEditor.cpp
+@@ -34,6 +34,8 @@
+ #include "Log.h"
+ 
+ RichTextHtmlEdit::RichTextHtmlEdit(QWidget *p) : QTextEdit(p) {
++	m_document = new LogDocument(this);
++	setDocument(m_document);
+ }
+ 
+ /* On nix, some programs send utf8, some send wchar_t. Some zeroterminate once, some twice, some not at all.
+@@ -620,3 +622,20 @@
+ 	bChanged = false;
+ 	return qptePlainText->toPlainText();
+ }
++
++bool RichTextImage::isValidImage(const QByteArray &ba, QByteArray &fmt) {
++	QBuffer qb;
++	qb.setData(ba);
++	if (!qb.open(QIODevice::ReadOnly)) {
++		return false;
++	}
++
++	QByteArray detectedFormat = QImageReader::imageFormat(&qb).toLower();
++	if (detectedFormat == QByteArray("png") || detectedFormat == QByteArray("jpg")
++	     || detectedFormat == QByteArray("jpeg") || detectedFormat == QByteArray("gif")) {
++		fmt = detectedFormat;
++		return true;
++	}
++
++	return false;
++}
+--- a/src/mumble/RichTextEditor.h
++++ b/src/mumble/RichTextEditor.h
+@@ -33,6 +33,8 @@
+ 
+ #include "mumble_pch.hpp"
+ 
++class LogDocument;
++
+ class RichTextHtmlEdit : public QTextEdit {
+ 	private:
+ 		Q_OBJECT
+@@ -41,6 +43,8 @@
+ 		void insertFromMimeData(const QMimeData *source);
+ 	public:
+ 		RichTextHtmlEdit(QWidget *p);
++	private:
++		LogDocument *m_document;
+ };
+ 
+ #include "ui_RichTextEditor.h"
+@@ -89,4 +93,9 @@
+ 		void onCurrentChanged(int);
+ };
+ 
++class RichTextImage {
++	public:
++		static bool isValidImage(const QByteArray &buf, QByteArray &fmt);
++};
++
+ #endif
+--- a/src/mumble/ServerHandler.cpp
++++ b/src/mumble/ServerHandler.cpp
+@@ -39,6 +39,7 @@
+ #include "Global.h"
+ #include "Database.h"
+ #include "PacketDataStream.h"
++#include "RichTextEditor.h"
+ #include "NetworkConfig.h"
+ #include "OSInfo.h"
+ #include "SSL.h"
+@@ -588,11 +589,19 @@
+ 		texture = qba;
+ 	} else {
+ 		QByteArray raw = qba;
++
+ 		QBuffer qb(& raw);
+ 		qb.open(QIODevice::ReadOnly);
++
+ 		QImageReader qir;
+-		if (qba.startsWith("<?xml"))
+-			qir.setFormat("svg");
++		qir.setDecideFormatFromContent(false);
++
++		QByteArray fmt;
++		if (!RichTextImage::isValidImage(qba, fmt)) {
++			return;
++		}
++
++		qir.setFormat(fmt);
+ 		qir.setDevice(&qb);
+ 
+ 		QSize sz = qir.size();
diff -Nru mumble-1.2.2/debian/patches/0007-fix-CVE-2014-3756.patch mumble-1.2.2/debian/patches/0007-fix-CVE-2014-3756.patch
--- mumble-1.2.2/debian/patches/0007-fix-CVE-2014-3756.patch	1969-12-31 19:00:00.000000000 -0500
+++ mumble-1.2.2/debian/patches/0007-fix-CVE-2014-3756.patch	2015-12-25 23:24:06.000000000 -0500
@@ -0,0 +1,512 @@
+Description: patch to fix CVE-2014-3756
+ Patch ported by Chris Knadle <Chris.Knadle@coredump.us> from fix
+ for the same bug for mumble in wheezy.
+commit e30d7acda6c04b667618ac86f49786cf966a08fb
+Author: Mikkel Krautz <mikkel@krautz.dk>
+Date:   Tue May 13 20:54:27 2014 +0200
+Last-Updated: 2015-12-25
+
+    mumble: fix Mumble-SA-2014-006.
+    
+    Usernames and channel names were not properly HTML-escaped
+    when used in Qt widgets that are rich-text enabled.
+    
+    This commit fixes that, but also touches various other
+    similar cases where an escaped version is appropriate.
+    
+    This commit is based on the following commits from the
+    master branch (Mumble 1.3.0):
+    
+      b7d9387bd6dacbad0b2345f03dd8502a51c42f6a
+      1caaec763b91c8a12b11d7ceb37e21622f4da76e
+      a0ebded7df388ce625dfbeb0c2bd65fb782da2a4
+      c52dedce8409da0654fd197690ff95411df3f9b2
+      1f6ddaf35f9583ef72f2d924b76b425ec85fc692
+      73a1a98d16a29c78d85e1c19b8feac7ba22dddfe
+      d58990c374502cfdd4a5f2bd8dbd490f19e9e511
+      b6e17cac696396d5bcbc3391846f9cacb9c072c4
+      9837c4dc2d1d6c60505f7246cd00ffa33ad808a9
+      17fa695b222a8b308438f9283e78dfba931e8712
+      d9ff1e947d4d00f6cd8d38fd04cd87f6e3167028
+    
+    Special thanks to Tim Cooper for various of the above
+    patches.
+
+--- a/src/mumble/ALSAAudio.cpp
++++ b/src/mumble/ALSAAudio.cpp
+@@ -360,7 +360,7 @@
+ 			snd_pcm_close(capture_handle);
+ 			capture_handle = NULL;
+ 		}
+-		g.mw->msgBox(tr("Opening chosen ALSA Input failed: %1").arg(QLatin1String(snd_strerror(err))));
++		g.mw->msgBox(tr("Opening chosen ALSA Input failed: %1").arg(Qt::escape(QLatin1String(snd_strerror(err)))));
+ 		return;
+ 	}
+ 
+@@ -495,7 +495,7 @@
+ 			snd_pcm_writei(pcm_handle, zerobuff, period_size);
+ 
+ 	if (! bOk) {
+-		g.mw->msgBox(tr("Opening chosen ALSA Output failed: %1").arg(QLatin1String(snd_strerror(err))));
++		g.mw->msgBox(tr("Opening chosen ALSA Output failed: %1").arg(Qt::escape(QLatin1String(snd_strerror(err)))));
+ 		if (pcm_handle) {
+ 			snd_pcm_close(pcm_handle);
+ 			pcm_handle = NULL;
+--- a/src/mumble/ASIOInput.cpp
++++ b/src/mumble/ASIOInput.cpp
+@@ -266,7 +266,7 @@
+ 			char err[255];
+ 			iasio->getErrorMessage(err);
+ 			SleepEx(10, false);
+-			QMessageBox::critical(this, QLatin1String("Mumble"), tr("ASIO Initialization failed: %1").arg(QLatin1String(err)), QMessageBox::Ok, QMessageBox::NoButton);
++			QMessageBox::critical(this, QLatin1String("Mumble"), tr("ASIO Initialization failed: %1").arg(Qt::escape(QLatin1String(err))), QMessageBox::Ok, QMessageBox::NoButton);
+ 		}
+ 		iasio->Release();
+ 	} else {
+@@ -293,7 +293,7 @@
+ 			char err[255];
+ 			iasio->getErrorMessage(err);
+ 			SleepEx(10, false);
+-			QMessageBox::critical(this, QLatin1String("Mumble"), tr("ASIO Initialization failed: %1").arg(QLatin1String(err)), QMessageBox::Ok, QMessageBox::NoButton);
++			QMessageBox::critical(this, QLatin1String("Mumble"), tr("ASIO Initialization failed: %1").arg(Qt::escape(QLatin1String(err))), QMessageBox::Ok, QMessageBox::NoButton);
+ 		}
+ 		iasio->Release();
+ 	} else {
+--- a/src/mumble/ASIOInput.ui
++++ b/src/mumble/ASIOInput.ui
+@@ -99,6 +99,9 @@
+         <property name="text">
+          <string/>
+         </property>
++        <property name="textFormat">
++         <enum>Qt::PlainText</enum>
++        </property>
+        </widget>
+       </item>
+       <item row="1" column="0">
+@@ -119,6 +122,9 @@
+         <property name="text">
+          <string/>
+         </property>
++        <property name="textFormat">
++         <enum>Qt::PlainText</enum>
++        </property>
+        </widget>
+       </item>
+      </layout>
+--- a/src/mumble/AudioConfigDialog.cpp
++++ b/src/mumble/AudioConfigDialog.cpp
+@@ -350,7 +350,7 @@
+ 
+ 		foreach(audioDevice d, ql) {
+ 			qcbDevice->addItem(d.first, d.second);
+-			qcbDevice->setItemData(idx, d.first, Qt::ToolTipRole);
++			qcbDevice->setItemData(idx, Qt::escape(d.first), Qt::ToolTipRole);
+ 			++idx;
+ 		}
+ 
+@@ -483,7 +483,7 @@
+ 
+ 		foreach(audioDevice d, ql) {
+ 			qcbDevice->addItem(d.first, d.second);
+-			qcbDevice->setItemData(idx, d.first, Qt::ToolTipRole);
++			qcbDevice->setItemData(idx, Qt::escape(d.first), Qt::ToolTipRole);
+ 			++idx;
+ 		}
+ 		bool canmute = aor->canMuteOthers();
+--- a/src/mumble/AudioOutput.cpp
++++ b/src/mumble/AudioOutput.cpp
+@@ -297,7 +297,7 @@
+ 		if ((sf = AudioOutputSample::loadSndfile(file)) == NULL) {
+ 			QMessageBox::critical(NULL,
+ 			                      tr("Invalid sound file"),
+-			                      tr("The file '%1' cannot be used by Mumble. Please select a file with a compatible format and encoding.").arg(file));
++			                      tr("The file '%1' cannot be used by Mumble. Please select a file with a compatible format and encoding.").arg(Qt::escape(file)));
+ 			return QString();
+ 		}
+ 		delete sf;
+--- a/src/mumble/Cert.cpp
++++ b/src/mumble/Cert.cpp
+@@ -51,6 +51,7 @@
+ 	grid->addWidget(l, 0, 0, 1, 1, Qt::AlignRight);
+ 
+ 	qlSubjectName = new QLabel();
++	qlSubjectName->setTextFormat(Qt::PlainText);
+ 	qlSubjectName->setWordWrap(true);
+ 	grid->addWidget(qlSubjectName, 0, 1, 1, 1);
+ 
+@@ -58,6 +59,7 @@
+ 	grid->addWidget(l, 1, 0, 1, 1, Qt::AlignRight);
+ 
+ 	qlSubjectEmail = new QLabel();
++	qlSubjectEmail->setTextFormat(Qt::PlainText);
+ 	qlSubjectEmail->setWordWrap(true);
+ 	grid->addWidget(qlSubjectEmail, 1, 1, 1, 1);
+ 
+@@ -65,6 +67,7 @@
+ 	grid->addWidget(l, 2, 0, 1, 1, Qt::AlignRight);
+ 
+ 	qlIssuerName = new QLabel();
++	qlIssuerName->setTextFormat(Qt::PlainText);
+ 	qlIssuerName->setWordWrap(true);
+ 	grid->addWidget(qlIssuerName, 2, 1, 1, 1);
+ 
+@@ -100,12 +103,12 @@
+ 		qlSubjectName->setText(tmpName);
+ 
+ 		if (emails.count() > 0)
+-			qlSubjectEmail->setText(emails.join(QLatin1String("<br />")));
++			qlSubjectEmail->setText(emails.join(QLatin1String("\n")));
+ 		else
+ 			qlSubjectEmail->setText(tr("(none)"));
+ 
+ 		if (qscCert.expiryDate() <= QDateTime::currentDateTime())
+-			qlExpiry->setText(QString::fromLatin1("<font color=\"red\"><b>%1</b></font>").arg(qscCert.expiryDate().toString(Qt::SystemLocaleDate)));
++			qlExpiry->setText(QString::fromLatin1("<font color=\"red\"><b>%1</b></font>").arg(Qt::escape(qscCert.expiryDate().toString(Qt::SystemLocaleDate))));
+ 		else
+ 			qlExpiry->setText(qscCert.expiryDate().toString(Qt::SystemLocaleDate));
+ 
+--- a/src/mumble/ConnectDialog.cpp
++++ b/src/mumble/ConnectDialog.cpp
+@@ -447,7 +447,7 @@
+ 		} else if (role == Qt::ToolTipRole) {
+ 			QStringList qsl;
+ 			foreach(const QHostAddress &qha, qlAddresses)
+-				qsl << qha.toString();
++				qsl << Qt::escape(qha.toString());
+ 
+ 			double ploss = 100.0;
+ 
+@@ -457,18 +457,17 @@
+ 			QString qs;
+ 			qs +=
+ 			    QLatin1String("<table>") +
+-			    QString::fromLatin1("<tr><th align=left>%1</th><td>%2</td></tr>").arg(ConnectDialog::tr("Servername"), qsName) +
+-			    QString::fromLatin1("<tr><th align=left>%1</th><td>%2</td></tr>").arg(ConnectDialog::tr("Hostname"), qsHostname);
+-
++			    QString::fromLatin1("<tr><th align=left>%1</th><td>%2</td></tr>").arg(ConnectDialog::tr("Servername"), Qt::escape(qsName)) +
++			    QString::fromLatin1("<tr><th align=left>%1</th><td>%2</td></tr>").arg(ConnectDialog::tr("Hostname"), Qt::escape(qsHostname));
+ 			if (! qsBonjourHost.isEmpty())
+-				qs += QString::fromLatin1("<tr><th align=left>%1</th><td>%2</td></tr>").arg(ConnectDialog::tr("Bonjour name"), qsBonjourHost);
++				qs += QString::fromLatin1("<tr><th align=left>%1</th><td>%2</td></tr>").arg(ConnectDialog::tr("Bonjour name"), Qt::escape(qsBonjourHost));
+ 
+ 			qs +=
+ 			    QString::fromLatin1("<tr><th align=left>%1</th><td>%2</td></tr>").arg(ConnectDialog::tr("Port")).arg(usPort) +
+ 			    QString::fromLatin1("<tr><th align=left>%1</th><td>%2</td></tr>").arg(ConnectDialog::tr("Addresses"), qsl.join(QLatin1String(", ")));
+ 
+ 			if (! qsUrl.isEmpty())
+-				qs += QString::fromLatin1("<tr><th align=left>%1</th><td>%2</td></tr>").arg(ConnectDialog::tr("Website"), qsUrl);
++				qs += QString::fromLatin1("<tr><th align=left>%1</th><td>%2</td></tr>").arg(ConnectDialog::tr("Website"), Qt::escape(qsUrl));
+ 
+ 			if (uiSent > 0) {
+ 				qs += QString::fromLatin1("<tr><th align=left>%1</th><td>%2</td></tr>").arg(ConnectDialog::tr("Packet loss"), QString::fromLatin1("%1% (%2/%3)").arg(ploss, 0, 'f', 1).arg(uiRecv).arg(uiSent));
+@@ -622,7 +621,7 @@
+ 	mime->setUrls(urls);
+ 
+ 	mime->setText(qs);
+-	mime->setHtml(QString::fromLatin1("<a href=\"%1\">%2</a>").arg(qs).arg(qsName));
++	mime->setHtml(QString::fromLatin1("<a href=\"%1\">%2</a>").arg(qs).arg(Qt::escape(qsName)));
+ 
+ 	if (itType == FavoriteType)
+ 		mime->setData(QLatin1String("OriginatedInMumble"), QByteArray());
+--- a/src/mumble/Database.cpp
++++ b/src/mumble/Database.cpp
+@@ -88,7 +88,7 @@
+ 	QFileInfo fi(db.databaseName());
+ 
+ 	if (! fi.isWritable()) {
+-		QMessageBox::critical(NULL, QLatin1String("Mumble"), tr("The database '%1' is read-only. Mumble can not store server settings (ie. SSL certificates) until you fix this problem.").arg(fi.filePath()), QMessageBox::Ok | QMessageBox::Default, QMessageBox::NoButton);
++		QMessageBox::critical(NULL, QLatin1String("Mumble"), tr("The database '%1' is read-only. Mumble cannot store server settings (i.e. SSL certificates) until you fix this problem.").arg(Qt::escape(fi.filePath())), QMessageBox::Ok | QMessageBox::Default, QMessageBox::NoButton);
+ 		qWarning("Database: Database is read-only");
+ 	}
+ 
+--- a/src/mumble/LCD.cpp
++++ b/src/mumble/LCD.cpp
+@@ -109,7 +109,7 @@
+ 		qtwi->setFlags(Qt::ItemIsEnabled |Qt::ItemIsUserCheckable);
+ 
+ 		qtwi->setText(0, d->name());
+-		qtwi->setToolTip(0, d->name());
++		qtwi->setToolTip(0, Qt::escape(d->name()));
+ 
+ 		QSize lcdsize = d->size();
+ 		QString qsSize = QString::fromLatin1("%1x%2").arg(lcdsize.width()).arg(lcdsize.height());
+--- a/src/mumble/Log.cpp
++++ b/src/mumble/Log.cpp
+@@ -267,7 +267,7 @@
+ }
+ 
+ QString Log::formatChannel(::Channel *c) {
+-	return QString::fromLatin1("<a href='channelid://%1/%3' class='log-channel'>%2</a>").arg(c->iId).arg(c->qsName).arg(QString::fromLatin1(g.sh->qbaDigest.toBase64()));
++	return QString::fromLatin1("<a href='channelid://%1/%3' class='log-channel'>%2</a>").arg(c->iId).arg(Qt::escape(c->qsName)).arg(QString::fromLatin1(g.sh->qbaDigest.toBase64()));
+ }
+ 
+ QString Log::formatClientUser(ClientUser *cu, LogColorType t) {
+@@ -279,10 +279,11 @@
+ 	}
+ 
+ 	if (cu) {
++		QString name = Qt::escape(cu->qsName);
+ 		if (cu->qsHash.isEmpty()) {
+-			return QString::fromLatin1("<a href='clientid://%2/%4' class='log-user log-%1'>%3</a>").arg(className).arg(cu->uiSession).arg(cu->qsName).arg(QString::fromLatin1(g.sh->qbaDigest.toBase64()));
++			return QString::fromLatin1("<a href='clientid://%2/%4' class='log-user log-%1'>%3</a>").arg(className).arg(cu->uiSession).arg(name).arg(QString::fromLatin1(g.sh->qbaDigest.toBase64()));
+ 		} else {
+-			return QString::fromLatin1("<a href='clientid://%2' class='log-user log-%1'>%3</a>").arg(className).arg(cu->qsHash).arg(cu->qsName);
++			return QString::fromLatin1("<a href='clientid://%2' class='log-user log-%1'>%3</a>").arg(className).arg(cu->qsHash).arg(name);
+ 		}
+ 	} else {
+ 		return QString::fromLatin1("<span class='log-server log-%1'>%2</span>").arg(className).arg(tr("the server"));
+@@ -454,7 +455,7 @@
+ 		if (qdDate != dt.date()) {
+ 			qdDate = dt.date();
+ 			tc.insertBlock();
+-			tc.insertHtml(tr("[Date changed to %1]\n").arg(qdDate.toString(Qt::DefaultLocaleShortDate)));
++			tc.insertHtml(tr("[Date changed to %1]\n").arg(Qt::escape(qdDate.toString(Qt::DefaultLocaleShortDate))));
+ 			tc.movePosition(QTextCursor::End);
+ 		}
+ 
+@@ -467,7 +468,7 @@
+ 		} else if (! g.mw->qteLog->document()->isEmpty()) {
+ 			tc.insertBlock();
+ 		}
+-		tc.insertHtml(Log::msgColor(QString::fromLatin1("[%1] ").arg(dt.time().toString(Qt::DefaultLocaleShortDate)), Log::Time));
++		tc.insertHtml(Log::msgColor(QString::fromLatin1("[%1] ").arg(Qt::escape(dt.time().toString(Qt::DefaultLocaleShortDate))), Log::Time));
+ 		validHtml(console, true, &tc);
+ 		tc.movePosition(QTextCursor::End);
+ 		g.mw->qteLog->setTextCursor(tc);
+--- a/src/mumble/MainWindow.cpp
++++ b/src/mumble/MainWindow.cpp
+@@ -509,7 +509,7 @@
+ }
+ 
+ void MainWindow::openUrl(const QUrl &url) {
+-	g.l->log(Log::Information, tr("Opening URL %1").arg(url.toString()));
++	g.l->log(Log::Information, tr("Opening URL %1").arg(Qt::escape(url.toString())));
+ 	if (url.scheme() == QLatin1String("file")) {
+ 		QFile f(url.toLocalFile());
+ 		if (! f.exists() || ! f.open(QIODevice::ReadOnly)) {
+@@ -607,7 +607,7 @@
+ 	g.s.qsLastServer = name;
+ 	rtLast = MumbleProto::Reject_RejectType_None;
+ 	qaServerDisconnect->setEnabled(true);
+-	g.l->log(Log::Information, tr("Connecting to server %1.").arg(Log::msgColor(host, Log::Server)));
++	g.l->log(Log::Information, tr("Connecting to server %1.").arg(Log::msgColor(Qt::escape(host), Log::Server)));
+ 	g.sh->setConnectionInfo(host, port, user, pw);
+ 	g.sh->start(QThread::TimeCriticalPriority);
+ }
+@@ -791,7 +791,7 @@
+ 		qsDesiredChannel = QString();
+ 		rtLast = MumbleProto::Reject_RejectType_None;
+ 		qaServerDisconnect->setEnabled(true);
+-		g.l->log(Log::Information, tr("Connecting to server %1.").arg(Log::msgColor(cd->qsServer, Log::Server)));
++		g.l->log(Log::Information, tr("Connecting to server %1.").arg(Log::msgColor(Qt::escape(cd->qsServer), Log::Server)));
+ 		g.sh->setConnectionInfo(cd->qsServer, cd->usPort, cd->qsUsername, cd->qsPassword);
+ 		g.sh->start(QThread::TimeCriticalPriority);
+ 	}
+@@ -858,7 +858,7 @@
+ 		return;
+ 
+ 	QMessageBox::StandardButton result;
+-	result = QMessageBox::question(this, tr("Register yourself as %1").arg(p->qsName), tr("<p>You are about to register yourself on this server. This action cannot be undone, and your username cannot be changed once this is done. You will forever be known as '%1' on this server.</p><p>Are you sure you want to register yourself?</p>").arg(p->qsName), QMessageBox::Yes|QMessageBox::No);
++	result = QMessageBox::question(this, tr("Register yourself as %1").arg(p->qsName), tr("<p>You are about to register yourself on this server. This action cannot be undone, and your username cannot be changed once this is done. You will forever be known as '%1' on this server.</p><p>Are you sure you want to register yourself?</p>").arg(Qt::escape(p->qsName)), QMessageBox::Yes|QMessageBox::No);
+ 
+ 	if (result == QMessageBox::Yes)
+ 		g.sh->registerUser(p->uiSession);
+@@ -932,7 +932,7 @@
+ 		qsVersion.append(tr("<p>No build information or OS version available.</p>"));
+ 	} else {
+ 		qsVersion.append(tr("<p>%1 (%2)<br />%3</p>")
+-		                 .arg(g.sh->qsRelease, g.sh->qsOS, g.sh->qsOSVersion));
++		                 .arg(Qt::escape(g.sh->qsRelease), Qt::escape(g.sh->qsOS), Qt::escape(g.sh->qsOSVersion)));
+ 	}
+ 
+ 	QString host, uname, pw;
+@@ -941,10 +941,10 @@
+ 	g.sh->getConnectionInfo(host,port,uname,pw);
+ 
+ 	QString qsControl=tr("<h2>Control channel</h2><p>Encrypted with %1 bit %2<br />%3 ms average latency (%4 deviation)</p><p>Remote host %5 (port %6)</p>").arg(QString::number(qsc.usedBits()),
+-	                  qsc.name(),
++	                  Qt::escape(qsc.name()),
+ 	                  QString::fromLatin1("%1").arg(boost::accumulators::mean(g.sh->accTCP), 0, 'f', 2),
+ 	                  QString::fromLatin1("%1").arg(sqrt(boost::accumulators::variance(g.sh->accTCP)),0,'f',2),
+-	                  host,
++	                  Qt::escape(host),
+ 	                  QString::number(port));
+ 	QString qsVoice, qsCrypt, qsAudio;
+ 
+@@ -1139,9 +1139,9 @@
+ 	QMessageBox::StandardButton result;
+ 
+ 	if (session == g.uiSession)
+-		result = QMessageBox::question(this, tr("Register yourself as %1").arg(p->qsName), tr("<p>You are about to register yourself on this server. This action cannot be undone, and your username cannot be changed once this is done. You will forever be known as '%1' on this server.</p><p>Are you sure you want to register yourself?</p>").arg(p->qsName), QMessageBox::Yes|QMessageBox::No);
++		result = QMessageBox::question(this, tr("Register yourself as %1").arg(p->qsName), tr("<p>You are about to register yourself on this server. This action cannot be undone, and your username cannot be changed once this is done. You will forever be known as '%1' on this server.</p><p>Are you sure you want to register yourself?</p>").arg(Qt::escape(p->qsName)), QMessageBox::Yes|QMessageBox::No);
+ 	else
+-		result = QMessageBox::question(this, tr("Register user %1").arg(p->qsName), tr("<p>You are about to register %1 on the server. This action cannot be undone, the username cannot be changed, and as a registered user, %1 will have access to the server even if you change the server password.</p><p>From this point on, %1 will be authenticated with the certificate currently in use.</p><p>Are you sure you want to register %1?</p>").arg(p->qsName), QMessageBox::Yes|QMessageBox::No);
++		result = QMessageBox::question(this, tr("Register user %1").arg(p->qsName), tr("<p>You are about to register %1 on the server. This action cannot be undone, the username cannot be changed, and as a registered user, %1 will have access to the server even if you change the server password.</p><p>From this point on, %1 will be authenticated with the certificate currently in use.</p><p>Are you sure you want to register %1?</p>").arg(Qt::escape(p->qsName)), QMessageBox::Yes|QMessageBox::No);
+ 
+ 	if (result == QMessageBox::Yes) {
+ 		p = ClientUser::get(session);
+@@ -1267,7 +1267,7 @@
+ 	unsigned int session = p->uiSession;
+ 
+ 	int ret = QMessageBox::question(this, QLatin1String("Mumble"),
+-	                                tr("Are you sure you want to reset the comment of user %1?").arg(p->qsName),
++	                                tr("Are you sure you want to reset the comment of user %1?").arg(Qt::escape(p->qsName)),
+ 	                                QMessageBox::Yes, QMessageBox::No);
+ 	if (ret == QMessageBox::Yes) {
+ 		g.sh->setUserComment(session, QString());
+@@ -1452,7 +1452,7 @@
+ 
+ 	int id = c->iId;
+ 
+-	ret=QMessageBox::question(this, QLatin1String("Mumble"), tr("Are you sure you want to delete %1 and all its sub-channels?").arg(c->qsName), QMessageBox::Yes, QMessageBox::No);
++	ret=QMessageBox::question(this, QLatin1String("Mumble"), tr("Are you sure you want to delete %1 and all its sub-channels?").arg(Qt::escape(c->qsName)), QMessageBox::Yes, QMessageBox::No);
+ 
+ 	c = Channel::get(id);
+ 	if (!c)
+@@ -2079,7 +2079,7 @@
+ 
+ 	if (! g.sh->qlErrors.isEmpty()) {
+ 		foreach(QSslError e, g.sh->qlErrors)
+-			g.l->log(Log::Warning, tr("SSL Verification failed: %1").arg(e.errorString()));
++			g.l->log(Log::Warning, tr("SSL Verification failed: %1").arg(Qt::escape(e.errorString())));
+ 		if (! g.sh->qscCert.isEmpty()) {
+ 			QSslCertificate c = g.sh->qscCert.at(0);
+ 			QString basereason;
+@@ -2090,7 +2090,7 @@
+ 			}
+ 			QStringList qsl;
+ 			foreach(QSslError e, g.sh->qlErrors)
+-				qsl << QString::fromLatin1("<li>%1</li>").arg(e.errorString());
++				qsl << QString::fromLatin1("<li>%1</li>").arg(Qt::escape(e.errorString()));
+ 
+ 			QMessageBox qmb(QMessageBox::Warning, QLatin1String("Mumble"),
+ 			                tr("<p>%1.<br />The specific errors with this certificate are: </p><ol>%2</ol>"
+@@ -2150,7 +2150,7 @@
+ 		bool matched = false;
+ 
+ 		if (! reason.isEmpty()) {
+-			g.l->log(Log::ServerDisconnected, tr("Server connection failed: %1.").arg(reason));
++			g.l->log(Log::ServerDisconnected, tr("Server connection failed: %1.").arg(Qt::escape(reason)));
+ 		}  else {
+ 			g.l->log(Log::ServerDisconnected, tr("Disconnected from server."));
+ 		}
+@@ -2257,10 +2257,10 @@
+ 		if (c == NULL) // If no channel selected fallback to current one
+ 			c = ClientUser::get(g.uiSession)->cChannel;
+ 
+-		qleChat->setDefaultText(tr("Type message to channel '%1' here").arg(c->qsName));
++		qleChat->setDefaultText(tr("Type message to channel '%1' here").arg(Qt::escape(c->qsName)));
+ 	} else {
+ 		// User target
+-		qleChat->setDefaultText(tr("Type message to user '%1' here").arg(p->qsName));
++		qleChat->setDefaultText(tr("Type message to user '%1' here").arg(Qt::escape(p->qsName)));
+ 	}
+ 
+ 	updateMenuPermissions();
+--- a/src/mumble/Messages.cpp
++++ b/src/mumble/Messages.cpp
+@@ -85,7 +85,7 @@
+ 
+ void MainWindow::msgReject(const MumbleProto::Reject &msg) {
+ 	rtLast = msg.type();
+-	g.l->log(Log::ServerDisconnected, tr("Server connection rejected: %1.").arg(u8(msg.reason())));
++	g.l->log(Log::ServerDisconnected, tr("Server connection rejected: %1.").arg(Qt::escape(u8(msg.reason()))));
+ 	g.l->setIgnore(Log::ServerDisconnected, 1);
+ }
+ 
+@@ -126,7 +126,7 @@
+ 	ClientUser *p=ClientUser::get(g.uiSession);
+ 	connect(p, SIGNAL(talkingChanged()), this, SLOT(talkingChanged()));
+ 
+-	qstiIcon->setToolTip(tr("Mumble: %1").arg(Channel::get(0)->qsName));
++	qstiIcon->setToolTip(tr("Mumble: %1").arg(Qt::escape(Channel::get(0)->qsName)));
+ 	updateTrayIcon();
+ }
+ 
+@@ -180,7 +180,7 @@
+ 				g.s.bTTS = true;
+ 				quint32 oflags = g.s.qmMessages.value(Log::PermissionDenied);
+ 				g.s.qmMessages[Log::PermissionDenied] = (oflags | Settings::LogTTS) & (~Settings::LogSoundfile);
+-				g.l->log(Log::PermissionDenied, QString::fromAscii(m).arg(g.s.qsUsername));
++				g.l->log(Log::PermissionDenied, QString::fromAscii(m).arg(Qt::escape(g.s.qsUsername)));
+ 				g.s.qmMessages[Log::PermissionDenied] = oflags;
+ 				g.s.bDeaf = bold;
+ 				g.s.bTTS = bold2;
+@@ -202,7 +202,7 @@
+ 			break;
+ 		case MumbleProto::PermissionDenied_DenyType_UserName: {
+ 				if (msg.has_name())
+-					g.l->log(Log::PermissionDenied, tr("Invalid username: %1.").arg(u8(msg.name())));
++					g.l->log(Log::PermissionDenied, tr("Invalid username: %1.").arg(Qt::escape(u8(msg.name()))));
+ 				else
+ 					g.l->log(Log::PermissionDenied, tr("Invalid username."));
+ 			}
+@@ -213,7 +213,7 @@
+ 			break;
+ 		default: {
+ 				if (msg.has_reason())
+-					g.l->log(Log::PermissionDenied, tr("Denied: %1.").arg(u8(msg.reason())));
++					g.l->log(Log::PermissionDenied, tr("Denied: %1.").arg(Qt::escape(u8(msg.reason()))));
+ 				else
+ 					g.l->log(Log::PermissionDenied, tr("Permission denied."));
+ 			}
+@@ -430,7 +430,7 @@
+ 	ACTOR_INIT;
+ 	SELF_INIT;
+ 
+-	QString reason = u8(msg.reason());
++	QString reason = Qt::escape(u8(msg.reason()));
+ 
+ 	if (pDst == pSelf) {
+ 		if (msg.ban())
+--- a/src/mumble/Overlay.cpp
++++ b/src/mumble/Overlay.cpp
+@@ -640,7 +640,7 @@
+ #endif
+ 
+ 	if (! qlsServer->listen(pipepath)) {
+-		QMessageBox::warning(NULL, QLatin1String("Mumble"), tr("Failed to create communication with overlay at %2: %1. No overlay will be available.").arg(qlsServer->errorString(),pipepath), QMessageBox::Ok, QMessageBox::NoButton);
++		QMessageBox::warning(NULL, QLatin1String("Mumble"), tr("Failed to create communication with overlay at %2: %1. No overlay will be available.").arg(Qt::escape(qlsServer->errorString()), Qt::escape(pipepath)), QMessageBox::Ok, QMessageBox::NoButton);
+ 	} else {
+ 		qWarning() << "Overlay: Listening on" << qlsServer->fullServerName();
+ 		connect(qlsServer, SIGNAL(newConnection()), this, SLOT(newConnection()));
+--- a/src/mumble/Plugins.cpp
++++ b/src/mumble/Plugins.cpp
+@@ -316,7 +316,7 @@
+ 	QMutexLocker lock(&qmPlugins);
+ 
+ 	if (prevlocked) {
+-		g.l->log(Log::Information, tr("%1 lost link.").arg(prevlocked->shortname));
++		g.l->log(Log::Information, tr("%1 lost link.").arg(Qt::escape(prevlocked->shortname)));
+ 		prevlocked = NULL;
+ 	}
+ 
+@@ -363,7 +363,7 @@
+ 	PluginInfo *pi = qlPlugins.at(iPluginTry);
+ 	if (pi->enabled && pi->p->trylock()) {
+ 		pi->shortname = QString::fromStdWString(pi->p->shortname);
+-		g.l->log(Log::Information, tr("%1 linked.").arg(pi->shortname));
++		g.l->log(Log::Information, tr("%1 linked.").arg(Qt::escape(pi->shortname)));
+ 		pi->locked = true;
+ 		bUnlink = false;
+ 		locked = pi;
+@@ -536,15 +536,15 @@
+ 						if (f.open(QIODevice::WriteOnly)) {
+ 							f.write(qba);
+ 							f.close();
+-							g.mw->msgBox(tr("Downloaded new or updated plugin to %1.").arg(f.fileName()));
++							g.mw->msgBox(tr("Downloaded new or updated plugin to %1.").arg(Qt::escape(f.fileName())));
+ 						} else {
+ 							f.setFileName(qsUserPlugins + QLatin1String("/") + fname);
+ 							if (f.open(QIODevice::WriteOnly)) {
+ 								f.write(qba);
+ 								f.close();
+-								g.mw->msgBox(tr("Downloaded new or updated plugin to %1.").arg(f.fileName()));
++								g.mw->msgBox(tr("Downloaded new or updated plugin to %1.").arg(Qt::escape(f.fileName())));
+ 							} else {
+-								g.mw->msgBox(tr("Failed to install new plugin to %1.").arg(f.fileName()));
++								g.mw->msgBox(tr("Failed to install new plugin to %1.").arg(Qt::escape(f.fileName())));
+ 							}
+ 						}
+ 
diff -Nru mumble-1.2.2/debian/patches/series mumble-1.2.2/debian/patches/series
--- mumble-1.2.2/debian/patches/series	2012-02-17 08:27:32.000000000 -0500
+++ mumble-1.2.2/debian/patches/series	2015-12-26 02:14:15.000000000 -0500
@@ -3,3 +3,5 @@
 0003-fix-long-username-query.patch
 0004-fix-username-validation.patch
 0005-set-file-permissions.patch
+0006-fix-CVE-2014-3755.patch
+0007-fix-CVE-2014-3756.patch

Attachment: signature.asc
Description: OpenPGP digital signature


Reply to: