Skip to content

feat: integrate deepin-security-loader for dde-lock#68

Merged
xionglinlin merged 1 commit into
linuxdeepin:masterfrom
xionglinlin:master
Jun 11, 2026
Merged

feat: integrate deepin-security-loader for dde-lock#68
xionglinlin merged 1 commit into
linuxdeepin:masterfrom
xionglinlin:master

Conversation

@xionglinlin

Copy link
Copy Markdown
Contributor
  1. Add SecurityLoaderHelper class to handle loader handshake protocol
  2. Move dde-lock binary to /usr/libexec/deepin for loader wrapping
  3. Create loader wrapper script that launches dde-lock via deepin- security-loader
  4. Define permission configuration for authorized D-Bus interfaces
  5. Update build system and packaging to support new installation layout
  6. Support receiving file descriptors from loader for authorization

Log: dde-lock now integrates with deepin-security-loader for system authorization

Influence:

  1. Test dde-lock launch with security loader available
  2. Test dde-lock launch without security loader (fallback)
  3. Verify D-Bus authorization for Lastore1 and Authenticate1 interfaces
  4. Test wrapper script error handling and logging
  5. Verify installation paths in /usr/libexec/deepin and /usr/bin
  6. Test package dependency on deepin-security-loader

feat: 集成 deepin-security-loader 到 dde-lock

  1. 添加 SecurityLoaderHelper 类处理加载器握手协议
  2. 将 dde-lock 二进制移至 /usr/libexec/deepin 供加载器包装
  3. 创建加载器包装脚本,通过 deepin-security-loader 启动 dde-lock
  4. 定义授权 D-Bus 接口的权限配置
  5. 更新构建系统和打包配置以支持新的安装布局
  6. 支持从加载器接收文件描述符进行授权

Log: dde-lock 现已集成 deepin-security-loader 实现系统授权

Influence:

  1. 测试安全加载器可用时的 dde-lock 启动
  2. 测试无安全加载器时 dde-lock 的降级启动
  3. 验证对 Lastore1 和 Authenticate1 接口的 D-Bus 授权
  4. 测试包装脚本的错误处理和日志记录
  5. 验证 /usr/libexec/deepin 和 /usr/bin 的安装路径
  6. 测试对 deepin-security-loader 的软件包依赖

PMS: TASK-390841
Change-Id: Iee9371e11f9525b5bae506412db914298f8cbb99

@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.

Sorry @xionglinlin, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

Comment thread src/dde-lock/securityloaderhelper.cpp Outdated
Comment thread src/dde-lock/securityloaderhelper.cpp Outdated
@deepin-ci-robot

Copy link
Copy Markdown

deepin pr auto review

你好!我是CodeGeeX。我已仔细审查了你提供的Git Diff,该Diff主要实现了通过 deepin-security-loaderdde-lock 注入权限,以避免在调用受保护的系统D-Bus服务时弹出Polkit授权弹窗。

整体来看,该功能的设计思路清晰(Wrapper脚本 -> Loader提权 -> 业务进程握手),但代码在安全性、逻辑严谨性、性能和代码规范上存在一些需要改进的地方。以下是详细的审查意见:

一、 代码安全

这是本次审查最关键的部分,涉及提权和D-Bus鉴权,极易成为提权漏洞的攻击面。

  1. 文件描述符(FD)未验证来源,存在严重提权风险

    • 问题:在 dde-lock.cpp 中,直接从命令行参数获取 fd1fd2,并传递给 SecurityLoaderHelper::doSecurityLoader。如果恶意进程以普通用户身份运行,可以随意传入属于该用户的任意FD(甚至可以伪造Loader的通信协议),骗取 dde-lock 信任,从而越权调用受保护的D-Bus接口。
    • 改进:必须验证传入FD的有效性。在Linux下,可以通过 fcntl(fd, F_GETFD) 检查FD是否有效;更重要的是,需要验证对端进程是否是合法的 deepin-security-loader-exec。可以通过读取 /proc/self/fd/{fd} 的符号链接,或者使用 SO_PEERCRED(如果是Unix Socket)来验证对端PID的UID/GID是否为 root 或特权组。
  2. Wrapper脚本中硬编码路径,且未校验二进制完整性

    • 问题files/dde-lock-loader-wrapper 中硬编码了 /usr/libexec/deepin/dde-lock/usr/bin/deepin-security-loader-exec。如果恶意用户替换了这些二进制文件,可能导致提权后执行恶意代码。
    • 改进
      • 路径应尽量通过编译时变量或配置读取,避免硬编码。
      • Wrapper脚本在执行 REAL_BINARY 前,应检查其签名或Hash(如果系统支持),或者至少确保其属主和权限为 root:root 且未开启写权限。
  3. FD 读写未设置超时,存在阻塞拒绝服务风险

    • 问题performHandshakefd1File.write(jsonData)fd2File.readAll() 是阻塞操作。如果 security-loader 异常卡死,dde-lock 将永久阻塞,导致锁屏界面无法加载(拒绝服务)。
    • 改进:使用 QSocketNotifier 监听 fd2 的可读事件,配合 QTimer 设置超时(如3秒),在异步或带超时的机制下完成握手。
  4. 版权年份错误

    • 问题dde-lock.cpp 和相关新文件中的版权年份被修改为了 2026(未来时间),这通常是笔误。
    • 改进:更正为当前年份或合理的范围(如 2015 - 2024)。

二、 语法与逻辑

  1. QFile::open(int fd) 不会接管FD的生命周期,导致FD泄漏

    • 问题:在 performHandshake 中,使用 QFile::open(fd1, ...)QFile::open(fd2, ...)。Qt默认不会在 QFile 析构时关闭底层FD。这意味着握手完成后,fd1fd2 仍然处于打开状态,造成文件描述符泄漏。
    • 改进:在握手完成后,显式调用 ::close(fd1); ::close(fd2);。或者在打开时传递 QFile::AutoCloseHandle(但需注意如果QFile拷贝构造可能失效,最安全的是原生 close)。
  2. fd2File.readAll() 存在死循环/内存耗尽风险

    • 问题fd2 是一个管道或Socket,readAll() 会一直读取直到遇到EOF。如果Loader端没有正确关闭FD,readAll() 可能会阻塞或返回不完整的数据。
    • 改进:建议先读取固定长度(例如4字节表示后续JSON长度),再读取指定长度的JSON;或者使用带有超时的逐块读取。
  3. 未使用的变量和无效的D-Bus调用

    • 问题performHandshake 中有一行 systemBus.interface()->isServiceRegistered("org.freedesktop.DBus");,其返回值被丢弃,且检查DBus daemon是否存在对获取 baseService 毫无帮助。
    • 改进:删除这行无意义的代码。
  4. dde-lock.cpp 中的冗余代码

    • 问题QStringList xddd = app->arguments(); 这行代码获取了参数但从未使用,且变量名不规范。
    • 改进:直接删除此行。
  5. appendCurrentUserAccountsUserDest 被注释掉但保留了实现

    • 问题:在 doSecurityLoader// appendCurrentUserAccountsUserDest(); 被注释,但相关代码依然存在。
    • 改进:如果确认不再需要动态获取当前用户路径,建议一并删除 appendCurrentUserAccountsUserDestcurrentUserAccountsPath 的实现,保持代码整洁。如果后续需要,应通过配置文件注入而不是硬编码D-Bus寻址逻辑。

三、 代码性能

  1. JSON解析与查重算法效率低

    • 问题appendDest 中通过遍历 m_destList (QJsonArray) 来去重,时间复杂度为 O(N)。虽然目前 DestList 数量很少,但 QJsonArray 的遍历和比较效率本身较差。
    • 改进:可以在内存中使用 QSet<QString>QMap 来维护已添加的 Dest 键值(如 DbusName + DbusPath + DbusInterface),以 O(1) 复杂度去重,仅在最终需要写入FD时再转换为 QJsonArray
  2. 单例模式的线程安全与初始化时机

    • 问题SecurityLoaderHelper::instance() 使用了局部静态变量,C++11保证其线程安全,但 doSecurityLoadermain 函数早期被调用,此时D-Bus连接可能尚未完全建立事件循环。
    • 改进:目前由于 loadConfig 只是读本地文件,而握手是同步阻塞的,暂无大碍。但若未来改为异步握手,需注意将 SecurityLoaderHelper 的初始化和D-Bus操作移到 QApplication 事件循环启动之后。

四、 改进后的代码示例

针对核心问题,提供以下修改建议代码:

1. dde-lock.cpp 修复与清理

// ... 头文件保持不变 ...
    QCommandLineOption fd1Opt("fd1", "fd1 from security loader", "fd1");
    cmdParser.addOption(fd1Opt);
    QCommandLineOption fd2Opt("fd2", "fd2 from security loader", "fd2");
    cmdParser.addOption(fd2Opt);

    // 删除: QStringList xddd = app->arguments();
    cmdParser.process(*app);

    int fd1 = cmdParser.isSet(fd1Opt) ? cmdParser.value(fd1Opt).toInt() : -1;
    int fd2 = cmdParser.isSet(fd2Opt) ? cmdParser.value(fd2Opt).toInt() : -1;
    
    // 安全提示:此处应增加对FD有效性的校验逻辑
    if (fd1 >= 0 && fcntl(fd1, F_GETFD) != -1 && fd2 >= 0 && fcntl(fd2, F_GETFD) != -1) {
        SecurityLoaderHelper::instance().doSecurityLoader(fd1, fd2);
    } else {
        qCWarning(secLoader) << "Invalid fd1 or fd2 passed from command line";
    }
// ...

2. securityloaderhelper.cpp 核心握手逻辑优化

bool SecurityLoaderHelper::performHandshake(int fd1, int fd2)
{
    if (m_destList.isEmpty()) {
        qCInfo(secLoader) << "No D-Bus interfaces loaded, skipping handshake";
        return true;
    }

    qCInfo(secLoader) << "Performing loader handshake...";

    QDBusConnection systemBus = QDBusConnection::systemBus();
    if (!systemBus.isConnected()) {
        qCWarning(secLoader) << "Cannot connect to system bus";
        return false;
    }

    // 删除无意义的 isServiceRegistered 调用
    QString uniqueName = systemBus.baseService();
    qCInfo(secLoader) << "System Bus UniqueName:" << uniqueName;

    QJsonObject request;
    request["UniqueName"] = uniqueName;
    request["DestList"] = m_destList;

    QJsonDocument doc(request);
    QByteArray jsonData = doc.toJson(QJsonDocument::Compact);

    qCInfo(secLoader) << "Sending request with" << m_destList.size() << "interfaces";

    // 写入 fd1
    QFile fd1File;
    if (!fd1File.open(fd1, QIODevice::WriteOnly)) {
        qCWarning(secLoader) << "Cannot open fd1 for writing";
        return false;
    }
    fd1File.write(jsonData);
    fd1File.close(); // 关闭QFile句柄

    // 读取 fd2 (建议增加超时机制,此处仅为同步读取的改进)
    QFile fd2File;
    if (!fd2File.open(fd2, QIODevice::ReadOnly)) {
        qCWarning(secLoader) << "Cannot open fd2 for reading";
        return false;
    }

    // TODO: 实际生产环境中,管道读取应配合 QSocketNotifier + QTimer 防止阻塞
    QByteArray response = fd2File.readAll();
    fd2File.close(); // 关闭QFile句柄

    // 显式关闭底层文件描述符,防止泄漏
    ::close(fd1);
    ::close(fd2);

    QJsonParseError parseError;
    QJsonDocument responseDoc = QJsonDocument::fromJson(response, &parseError);
    if (parseError.error != QJsonParseError::NoError) {
        qCWarning(secLoader) << "Invalid JSON response from loader:" << parseError.errorString();
        return false;
    }

    QJsonObject result = responseDoc.object();
    if (result["Result"].toBool()) {
        qCInfo(secLoader) << "Loader handshake completed successfully";
        return true;
    } else {
        qCWarning(secLoader) << "Loader authorization response:" << result["Message"].toString();
        return false;
    }
}

3. Wrapper 脚本安全加固 (files/dde-lock-loader-wrapper)

#!/bin/bash
# ... 注释保持不变 ...

REAL_BINARY="/usr/libexec/deepin/dde-lock"
LOADER="/usr/bin/deepin-security-loader"
LOADER_EXEC="/usr/bin/deepin-security-loader-exec"

log_to_journal() {
    logger -t dde-lock -p user.info "$1"
}

log_to_journal "dde-lock launched with args: $*"

# 安全校验:确保目标二进制属于root且没有异常权限
check_binary_security() {
    local bin="$1"
    if [ ! -f "$bin" ]; then return 1; fi
    # 检查属主是否为root,且未开启others写权限
    local perms=$(stat -c "%U %a" "$bin" 2>/dev/null)
    if [[ "$perms" != root\ * ]] || [[ "${perms: -1}" =~ [wxs] ]]; then
        log_to_journal "Security warning: $bin has unsafe permissions: $perms"
        return 1
    fi
    return 0
}

if [ -x "$LOADER" ] && [ -x "$LOADER_EXEC" ]; then
    if getcap "$LOADER_EXEC" 2>/dev/null | grep -q cap_setgid; then
        if check_binary_security "$REAL_BINARY"; then
            log_to_journal "Using deepin-security-loader with authorization groups"
            exec "$LOADER" --group deepin-daemon -- "$REAL_BINARY" "$@"
        fi
    fi
fi

log_to_journal "Fallback: launching directly without security loader"
if check_binary_security "$REAL_BINARY"; then
    exec "$REAL_BINARY" "$@"
else
    log_to_journal "Critical: Refusing to execute insecure binary $REAL_BINARY"
    exit 1
fi

总结

该Diff的核心风险点在于FD来源未校验握手过程可能死锁。强烈建议在 doSecurityLoader 之前验证对端进程身份,并将 performHandshake 改造为带超时的非阻塞/异步模式,以确保锁屏进程的健壮性和系统的安全性。

deepin-ci-robot added a commit to linuxdeepin/dde-session-shell-snipe that referenced this pull request Jun 10, 2026
Synchronize source files from linuxdeepin/dde-session-shell.

Source-pull-request: linuxdeepin/dde-session-shell#68
yixinshark
yixinshark previously approved these changes Jun 10, 2026
1. Add SecurityLoaderHelper class to handle loader handshake protocol
2. Move dde-lock binary to /usr/libexec/deepin for loader wrapping
3. Create loader wrapper script that launches dde-lock via deepin-
security-loader
4. Define permission configuration for authorized D-Bus interfaces
5. Update build system and packaging to support new installation layout
6. Support receiving file descriptors from loader for authorization

Log: dde-lock now integrates with deepin-security-loader for system
authorization

Influence:
1. Test dde-lock launch with security loader available
2. Test dde-lock launch without security loader (fallback)
3. Verify D-Bus authorization for Lastore1 and Authenticate1 interfaces
4. Test wrapper script error handling and logging
5. Verify installation paths in /usr/libexec/deepin and /usr/bin
6. Test package dependency on deepin-security-loader

feat: 集成 deepin-security-loader 到 dde-lock

1. 添加 SecurityLoaderHelper 类处理加载器握手协议
2. 将 dde-lock 二进制移至 /usr/libexec/deepin 供加载器包装
3. 创建加载器包装脚本,通过 deepin-security-loader 启动 dde-lock
4. 定义授权 D-Bus 接口的权限配置
5. 更新构建系统和打包配置以支持新的安装布局
6. 支持从加载器接收文件描述符进行授权

Log: dde-lock 现已集成 deepin-security-loader 实现系统授权

Influence:
1. 测试安全加载器可用时的 dde-lock 启动
2. 测试无安全加载器时 dde-lock 的降级启动
3. 验证对 Lastore1 和 Authenticate1 接口的 D-Bus 授权
4. 测试包装脚本的错误处理和日志记录
5. 验证 /usr/libexec/deepin 和 /usr/bin 的安装路径
6. 测试对 deepin-security-loader 的软件包依赖

PMS: TASK-390841
Change-Id: Iee9371e11f9525b5bae506412db914298f8cbb99
deepin-ci-robot added a commit to linuxdeepin/dde-session-shell-snipe that referenced this pull request Jun 11, 2026
Synchronize source files from linuxdeepin/dde-session-shell.

Source-pull-request: linuxdeepin/dde-session-shell#68
@deepin-ci-robot

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: mhduiy, xionglinlin

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

@xionglinlin xionglinlin merged commit 6964bb3 into linuxdeepin:master Jun 11, 2026
15 of 17 checks passed
xionglinlin pushed a commit to linuxdeepin/dde-session-shell-snipe that referenced this pull request Jun 11, 2026
Synchronize source files from linuxdeepin/dde-session-shell.

Source-pull-request: linuxdeepin/dde-session-shell#68
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.

4 participants