Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(Security): Add process sandbox for image parsing. #408

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .ci-scripts/build-local-qt.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ install_deps \
qttools \
qtsvg \
qtimageformats \
qtremoteobjects \
qtwayland
16 changes: 13 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ execute_process(
OUTPUT_VARIABLE QT_PREFIX_PATH
OUTPUT_STRIP_TRAILING_WHITESPACE)

project(qtox)
project(qtox LANGUAGES CXX)

# C++ and C standards.
set(CMAKE_CXX_STANDARD 20)
Expand Down Expand Up @@ -262,6 +262,8 @@ set(${PROJECT_NAME}_SOURCES
src/chatlog/customtextdocument.h
src/chatlog/documentcache.cpp
src/chatlog/documentcache.h
src/chatlog/imageloader.cpp
src/chatlog/imageloader.h
src/chatlog/pixmapcache.cpp
src/chatlog/pixmapcache.h
src/core/toxfileprogress.cpp
Expand Down Expand Up @@ -430,6 +432,12 @@ set(${PROJECT_NAME}_SOURCES
src/platform/desktop_notifications/desktopnotifybackend.h
src/platform/posixsignalnotifier.cpp
src/platform/posixsignalnotifier.h
src/platform/sandbox.cpp
src/platform/sandbox.h
src/platform/sandboxclient.cpp
src/platform/sandboxclient.h
src/platform/sandboxserver.cpp
src/platform/sandboxserver.h
src/platform/timer.h
src/platform/timer_osx.cpp
src/platform/timer_win.cpp
Expand Down Expand Up @@ -653,6 +661,8 @@ add_subdirectory(cmake/warnings)

add_library(${PROJECT_NAME}_static STATIC ${${PROJECT_NAME}_FORMS}
${${PROJECT_NAME}_SOURCES})
qt_add_repc_sources(${PROJECT_NAME}_static src/platform/sandbox.rep)
qt_add_repc_replicas(${PROJECT_NAME}_static src/platform/sandbox.rep)
target_link_libraries(${PROJECT_NAME}_static ${CMAKE_REQUIRED_LIBRARIES}
${ALL_LIBRARIES} coverage_config)

Expand All @@ -667,8 +677,8 @@ if(COMMAND qt_policy)
qt_policy(SET QTP0002 NEW)
endif()

qt_add_executable(${PROJECT_NAME} WIN32 MACOSX_BUNDLE
${${PROJECT_NAME}_RESOURCES} ${SMILEY_RESOURCES} src/main.cpp)
qt_add_executable(${PROJECT_NAME} ${${PROJECT_NAME}_RESOURCES} ${SMILEY_RESOURCES} src/main.cpp)
set_target_properties(${PROJECT_NAME} PROPERTIES WIN32_EXECUTABLE TRUE MACOSX_BUNDLE TRUE)
target_link_libraries(
${PROJECT_NAME} PRIVATE ${PROJECT_NAME}_static ${CMAKE_REQUIRED_LIBRARIES}
${ALL_LIBRARIES})
Expand Down
25 changes: 14 additions & 11 deletions cmake/Dependencies.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,18 @@
################################################################################

# This should go into subdirectories later.
find_package(PkgConfig REQUIRED)
find_package(Qt6Concurrent REQUIRED)
find_package(Qt6Core REQUIRED)
find_package(Qt6Gui REQUIRED)
find_package(Qt6Linguist REQUIRED)
find_package(Qt6Network REQUIRED)
find_package(Qt6Svg REQUIRED)
find_package(Qt6Test REQUIRED)
find_package(Qt6Widgets REQUIRED)
find_package(Qt6Xml REQUIRED)
find_package(PkgConfig REQUIRED)
find_package(Qt6 REQUIRED COMPONENTS
Concurrent
Core
Gui
Linguist
Network
RemoteObjects
Svg
Test
Widgets
Xml)

function(add_dependency)
set(ALL_LIBRARIES ${ALL_LIBRARIES} ${ARGN} PARENT_SCOPE)
Expand All @@ -29,6 +31,7 @@ add_dependency(
Qt6::Core
Qt6::Gui
Qt6::Network
Qt6::RemoteObjects
Qt6::Svg
Qt6::Widgets
Qt6::Xml)
Expand Down Expand Up @@ -214,7 +217,7 @@ if(QT_FEATURE_static)
find_library(KIMG_${fmt_lib}_LIBRARY kimg_${fmt}
PATHS "${QT6_INSTALL_PREFIX}/plugins/imageformats")
if(KIMG_${fmt_lib}_LIBRARY)
message(STATUS "Found ${fmt_lib} imageformats plugin: ${KIMG_${fmt}_LIBRARY}")
message(STATUS "Found ${fmt_lib} imageformats plugin: ${KIMG_${fmt_lib}_LIBRARY}")
add_dependency(${KIMG_${fmt_lib}_LIBRARY})
set_property(SOURCE src/main.cpp APPEND PROPERTY COMPILE_DEFINITIONS QTOX_USE_KIMG_${fmt_lib})
else()
Expand Down
38 changes: 28 additions & 10 deletions src/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
load("@rules_cc//cc:defs.bzl", "cc_library", "objc_library")
load("//third_party/qt:build_defs.bzl", "qt_moc", "qt_uic")
load("//third_party/qt:build_defs.bzl", "qt_moc", "qt_repc", "qt_uic")
load("//tools/project:build_defs.bzl", "mkstamp")

DEFINES = [
Expand All @@ -10,6 +10,20 @@ DEFINES = [
"UPDATE_CHECK_ENABLED",
]

qt_repc(
name = "src_repc_source",
srcs = ["platform/sandbox.rep"],
tags = ["qt"],
type = "source",
)

qt_repc(
name = "src_repc_replica",
srcs = ["platform/sandbox.rep"],
tags = ["qt"],
type = "replica",
)

qt_moc(
name = "src_moc",
srcs = [
Expand All @@ -24,6 +38,7 @@ qt_moc(
"chatlog/content/text.h",
"chatlog/content/timestamp.h",
"chatlog/customtextdocument.h",
"chatlog/imageloader.h",
"core/core.h",
"core/coreav.h",
"core/corefile.h",
Expand Down Expand Up @@ -60,6 +75,9 @@ qt_moc(
"platform/desktop_notifications/desktopnotify.h",
"platform/desktop_notifications/desktopnotifybackend.h",
"platform/posixsignalnotifier.h",
"platform/sandbox.h",
"platform/sandboxclient.h",
"platform/sandboxserver.h",
"video/camerasource.h",
"video/corevideosource.h",
"video/netcamview.h",
Expand Down Expand Up @@ -124,15 +142,19 @@ qt_moc(
"widget/tool/screenshotgrabber.h",
"widget/tool/toolboxgraphicsitem.h",
"widget/widget.h",
":src_repc_replica",
":src_repc_source",
],
hdrs = glob(["**/*.h"]),
mocopts = [
"-Iqtox",
"-Iqtox/src",
"-Iqtox/util/include",
] + ["-D%s=1" % d for d in DEFINES],
tags = ["qt"],
deps = [
"//qtox/util",
"@qt//:qt_remoteobjects",
"@qt//:qt_widgets",
],
)
Expand Down Expand Up @@ -166,6 +188,7 @@ mkstamp(
COPTS = [
"-Iqtox",
"-I$(GENDIR)/qtox",
"-I$(GENDIR)/qtox/src/platform",
] + select({
"//tools/config:freebsd": [],
"//tools/config:linux": ["-fPIC"],
Expand All @@ -187,6 +210,8 @@ cc_library(
name = "src",
srcs = [":version"] + [
":src_moc",
":src_repc_replica",
":src_repc_source",
":src_ui",
] + glob(
["**/*.cpp"],
Expand Down Expand Up @@ -227,6 +252,7 @@ cc_library(
"@qt//:qt_dbus",
"@qt//:qt_gui",
"@qt//:qt_network",
"@qt//:qt_remoteobjects",
"@qt//:qt_svg",
"@qt//:qt_widgets",
"@qt//:qt_xml",
Expand All @@ -245,15 +271,7 @@ cc_library(
cc_library(
name = "main",
srcs = ["main.cpp"],
copts = [
"-Iqtox",
"-I$(GENDIR)/qtox",
] + select({
"//tools/config:freebsd": [],
"//tools/config:linux": ["-fPIC"],
"//tools/config:osx": [],
"//tools/config:windows": [],
}),
copts = COPTS,
tags = ["qt"],
visibility = ["//qtox:__subpackages__"],
deps = [
Expand Down
94 changes: 58 additions & 36 deletions src/appmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
#include "src/persistence/settings.h"
#include "src/persistence/toxsave.h"
#include "src/platform/posixsignalnotifier.h"
#include "src/platform/sandboxclient.h"
#include "src/platform/sandboxserver.h"
#include "src/version.h"
#include "src/video/camerasource.h"
#include "src/widget/tool/messageboxmanager.h"
Expand All @@ -25,6 +27,7 @@
#include <QFontDatabase>
#include <QMessageBox>
#include <QObject>
#include <QRemoteObjectHost>

namespace {
// logMessageHandler and associated data must be static due to qInstallMessageHandler's
Expand Down Expand Up @@ -189,7 +192,6 @@ AppManager::AppManager(int& argc, char** argv)
: qapp((preConstructionInitialization(), new QApplication(argc, argv)))
, messageBoxManager(new MessageBoxManager(nullptr))
, settings(new Settings(*messageBoxManager))
, ipc(new IPC(settings->getCurrentProfileId()))
{
}

Expand All @@ -200,6 +202,37 @@ void AppManager::preConstructionInitialization()

int AppManager::startGui(QCommandLineParser& parser)
{
// Terminating signals are connected directly to quit() without any filtering.
connect(&PosixSignalNotifier::globalInstance(), &PosixSignalNotifier::terminatingSignal,
qapp.get(), &QApplication::quit);
PosixSignalNotifier::watchCommonTerminatingSignals();

// User signal 1 is used to screenshot the application.
connect(&PosixSignalNotifier::globalInstance(), &PosixSignalNotifier::usrSignal, qapp.get(),
[this](PosixSignalNotifier::UserSignal signal) {
if (signal == PosixSignalNotifier::UserSignal::Screenshot) {
nexus->screenshot();
}
});
PosixSignalNotifier::watchUsrSignals();

// Install Unicode 6.1 supporting font
// Keep this as close to the beginning of `main()` as possible, otherwise
// on systems that have poor support for Unicode qTox will look bad.
if (QFontDatabase::addApplicationFont(":/font/DejaVuSans.ttf") == -1) {
qWarning() << "Couldn't load font";
}

if (parser.isSet("portable")) {
// We don't go through settings here, because we're not making qTox
// portable (which moves files around). Instead, we start up in
// portable mode as a one-off.
settings->getPaths().setPortable(true);
settings->getPaths().setPortablePath(parser.value("portable"));
}

ipc = std::make_unique<IPC>(settings->getCurrentProfileId());

if (ipc->isAttached()) {
connect(settings.get(), &Settings::currentProfileIdChanged, ipc.get(), &IPC::setProfileId);
} else {
Expand Down Expand Up @@ -253,6 +286,14 @@ int AppManager::startGui(QCommandLineParser& parser)
qDebug() << "Commit:" << VersionInfo::gitVersion();
qDebug() << "Process ID:" << QCoreApplication::applicationPid();

if (settings->getExperimentalSandbox()) {
sandbox = std::make_unique<SandboxClient>(this);
qDebug() << "Sandbox ready:" << sandbox->isReady();
} else {
sandbox = std::make_unique<SandboxServer>(this);
qDebug() << "Sandbox disabled";
}

QString profileName;
bool autoLogin = settings->getAutoLogin();

Expand Down Expand Up @@ -317,7 +358,7 @@ int AppManager::startGui(QCommandLineParser& parser)
// note: Because Settings is shouldering global settings as well as model specific ones it
// cannot be integrated into a central model object yet
cameraSource = std::unique_ptr<CameraSource>(new CameraSource{*settings});
nexus = std::unique_ptr<Nexus>(new Nexus{*settings, *messageBoxManager, *cameraSource, *ipc});
nexus = std::unique_ptr<Nexus>(new Nexus{*settings, *messageBoxManager, *cameraSource, *ipc, *sandbox});
// Autologin
// TODO (kriby): Shift responsibility of linking views to model objects from nexus
// Further: generate view instances separately (loginScreen, mainGUI, audio)
Expand Down Expand Up @@ -364,20 +405,6 @@ int AppManager::startGui(QCommandLineParser& parser)

int AppManager::run()
{
// Terminating signals are connected directly to quit() without any filtering.
connect(&PosixSignalNotifier::globalInstance(), &PosixSignalNotifier::terminatingSignal,
qapp.get(), &QApplication::quit);
PosixSignalNotifier::watchCommonTerminatingSignals();

// User signal 1 is used to screenshot the application.
connect(&PosixSignalNotifier::globalInstance(), &PosixSignalNotifier::usrSignal, qapp.get(),
[this](PosixSignalNotifier::UserSignal signal) {
if (signal == PosixSignalNotifier::UserSignal::Screenshot) {
nexus->screenshot();
}
});
PosixSignalNotifier::watchUsrSignals();

qapp->setApplicationName("qTox");
qapp->setDesktopFileName("io.github.qtox.qTox");
qapp->setApplicationVersion(QStringLiteral("%1, git commit %2 (%3)")
Expand All @@ -387,13 +414,6 @@ int AppManager::run()
? QStringLiteral("stable")
: QStringLiteral("unstable")));

// Install Unicode 6.1 supporting font
// Keep this as close to the beginning of `main()` as possible, otherwise
// on systems that have poor support for Unicode qTox will look bad.
if (QFontDatabase::addApplicationFont("://font/DejaVuSans.ttf") == -1) {
qWarning() << "Couldn't load font";
}

QString locale = settings->getTranslation();
// We need to init the resources in the translations_library explicitly.
// See https://doc.qt.io/qt-5/resources.html#using-resources-in-a-library
Expand All @@ -417,17 +437,10 @@ int AppManager::run()
#ifdef UPDATE_CHECK_ENABLED
{{"u", "update-check"}, tr("Checks whether this program is running the latest qTox version.")},
#endif // UPDATE_CHECK_ENABLED
{{"S", "sandbox"}, tr("Start the qTox sandbox process (internal, don't use).")},
});
parser.process(*qapp);

if (parser.isSet("portable")) {
// We don't go through settings here, because we're not making qTox
// portable (which moves files around). Instead, we start up in
// portable mode as a one-off.
settings->getPaths().setPortable(true);
settings->getPaths().setPortablePath(parser.value("portable"));
}

// If update-check is requested, do it and exit.
if (parser.isSet("update-check")) {
UpdateCheck* updateCheck = new UpdateCheck(*settings, qapp.get());
Expand All @@ -442,11 +455,20 @@ int AppManager::run()
QTextStream(stdout) << message;
qapp->quit();
});
} else {
const int result = startGui(parser);
if (result != 0) {
return result;
}
return qapp->exec();
}

if (parser.isSet("sandbox")) {
// Start the sandbox process.
SandboxServer sandboxServer;
QRemoteObjectHost srcNode(QUrl(QStringLiteral("local:replica")));
srcNode.enableRemoting(&sandboxServer);
return qapp->exec();
}

const int result = startGui(parser);
if (result != 0) {
return result;
}

return qapp->exec();
Expand Down
Loading
Loading