Skip to content

fix(control): fix grouped VT leak on destroy request - #8

Merged
zccrs merged 1 commit into
linuxdeepin:masterfrom
glyvut:master
Jul 13, 2026
Merged

zccrs merged 1 commit into
linuxdeepin:masterfrom
glyvut:master

Conversation

@glyvut

@glyvut glyvut commented Jul 13, 2026 •

Copy link
Copy Markdown
Contributor

Process EVENT_READABLE before EVENT_HANGUP in the control client handler. Checking HANGUP first discards unread data when the peer closes the socket right after sending a fire-and-forget request, causing the destroy opcode to never be dispatched. Also remove the owner_pid != client->pid permission check in handle_destroy_group_vt: the control socket is already restricted to root, and ddm — not Treeland — is the lifecycle owner that issues destroy, so the check always failed with EPERM.

在 control 客户端事件处理中将 EVENT_READABLE 提前到 EVENT_HANGUP 之前。 先检查 HANGUP 会丢弃未读数据,导致 fire-and-forget 请求的 destroy 操作 码无法分发。同时移除 handle_destroy_group_vt 中的 owner_pid != client->pid 权限校验:control socket 已限制仅 root 可连接,且 ddm(非 Treeland)才是发起 destroy 的生命周期管理者,该校验必然返回 EPERM。

Log: 修复 grouped VT 销毁请求丢失导致 VT 泄漏
PMS: BUG-367465
Influence: 修复后手动注销时 grouped VT 能正常释放,避免 VT 逐个泄漏耗尽导致登录无响应。

Summary by Sourcery

Handle control client readable events before hangup and relax grouped VT destroy permissions to ensure destroy requests are processed and resources freed correctly.

Bug Fixes:

  • Ensure fire-and-forget destroy_group_vt requests are dispatched by processing readable data before treating the control socket as hung up.
  • Allow grouped VT destroy operations to succeed by removing an incorrect owner PID permission check that always rejected valid destroy requests.

Summary by Sourcery

Ensure grouped VT destroy requests from the control socket are reliably processed so associated VTs are correctly freed.

Bug Fixes:

  • Prevent loss of fire-and-forget destroy_group_vt requests by handling readable control client data before reacting to hangup events.
  • Allow grouped VT destroy operations to succeed by removing an incorrect owner PID permission check tied to the client process.

@deepin-ci-robot

Copy link
Copy Markdown

Skipping CI for Draft Pull Request.
If you want CI signal for your change, please convert it to an actual PR.
You can still manually trigger a test run with /test all

@sourcery-ai

sourcery-ai Bot commented Jul 13, 2026 •

Copy link
Copy Markdown
Reviewer's guide (collapsed on small PRs)

Reviewer's Guide

This PR fixes loss of destroy_group_vt requests (causing grouped VT leaks) by reordering control client event handling to consume readable data before treating sockets as hung up and by removing an incorrect PID-based permission check in the grouped VT destroy path.

Sequence diagram for updated control_client_handle_connection event ordering

sequenceDiagram
    participant EventLoop
    participant ControlClient
    participant Connection
    participant Server

    EventLoop->>ControlClient: control_client_handle_connection(fd, mask, client)
    alt mask has EVENT_READABLE
        ControlClient->>Connection: connection_read(&client->connection)
        Connection-->>ControlClient: len > 0
        ControlClient->>Server: handle_destroy_group_vt(client)
        Server->>Server: seat_destroy_group_vt(seat, request.vt)
    end
    alt mask has EVENT_HANGUP
        ControlClient->>ControlClient: goto fail
    end
Loading

Flow diagram for handle_destroy_group_vt without PID ownership check

flowchart TD
    A["handle_destroy_group_vt(client)"] --> B["seat = seat_get(client)"]
    B --> C{seat == NULL?}
    C -->|yes| D["control_send_error(client, ENOENT)"]
    C -->|no| E["seat_destroy_group_vt(seat, request.vt)"]
    E --> F{return value == -1?}
    F -->|yes| G["control_send_error(client, errno)"]
    F -->|no| H["control_send_success(client)"]
Loading

File-Level Changes

Change Details Files
Relax grouped VT destroy permissions so valid destroy requests from the control client are no longer rejected.
  • Remove lookup of group VT owner PID before destroy
  • Remove comparison of owner PID against control client PID
  • Allow seat_destroy_group_vt to be called unconditionally once the seat and VT exist, with errors reported directly from destroy
seatd/control.c
Ensure readable control socket data is processed before hangup, so fire-and-forget destroy requests are not dropped when the peer closes the connection immediately after sending.
  • Stop treating EVENT_HANGUP as an immediate failure at the start of control_client_handle_connection
  • Process EVENT_WRITABLE and EVENT_READABLE (including command dispatch) before any hangup handling
  • Add a final EVENT_HANGUP check after readable data has been fully consumed to close the client cleanly
seatd/control.c

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

@glyvut
glyvut marked this pull request as ready for review July 13, 2026 05:10

@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 left some high level feedback:

  • Given the removal of the owner_pid permission check, consider adding a brief comment near handle_destroy_group_vt explaining why root-only control access and ddm ownership are sufficient for security, so future readers don’t reintroduce the check.
  • In control_client_handle_connection, it may be helpful to clarify in a short comment or assertion that EVENT_HANGUP will not be processed before all readable data is consumed even when both bits are set, to make the intent around fire-and-forget requests explicit.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- Given the removal of the owner_pid permission check, consider adding a brief comment near handle_destroy_group_vt explaining why root-only control access and ddm ownership are sufficient for security, so future readers don’t reintroduce the check.
- In control_client_handle_connection, it may be helpful to clarify in a short comment or assertion that EVENT_HANGUP will not be processed before all readable data is consumed even when both bits are set, to make the intent around fire-and-forget requests explicit.

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.

@glyvut

glyvut commented Jul 13, 2026

Copy link
Copy Markdown
Contributor Author

deepin pr auto review

★ 总体评分:40分

一个恶意的且拿到了 root 的客户端是在这儿加个判定就能防住的吗

@glyvut
glyvut requested a review from zccrs July 13, 2026 06:38
Process EVENT_READABLE before EVENT_HANGUP in the control client
handler.  Checking HANGUP first discards unread data when the peer
closes the socket right after sending a fire-and-forget request,
causing the destroy opcode to never be dispatched.  Also remove the
owner_pid != client->pid permission check in handle_destroy_group_vt:
the control socket is already restricted to root, and ddm — not
Treeland — is the lifecycle owner that issues destroy, so the check
always failed with EPERM.

在 control 客户端事件处理中将 EVENT_READABLE 提前到 EVENT_HANGUP 之前。
先检查 HANGUP 会丢弃未读数据,导致 fire-and-forget 请求的 destroy 操作
码无法分发。同时移除 handle_destroy_group_vt 中的 owner_pid !=
client->pid 权限校验:control socket 已限制仅 root 可连接,且 ddm(非
Treeland)才是发起 destroy 的生命周期管理者,该校验必然返回 EPERM.

Log: 修复 grouped VT 销毁请求丢失导致 VT 泄漏
PMS: BUG-367465
Influence: 修复后手动注销时 grouped VT 能正常释放,避免 VT 逐个泄漏耗尽导致登录无响应
@deepin-ci-robot

Copy link
Copy Markdown

deepin pr auto review

★ 总体评分:40分

■ 【总体评价】

代码修复了客户端断连时未处理已读数据的竞态问题,但移除了VT销毁的权限校验引入严重安全漏洞
逻辑部分改进正确,但因删除权限校验导致高危漏洞扣分且触发安全上限

■ 【详细分析】

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

control_client_handle_connection 中将 EVENT_HANGUP 的处理移至 EVENT_READABLE 之后,逻辑正确,有效避免了客户端断开连接时未消费数据被丢弃的竞态问题。但 handle_destroy_group_vt 中直接删除了 VT owner PID 的校验逻辑,导致核心权限控制逻辑缺失。
潜在问题:任意客户端可触发 VT 销毁逻辑,破坏系统正常会话管理
建议:恢复 handle_destroy_group_vt 中的 PID 权限校验逻辑,或采用更安全的替代验证机制

  • 2.代码质量(良好)✓

新增的注释 /* Process readable data BEFORE acting on HANGUP. */ 和 /* All readable data has been consumed. Now honour the hangup. */ 清晰说明了调整事件处理顺序的意图和原因,代码可读性良好。
潜在问题:无
建议:保持当前注释风格,在涉及安全校验的代码处补充相应说明

  • 3.代码性能(无性能问题)✓

事件处理顺序的调整不涉及额外计算或内存开销,对性能无负面影响。
潜在问题:无
建议:无

  • 4.代码安全(存在 1 个安全漏洞)✕

漏洞对比统计:新增漏洞 1 个,减少漏洞 0 个,持平 0 个
移除权限校验导致任意客户端可越权销毁 VT,攻击面位于 seatd 的 control socket 通信层

  • 安全漏洞1【高危】:权限绕过 在 handle_destroy_group_vt 中,移除了 seat_get_group_vt_owner_pid 和 owner_pid != client->pid 的校验,导致任意已连接的 control client 可以销毁不属于其拥有的 VT,可被恶意利用引发拒绝服务或破坏其他用户会话 ——非常重要

  • 建议:恢复权限校验代码,确保只有 VT 的所有者才能发起销毁请求

■ 【改进建议代码示例】

diff --git a/seatd/control.c b/seatd/control.c
index ae9ce22..537c039 100644
--- a/seatd/control.c
+++ b/seatd/control.c
@@ -226,13 +226,6 @@ static int handle_destroy_group_vt(struct control_client *client) {
 	if (seat == NULL) {
 		return control_send_error(client, ENOENT);
 	}
+	/* 必须保留权限校验,防止越权销毁 VT */
+	pid_t owner_pid = -1;
+	if (seat_get_group_vt_owner_pid(seat, request.vt, &owner_pid) == -1) {
+		return control_send_error(client, errno);
+	}
+	if (owner_pid != client->pid) {
+		return control_send_error(client, EPERM);
+	}
 	if (seat_destroy_group_vt(seat, request.vt) == -1) {
 		return control_send_error(client, errno);
 	}
@@ -322,9 +315,6 @@ static int control_client_handle_connection(int fd, uint32_t mask, void *data) {
 	if (mask & EVENT_ERROR) {
 		goto fail;
 	}
-	if (mask & EVENT_HANGUP) {
-		goto fail;
-	}
 
 	if (mask & EVENT_WRITABLE) {
 		int len = connection_flush(&client->connection);
@@ -337,6 +327,7 @@ static int control_client_handle_connection(int fd, uint32_t mask, void *data) {
 		}
 	}
 
+	/* Process readable data BEFORE acting on HANGUP. */
 	if (mask & EVENT_READABLE) {
 		int len = connection_read(&client->connection);
 		if (len == -1 && errno != EAGAIN) {
@@ -358,6 +349,11 @@ static int control_client_handle_connection(int fd, uint32_t mask, void *data) {
 		}
 	}
 
+	/* All readable data has been consumed. Now honour the hangup. */
+	if (mask & EVENT_HANGUP) {
+		goto fail;
+	}
+
 	return 0;
 
 fail:

@deepin-ci-robot

Copy link
Copy Markdown

@glyvut: 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 2c8b35b 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.

@deepin-ci-robot

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: glyvut, 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

@glyvut

glyvut commented Jul 13, 2026

Copy link
Copy Markdown
Contributor Author

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

任意客户端可触发 VT 销毁逻辑,破坏系统正常会话管理

  • 能触发 VT 销毁的前提是它首先得能够连上 control socket ,而这个校验已经在 seatd/control.c:393-397 control_handle_connection 中进行了。一旦能连上则表明这个客户端已有相当高的权限。
  • 且创建时传入的是 treeland 的 PID,而 destroy 则由 DDM 触发,两者无法匹配;再者对本身已经有极高权限的客户端进行身份校验本身也是多余而无用的。
  • ddm 不是 VT owner(Treeland 才是),但 ddm 是唯一能连 control socket 的进程,也是唯一会发 destroy 的进程

4.代码安全(存在 1 个安全漏洞)✕

原因同上。

@zccrs
zccrs merged commit 57921c2 into linuxdeepin:master Jul 13, 2026
10 of 12 checks passed
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