Skip to content

Conversation

@LiHua000
Copy link
Contributor

@LiHua000 LiHua000 commented Dec 4, 2025

  • Replace single-pass "../" removal with loop to remove all occurrences
  • Add final path validation to ensure extracted files stay within target directory

Log: fix CITIVD

Bug: https://pms.uniontech.com/bug-view-342883.html

Summary by Sourcery

Harden zip entry extraction to prevent directory traversal when unpacking archives.

Bug Fixes:

  • Ensure all "../" components are stripped from archive entry paths before extraction to mitigate path traversal attacks.
  • Validate the resolved destination path to guarantee extracted files remain within the configured target directory.

- Replace single-pass "../" removal with loop to remove all occurrences
- Add final path validation to ensure extracted files stay within target directory

Log: fix CITIVD

Bug: https://pms.uniontech.com/bug-view-342883.html
@sourcery-ai
Copy link

sourcery-ai bot commented Dec 4, 2025

Reviewer's guide (collapsed on small PRs)

Reviewer's Guide

Tightens zip extraction security by fully stripping "../" segments from entry names and adding a final absolute-path check to ensure extracted files never escape the configured target directory.

Sequence diagram for secure zip entry extraction with path validation

sequenceDiagram
    participant Caller
    participant LibzipPlugin
    participant QDir
    participant QFile

    Caller->>LibzipPlugin: extractEntry(archive, index, options)
    LibzipPlugin->>LibzipPlugin: trans2uft8(statBuffer.name, m_mapFileCode[index]) -> strFileName
    loop Remove_all_parent_components
        LibzipPlugin->>LibzipPlugin: while strFileName.contains(../)
        LibzipPlugin->>LibzipPlugin: replace(../, "") on strFileName
    end
    LibzipPlugin->>LibzipPlugin: strDestFileName = options.strTargetPath + separator + strFileName

    LibzipPlugin->>QDir: cleanTargetPath = cleanPath(absolutePath(strTargetPath))
    LibzipPlugin->>QDir: cleanDestPath = cleanPath(absolutePath(strDestFileName))
    LibzipPlugin->>LibzipPlugin: validate cleanDestPath within cleanTargetPath
    alt Path_traversal_detected
        LibzipPlugin-->>Caller: return ET_FileWriteError
    else Path_safe
        LibzipPlugin->>QFile: QFile(strDestFileName)
        QFile-->>LibzipPlugin: file_handle
        LibzipPlugin-->>Caller: return success
    end
Loading

Class diagram for LibzipPlugin with updated extractEntry security logic

classDiagram
    class LibzipPlugin {
        - CommonHelper* m_common
        - QMap~zip_int64_t, QString~ m_mapFileCode
        + ErrorType extractEntry(zip_t* archive, zip_int64_t index, const ExtractOptions& options)
    }

    class CommonHelper {
        + QString trans2uft8(const char* name, const QString& fileCode)
    }

    class ExtractOptions {
        + QString strTargetPath
    }

    class QDir {
        + QDir(const QString& path)
        + QString absolutePath()
        + static QString cleanPath(const QString& path)
        + static QChar separator()
    }

    class QFile {
        + QFile(const QString& fileName)
        + bool open()
    }

    LibzipPlugin --> CommonHelper : uses
    LibzipPlugin --> ExtractOptions : uses
    LibzipPlugin --> QDir : uses for path_cleaning
    LibzipPlugin --> QFile : uses for_file_output
Loading

File-Level Changes

Change Details Files
Hardened in-archive path sanitization to remove all "../" path traversal components from zip entry names before extraction.
  • Replaced a single indexOf check and replace call with a while loop that repeatedly removes all occurrences of "../" from the entry file name string
  • Updated the comment to clarify the purpose is preventing path traversal attacks while logging skipped components
3rdparty/libzipplugin/libzipplugin.cpp
Added post-sanitization destination path validation to guarantee extracted files stay within the target directory.
  • Constructs the destination path from target directory and sanitized file name, then resolves both to absolute, cleaned paths using QDir::cleanPath and absolutePath
  • Checks that the destination path either equals the target directory or starts with the target directory plus a path separator, rejecting any other case as path traversal
  • Logs a message when a path traversal is detected and returns ET_FileWriteError to abort extraction instead of creating the file
3rdparty/libzipplugin/libzipplugin.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

@deepin-ci-robot
Copy link

deepin pr auto review

我来对这段代码进行审查分析:

  1. 代码安全性改进:
// 原代码:
if(strFileName.indexOf("../") != -1) {
    strFileName = strFileName.replace("../", "");
}

// 改进后:
while(strFileName.contains("../")) {
    qInfo() << "skipped ../ path component(s) in " << strFileName;
    strFileName = strFileName.replace("../", "");
}

这是一个很好的改进:

  • 使用 contains() 替代 indexOf() 更语义化
  • 使用 while 循环确保所有的 "../" 都被移除,而不是只处理第一个
  • 添加了日志记录,便于追踪问题
  1. 新增的安全检查:
QString cleanTargetPath = QDir::cleanPath(QDir(options.strTargetPath).absolutePath());
QString cleanDestPath = QDir::cleanPath(QDir(strDestFileName).absolutePath());
if (!cleanDestPath.startsWith(cleanTargetPath + QDir::separator()) &&
    cleanDestPath != cleanTargetPath) {
    qInfo() << "Path traversal detected! Rejected path: " << strFileName;
    return ET_FileWriteError;
}

这个新增的安全检查非常必要:

  • 使用 QDir::cleanPath() 规范化路径,处理路径中的"."、".."等
  • 使用 absolutePath() 获取绝对路径,避免相对路径的潜在风险
  • 检查目标路径是否在预期的解压目录内,有效防止目录遍历攻击
  • 添加了适当的错误处理和日志记录
  1. 建议的进一步改进:
// 可以考虑添加对空文件名和绝对路径的检查
if (strFileName.isEmpty() || QDir::isAbsolutePath(strFileName)) {
    qInfo() << "Invalid filename detected: " << strFileName;
    return ET_FileWriteError;
}

// 在路径处理之前,可以考虑统一使用正斜杠
strFileName = QDir::fromNativeSeparators(strFileName);
  1. 性能考虑:
  • QDir::cleanPath() 和路径规范化操作会有一些性能开销,但考虑到安全性的重要性,这是值得的
  • 字符串操作(replace)在文件名很长时可能会有性能影响,但通常文件名长度有限,影响不大
  1. 代码质量:
  • 代码可读性良好,注释清晰
  • 错误处理完善
  • 日志记录适当

总结:
这次改进显著提升了代码的安全性,有效防止了目录遍历攻击。代码结构清晰,错误处理完善。建议的进一步改进主要集中在边界情况的处理上,可以使代码更加健壮。

Copy link

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

Hey there - I've reviewed your changes - here's some feedback:

  • Instead of manually looping and stripping "../" from strFileName, consider normalizing the entry path with QDir::cleanPath (and handling both / and \) so that all relative components (including ..) and platform-specific separators are treated consistently and safely.
  • The final path check using startsWith(cleanTargetPath + QDir::separator()) can be fragile (e.g., case sensitivity or subtle prefix issues); using QDir(cleanTargetPath).relativeFilePath(cleanDestPath) and rejecting any result that starts with ".." is a more robust way to ensure the extracted path stays within the target directory.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- Instead of manually looping and stripping "../" from `strFileName`, consider normalizing the entry path with `QDir::cleanPath` (and handling both `/` and `\`) so that all relative components (including `..`) and platform-specific separators are treated consistently and safely.
- The final path check using `startsWith(cleanTargetPath + QDir::separator())` can be fragile (e.g., case sensitivity or subtle prefix issues); using `QDir(cleanTargetPath).relativeFilePath(cleanDestPath)` and rejecting any result that starts with `".."` is a more robust way to ensure the extracted path stays within the target directory.

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.

@deepin-ci-robot
Copy link

[APPROVALNOTIFIER] This PR is NOT APPROVED

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

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

@LiHua000
Copy link
Contributor Author

LiHua000 commented Dec 4, 2025

/merge

@deepin-bot deepin-bot bot merged commit 2643052 into linuxdeepin:release/eagle Dec 4, 2025
15 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