summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorFredrik Orderud <fredrik.orderud@ge.com>2018-10-14 20:46:48 +0200
committerVolker Hilsheimer <volker.hilsheimer@qt.io>2018-10-19 13:50:44 +0000
commited59e85a6d1a12d6192c6c4bab54382f2fdb643d (patch)
tree12b6de1dad2a9abbd98cbb3de29d23bd0c9e2292 /tools
parentd36d6ca320125ea5dd0e3dd451616e97c568b907 (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.cpp2
-rw-r--r--tools/testcon/mainwindow.cpp75
-rw-r--r--tools/testcon/mainwindow.h4
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);