Package: release.debian.org Severity: normal Tags: trixie X-Debbugs-Cc: [email protected] Control: affects -1 + src:lomiri-download-manager User: [email protected] Usertags: pu
Please accept upload of lomiri-download-manager 0.2.1-3+deb13u1 to trixie. [ Reason ] Security fixes, preventing arbitrary filesystem access as root: CVE-2026-96424: Fix incorrect DBus policy for lomiri-upload-manager (part of lomiri-download-manager) that allows arbitrary user to read arbitrary file as root over DBus Source. CVE-2026-96425: Fix incorrect DBus policy for lomiri-download-manager that allows arbitrary user to run arbitrary command as root over DBus. [ Impact ] Security issues will not get fixed. [ Tests ] Manual tests in Lomiri on Debian 13. [ Risks ] Only for Lomiri users. [ Checklist ] [x] *all* changes are documented in the d/changelog [x] I reviewed all changes and I approve them [x] attach debdiff against the package in (old)stable [x] the issue is verified as fixed in unstable [ Changes ] + * debian/patches: + + Add 0001_src-downloads-dont-run-commands-when-privileged.patch and + 0002_src-uploads-downloads-daemon-conf-deny-access-to-system.patch. + CVE-2026-96424: Fix incorrect DBus policy for lomiri-upload-manager + (part of lomiri-download-manager) that allows arbitrary user to read + arbitrary file as root over DBus Source. + CVE-2026-96425: Fix incorrect DBus policy for lomiri-download-manager + that allows arbitrary user to run arbitrary command as root over DBus. + * debian/control: + + Add to B-D: libcap-dev. [ Other info ] Security team requested to upload this via trixie-pu.
diff -Nru lomiri-download-manager-0.2.1/debian/changelog lomiri-download-manager-0.2.1/debian/changelog --- lomiri-download-manager-0.2.1/debian/changelog 2025-04-10 06:24:51.000000000 +0200 +++ lomiri-download-manager-0.2.1/debian/changelog 2026-11-03 18:23:16.000000000 +0100 @@ -1,3 +1,18 @@ +lomiri-download-manager (0.2.1-3+deb13u1) trixie; urgency=medium + + * debian/patches: + + Add 0001_src-downloads-dont-run-commands-when-privileged.patch and + 0002_src-uploads-downloads-daemon-conf-deny-access-to-system.patch. + CVE-2026-96424: Fix incorrect DBus policy for lomiri-upload-manager + (part of lomiri-download-manager) that allows arbitrary user to read + arbitrary file as root over DBus Source. + CVE-2026-96425: Fix incorrect DBus policy for lomiri-download-manager + that allows arbitrary user to run arbitrary command as root over DBus. + * debian/control: + + Add to B-D: libcap-dev. + + -- Mike Gabriel <[email protected]> Tue, 03 Nov 2026 18:23:16 +0100 + lomiri-download-manager (0.2.1-3) unstable; urgency=medium * debian/rules: diff -Nru lomiri-download-manager-0.2.1/debian/control lomiri-download-manager-0.2.1/debian/control --- lomiri-download-manager-0.2.1/debian/control 2025-04-03 17:40:41.000000000 +0200 +++ lomiri-download-manager-0.2.1/debian/control 2026-11-03 18:23:16.000000000 +0100 @@ -13,6 +13,7 @@ libapparmor-dev, libboost-log-dev, libboost-program-options-dev, + libcap-dev, libdbus-1-dev, libqt5sql5-sqlite, libqt6sql6-sqlite, diff -Nru lomiri-download-manager-0.2.1/debian/patches/0001_src-downloads-dont-run-commands-when-privileged.patch lomiri-download-manager-0.2.1/debian/patches/0001_src-downloads-dont-run-commands-when-privileged.patch --- lomiri-download-manager-0.2.1/debian/patches/0001_src-downloads-dont-run-commands-when-privileged.patch 1970-01-01 01:00:00.000000000 +0100 +++ lomiri-download-manager-0.2.1/debian/patches/0001_src-downloads-dont-run-commands-when-privileged.patch 2026-11-03 18:17:15.000000000 +0100 @@ -0,0 +1,428 @@ +From 5fd50939a3cacef4181f6bcb58796bdcbc17984d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Maciej=20Sopy=C5=82o?= <[email protected]> +Date: Thu, 10 Sep 2026 14:24:43 +0200 +Subject: [PATCH] src/downloads: don't run commands when privileged + +--- + CMakeLists.txt | 1 + + src/common/priv/CMakeLists.txt | 4 + + .../priv/lomiri/transfers/system/apparmor.cpp | 3 +- + .../priv/lomiri/transfers/system/security.cpp | 64 ++++++++++++++ + .../priv/lomiri/transfers/system/security.h | 46 ++++++++++ + src/downloads/daemon/CMakeLists.txt | 1 + + src/downloads/priv/CMakeLists.txt | 1 + + .../priv/lomiri/downloads/file_download.cpp | 8 ++ + tests/common/security.h | 41 +++++++++ + tests/downloads/daemon/test_download.cpp | 83 +++++++++++++++++++ + tests/downloads/daemon/test_download.h | 3 + + 12 files changed, 255 insertions(+), 1 deletion(-) + create mode 100644 src/common/priv/lomiri/transfers/system/security.cpp + create mode 100644 src/common/priv/lomiri/transfers/system/security.h + create mode 100644 tests/common/security.h + +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -62,6 +62,7 @@ + pkg_check_modules(DBUS REQUIRED dbus-1) + pkg_check_modules(LOMIRI_API REQUIRED liblomiri-api) + pkg_check_modules(APPARMOR REQUIRED libapparmor) ++pkg_check_modules(CAP REQUIRED libcap) + + if(USE_SYSTEMD) + pkg_check_modules(SYSTEMD systemd) +--- a/src/common/priv/CMakeLists.txt ++++ b/src/common/priv/CMakeLists.txt +@@ -21,6 +21,7 @@ + lomiri/transfers/system/process.cpp + lomiri/transfers/system/process_factory.cpp + lomiri/transfers/system/request_factory.cpp ++ lomiri/transfers/system/security.cpp + lomiri/transfers/system/timer.cpp + lomiri/transfers/system/uuid_factory.cpp + lomiri/transfers/system/uuid_utils.cpp +@@ -50,6 +51,7 @@ + lomiri/transfers/system/process.h + lomiri/transfers/system/process_factory.h + lomiri/transfers/system/request_factory.h ++ lomiri/transfers/system/security.h + lomiri/transfers/system/timer.h + lomiri/transfers/system/uuid_factory.h + lomiri/transfers/system/uuid_utils.h +@@ -57,6 +59,7 @@ + + include_directories(${APPARMOR_INCLUDE_DIRS}) + include_directories(${DBUS_INCLUDE_DIRS}) ++include_directories(${CAP_INCLUDE_DIRS}) + include_directories(${CMAKE_CURRENT_SOURCE_DIR}) + include_directories(${CMAKE_CURRENT_BINARY_DIR}) + include_directories(${CMAKE_SOURCE_DIR}/src/common/public) +@@ -83,6 +86,7 @@ + Qt::Core + Qt::DBus + ldm-common${QT_SUFFIX} ++ ${CAP_LIBRARIES} + ) + + install(TARGETS ${TARGET} DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR}) +--- a/src/common/priv/lomiri/transfers/system/apparmor.cpp ++++ b/src/common/priv/lomiri/transfers/system/apparmor.cpp +@@ -28,6 +28,7 @@ + #include <lomiri/transfers/system/logger.h> + #include <sys/apparmor.h> + #include "apparmor.h" ++#include "security.h" + #include "dbus_proxy_factory.h" + #include "pending_reply.h" + #include "uuid_utils.h" +@@ -192,7 +193,7 @@ + AppArmor::getLocalPath(const QString& appId) { + // if the service is running as root we will always return /tmp + // as the local path root +- if (getuid() == 0){ ++ if (Security::instance()->isPrivileged()){ + LOG(INFO) << "Running as system bus using /tmp for downloads"; + return QStandardPaths::writableLocation( + QStandardPaths::TempLocation); +--- /dev/null ++++ b/src/common/priv/lomiri/transfers/system/security.cpp +@@ -0,0 +1,64 @@ ++/* ++ * Copyright (C) 2026 UBports Foundation. ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of version 3 of the GNU Lesser General Public ++ * License as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the ++ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, ++ * Boston, MA 02110-1301, USA. ++ */ ++ ++#include "security.h" ++ ++#include <unistd.h> ++#include <sys/capability.h> ++ ++namespace Lomiri { ++ ++namespace Transfers { ++ ++namespace System { ++ ++std::shared_ptr<Security> Security::_instance = nullptr; ++ ++std::shared_ptr<Security> ++Security::instance() { ++ if (!_instance) { ++ _instance = std::make_shared<Security>(); ++ } ++ return _instance; ++} ++ ++bool ++Security::isPrivileged() { ++ if (geteuid() == 0) { ++ return true; ++ } ++ ++ cap_t cap_current = cap_get_proc(); ++ cap_t cap_zero = cap_init(); ++ bool has_capabilities = cap_compare(cap_current, cap_zero) != 0; ++ cap_free(cap_current); ++ cap_free(cap_zero); ++ ++ return has_capabilities; ++} ++ ++void ++Security::setInstance(std::shared_ptr<Security> instance) { ++ _instance = std::move(instance); ++} ++ ++} // System ++ ++} // Transfers ++ ++} // Lomiri +--- /dev/null ++++ b/src/common/priv/lomiri/transfers/system/security.h +@@ -0,0 +1,46 @@ ++/* ++ * Copyright (C) 2026 UBports Foundation. ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of version 3 of the GNU Lesser General Public ++ * License as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the ++ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, ++ * Boston, MA 02110-1301, USA. ++ */ ++ ++#pragma once ++ ++#include <memory> ++ ++namespace Lomiri { ++ ++namespace Transfers { ++ ++namespace System { ++ ++class Security { ++ public: ++ static std::shared_ptr<Security> instance(); ++ ++ virtual bool isPrivileged(); ++ ++ // Only for testing ++ static void setInstance(std::shared_ptr<Security> instance); ++ ++ private: ++ static std::shared_ptr<Security> _instance; ++}; ++ ++} // System ++ ++} // Transfers ++ ++} // Lomiri +--- a/src/downloads/daemon/CMakeLists.txt ++++ b/src/downloads/daemon/CMakeLists.txt +@@ -22,6 +22,7 @@ + ldm-priv-common + lomiri-download-manager-common + lomiri-download-manager-priv ++ ${CAP_LIBRARIES} + ) + + configure_file( +--- a/src/downloads/priv/CMakeLists.txt ++++ b/src/downloads/priv/CMakeLists.txt +@@ -71,6 +71,7 @@ + ldm-common${QT_SUFFIX} + ldm-priv-common${QT_SUFFIX} + lomiri-download-manager-common${QT_SUFFIX} ++ ${CAP_LIBRARIES} + ) + + if (ENABLE_QT6) +--- a/src/downloads/priv/lomiri/downloads/file_download.cpp ++++ b/src/downloads/priv/lomiri/downloads/file_download.cpp +@@ -19,6 +19,7 @@ + #include <map> + + #include <glog/logging.h> ++#include <sys/capability.h> + + #include <QBuffer> + #include <QCryptographicHash> +@@ -42,6 +43,7 @@ + #include <lomiri/transfers/system/filename_mutex.h> + #include <lomiri/transfers/system/uuid_factory.h> + #include <lomiri/transfers/system/uuid_utils.h> ++#include <lomiri/transfers/system/security.h> + + #include "header_parser.h" + #include "file_download.h" +@@ -1031,6 +1033,12 @@ + postDownloadProcess->start(command, args); + return; + } else if (_metadata.contains(Metadata::COMMAND_KEY)) { ++ if (Security::instance()->isPrivileged()) { ++ DOWN_LOG(ERROR) << "Post processing commands are unavailable on the priviledged download manager"; ++ emitError(COMMAND_ERROR); ++ return; ++ } ++ + if (isConfined()) { + DOWN_LOG(ERROR) << "Post processing commands are unavailable to confined applications"; + emitError(COMMAND_ERROR); +--- /dev/null ++++ b/tests/common/security.h +@@ -0,0 +1,41 @@ ++/* ++ * Copyright (C) 2026 UBports Foundation. ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of version 3 of the GNU Lesser General Public ++ * License as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the ++ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, ++ * Boston, MA 02110-1301, USA. ++ */ ++ ++#pragma once ++ ++#include <lomiri/transfers/system/security.h> ++#include <gmock/gmock.h> ++ ++namespace Lomiri { ++ ++namespace Transfers { ++ ++using namespace System; ++ ++namespace Tests { ++ ++class MockSecurity : public Security { ++ public: ++ MOCK_METHOD0(isPrivileged, bool()); ++}; ++ ++} // System ++ ++} // Transfers ++ ++} // Lomir +--- a/tests/downloads/daemon/test_download.cpp ++++ b/tests/downloads/daemon/test_download.cpp +@@ -23,6 +23,7 @@ + #include <lomiri/transfers/metadata.h> + #include <lomiri/transfers/system/hash_algorithm.h> + #include <lomiri/transfers/system/uuid_utils.h> ++#include <lomiri/transfers/system/security.h> + #include <network_reply.h> + #include "filename_mutex.h" + #include "matchers.h" +@@ -60,6 +61,8 @@ + FileManager::setInstance(_fileManager); + _cryptoFactory = new MockCryptographicHashFactory(); + CryptographicHashFactory::setInstance(_cryptoFactory); ++ _security = std::make_shared<MockSecurity>(); ++ Security::setInstance(_security); + } + + void +@@ -2844,6 +2847,86 @@ + } + + void ++TestDownload::testProcessNotExecutedWhenPrivileged() { ++ QVariantMap metadata; ++ metadata["post-download-command"] = QStringList { "wont", "execute" }; ++ ++ QStringList args; ++ ++ QScopedPointer<MockFile> file(new MockFile("test")); ++ QScopedPointer<MockNetworkReply> reply(new MockNetworkReply()); ++ ++ // write the expectations of the reply which is what we are ++ // really testing ++ ++ EXPECT_CALL(*_networkSession, isOnline()) ++ .WillRepeatedly(Return(true)); ++ ++ EXPECT_CALL(*_reqFactory, get(_)) ++ .Times(1) ++ .WillOnce(Return(reply.data())); ++ ++ EXPECT_CALL(*reply.data(), setReadBufferSize(_)) ++ .Times(1); ++ ++ EXPECT_CALL(*reply.data(), attribute(_)) ++ .Times(1) ++ .WillOnce(Return(QVariant(200))); ++ ++ EXPECT_CALL(*reply.data(), hasRawHeader(_)) ++ .Times(2) ++ .WillOnce(Return(false)) ++ .WillOnce(Return(false)); ++ ++ // file system expectations ++ EXPECT_CALL(*_fileManager, createFile(_)) ++ .Times(1) ++ .WillOnce(Return(file.data())); ++ ++ EXPECT_CALL(*file.data(), open(QIODevice::ReadWrite | QFile::Append)) ++ .Times(1) ++ .WillOnce(Return(true)); ++ ++ EXPECT_CALL(*file, flush()) ++ .Times(1) ++ .WillOnce(Return(true)); ++ ++ EXPECT_CALL(*file.data(), remove()) ++ .Times(1) ++ .WillOnce(Return(true)); ++ ++ EXPECT_CALL(*_cryptoFactory, createCryptographicHash(_, _)) ++ .Times(0); ++ ++ EXPECT_CALL(*_security, isPrivileged()) ++ .WillRepeatedly(Return(true)); ++ ++ auto download = new FileDownload(_id, _appId, _path, ++ _isConfined, _rootPath, _url, metadata, _headers); ++ ++ SignalBarrier spy(download, SIGNAL(error(QString))); ++ SignalBarrier startedSpy(download, SIGNAL(started(bool))); ++ ++ download->start(); // change state ++ download->startTransfer(); ++ QVERIFY(startedSpy.ensureSignalEmitted()); ++ ++ // emit the finish signal and expect it to be raised ++ emit reply->finished(); ++ ++ QVERIFY(spy.ensureSignalEmitted()); ++ QCOMPARE(spy.count(), 1); ++ QCOMPARE(download->state(), Download::ERROR); ++ ++ delete download; ++ ++ QVERIFY(Mock::VerifyAndClearExpectations(file.data())); ++ QVERIFY(Mock::VerifyAndClearExpectations(reply.data())); ++ verifyMocks(); ++} ++ ++ ++void + TestDownload::testSetRawHeaderAcceptEncoding() { + auto file = new MockFile("test"); + auto reply = new MockNetworkReply(); +--- a/tests/downloads/daemon/test_download.h ++++ b/tests/downloads/daemon/test_download.h +@@ -29,6 +29,7 @@ + #include <process_factory.h> + #include <request_factory.h> + #include <network_session.h> ++#include <security.h> + + #include "base_testcase.h" + #include "cryptographic_hash.h" +@@ -128,6 +129,7 @@ + void testProcessError_data(); + void testProcessError(); + void testProcessFinishedCrash(); ++ void testProcessNotExecutedWhenPrivileged(); + + // test related to bug #1224678 + void testSetRawHeaderAcceptEncoding(); +@@ -210,6 +212,7 @@ + MockProcessFactory* _processFactory = nullptr; + MockFileManager* _fileManager = nullptr; + MockCryptographicHashFactory* _cryptoFactory = nullptr; ++ std::shared_ptr<MockSecurity> _security = nullptr; + }; + + #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) diff -Nru lomiri-download-manager-0.2.1/debian/patches/0002_src-uploads-downloads-daemon-conf-deny-access-to-system.patch lomiri-download-manager-0.2.1/debian/patches/0002_src-uploads-downloads-daemon-conf-deny-access-to-system.patch --- lomiri-download-manager-0.2.1/debian/patches/0002_src-uploads-downloads-daemon-conf-deny-access-to-system.patch 1970-01-01 01:00:00.000000000 +0100 +++ lomiri-download-manager-0.2.1/debian/patches/0002_src-uploads-downloads-daemon-conf-deny-access-to-system.patch 2026-11-03 18:18:05.000000000 +0100 @@ -0,0 +1,46 @@ +From 779dfd5bbeb5fe8877627b772e5024e40eda38aa Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Maciej=20Sopy=C5=82o?= <[email protected]> +Date: Fri, 11 Sep 2026 12:32:20 +0200 +Subject: [PATCH] src/{uploads,downloads}/daemon/*.conf: deny access to system + bus services + +--- + .../daemon/com.lomiri.applications.Downloader.conf | 7 ------- + src/uploads/daemon/com.lomiri.applications.Uploader.conf | 7 ------- + 2 files changed, 14 deletions(-) + +diff --git a/src/downloads/daemon/com.lomiri.applications.Downloader.conf b/src/downloads/daemon/com.lomiri.applications.Downloader.conf +index 766214bc..cd7be264 100644 +--- a/src/downloads/daemon/com.lomiri.applications.Downloader.conf ++++ b/src/downloads/daemon/com.lomiri.applications.Downloader.conf +@@ -8,11 +8,4 @@ + <allow own="com.lomiri.applications.Downloader"/> + <allow send_destination="com.lomiri.applications.Downloader"/> + </policy> +- +- <policy context="default"> +- <allow send_destination="com.lomiri.applications.Downloader"/> +- <allow send_destination="com.lomiri.applications.Downloader" +- send_interface="org.freedesktop.DBus.Introspectable"/> +- </policy> +- + </busconfig> +diff --git a/src/uploads/daemon/com.lomiri.applications.Uploader.conf b/src/uploads/daemon/com.lomiri.applications.Uploader.conf +index 132e272a..b696d3b9 100644 +--- a/src/uploads/daemon/com.lomiri.applications.Uploader.conf ++++ b/src/uploads/daemon/com.lomiri.applications.Uploader.conf +@@ -8,11 +8,4 @@ + <allow own="com.lomiri.applications.Uploader"/> + <allow send_destination="com.lomiri.applications.Uploader"/> + </policy> +- +- <policy context="default"> +- <allow send_destination="com.lomiri.applications.Uploader"/> +- <allow send_destination="com.lomiri.applications.Uploader" +- send_interface="org.freedesktop.DBus.Introspectable"/> +- </policy> +- + </busconfig> +-- +GitLab + diff -Nru lomiri-download-manager-0.2.1/debian/patches/series lomiri-download-manager-0.2.1/debian/patches/series --- lomiri-download-manager-0.2.1/debian/patches/series 1970-01-01 01:00:00.000000000 +0100 +++ lomiri-download-manager-0.2.1/debian/patches/series 2026-11-03 18:18:39.000000000 +0100 @@ -0,0 +1,2 @@ +0001_src-downloads-dont-run-commands-when-privileged.patch +0002_src-uploads-downloads-daemon-conf-deny-access-to-system.patch

