From 8bcde84d892399ceeff0b818baa8d24c28b125af Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 27 Jun 2019 16:37:56 -0700 Subject: [PATCH] Disable remote QML unless whitelisted --- interface/src/Application.cpp | 15 +++++++++++++++ libraries/qml/src/qml/OffscreenSurface.cpp | 22 ++++++++++++++++++++++ libraries/qml/src/qml/OffscreenSurface.h | 6 +++++- 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 1a0030bc12..632a8c78ae 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3081,7 +3081,22 @@ void Application::showLoginScreen() { #endif } +static const QUrl AUTHORIZED_EXTERNAL_QML_SOURCE { "https://content.highfidelity.com/Experiences/Releases" }; + void Application::initializeUi() { + + // Allow remote QML content from trusted sources ONLY + { + auto defaultUrlValidator = OffscreenQmlSurface::getUrlValidator(); + auto newValidator = [=](const QUrl& url)->bool { + if (AUTHORIZED_EXTERNAL_QML_SOURCE.isParentOf(url)) { + return true; + } + return defaultUrlValidator(url); + }; + OffscreenQmlSurface::setUrlValidator(newValidator); + } + AddressBarDialog::registerType(); ErrorDialog::registerType(); LoginDialog::registerType(); diff --git a/libraries/qml/src/qml/OffscreenSurface.cpp b/libraries/qml/src/qml/OffscreenSurface.cpp index 69e6c833ee..117ff61c6e 100644 --- a/libraries/qml/src/qml/OffscreenSurface.cpp +++ b/libraries/qml/src/qml/OffscreenSurface.cpp @@ -23,6 +23,7 @@ #include #include +#include #include "Logging.h" #include "impl/SharedObject.h" @@ -33,6 +34,23 @@ using namespace hifi::qml; using namespace hifi::qml::impl; +QmlUrlValidator OffscreenSurface::validator = [](const QUrl& url) -> bool { + if (url.isRelative()) { + return true; + } + + if (url.isLocalFile()) { + return true; + } + + if (url.scheme() == URL_SCHEME_QRC) { + return true; + } + + // By default, only allow local QML, either from the local filesystem or baked into the QRC + return false; +}; + static uvec2 clampSize(const uvec2& size, uint32_t maxDimension) { return glm::clamp(size, glm::uvec2(1), glm::uvec2(maxDimension)); } @@ -307,6 +325,10 @@ void OffscreenSurface::loadInternal(const QUrl& qmlSource, // For desktop toolbar mode window: stop script when window is closed. if (qmlSource.isEmpty()) { getSurfaceContext()->engine()->quit(); + } + + if (!validator(qmlSource)) { + qCWarning(qmlLogging) << "Unauthorized QML URL found" << qmlSource; return; } diff --git a/libraries/qml/src/qml/OffscreenSurface.h b/libraries/qml/src/qml/OffscreenSurface.h index 18d24c93f7..528baf76be 100644 --- a/libraries/qml/src/qml/OffscreenSurface.h +++ b/libraries/qml/src/qml/OffscreenSurface.h @@ -40,6 +40,7 @@ class SharedObject; using QmlContextCallback = ::std::function; using QmlContextObjectCallback = ::std::function; +using QmlUrlValidator = std::function; class OffscreenSurface : public QObject { Q_OBJECT @@ -47,10 +48,13 @@ class OffscreenSurface : public QObject { public: static const QmlContextObjectCallback DEFAULT_CONTEXT_OBJECT_CALLBACK; static const QmlContextCallback DEFAULT_CONTEXT_CALLBACK; - + static QmlUrlValidator validator; using TextureAndFence = std::pair; using MouseTranslator = std::function; + + static const QmlUrlValidator& getUrlValidator() { return validator; } + static void setUrlValidator(const QmlUrlValidator& newValidator) { validator = newValidator; } static void setSharedContext(QOpenGLContext* context); OffscreenSurface();