diff options
author | Fredrik Orderud <fredrik.orderud@ge.com> | 2018-10-14 20:46:48 +0200 |
---|---|---|
committer | Volker Hilsheimer <volker.hilsheimer@qt.io> | 2018-10-19 13:50:44 +0000 |
commit | ed59e85a6d1a12d6192c6c4bab54382f2fdb643d (patch) | |
tree | 12b6de1dad2a9abbd98cbb3de29d23bd0c9e2292 /tools | |
parent | d36d6ca320125ea5dd0e3dd451616e97c568b907 (diff) |
Implement sandboxing support in TestCon
Leverage QAxWidget::setClassContext and integrity level impersonation to require the
ActiveX control to either be started in a separate process, or in a separate
"low integrity" process.
Based on "Designing Applications to Run at a Low Integrity Level" https://msdn.microsoft.com/en-us/library/bb625960.aspx
Task-number: QTBUG-70983
Change-Id: Ic71a076c9d54b433e7b0285e958bb86a6ff163bb
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
Diffstat (limited to 'tools')
-rw-r--r-- | tools/testcon/main.cpp | 2 | ||||
-rw-r--r-- | tools/testcon/mainwindow.cpp | 75 | ||||
-rw-r--r-- | tools/testcon/mainwindow.h | 4 |
3 files changed, 75 insertions, 6 deletions
diff --git a/tools/testcon/main.cpp b/tools/testcon/main.cpp index 2454084..c9a5fd9 100644 --- a/tools/testcon/main.cpp +++ b/tools/testcon/main.cpp @@ -98,7 +98,7 @@ int main( int argc, char **argv ) const QStringList positionalArguments = parser.positionalArguments(); for (const QString &a : positionalArguments) { if (a.startsWith(QLatin1Char('{')) && a.endsWith(QLatin1Char('}'))) - mw.addControlFromClsid(a); + mw.addControlFromClsid(a, QAxSelect::SandboxingNone); else mw.addControlFromFile(a); } diff --git a/tools/testcon/mainwindow.cpp b/tools/testcon/mainwindow.cpp index 06ce0a0..ae496e7 100644 --- a/tools/testcon/mainwindow.cpp +++ b/tools/testcon/mainwindow.cpp @@ -45,9 +45,10 @@ #include <QtCore/QLibraryInfo> #include <QtCore/qt_windows.h> #include <ActiveQt/QAxScriptManager> -#include <ActiveQt/QAxSelect> #include <ActiveQt/QAxWidget> #include <ActiveQt/qaxtypes.h> +#include <memory> +#include <sddl.h> QT_BEGIN_NAMESPACE @@ -118,10 +119,75 @@ QList<QAxWidget *> MainWindow::axWidgets() const return result; } -bool MainWindow::addControlFromClsid(const QString &clsid) + +/** RAII class for temporarily impersonating low-integrity level for the current thread. + Intended to be used together with CLSCTX_ENABLE_CLOAKING when creating COM objects. + Based on "Designing Applications to Run at a Low Integrity Level" https://msdn.microsoft.com/en-us/library/bb625960.aspx */ +struct LowIntegrity { + LowIntegrity() + { + HANDLE cur_token = nullptr; + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_DUPLICATE | TOKEN_ADJUST_DEFAULT | TOKEN_QUERY | TOKEN_ASSIGN_PRIMARY, &cur_token)) + abort(); + + if (!DuplicateTokenEx(cur_token, 0, NULL, SecurityImpersonation, TokenPrimary, &m_token)) + abort(); + + CloseHandle(cur_token); + + PSID li_sid = nullptr; + if (!ConvertStringSidToSid(L"S-1-16-4096", &li_sid)) // low integrity SID + abort(); + + // reduce process integrity level + TOKEN_MANDATORY_LABEL TIL = {}; + TIL.Label.Attributes = SE_GROUP_INTEGRITY; + TIL.Label.Sid = li_sid; + if (!SetTokenInformation(m_token, TokenIntegrityLevel, &TIL, sizeof(TOKEN_MANDATORY_LABEL) + GetLengthSid(li_sid))) + abort(); + + if (!ImpersonateLoggedOnUser(m_token)) // change current thread integrity + abort(); + + LocalFree(li_sid); + li_sid = nullptr; + } + + ~LowIntegrity() + { + if (!RevertToSelf()) + abort(); + + CloseHandle(m_token); + m_token = nullptr; + } + +private: + HANDLE m_token = nullptr; +}; + +bool MainWindow::addControlFromClsid(const QString &clsid, QAxSelect::SandboxingLevel sandboxing) { QAxWidget *container = new QAxWidget; - const bool result = container->setControl(clsid); + + bool result = false; + { + std::unique_ptr<LowIntegrity> low_integrity; + + if (sandboxing == QAxSelect::SandboxingProcess) { + // require out-of-process + container->setClassContext(CLSCTX_LOCAL_SERVER); + } else if (sandboxing == QAxSelect::SandboxingLowIntegrity) { + // impersonate "low integrity" + low_integrity.reset(new LowIntegrity); + // require out-of-process and + // propagate integrity level when calling setControl + container->setClassContext(CLSCTX_LOCAL_SERVER | CLSCTX_ENABLE_CLOAKING); + } + + result = container->setControl(clsid); + } + if (result) { container->setObjectName(container->windowTitle()); m_mdiArea->addSubWindow(container); @@ -154,7 +220,8 @@ void MainWindow::appendLogText(const QString &message) void MainWindow::on_actionFileNew_triggered() { QAxSelect select(this); - while (select.exec() && !addControlFromClsid(select.clsid())) { } + while (select.exec() && !addControlFromClsid(select.clsid(), select.sandboxingLevel())) { + } } void MainWindow::on_actionFileLoad_triggered() diff --git a/tools/testcon/mainwindow.h b/tools/testcon/mainwindow.h index 7e6575b..14dbff4 100644 --- a/tools/testcon/mainwindow.h +++ b/tools/testcon/mainwindow.h @@ -29,6 +29,8 @@ #ifndef MAINWINDOW_H #define MAINWINDOW_H +#include <ActiveQt/QAxSelect> + #include "ui_mainwindow.h" QT_BEGIN_NAMESPACE @@ -54,7 +56,7 @@ public: static MainWindow *instance() { return m_instance; } - bool addControlFromClsid(const QString &clsid); + bool addControlFromClsid(const QString &clsid, QAxSelect::SandboxingLevel sandboxing); bool addControlFromFile(const QString &fileName); bool loadScript(const QString &file); |