Skip to content

fix: correct directory ownership when creating cache dirs with sudo - #535

Merged
deepin-bot[bot] merged 1 commit into
linuxdeepin:masterfrom
wangrong1069:agent/pms-bug-bot/53bc45b51c92
Sep 30, 2026
Merged

deepin-bot[bot] merged 1 commit into
linuxdeepin:masterfrom
wangrong1069:agent/pms-bug-bot/53bc45b51c92

Conversation

@wangrong1069

@wangrong1069 wangrong1069 commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

修复:sudo 执行时缓存目录属主为 root 的问题

问题

当 ~/.cache/deepin/deepin-log-viewer/ 不存在且有未汇报的 coredump 时,执行 sudo deepin-log-viewer --reportcoredump 会创建该目录,但属主属组都是 root,导致后续正常启动的 deepin-log-viewer 无法写入。

根因

sudo deepin-log-viewer --reportcoredump 以 root 身份运行,QDir().mkpath() 创建的目录属主为 root。Utils::homePath 虽然能正确解析真实登录用户家目录,但未处理目录创建后的属主问题。

修复内容

  1. 在 Utils 新增 fixDirOwnership() 静态方法:通过 stat(homePath) 获取真实登录用户 UID/GID,当 getuid() != 真实登录用户UID 时 chown 新建目录。
  2. 在所有创建 ~/.cache/deepin/deepin-log-viewer/ 子目录的 mkpath 调用后添加 fixDirOwnership():
    • Utils::updateRepeatCoredumpExePaths()
    • UserLogAccess 构造函数
    • UserLogAccess::createExtractSubdir()
  3. 对 createExtractSubdir() 返回空字符串(mkpath 失败)的情况添加错误处理,跳过 unzip 并直接返回原始文件路径。
  4. 对项目中未检查 mkpath 返回值的地方添加 qCWarning 日志。

PMS: TASK-395141

Summary by Sourcery

Correct ownership of user cache directories created with elevated privileges and improve failure handling for directory creation.

Bug Fixes:

  • Ensure cache and extracted log directories created under sudo are reassigned to the real logged-in user, preventing normal application runs from losing write access.
  • Handle directory-creation failures by skipping decompression when extraction directories cannot be created and preserving the original file paths.

Enhancements:

  • Add defensive directory ownership correction that validates paths and avoids unsafe symlink traversal.
  • Add warnings for previously unchecked directory-creation failures across application and service components.

@sourcery-ai

sourcery-ai Bot commented Sep 29, 2026

Copy link
Copy Markdown

Reviewer's Guide

The PR fixes sudo-created cache directories by adding a home-path-scoped UID/GID correction step after relevant mkpath calls, adds safe handling for extraction setup failures, and audits other directory creation sites to report failures through warnings.

Sequence diagram for sudo cache directory ownership correction

sequenceDiagram
    participant App as deepin-log-viewer
    participant QDir
    participant Utils
    participant OS
    App->>QDir: mkpath(cacheDirectory)
    alt mkpath fails
        QDir-->>App: false
        App->>App: qCWarning
    else directory created
        QDir-->>App: true
        App->>Utils: fixDirOwnership(cacheDirectory)
        Utils->>OS: stat(homePath)
        OS-->>Utils: realUID and realGID
        alt getuid differs from realUID
            Utils->>OS: chown(cacheDirectory, realUID, realGID)
        end
    end
Loading

Sequence diagram for extraction directory creation failure

sequenceDiagram
    participant Caller as getFileInfo or getOtherFileInfo
    participant Access as UserLogAccess
    participant QDir
    participant Unzip
    Caller->>Access: createExtractSubdir()
    Access->>QDir: mkpath(extractSubdir)
    alt mkpath fails
        QDir-->>Access: false
        Access-->>Caller: empty string
        Caller->>Caller: skip unzip
        Caller-->>Caller: retain original file path
    else directory created
        QDir-->>Access: true
        Access-->>Caller: extractSubdir
        Caller->>Unzip: unzipToTempFile(file, template)
    end
Loading

File-Level Changes

Change Details Files
Correct ownership of cache directories created under sudo while preserving the real login user’s home directory.
  • Added a guarded ownership-repair helper that derives UID/GID from the home directory and applies them with chown only when running under a different UID.
  • Invoked ownership repair after creating the coredump and user-log extraction directories, including parent directories created implicitly by mkpath.
  • Added warnings when directory creation fails.
application/utils.cpp
application/utils.h
application/dbusproxy/userlogaccess.cpp
Handle extraction-directory creation failures without attempting invalid unzip paths.
  • Return an empty path when extraction subdirectory creation fails.
  • Skip gzip extraction when no temporary directory is available, allowing original file paths to remain usable.
application/dbusproxy/userlogaccess.cpp
Improve observability of directory creation failures across application and service paths.
  • Check mkpath results and emit component-specific warnings for output, config, app-data, service-log, export, and copy destinations.
application/logbackend.cpp
application/logsettings.cpp
application/utils.cpp
logViewerService/main.cpp
logViewerService/opslogexport.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

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="application/utils.cpp" line_range="375" />
<code_context>
+    }
+    uid_t realUID = st.st_uid;
+    if (getuid() != realUID) {
+        if (chown(dirPath.toUtf8().constData(), realUID, st.st_gid) != 0) {
+            qCWarning(logApp) << "fixDirOwnership: failed to chown" << dirPath << "to uid:" << realUID << "gid:" << st.st_gid << "error:" << strerror(errno);
+        }
</code_context>
<issue_to_address>
**🚨 issue (security):** `chown(dirPath, ...)` follows symlinks, so a user-controlled symlink anywhere below `Utils::homePath` can redirect the privileged sudo process to chown an arbitrary target outside the home directory. For example, a pre-created `~/.cache/deepin/deepin-log-viewer/user-log` symlink to `/etc` is accepted by the lexical prefix check and causes `/etc` itself to be reassigned to the logged-in user.

**Triggers:** When the cache or extraction path is a symlink created or replaced by the unprivileged logged-in user before the sudo process calls `fixDirOwnership()`.

**Suggested fix:** Reject symlinks and use no-follow, directory-relative ownership operations (such as `openat`/`fstatat` with `O_NOFOLLOW`) before changing ownership.
</issue_to_address>

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

Comment thread application/utils.cpp Outdated
@wangrong1069
wangrong1069 force-pushed the agent/pms-bug-bot/53bc45b51c92 branch from 6306471 to f38094e Compare September 29, 2026 12:10
When running `sudo deepin-log-viewer --reportcoredump`, directories created
under ~/.cache/deepin/deepin-log-viewer/ are owned by root, causing subsequent
normal launches to fail writing to them.

Add Utils::fixDirOwnership() to chown newly created directories to the real
logged-in user (detected via lstat(homePath)) when getuid() differs from the
real user UID. Apply it to all mkpath call sites that create cache directories
under the user's home: updateRepeatCoredumpExePaths, UserLogAccess constructor,
and UserLogAccess::createExtractSubdir.

Harden fixDirOwnership() against symlink attacks: walk the target path from
root using openat(O_DIRECTORY | O_NOFOLLOW) at each level, then fchown() the
resulting fd. This prevents a non-privileged user from pre-creating a symlink
along the path to trick the privileged sudo process into chowning arbitrary
targets outside the home directory.

Add error handling for createExtractSubdir() returning empty string (mkpath
failure) at all three call sites: skip unzip and fall back to returning
original file paths directly, preventing silent file loss.

Also add qCWarning logging for unchecked mkpath return values across the
project.

PMS: TASK-395141
@wangrong1069
wangrong1069 force-pushed the agent/pms-bug-bot/53bc45b51c92 branch from f38094e to 2d704d2 Compare September 29, 2026 13:13
@deepin-ci-robot

Copy link
Copy Markdown

deepin pr auto review

🤖 AI 代码审查报告

总体评分: 100 分 (通过阈值: 70分)

Pass


📊 总体评价

项目 结果
审查结论 代码审查通过
评分详情 总体评分 100 分,大于 70 分通过阈值,代码质量符合要求。本次提交修复了 sudo 执行时缓存目录属主为 root 的问题,新增 fixDirOwnership 方法采用 openat(O_NOFOLLOW) 安全遍历路径防止 symlink 攻击,对所有 mkpath 调用添加了返回值检查和错误日志,代码实现与 commit 目的完全一致。

🔍 详细分析

1. 语法逻辑 ✅

评价: 优秀 ✅ 通过

潜在问题:
✅ 未发现明显问题

建议: 语法正确,逻辑清晰。fixDirOwnership 函数使用 openat 逐级遍历路径组件,文件描述符管理无泄漏:openat 失败时 close(fd) 后返回,成功时 close 旧 fd 并使用新 fd,循环结束后 fchown 再 close。createExtractSubdir 在 mkpath 失败时正确返回空字符串,getFileInfo/getOtherFileInfo 中通过 else 分支正确返回原始文件路径,与 PR 描述的'跳过 unzip 并直接返回原始文件路径'一致。


2. 代码质量 ✅

评价: 优秀 ✅ 通过

潜在问题:
✅ 未发现明显问题

建议: 代码结构清晰,注释完整。fixDirOwnership 函数有详细的安全相关注释,解释了 lstat 不跟随符号链接、openat(O_NOFOLLOW) 防止 symlink 攻击的设计意图。header 文件中有简洁的方法说明。无重复代码,fixDirOwnership 集中在 Utils 类中。无残留调试代码,qCWarning 日志为合理的错误处理日志。opslogexport.cpp 中使用 qWarning() 与该文件现有风格一致。


3. 代码性能 ✅

评价: 优秀 ✅ 通过

潜在问题:
✅ 未发现明显问题

建议: 性能良好,资源使用合理。fixDirOwnership 仅在目录创建时调用,不在热路径上。openat 逐级遍历虽然需要多次系统调用,但路径深度有限(通常 5-6 级),且仅在 sudo 场景下触发。lstat 和 getuid 各调用一次,fchown 操作文件描述符而非路径,效率较高。文件描述符及时关闭,无资源泄漏。


4. 代码安全 🔒

评价: 优秀 ✅ 通过

🔐 发现 0 个安全漏洞

安全漏洞详情:
✅ 未发现安全漏洞

建议: 安全合规。fixDirOwnership 函数展现了良好的安全实践:1) 路径验证:仅处理 homePath 下的路径,防止误改系统目录;2) Symlink 攻击防护:使用 openat(O_DIRECTORY|O_NOFOLLOW) 逐级打开路径组件,任一组件为符号链接则拒绝继续;3) TOCTOU 防护:使用 fchown(fd) 而非 chown(path),操作已打开的文件描述符而非路径;4) 权限安全:仅将属主改为真实登录用户 UID/GID,通过 lstat(homePath) 获取,不允许任意 UID 变更;5) 无命令注入风险:无 system()/exec() 调用;6) 无信息泄露:qCWarning 日志仅输出路径和错误信息,无敏感数据。


💡 改进建议代码示例

// 本次提交代码质量优秀,无需修复示例。
// fixDirOwnership 已采用安全的 openat(O_NOFOLLOW) 模式实现,
// 是防范 symlink 攻击的最佳实践写法。

本报告由 AI 代码审查工具自动生成

@deepin-ci-robot

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: lzwind, wangrong1069

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

@wangrong1069

Copy link
Copy Markdown
Contributor Author

/merge

@deepin-bot
deepin-bot Bot merged commit 7d03d0c into linuxdeepin:master Sep 30, 2026
17 checks passed
@wangrong1069
wangrong1069 deleted the agent/pms-bug-bot/53bc45b51c92 branch September 30, 2026 01:07
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