Skip to content

feat: avoid duplicate ll-package-manager startup by checking existing#1707

Merged
dengbo11 merged 1 commit into
OpenAtom-Linyaps:masterfrom
dengbo11:fix-pm-socket
Jun 30, 2026
Merged

feat: avoid duplicate ll-package-manager startup by checking existing#1707
dengbo11 merged 1 commit into
OpenAtom-Linyaps:masterfrom
dengbo11:fix-pm-socket

Conversation

@dengbo11

Copy link
Copy Markdown
Collaborator

connection

  1. Add startProcess helper to launch detached processes with proper environment and cleanup on exit.
  2. Replace unconditional startDetached and sleep with a D-Bus peer connection check to see if ll-package-manager is already running.
  3. Only start a new process when no existing daemon is detected; otherwise log reuse of existing instance.
  4. Include signal handling to terminate spawned processes when the application quits.

Log: Improved process management for ll-package-manager to prevent duplicate instances.

Influence:

  1. Verify that ll-package-manager starts correctly when not already running.
  2. Test that when ll-package-manager is already running, a new process is not spawned.
  3. Confirm that spawned processes are terminated when the main application exits.
  4. Check logging output for "reuse existing process" or "start" messages.
  5. Verify D-Bus connection to the peer socket works as expected.
  6. Test in scenarios where the socket file might be stale or missing.

connection

1. Add `startProcess` helper to launch detached processes with proper
environment and cleanup on exit.
2. Replace unconditional `startDetached` and sleep with a D-Bus peer
connection check to see if `ll-package-manager` is already running.
3. Only start a new process when no existing daemon is detected;
otherwise log reuse of existing instance.
4. Include signal handling to terminate spawned processes when the
application quits.

Log: Improved process management for ll-package-manager to prevent
duplicate instances.

Influence:
1. Verify that ll-package-manager starts correctly when not already
running.
2. Test that when ll-package-manager is already running, a new process
is not spawned.
3. Confirm that spawned processes are terminated when the main
application exits.
4. Check logging output for "reuse existing process" or "start"
messages.
5. Verify D-Bus connection to the peer socket works as expected.
6. Test in scenarios where the socket file might be stale or missing.
@dengbo11 dengbo11 requested a review from reddevillg June 29, 2026 14:56

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request optimizes the startup of ll-package-manager by checking if it is already running via a peer-to-peer DBus connection before attempting to spawn a new process. It also introduces a helper function startProcess to handle starting the daemon detached and registering a cleanup hook to terminate it upon application exit. The review feedback highlights two critical issues: first, if startDetached fails, the PID remains 0, causing kill(0, SIGTERM) to prematurely terminate the entire process group; second, a failed connectToPeer call leaves a stale, unconnected connection in the global registry, which must be explicitly cleaned up using disconnectFromPeer to avoid caching issues in subsequent connection attempts.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread apps/ll-cli/src/main.cpp
Comment on lines +61 to +69
qint64 pid = 0;
process.startDetached(&pid);

LogD("start {} {} as {}", program.toStdString(), args.join(" ").toStdString(), pid);

QObject::connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, [pid]() {
LogD("kill {}", pid);
kill(pid, SIGTERM);
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

If QProcess::startDetached fails to start the process, pid will remain 0. Calling kill(0, SIGTERM) inside the aboutToQuit lambda will send SIGTERM to all processes in the current process group, terminating the calling application (ll-cli) and any other sibling processes prematurely.

We must check the return value of startDetached and ensure pid > 0 before registering the cleanup connection.

    qint64 pid = 0;
    if (!process.startDetached(&pid) || pid <= 0) {
        LogE("failed to start process: {}", program.toStdString());
        return;
    }

    LogD("start {} {} as {}", program.toStdString(), args.join(" ").toStdString(), pid);

    QObject::connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, [pid]() {
        LogD("kill {}", pid);
        kill(pid, SIGTERM);
    });

Comment thread apps/ll-cli/src/main.cpp
Comment on lines +719 to +734
// Check if ll-package-manager is already running
auto pkgManConn = QDBusConnection::connectToPeer(pkgManAddress, "ll-package-manager");
if (!pkgManConn.isConnected()) {
// Only start a new process if no existing one is listening
startProcess("sudo",
{ "--user",
LINGLONG_USERNAME,
"--preserve-env=QT_FORCE_STDERR_LOGGING",
"--preserve-env=QDBUS_DEBUG",
LINGLONG_LIBEXEC_DIR "/ll-package-manager",
"--no-dbus" });
using namespace std::chrono_literals;
std::this_thread::sleep_for(1s);
} else {
LogD("ll-package-manager is already running, reuse existing process");
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

When QDBusConnection::connectToPeer is called, it registers the connection globally under the specified name ("ll-package-manager"). If the connection attempt fails, this unconnected connection remains registered in the global registry.

Any subsequent call to QDBusConnection::connectToPeer with the same name (such as in Cli::getPkgMan()) will return this cached, unconnected connection instead of attempting a new connection to the newly spawned daemon.

To prevent this, we must call QDBusConnection::disconnectFromPeer("ll-package-manager") if isConnected() returns false.

        // Check if ll-package-manager is already running
        auto pkgManConn = QDBusConnection::connectToPeer(pkgManAddress, "ll-package-manager");
        if (!pkgManConn.isConnected()) {
            QDBusConnection::disconnectFromPeer("ll-package-manager");
            // Only start a new process if no existing one is listening
            startProcess("sudo",
                         { "--user",
                           LINGLONG_USERNAME,
                           "--preserve-env=QT_FORCE_STDERR_LOGGING",
                           "--preserve-env=QDBUS_DEBUG",
                           LINGLONG_LIBEXEC_DIR "/ll-package-manager",
                           "--no-dbus" });
            using namespace std::chrono_literals;
            std::this_thread::sleep_for(1s);
        } else {
            LogD("ll-package-manager is already running, reuse existing process");
        }

@deepin-ci-robot

Copy link
Copy Markdown
Collaborator

deepin pr auto review


★ 总体评分:30分

■ 【总体评价】

代码通过 DBus 探测优化了进程的重复启动问题,但存在严重的进程组信号误杀逻辑缺陷及本地安全风险
逻辑正确性存在严重缺陷且包含高危和中危安全漏洞,依据安全优先原则强制扣分至30分

■ 【详细分析】

  • 1.语法逻辑(存在严重错误)✕

startProcess 函数中,若 QProcess::startDetached 执行失败,传入的 pid 引用不会被修改,其值保持为 0。当主进程退出触发 aboutToQuit 信号时,Lambda 表达式会执行 kill(0, SIGTERM)。根据 POSIX 标准,向 pid 为 0 发送信号会将该信号发送给调用进程所在的整个进程组,导致当前进程及同组进程全部被异常终止,属于致命的逻辑缺陷。
潜在问题:进程启动失败时导致自身及关联进程被批量误杀;DBus 连接对象 pkgManConn 在 if 作用域结束时析构,可能引发不必要的资源波动
建议:必须校验 startDetached 的返回值,并在返回值为 false 或 pid 为 0 时直接返回,不注册清理回调

  • 2.代码质量(一般)✕

startProcess 封装提高了复用性,但缺少对底层调用失败情况的处理,且在主流程中硬编码了 Socket 路径。此外,使用 std::this_thread::sleep_for(1s) 进行固定时长阻塞等待属于不良实践,未体现超时重试或事件驱动的现代编程规范。
潜在问题:硬编码路径降低了代码可维护性与跨环境适配能力;静默忽略进程启动失败错误
建议:将 Socket 路径提取为全局宏或常量;将固定睡眠改为基于 DBus 连接成功的轮询等待机制

  • 3.代码性能(存在性能问题)✕

修改后的代码保留了原有的 std::this_thread::sleep_for(1s) 阻塞主线程逻辑。在实际生产环境中,服务启动时间可能小于 1 秒导致资源闲置,也可能大于 1 秒导致后续操作失败,固定阻塞无法平衡效率与可靠性。
潜在问题:主线程无谓阻塞降低了 CLI 工具的响应速度
建议:实现指数退避轮询机制,循环尝试连接 DBus Peer,直到成功或达到最大超时阈值

  • 4.代码安全(存在 2 个安全漏洞(高危1个,中危1个))✕

漏洞对比统计:新增漏洞 2 个,减少漏洞 0 个,持平 0 个
代码在进程生命周期管理与 IPC 通信寻址上引入了本地拒绝服务与劫持风险,攻击面集中于信号处理与文件系统路径

  • 安全漏洞1:【高危】在 startProcess 函数中,当 QProcess::startDetached 启动失败时,pid 变量保持初始值 0。此时若主进程退出触发 aboutToQuit 信号,会执行 kill(0, SIGTERM)。根据 POSIX 标准,向 pid 为 0 发送信号会将其发送给调用进程所在的整个进程组,导致当前进程及其同组进程全部被异常终止,构成本地拒绝服务及潜在的权限绕过风险。——非常重要

  • 安全漏洞2:【中危】在 main.cpp 的启动逻辑中,硬编码了 DBus socket 路径 /tmp/linglong-package-manager.socket/tmp 目录通常具有全局可写权限,攻击者可预先创建同名符号链接指向恶意服务的 socket。当客户端尝试连接时,会导致与恶意服务通信,引发敏感信息泄露或指令伪造。——非常重要

  • 建议:在 startProcess 中增加 if (!started || pid == 0) return; 的防御性判断;将 Socket 路径从 /tmp 迁移至受权限保护的 XDG_RUNTIME_DIR 目录

■ 【改进建议代码示例】

+++ b/apps/ll-cli/src/main.cpp
@@ -49,20 +49,30 @@ namespace {
 
 void startProcess(const QString &program, const QStringList &args = {})
 {
     QProcess process;
     auto envs = process.environment();
     envs.push_back("QT_FORCE_STDERR_LOGGING=1");
     process.setEnvironment(envs);
     process.setProgram(program);
     process.setArguments(args);
 
     qint64 pid = 0;
-    process.startDetached(&pid);
+    bool started = process.startDetached(&pid);
 
-    LogD("start {} {} as {}", program.toStdString(), args.join(" ").toStdString(), pid);
+    if (!started || pid == 0) {
+        LogE("Failed to start process {} {}", program.toStdString(), args.join(" ").toStdString());
+        return;
+    }
+
+    LogD("start {} {} as pid {}", program.toStdString(), args.join(" ").toStdString(), pid);
 
     QObject::connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, [pid]() {
         LogD("kill {}", pid);
         kill(pid, SIGTERM);
     });
 }
@@ -714,7 +724,8 @@ You can report bugs to the linyaps team under this project: https://github.com/O
             return -1;
         }
 
-        const auto pkgManAddress = QString("unix:path=/tmp/linglong-package-manager.socket");
+        // Use secure runtime directory instead of /tmp to prevent Symlink Attacks
+        const auto pkgManAddress = QString("unix:path=%1/linglong-package-manager.socket").arg(qgetenv("XDG_RUNTIME_DIR"));
 
         // Check if ll-package-manager is already running
         auto pkgManConn = QDBusConnection::connectToPeer(pkgManAddress, "ll-package-manager");

@codecov

codecov Bot commented Jun 29, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 0% with 20 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
apps/ll-cli/src/main.cpp 0.00% 20 Missing ⚠️
Files with missing lines Coverage Δ
apps/ll-cli/src/main.cpp 0.00% <0.00%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@deepin-ci-robot

Copy link
Copy Markdown
Collaborator

@dengbo11: The following test failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
github-pr-review-ci 024103d link true /test github-pr-review-ci

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. I understand the commands that are listed here.

@dengbo11 dengbo11 merged commit 2bdacb7 into OpenAtom-Linyaps:master Jun 30, 2026
15 of 18 checks passed
@deepin-ci-robot

Copy link
Copy Markdown
Collaborator

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: dengbo11, reddevillg

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@dengbo11 dengbo11 deleted the fix-pm-socket branch July 1, 2026 05:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants