Skip to content

fix: stabilize Treeland VT session switching#94

Open
zccrs wants to merge 3 commits into
linuxdeepin:masterfrom
zccrs:vt-treeland-dde-seatd
Open

fix: stabilize Treeland VT session switching#94
zccrs wants to merge 3 commits into
linuxdeepin:masterfrom
zccrs:vt-treeland-dde-seatd

Conversation

@zccrs
Copy link
Copy Markdown
Member

@zccrs zccrs commented May 27, 2026

Summary

  • integrate standalone dde-seatd service and inject SEATD_SOCK for treeland.service
  • run Treeland PAM sessions through a clean helper process to preserve keyring unlock
  • fix managed/unmanaged VT switching and add wlroots VM validation tools

Validation

  • cmake --build build
  • ctest --test-dir build --output-on-failure
  • git diff --check
  • product VM validation: alice tty2, bob tty3, unmanaged tty6 pause/resume

Related

Copy link
Copy Markdown

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

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

Sorry @zccrs, your pull request is larger than the review limit of 150000 diff characters

@deepin-ci-robot
Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: zccrs

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

@zccrs zccrs force-pushed the vt-treeland-dde-seatd branch 8 times, most recently from 1dcc5df to fec0370 Compare May 28, 2026 06:53
Depend on dde-seatd.service from the dde-seatd package and point Treeland at /run/dde-seatd.sock. This keeps DDM from installing its own seatd service while preserving the product runtime wiring.
@zccrs zccrs force-pushed the vt-treeland-dde-seatd branch from fec0370 to 235d3d6 Compare May 28, 2026 10:17
Connect DDM to the dde-seatd control socket and register Treeland user VTs with the compositor owner pidfd. This keeps DDM focused on session policy while dde-seatd owns grouped VT switching and seat client lifetime.
@zccrs zccrs force-pushed the vt-treeland-dde-seatd branch from 235d3d6 to 64abec6 Compare May 28, 2026 10:29
@zccrs zccrs requested a review from Copilot May 30, 2026 06:11
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Stabilizes Treeland VT session switching by integrating an external dde-seatd control socket for grouped-VT allocation/events, running Treeland PAM sessions in a separate helper process to preserve the kernel keyring, and reworking VT management (managed/unmanaged switching, new activateVt helper) to remove the previous wl_callback-based render handshake.

Changes:

  • Replace the in-process VT release/acquire handshake with a control protocol over /run/dde-seatd-control.sock, including new request/event opcodes and async event handling in TreelandConnector.
  • Refactor UserSession::childModifier to be side-effect-isolated (no Qt allocations after fork) and add UserSession::startDirect so the session leader can fork/exec the Treeland session directly from the PAM helper process.
  • Add a --session-helper mode of the ddm binary plus serializable request/response plumbing in Auth, switch systemd units to require dde-seatd.service, and bookkeeping changes in Display::login for the new grouped-VT lifecycle.

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
src/daemon/VirtualTerminal.h Declare new activateVt helper.
src/daemon/VirtualTerminal.cpp Implement activateVt; guard signal connection against duplicates.
src/daemon/UserSession.h Add startDirect, child context fields, prepareChildContext.
src/daemon/UserSession.cpp Cache child context pre-fork; reimplement childModifier with async-signal-safe primitives; add startDirect.
src/daemon/TreelandDisplayServer.cpp Check D-Bus reply when starting treeland.service.
src/daemon/TreelandConnector.h New control-socket members and grouped-VT API.
src/daemon/TreelandConnector.cpp Replace VT signal handshake with dde-seatd control protocol; add create/destroy grouped VT, event handling.
src/daemon/SocketServer.cpp Fall back to serverName() when fullServerName() is empty.
src/daemon/Display.cpp Allocate per-user VT, manage auth list early, destroy grouped VT on failure, tweak unlock VT switch.
src/daemon/DaemonApp.cpp Dispatch --session-helper to runSessionHelper.
src/daemon/Auth.h Declare runSessionHelper and helper-process entry.
src/daemon/Auth.cpp Add session-helper subprocess with serialized request/response and lifecycle FD; route Treeland sessions through helper.
src/common/SignalHandler.cpp Unblock added custom signals after installing the handler.
services/treeland-dde-seatd.conf.in New drop-in pointing Treeland at the dde-seatd socket.
services/ddm.service.in Require dde-seatd.service instead of seatd.service.
services/CMakeLists.txt Install the new Treeland drop-in.
debian/control Switch packaging dependency to dde-seatd.

Comment thread src/daemon/TreelandConnector.cpp Outdated
Comment thread src/daemon/TreelandConnector.cpp
Comment thread src/daemon/VirtualTerminal.cpp Outdated
Comment thread src/daemon/Display.cpp
Comment thread src/daemon/UserSession.cpp
Comment thread services/treeland-dde-seatd.conf.in
Route Treeland-owned VT events back to the greeter or user session.

将Treeland管理的VT事件路由回greeter或用户会话。

Log: 完善Treeland VT激活处理

Influence: DDM根据dde-seatd的VT激活事件恢复Treeland渲染和greeter状态,便于定位tty切换问题。
@zccrs zccrs force-pushed the vt-treeland-dde-seatd branch from ab14efa to b611e69 Compare May 30, 2026 10:15
@deepin-ci-robot
Copy link
Copy Markdown

deepin pr auto review

这是一次非常庞大且核心的改动,主要涉及将显示管理器 (ddm) 与 seatd 的集成方式从原生 seatd 迁移至自定义的 dde-seatd,并重构了 Treeland 会话的 VT(虚拟终端)管理、会话启动流程(引入了 Helper 进程隔离机制)以及子进程上下文初始化。

以下是对该 diff 的详细代码审查意见,分为语法逻辑、代码质量、代码性能和代码安全四个方面:

一、 语法与逻辑

  1. 管道文件描述符(FD)泄漏风险

    • 文件src/daemon/Auth.cpp -> openSessionInHelperProcess
    • 问题:在 fork() 之后的子进程分支 (case 0) 中,代码使用了 dup2 将管道重定向到 STDIN/STDOUT,并关闭了原管道的一端,但没有关闭 lifecyclePipe[1] 的写端。虽然父进程关闭了 lifecyclePipe[1],但子进程依然持有它的引用。如果后续子进程意外写入,可能会导致父进程的 QSocketNotifier 误触发。
    • 建议:在子进程 dup2 之后,显式关闭不需要的 FD:
      close(lifecyclePipe[1]); // 子进程不需要生命周期管道的写端
  2. read 系统调用的部分读取逻辑缺失

    • 文件src/daemon/Auth.cpp -> openSession
    • 问题:在父进程读取 xdgSessionIdsessionPid 时,虽然增加了对 read 返回值大小的校验,但 read 可能会返回部分数据(例如只读到了 2 字节的 int),此时 sessionIdBytes != sizeof(int) 会直接失败。
    • 建议:对于管道读取,应当使用类似 readAllFromFd 或循环读取的逻辑,确保读满所需的 sizeof(int)sizeof(qint64),而不是一次 read 就期望读全。
  3. Qt 元类型系统注册缺失(潜在崩溃风险)

    • 文件src/daemon/Auth.cpp
    • 问题:新增了 SessionHelperRequestSessionHelperResponse 结构体,并为它们重载了 QDataStream<<>> 操作符。虽然代码中主要使用自定义的 serializeRequest 进行序列化,但如果未来有人将这些结构体放入 Qt 的信号槽或 QVariant 中,会导致编译或运行时错误。
    • 建议:如果仅用于当前的手动序列化,可以不注册;但为了健壮性,建议在文件开头或 main 函数中使用 Q_DECLARE_METATYPEqRegisterMetaType 进行注册。
  4. Lambda 捕获悬空引用风险

    • 文件src/daemon/Auth.cpp -> openSessionInHelperProcess
    • 问题QObject::connect(m_notifier, ..., [this, lifecyclePipe] { ... }); 这里按值捕获了 lifecyclePipe(一个数组),按指针捕获了 this。如果 Auth 对象在生命周期管道关闭之前被析构,this 将变为悬空指针。
    • 建议:确保 QSocketNotifier 的生命周期严格受 Auth 对象控制,或者在 lambda 中使用 QObject::deleteLater 和断开连接的逻辑来防止 this 被非法访问。

二、 代码质量

  1. 调试日志滥用 qWarning

    • 文件src/daemon/TreelandConnector.cpp, src/daemon/TreelandDisplayServer.cpp, src/daemon/Display.cpp
    • 问题:大量正常业务逻辑的输出使用了 qWarning,例如:
      • qWarning("dde-seatd VT active event: ...")
      • qWarning("Calling treeland switch_to_greeter")
      • qWarning("Send greeter activation: ...")
    • 建议:正常的状态流转和信息输出应使用 qDebugqInfoqWarningqCritical 应保留给真正的异常和错误情况,以免系统日志被无用信息淹没,掩盖真正的错误。
  2. childModifier 中的错误处理重构

    • 文件src/daemon/UserSession.cpp
    • 优点:引入了 childDiechildDieErrno,统一了子进程 fork() 后的错误退出逻辑,避免了 Qt 的 qCritical 在子进程中的不安全性,这是一个非常好的改进。
    • 建议:保持一致性,将子进程中所有的异常退出都替换为这两个函数。
  3. 魔法数字

    • 文件src/daemon/TreelandConnector.cpp -> handleControlSocket
    • 问题if (header.size > 4096) 使用了硬编码的魔法数字。
    • 建议:定义为常量,如 static constexpr uint16_t MAX_CONTROL_PAYLOAD_SIZE = 4096;

三、 代码性能

  1. QDataStream 序列化的开销

    • 文件src/daemon/Auth.cpp
    • 问题:Helper 进程通信使用了 QDataStreamQDataStream 在序列化时会附加版本号等信息,且对于字符串列表(如 environment)的序列化涉及多次内存分配。对于高频调用的 IPC,这有一定开销。
    • 建议:当前场景(登录开session)频率极低,性能影响可忽略不计。但需注意 Qt 版本升级可能导致 QDataStream 默认版本变化从而引发兼容性问题。建议在 QDataStream 初始化时显式指定版本:QDataStream stream(&data, QIODevice::WriteOnly); stream.setVersion(QDataStream::Qt_5_15);
  2. fetchAvailableUserVt 的轮询效率

    • 文件src/daemon/Display.cpp
    • 问题:遍历从 DDM_INITIAL_VTMAX_NR_CONSOLES 的所有 VT,并在内部调用 isTtyInUse,这可能涉及多次文件系统 /dev/ttyXstatopen 调用。
    • 建议:如果 MAX_NR_CONSOLES 很大(如 63),这在极端情况下会有微小的延迟。目前可接受,但如果后续有性能瓶颈,可以考虑通过 logind 的 DBus 接口一次性获取活跃的 session 列表来判断。

四、 代码安全

  1. 敏感信息(密码)内存残留

    • 文件src/daemon/Auth.cpp
    • 优点:代码中已经注意到了这一点,使用了 secret.fill('\0')request->secret.fill('\0') 来清空密码内存,这是非常好的安全实践。
    • 隐患QByteArrayfill('\0') 后,其底层 d 指针的内存依然存在,且如果 Qt 发生了隐式共享的深拷贝,之前的内存可能不会被清零。
    • 建议:对于极高安全要求的场景,建议使用自定义的安全 Buffer 类(类似 OpenSSL 的 OPENSSL_cleanse 或带有 volatile 修饰的内存清零),或者确保 QByteArrayfill 后调用 squeeze() 释放多余内存,并尽量避免在传递过程中触发隐式共享分离。
  2. 子进程环境变量泄露

    • 文件src/daemon/Auth.cpp -> runSessionHelper
    • 问题:Helper 子进程通过 setenv("DDM_SESSION_HELPER_LIFECYCLE_FD", ...) 传递 FD。这个环境变量会随着 execve 继承到后续的 UserSession 中。
    • 建议:在 UserSession::startDirectchildModifierexecve 之前,应当 unsetenv("DDM_SESSION_HELPER_LIFECYCLE_FD"),防止普通用户会话进程看到并恶意操作这个 FD。
  3. Socket 权限与路径安全

    • 文件src/daemon/TreelandConnector.cpp -> connectUnixSocket
    • 问题:硬编码了 /run/dde-seatd-control.sock。在连接时,没有校验该 Socket 文件的属主和权限。
    • 建议:在连接前,建议通过 stat 检查该 Socket 文件的 UID 是否为 root(或预期的特权用户),防止本地普通用户通过符号链接等方式进行劫持(虽然 /run 通常只有 root 可写,但防御性编程总是好的)。
  4. makeParentDirs 的目录权限

    • 文件src/daemon/UserSession.cpp
    • 问题:创建目录时使用了 mkdir(dir, 0700),这是安全的。但需确保在 setuid 之前执行此操作,否则可能由于权限不足创建在错误的位置。当前代码在 childModifier 中,执行顺序是先处理 VT,再 setuid,再创建目录,逻辑上似乎有些错位。
    • 建议:仔细核对 makeParentDirs 的执行时机。由于此时已经 chdir 到用户目录,相对路径的日志文件会在用户目录下创建,0700 权限是合理的。

总结

这次重构整体质量很高,特别是引入 Helper 进程来隔离 PAM 和 Session 启动逻辑,以及使用 dde-seatd 替代原生 VT 信号处理,解决了 Wayland 合成器下 VT 切换的复杂时序问题。代码的错误处理和子进程安全性得到了显著提升。

必须修改的关键点

  1. 修复 Helper 子进程中 lifecyclePipe[1] 未关闭的逻辑漏洞。
  2. 将正常流程的 qWarning 降级为 qDebugqInfo
  3. 在用户会话启动前清除 DDM_SESSION_HELPER_LIFECYCLE_FD 环境变量。

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