mirror of
https://github.com/PrismLauncher/PrismLauncher
synced 2026-04-23 09:05:03 +00:00
[Backport release-10.x] fix zip path traversal (#5160)
This commit is contained in:
commit
7372d3587b
|
|
@ -233,7 +233,7 @@ std::optional<QStringList> extractSubDir(ArchiveReader* zip, const QString& subd
|
|||
<< target;
|
||||
return false;
|
||||
}
|
||||
if (!f->writeFile(ext, target_file_path)) {
|
||||
if (!f->writeFile(ext, target_file_path, target)) {
|
||||
qWarning() << "Failed to extract file" << original_name << "to" << target_file_path;
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,9 @@
|
|||
#include <archive_entry.h>
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
#include <QUrl>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
namespace MMCZip {
|
||||
QStringList ArchiveReader::getFiles()
|
||||
|
|
@ -128,7 +130,37 @@ static int copy_data(struct archive* ar, struct archive* aw, bool notBlock = fal
|
|||
}
|
||||
}
|
||||
|
||||
bool willEscapeRoot(const QDir& root, archive_entry* entry)
|
||||
{
|
||||
const char* entryPathC = archive_entry_pathname(entry);
|
||||
const char* linkTargetC = archive_entry_symlink(entry);
|
||||
const char* hardlinkC = archive_entry_hardlink(entry);
|
||||
|
||||
if (!entryPathC || (!linkTargetC && !hardlinkC))
|
||||
return false;
|
||||
|
||||
QString entryPath = QString::fromUtf8(entryPathC);
|
||||
QString linkTarget = linkTargetC ? QString::fromUtf8(linkTargetC) : QString::fromUtf8(hardlinkC);
|
||||
|
||||
QString linkFullPath = root.filePath(entryPath);
|
||||
auto rootDir = QUrl::fromLocalFile(root.absolutePath());
|
||||
|
||||
if (!rootDir.isParentOf(QUrl::fromLocalFile(linkFullPath)))
|
||||
return true;
|
||||
|
||||
QDir linkDir = QFileInfo(linkFullPath).dir();
|
||||
if (!QDir::isAbsolutePath(linkTarget)) {
|
||||
linkTarget = (linkTargetC ? linkDir : root).filePath(linkTarget);
|
||||
}
|
||||
return !rootDir.isParentOf(QUrl::fromLocalFile(QDir::cleanPath(linkTarget)));
|
||||
}
|
||||
|
||||
bool ArchiveReader::File::writeFile(archive* out, QString targetFileName, bool notBlock)
|
||||
{
|
||||
return writeFile(out, targetFileName, {}, notBlock);
|
||||
};
|
||||
|
||||
bool ArchiveReader::File::writeFile(archive* out, QString targetFileName, std::optional<QDir> root, bool notBlock)
|
||||
{
|
||||
auto entry = m_entry;
|
||||
std::unique_ptr<archive_entry, decltype(&archive_entry_free)> entryClone(nullptr, &archive_entry_free);
|
||||
|
|
@ -138,6 +170,10 @@ bool ArchiveReader::File::writeFile(archive* out, QString targetFileName, bool n
|
|||
auto nameUtf8 = targetFileName.toUtf8();
|
||||
archive_entry_set_pathname_utf8(entry, nameUtf8.constData());
|
||||
}
|
||||
if (root.has_value() && willEscapeRoot(root.value(), entry)) {
|
||||
qCritical() << "Failed to write header to entry:" << filename() << "-" << "file outside root";
|
||||
return false;
|
||||
}
|
||||
if (archive_write_header(out, entry) < ARCHIVE_OK) {
|
||||
qCritical() << "Failed to write header to entry:" << filename() << "-" << archive_error_string(out);
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -19,8 +19,10 @@
|
|||
|
||||
#include <QByteArray>
|
||||
#include <QDateTime>
|
||||
#include <QDir>
|
||||
#include <QStringList>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
struct archive;
|
||||
struct archive_entry;
|
||||
|
|
@ -49,6 +51,7 @@ class ArchiveReader {
|
|||
QByteArray readAll(int* outStatus = nullptr);
|
||||
bool skip();
|
||||
bool writeFile(archive* out, QString targetFileName = "", bool notBlock = false);
|
||||
bool writeFile(archive* out, QString targetFileName, std::optional<QDir> root, bool notBlock = false);
|
||||
|
||||
private:
|
||||
int readNextHeader();
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ auto ExtractZipTask::extractZip() -> ZipResult
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!f->writeFile(ext, target_file_path)) {
|
||||
if (!f->writeFile(ext, target_file_path, target)) {
|
||||
result = ZipResult(tr("Failed to extract file %1 to %2").arg(original_name, target_file_path));
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ static bool unzipNatives(QString source, QString targetFolder, bool applyJnilibH
|
|||
name = replaceSuffix(name, ".jnilib", ".dylib");
|
||||
}
|
||||
QString absFilePath = directory.absoluteFilePath(name);
|
||||
return f->writeFile(ext, absFilePath);
|
||||
return f->writeFile(ext, absFilePath, directory);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue