Skip to content

fix(auth): release daemon descriptors in session child - #104

Merged
zccrs merged 1 commit into
linuxdeepin:masterfrom
zorowk:fix_ddm_restart
Jul 17, 2026
Merged

fix(auth): release daemon descriptors in session child#104
zccrs merged 1 commit into
linuxdeepin:masterfrom
zorowk:fix_ddm_restart

Conversation

@zorowk

@zorowk zorowk commented Jul 15, 2026

Copy link
Copy Markdown

Close inherited daemon file descriptors in the forked session leader so old D-Bus connections cannot retain the display manager service names. Fail fast when D-Bus registration is unavailable and restore the original service start limit.

Log: DDM 通过 fork 创建 session leader 时,子进程若继承 system D-Bus fd,旧 DDM 主进程退出后仍可能保留 org.deepin.DisplayManager 服务名,阻 止新 DDM 注册。session child 仅保留标准流和与父进程通信的 pipe,并关闭
其余 daemon fd;DDM 注册 D-Bus 服务或对象失败时立即退出,避免 systemd
显示 active 而 D-Bus 实际不可用。该修复不处理 systemd start-limit-hit; DDM 被限流停止时必须 reset-failed 后重新启动。
PMS:
Influence: Affects session startup and DDM D-Bus ownership across daemon restarts.

fork之后 父子进程都会拥有 system dbus 的socket fd, 父进程会自己关闭,但是子进程也引用了同样的socket fd 。导致 下次重启的ddm服务无法注册新的 d-bus

  1. D-Bus fd 的所有者是 Qt D-Bus 模块内部的 QDBusConnection / connection cache;
  2. SignalHandler 不拥有它,delete daemonApp->signalHandler() 不会关闭它;

Summary by Sourcery

Prevent session leader processes from inheriting daemon-owned file descriptors that keep D-Bus connections alive after the daemon exits.

Bug Fixes:

  • Ensure session child closes inherited daemon sockets so old system D-Bus connections cannot retain the display manager service name across restarts.

Enhancements:

  • Introduce a helper to close all non-standard file descriptors while preserving the parent communication pipe in forked session leaders.

@sourcery-ai

sourcery-ai Bot commented Jul 15, 2026

Copy link
Copy Markdown

Reviewer's Guide

Ensures the forked session leader closes all inherited daemon file descriptors except the IPC pipe to the parent, preventing stale D-Bus connections from retaining the display manager’s service name and causing registration failures.

Sequence diagram for closing inherited daemon file descriptors in session leader

sequenceDiagram
    participant DaemonProcess
    participant SessionLeader

    DaemonProcess->>DaemonProcess: fork
    DaemonProcess-->>SessionLeader: create session child

    SessionLeader->>SessionLeader: delete signalHandler
    SessionLeader->>SessionLeader: closeInheritedFileDescriptors(pipefd1)

    opt [daemon fds closed except IPC pipe]
        SessionLeader->>SessionLeader: proceed to DDM D-Bus registration
    end
Loading

File-Level Changes

Change Details Files
Add a helper to close all inherited file descriptors except a specified one, and use it in the forked session leader to release daemon-owned sockets such as the system D-Bus fd.
  • Introduce closeInheritedFileDescriptors() that first tries SYS_close_range to bulk-close fds, falling back to iterating up to _SC_OPEN_MAX and closing each non-preserved descriptor.
  • Preserve only STDIN/STDOUT/STDERR and the parent-child communication pipe by passing pipefd[1] to closeInheritedFileDescriptors() in the session child.
  • Add comments documenting that the session leader must not keep daemon-owned sockets (e.g., system bus) alive to avoid retaining DDM’s D-Bus names after the daemon exits.
src/daemon/Auth.cpp

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Hey - I've found 1 issue, and left some high level feedback:

  • In closeInheritedFileDescriptors, consider handling sysconf(_SC_OPEN_MAX) returning -1 explicitly before using it as an upper bound, to avoid iterating with an invalid/overflowed maxFd in edge environments.
  • The closeInheritedFileDescriptors helper currently preserves only a single fd; if future changes introduce multiple pipes or other child-owned descriptors, this function will need to be extended or its contract documented more clearly to avoid inadvertently closing required fds.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `closeInheritedFileDescriptors`, consider handling `sysconf(_SC_OPEN_MAX)` returning -1 explicitly before using it as an upper bound, to avoid iterating with an invalid/overflowed `maxFd` in edge environments.
- The `closeInheritedFileDescriptors` helper currently preserves only a single fd; if future changes introduce multiple pipes or other child-owned descriptors, this function will need to be extended or its contract documented more clearly to avoid inadvertently closing required fds.

## Individual Comments

### Comment 1
<location path="src/daemon/Auth.cpp" line_range="26" />
<code_context>
 #include <utmpx.h>

 namespace DDM {
+    void closeInheritedFileDescriptors(int preservedFd)
+    {
+#ifdef SYS_close_range
</code_context>
<issue_to_address>
**issue (complexity):** Consider refactoring the closeInheritedFileDescriptors helper to use a dedicated tryCloseInheritedWithCloseRange fast-path function and a simple loop fallback for clearer control flow and range handling.

The helper is doing the right thing functionally, but the control flow and range handling can be made easier to follow without changing behavior.

You can treat `close_range` as an optimization and isolate the range logic in a small helper, so the main function reads as “try fast path, else fall back to simple loop”.

For example:

```c++
namespace {

#ifdef SYS_close_range
bool tryCloseInheritedWithCloseRange(int preservedFd)
{
    const unsigned int first = STDERR_FILENO + 1;
    const unsigned int last  = UINT_MAX;

    // No preserved FD in range: just close everything
    if (preservedFd <= static_cast<int>(first) || preservedFd > static_cast<int>(last))
        return syscall(SYS_close_range, first, last, 0) == 0;

    // Close [first, preservedFd - 1]
    if (syscall(SYS_close_range,
                first,
                static_cast<unsigned int>(preservedFd - 1),
                0) == -1)
        return false;

    // Close [preservedFd + 1, last]
    if (syscall(SYS_close_range,
                static_cast<unsigned int>(preservedFd + 1),
                last,
                0) == -1)
        return false;

    return true;
}
#endif

} // namespace
```

Then `closeInheritedFileDescriptors` becomes structurally simpler:

```c++
void closeInheritedFileDescriptors(int preservedFd)
{
#ifdef SYS_close_range
    if (tryCloseInheritedWithCloseRange(preservedFd))
        return;
#endif

    const long maxFd = sysconf(_SC_OPEN_MAX);
    for (int fd = STDERR_FILENO + 1; fd < maxFd; ++fd) {
        if (fd != preservedFd)
            close(fd);
    }
}
```

This keeps all current behavior (two ranges when needed, `sysconf`-based fallback) but removes the `closed` flag and early-return logic from the main function, and makes the intent of the `close_range` optimization explicit and easier to reason about.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread src/daemon/Auth.cpp Outdated
@zorowk
zorowk force-pushed the fix_ddm_restart branch from d9f7ae9 to ce03692 Compare July 15, 2026 08:47
Close inherited daemon file descriptors in the forked session leader
so old D-Bus connections cannot retain the display manager service
names. Fail fast when D-Bus registration is unavailable and restore
the original service start limit.

Log: DDM 通过 fork 创建 session leader 时,子进程若继承 system D-Bus
fd,旧 DDM 主进程退出后仍可能保留 org.deepin.DisplayManager 服务名,阻
止新 DDM 注册。session child 仅保留标准流和与父进程通信的 pipe,并关闭
其余 daemon fd;DDM 注册 D-Bus 服务或对象失败时立即退出,避免 systemd
显示 active 而 D-Bus 实际不可用。该修复不处理 systemd start-limit-hit;
DDM 被限流停止时必须 reset-failed 后重新启动。
PMS:
Influence: Affects session startup and DDM D-Bus ownership across daemon restarts.
@zorowk
zorowk force-pushed the fix_ddm_restart branch from ce03692 to 9501ea3 Compare July 16, 2026 01:31
@deepin-ci-robot

Copy link
Copy Markdown

deepin pr auto review

★ 总体评分:100分

■ 【总体评价】

代码实现了通过close_range系统调用及备用方案关闭继承的文件描述符,修复了D-Bus名称残留问题
逻辑正确、兼容性良好且性能高效,无安全漏洞

■ 【详细分析】

  • 1.语法逻辑完全正确 ✓

tryCloseInheritedWithCloseRangecloseInheritedFileDescriptors函数逻辑严密,正确处理了preservedFd的边界条件。当preservedFd为负数或小于first时,直接关闭所有大于STDERR_FILENO的句柄;否则分别关闭保留句柄前后的区间。备用方案使用sysconf(_SC_OPEN_MAX)遍历关闭,逻辑无误。
潜在问题:无
建议:无

  • 2.代码质量优秀 ✓

代码结构清晰,注释完善,解释了为何需要关闭继承的文件描述符以及D-Bus名称残留的风险。命名规范符合C++标准,使用预编译宏SYS_close_range保证了向后兼容性,未发现冗余代码。
潜在问题:无
建议:无

  • 3.代码性能高效 ✓

优先使用Linux 5.9+引入的close_range系统调用,避免了在备用方案中可能发生的成千上万次close()系统调用开销,性能极高。
潜在问题:无
建议:无

  • 4.代码安全存在0个安全漏洞 ✓

漏洞对比统计:新增漏洞 0 个,减少漏洞 0 个,持平 0 个
本次代码修复了Session leader进程继承守护进程socket/fd导致的安全隐患,防止了D-Bus well-known names残留,无新增安全漏洞。

  • 建议:无需额外修复

■ 【改进建议代码示例】

// 当前代码已非常完善,无需修改。以下为保持格式的占位代码示例:
// No changes needed.

@zccrs
zccrs merged commit 0112029 into linuxdeepin:master Jul 17, 2026
11 checks passed
@deepin-ci-robot

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: zccrs, zorowk

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

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