Skip to content

fix(security): use mkdtemp for secure temp dir creation in mkTempDir - #227

Merged
max-lvs merged 1 commit into
linuxdeepin:release/1071from
tianming-1996:agent/pms-bug-bot/1b89a1ea1528
Sep 29, 2026
Merged

max-lvs merged 1 commit into
linuxdeepin:release/1071from
tianming-1996:agent/pms-bug-bot/1b89a1ea1528

Conversation

@tianming-1996

@tianming-1996 tianming-1996 commented Sep 28, 2026 •

Copy link
Copy Markdown

Root Cause Analysis

The mkTempDir function in basestruct/utils.cpp constructs a predictable temporary directory path using a literal "XXXXXX" suffix and creates it via non-atomic QDir::exists() + QDir::mkpath(). This introduces three CWE vulnerabilities:

  • CWE-377: The path /var/tmp/XXXXXX is predictable — an attacker can pre-place a symlink.
  • CWE-367: The exists() check and mkpath() call are non-atomic, creating a TOCTOU race window.
  • CWE-59: QDir::mkpath() follows symlinks, and if the path already exists it returns without rejection.

Trigger path: attacker pre-creates ln -s /etc /var/tmp/XXXXXX → root-privileged diskmanager mounts a filesystem to /var/tmp/XXXXXX → critical system directory overwritten.

Fix

Replace the manual path construction + QDir::mkpath() with POSIX mkdtemp(3), which atomically creates a randomly-named directory. This eliminates all three CWE classes in a single function change. Return value semantics are preserved — callers already check isEmpty() for failure.

Change Safety Assessment

Risk level: Low

  • Change is limited to the mkTempDir function body; function signature unchanged.
  • Both callers (xfs.cpp:146, btrfs.cpp:204) check mountPoint.isEmpty() and return false on failure — fully compatible with the new empty-string-on-failure behavior.
  • No historical fixes are reverted; the path traversal check added in 2026-02-02 is preserved.

Business Impact

Affects XFS and BTRFS filesystem resize operations that create temporary mount points. After the fix, temporary mount directories use random names, preventing symlink-based attacks. Normal resize operations are unaffected.

Verification Suggestion

Verify that XFS and BTRFS partition resize operations still work correctly — the temporary mount point should be created and cleaned up as before.


根因分析

basestruct/utils.cpp 的 mkTempDir 函数使用字面量 "XXXXXX" 拼接固定路径,通过非原子的 QDir::exists() + QDir::mkpath() 创建目录,存在三类 CWE 漏洞:

  • CWE-377:路径 /var/tmp/XXXXXX 可预测,攻击者可预置符号链接。
  • CWE-367:exists() 与 mkpath() 非原子操作,存在 TOCTOU 竞态窗口。
  • CWE-59:QDir::mkpath() 跟随符号链接,路径已存在时直接返回不拒绝。

触发路径:攻击者预置 ln -s /etc /var/tmp/XXXXXX → root 权限 diskmanager 挂载文件系统到 /var/tmp/XXXXXX → 系统关键目录被覆盖。

修复方案

使用 POSIX mkdtemp(3) 替代手动拼接 + QDir::mkpath(),原子创建随机命名目录,一次消除三类 CWE。返回值语义保持不变——调用方已检查 isEmpty() 处理失败。

改动安全评估

风险等级:低

  • 改动仅限 mkTempDir 函数体,函数签名不变。
  • 两个调用方(xfs.cpp:146、btrfs.cpp:204)均检查 mountPoint.isEmpty() 并返回 false,与新失败语义完全兼容。
  • 不撤销历史修复,2026-02-02 添加的路径遍历检查保留不变。

业务影响范围

影响 XFS 和 BTRFS 文件系统调整大小操作中创建临时挂载点的行为。修复后临时挂载目录使用随机名称,防止符号链接攻击。正常调整操作不受影响。

验证建议

验证 XFS 和 BTRFS 分区调整大小操作是否正常工作——临时挂载点的创建和清理应与之前一致。

Summary by Sourcery

Harden temporary mount-point creation against predictable-path, TOCTOU, and symlink attacks.

Bug Fixes:

  • Secure temporary directory creation by replacing predictable, symlink-vulnerable paths with atomically generated random directories.
  • Preserve failure handling for XFS and BTRFS resize operations while reporting temporary-directory creation errors.

Chores:

  • Add the GPL-3.0-or-later license text.

@sourcery-ai

sourcery-ai Bot commented Sep 28, 2026

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

Reviewer's Guide

Hardens temporary mount-point creation by replacing the predictable QDir exists/mkpath sequence with POSIX mkdtemp, preventing symlink and TOCTOU attacks while preserving naming, failure, and caller compatibility.

Sequence diagram for secure temporary mount-point creation

sequenceDiagram
    participant Resize as XFS/BTRFS resize
    participant Utils
    participant FS as POSIX filesystem

    Resize->>Utils: mkTempDir(infix)
    Utils->>FS: mkdtemp(templateBytes)
    alt directory created
        FS-->>Utils: random directory path
        Utils-->>Resize: mountPoint
        Resize->>Utils: rmTempDir(dirName)
    else creation failed
        FS-->>Utils: nullptr
        Utils-->>Resize: empty QString
    end
Loading

File-Level Changes

Change Details Files
Replace predictable, non-atomic temporary-directory creation with POSIX atomic random directory creation.
  • Build a mkdtemp-compatible template under /var/tmp, preserving the optional infix naming convention.
  • Call mkdtemp to atomically create the directory and convert the resulting path back to QString.
  • Return an empty QString and log errno details when creation fails, preserving existing caller-facing failure semantics.
  • Add the required C standard-library, string, and errno headers while leaving the function signature and cleanup behavior unchanged.
basestruct/utils.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 reviewed your changes and they look great!


Sourcery is free for open source - if you like our reviews please consider sharing them ✨

1. Root cause: mkTempDir used predictable 'XXXXXX' literal with
   non-atomic exists()+mkpath(), vulnerable to CWE-377/367/59;
   LICENSES/ missing GPL-3.0-or-later.txt causing REUSE lint fail
2. Fix: replace with POSIX mkdtemp(3) for atomic random temp dir
   creation; add missing GPL-3.0-or-later.txt license file
3. Impact: callers unchanged (isEmpty() check preserved);
   CI license-check now passes

Influence:
1. Verify temp directory creation succeeds with random paths
2. Verify existing mkTempDir callers work correctly
3. Confirm REUSE lint passes in CI

fix: 安全创建临时目录并补充许可证文件

1. 根因:mkTempDir使用可预测的'XXXXXX'字面量配合非原子的
   exists()+mkpath(),存在CWE-377/367/59漏洞;LICENSES/目录
   缺少GPL-3.0-or-later.txt导致REUSE lint检查失败
2. 方案:替换为POSIX mkdtemp(3)实现原子随机临时目录创建;
   补充缺失的GPL-3.0-or-later.txt许可证文件
3. 影响:所有调用方不变(isEmpty()检查保留);CI许可证检查通过

Influence:
1. 验证临时目录创建成功且路径随机
2. 验证现有mkTempDir调用方仍正常工作
3. 确认REUSE lint在CI中通过

PMS: BUG-378601
@tianming-1996
tianming-1996 force-pushed the agent/pms-bug-bot/1b89a1ea1528 branch from 78615f7 to 735dd37 Compare September 28, 2026 13:16
@deepin-ci-robot

Copy link
Copy Markdown

deepin pr auto review

AI 代码审查报告

项目: linuxdeepin/deepin-diskmanager
PR: #227 - fix(security): use mkdtemp for secure temp dir creation in mkTempDir
分支: agent/pms-bug-bot/1b89a1ea1528 → release/1071
作者: tianming-1996
审查时间: 2026-09-28


总体评价

总分: 100/100
评级: 优秀
结论: 代码审查通过

本次 PR 修复了 basestruct/utils.cpp 中 mkTempDir 函数的三类安全漏洞(CWE-377 可预测临时路径、CWE-367 TOCTOU 竞态条件、CWE-59 符号链接跟随),使用 POSIX mkdtemp(3) 替代非原子的 QDir::exists() + QDir::mkpath() 模式。修复方案正确、完整,与现有调用方完全兼容,未引入新的安全漏洞。同时新增了 GPL-3.0-or-later 许可证文件。


修改文件列表

文件 变更类型 行数变化
basestruct/utils.cpp 修改 +10/-8
LICENSES/GPL-3.0-or-later.txt 新增 +232/-0

四维度评分

维度1: 语法逻辑 ✓ (25/25)

语法正确,逻辑清晰,边界处理完善

分析:

  1. mkdtemp(3) 函数调用语法正确,QByteArray::data() 返回可写的 char* 指针,符合 mkdtemp 原地修改模板的要求
  2. 错误处理逻辑完善:mkdtemp 失败时返回 nullptr,代码正确检查并返回空 QString(),与调用方的 isEmpty() 检查完全兼容
  3. QString::fromLocal8Bit(result) 转换正确,mkdtemp 成功时 result 指向被修改后的模板字节(XXXXXX 被替换为随机字符),转换为 QString 后返回路径正确
  4. 旧代码存在逻辑缺陷:!dir.exists() && dir.mkpath(dirTemplate) 条件为 false 时仍返回 dirTemplate(即目录已存在或创建失败都返回路径),新代码修复了此问题——仅在 mkdtemp 成功时返回路径
  5. 两个调用方(btrfs.cpp:204、xfs.cpp:146)均调用 Utils::mkTempDir("") 并检查 mountPoint.isEmpty() 返回 false,与新代码的失败语义完全兼容

维度2: 代码质量 ✓ (25/25)

代码结构清晰,注释完整,无重复代码

分析:

  1. 新增注释清晰说明了修复目的和对应的 CWE 编号(CWE-377、CWE-367、CWE-59),便于后续维护理解安全修复背景
  2. 函数体结构清晰:路径遍历检查 → 模板构建 → 原子创建 → 错误处理 → 返回结果,逻辑层次分明
  3. qWarning() 日志输出 strerror(errno) 是合理的错误日志(非调试代码),仅在 mkdtemp 失败时触发,不泄露敏感信息
  4. 新增的 #include <cstdlib>、<cstring>、<errno.h> 头文件包含正确,分别提供 mkdtemp、strerror、errno 声明
  5. LICENSES/GPL-3.0-or-later.txt 为标准 GPL-3.0 许可证文本,内容完整正确

维度3: 代码性能 ✓ (20/20)

性能良好,资源使用合理,无性能瓶颈

分析:

  1. mkdtemp(3) 是单次原子系统调用,替代了旧代码的 QDir::exists() + QDir::mkpath() 两次系统调用,性能有所提升
  2. toLocal8Bit() 和 fromLocal8Bit() 为轻量级字符串编码转换,开销可忽略
  3. QByteArray templateBytes 为栈上局部变量,函数返回后自动释放,无内存泄漏风险
  4. 错误路径仅执行 qWarning() 日志输出和返回空字符串,无额外性能开销

维度4: 代码安全 ✓ (30/30)

存在0个安全漏洞

分析:

本次 PR 修复了以下三类预存安全漏洞:

  1. CWE-377(可预测临时路径):旧代码使用字面量 "XXXXXX" 拼接固定路径 /var/tmp/XXXXXX,路径可预测,攻击者可预置符号链接。修复后使用 mkdtemp(3) 生成随机命名目录,消除可预测性
  2. CWE-367(TOCTOU 竞态条件):旧代码 exists() 检查与 mkpath() 创建之间存在竞态窗口。修复后 mkdtemp(3) 为原子操作,消除竞态
  3. CWE-59(符号链接跟随):旧代码 QDir::mkpath() 跟随符号链接且路径已存在时不拒绝。修复后 mkdtemp(3) 原子创建新目录,不跟随已有符号链接

当前代码安全状态:

  • mkdtemp(3) 创建目录权限为 0700(仅所有者可访问),比旧代码 mkpath() 的默认权限更安全
  • 路径遍历检查(infix.contains(".."))保留不变,防止注入恶意路径
  • qWarning() 日志仅输出 strerror(errno) 错误描述,不包含用户输入或敏感信息
  • 无硬编码密钥、无命令注入、无 SQL 注入、无路径遍历、无敏感信息泄露

漏洞对比统计: 新增漏洞 0 个,减少漏洞 0 个,持平 0 个(GitHub 全量分析模式,无历史对比)

OCR 审查结果: 0 条问题("Looks good to me")


改进建议

虽然本次 PR 代码质量优秀,以下为可选的后续优化建议:

  1. strerror(errno) 在多线程环境下非线程安全,可考虑使用 strerror_r 替代(当前代码在错误路径使用,实际风险极低)
  2. #include <errno.h> 可改为 #include <cerrno> 以保持 C++ 风格一致性(功能等价,仅为风格偏好)

审查结论

本次 PR 是一个高质量的安全修复,正确使用 POSIX mkdtemp(3) 消除了三类 CWE 漏洞。代码变更范围小、风险低,与现有调用方完全兼容。注释完善,错误处理得当,未引入新的安全漏洞。建议合并。

@deepin-ci-robot

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: max-lvs, tianming-1996

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

@max-lvs
max-lvs merged commit 5acf8ce into linuxdeepin:release/1071 Sep 29, 2026
17 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