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