Don't read unlimited data from files

It now guards against reading infinite files such as `/dev/zero`.
And most readings are bound with a (lax) limit.
As a side effect, more checking are done when reading a file and
overall the reading procedure is more robust.

PR #19095.
This commit is contained in:
Chocobo1
2023-06-14 13:38:19 +08:00
committed by GitHub
parent 81bc910d68
commit 79ca2e145f
24 changed files with 370 additions and 199 deletions

View File

@@ -28,11 +28,10 @@
#include "aboutdialog.h"
#include <QFile>
#include "base/global.h"
#include "base/path.h"
#include "base/unicodestrings.h"
#include "base/utils/io.h"
#include "base/utils/misc.h"
#include "base/version.h"
#include "ui_aboutdialog.h"
@@ -75,27 +74,24 @@ AboutDialog::AboutDialog(QWidget *parent)
m_ui->labelMascot->setPixmap(Utils::Gui::scaledPixmap(Path(u":/icons/mascot.png"_qs), this));
// Thanks
QFile thanksfile(u":/thanks.html"_qs);
if (thanksfile.open(QIODevice::ReadOnly | QIODevice::Text))
if (const auto readResult = Utils::IO::readFile(Path(u":/thanks.html"_qs), -1, QIODevice::Text)
; readResult)
{
m_ui->textBrowserThanks->setHtml(QString::fromUtf8(thanksfile.readAll().constData()));
thanksfile.close();
m_ui->textBrowserThanks->setHtml(QString::fromUtf8(readResult.value()));
}
// Translation
QFile translatorsfile(u":/translators.html"_qs);
if (translatorsfile.open(QIODevice::ReadOnly | QIODevice::Text))
if (const auto readResult = Utils::IO::readFile(Path(u":/translators.html"_qs), -1, QIODevice::Text)
; readResult)
{
m_ui->textBrowserTranslation->setHtml(QString::fromUtf8(translatorsfile.readAll().constData()));
translatorsfile.close();
m_ui->textBrowserTranslation->setHtml(QString::fromUtf8(readResult.value()));
}
// License
QFile licensefile(u":/gpl.html"_qs);
if (licensefile.open(QIODevice::ReadOnly | QIODevice::Text))
if (const auto readResult = Utils::IO::readFile(Path(u":/gpl.html"_qs), -1, QIODevice::Text)
; readResult)
{
m_ui->textBrowserLicense->setHtml(QString::fromUtf8(licensefile.readAll().constData()));
licensefile.close();
m_ui->textBrowserLicense->setHtml(QString::fromUtf8(readResult.value()));
}
// Software Used

View File

@@ -52,6 +52,7 @@
#include "base/rss/rss_session.h"
#include "base/torrentfileguard.h"
#include "base/torrentfileswatcher.h"
#include "base/utils/io.h"
#include "base/utils/misc.h"
#include "base/utils/net.h"
#include "base/utils/password.h"
@@ -1751,46 +1752,22 @@ Path OptionsDialog::getFilter() const
#ifndef DISABLE_WEBUI
void OptionsDialog::webUIHttpsCertChanged(const Path &path)
{
const auto isCertFileValid = [&path]() -> bool
{
if (path.isEmpty())
return false;
QFile file {path.data()};
if (!file.open(QIODevice::ReadOnly))
return false;
if (!Utils::Net::isSSLCertificatesValid(file.read(Utils::Net::MAX_SSL_FILE_SIZE)))
return false;
return true;
};
const auto readResult = Utils::IO::readFile(path, Utils::Net::MAX_SSL_FILE_SIZE);
const bool isCertValid = Utils::Net::isSSLCertificatesValid(readResult.value_or(QByteArray()));
m_ui->textWebUIHttpsCert->setSelectedPath(path);
m_ui->lblSslCertStatus->setPixmap(UIThemeManager::instance()->getScaledPixmap(
(isCertFileValid() ? u"security-high"_qs : u"security-low"_qs), 24));
(isCertValid ? u"security-high"_qs : u"security-low"_qs), 24));
}
void OptionsDialog::webUIHttpsKeyChanged(const Path &path)
{
const auto isKeyFileValid = [&path]() -> bool
{
if (path.isEmpty())
return false;
QFile file {path.data()};
if (!file.open(QIODevice::ReadOnly))
return false;
if (!Utils::Net::isSSLKeyValid(file.read(Utils::Net::MAX_SSL_FILE_SIZE)))
return false;
return true;
};
const auto readResult = Utils::IO::readFile(path, Utils::Net::MAX_SSL_FILE_SIZE);
const bool isKeyValid = Utils::Net::isSSLKeyValid(readResult.value_or(QByteArray()));
m_ui->textWebUIHttpsKey->setSelectedPath(path);
m_ui->lblSslKeyStatus->setPixmap(UIThemeManager::instance()->getScaledPixmap(
(isKeyFileValid() ? u"security-high"_qs : u"security-low"_qs), 24));
(isKeyValid ? u"security-high"_qs : u"security-low"_qs), 24));
}
bool OptionsDialog::isWebUiEnabled() const

View File

@@ -30,7 +30,6 @@
#include <QAction>
#include <QDir>
#include <QFile>
#include <QHeaderView>
#include <QMenu>
#include <QMessageBox>

View File

@@ -458,15 +458,16 @@ void AutomatedRssDownloader::onImportBtnClicked()
const Path path {QFileDialog::getOpenFileName(
this, tr("Import RSS rules"), QDir::homePath()
, u"%1;;%2"_qs.arg(m_formatFilterJSON, m_formatFilterLegacy), &selectedFilter)};
if (!path.exists())
return;
QFile file {path.data()};
if (!file.open(QIODevice::ReadOnly))
const int fileMaxSize = 10 * 1024 * 1024;
const auto readResult = Utils::IO::readFile(path, fileMaxSize);
if (!readResult)
{
QMessageBox::critical(
this, tr("I/O Error")
, tr("Failed to open the file. Reason: %1").arg(file.errorString()));
if (readResult.error().status == Utils::IO::ReadError::NotExist)
return;
QMessageBox::critical(this, tr("Import error")
, tr("Failed to read the file. %1").arg(readResult.error().message));
return;
}
@@ -479,13 +480,12 @@ void AutomatedRssDownloader::onImportBtnClicked()
try
{
RSS::AutoDownloader::instance()->importRules(file.readAll(),format);
RSS::AutoDownloader::instance()->importRules(readResult.value(), format);
}
catch (const RSS::ParsingError &error)
{
QMessageBox::critical(
this, tr("Import Error")
, tr("Failed to import the selected rules file. Reason: %1").arg(error.message()));
QMessageBox::critical(this, tr("Import error")
, tr("Failed to import the selected rules file. Reason: %1").arg(error.message()));
}
}

View File

@@ -30,7 +30,6 @@
#include <QColor>
#include <QColorDialog>
#include <QFile>
#include <QFileDialog>
#include <QJsonDocument>
#include <QJsonObject>

View File

@@ -30,30 +30,17 @@
#include "uithemesource.h"
#include <QFile>
#include <QJsonDocument>
#include <QJsonObject>
#include "base/global.h"
#include "base/logger.h"
#include "base/profile.h"
#include "base/utils/io.h"
namespace
{
QByteArray readFile(const Path &filePath)
{
QFile file {filePath.data()};
if (!file.exists())
return {};
if (file.open(QIODevice::ReadOnly | QIODevice::Text))
return file.readAll();
LogMsg(UIThemeSource::tr("UITheme - Failed to open \"%1\". Reason: %2")
.arg(filePath.filename(), file.errorString())
, Log::WARNING);
return {};
}
const qint64 FILE_MAX_SIZE = 1024 * 1024;
QJsonObject parseThemeConfig(const QByteArray &data)
{
@@ -165,7 +152,16 @@ Path DefaultThemeSource::getIconPath(const QString &iconId, const ColorMode colo
void DefaultThemeSource::loadColors()
{
const QByteArray configData = readFile(m_userPath / Path(CONFIG_FILE_NAME));
const auto readResult = Utils::IO::readFile((m_userPath / Path(CONFIG_FILE_NAME)), FILE_MAX_SIZE, QIODevice::Text);
if (!readResult)
{
if (readResult.error().status != Utils::IO::ReadError::NotExist)
LogMsg(tr("Failed to load default theme colors. %1").arg(readResult.error().message), Log::WARNING);
return;
}
const QByteArray configData = readResult.value();
if (configData.isEmpty())
return;
@@ -233,7 +229,16 @@ Path CustomThemeSource::getIconPath(const QString &iconId, const ColorMode color
QByteArray CustomThemeSource::readStyleSheet()
{
return readFile(themeRootPath() / Path(STYLESHEET_FILE_NAME));
const auto readResult = Utils::IO::readFile((themeRootPath() / Path(STYLESHEET_FILE_NAME)), FILE_MAX_SIZE, QIODevice::Text);
if (!readResult)
{
if (readResult.error().status != Utils::IO::ReadError::NotExist)
LogMsg(tr("Failed to load custom theme style sheet. %1").arg(readResult.error().message), Log::WARNING);
return {};
}
return readResult.value();
}
DefaultThemeSource *CustomThemeSource::defaultThemeSource() const
@@ -243,7 +248,16 @@ DefaultThemeSource *CustomThemeSource::defaultThemeSource() const
void CustomThemeSource::loadColors()
{
const QByteArray configData = readFile(themeRootPath() / Path(CONFIG_FILE_NAME));
const auto readResult = Utils::IO::readFile((themeRootPath() / Path(CONFIG_FILE_NAME)), FILE_MAX_SIZE, QIODevice::Text);
if (!readResult)
{
if (readResult.error().status != Utils::IO::ReadError::NotExist)
LogMsg(tr("Failed to load custom theme colors. %1").arg(readResult.error().message), Log::WARNING);
return;
}
const QByteArray configData = readResult.value();
if (configData.isEmpty())
return;

View File

@@ -177,10 +177,12 @@ void Utils::Gui::openFolderSelect(const Path &path)
QObject::connect(thread, &QThread::finished, thread, &QObject::deleteLater);
thread->start();
#elif defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)
const int lineMaxLength = 64;
QProcess proc;
proc.start(u"xdg-mime"_qs, {u"query"_qs, u"default"_qs, u"inode/directory"_qs});
proc.waitForFinished();
const auto output = QString::fromLocal8Bit(proc.readLine().simplified());
const auto output = QString::fromLocal8Bit(proc.readLine(lineMaxLength).simplified());
if ((output == u"dolphin.desktop") || (output == u"org.kde.dolphin.desktop"))
{
proc.startDetached(u"dolphin"_qs, {u"--select"_qs, path.toString()});
@@ -190,7 +192,7 @@ void Utils::Gui::openFolderSelect(const Path &path)
{
proc.start(u"nautilus"_qs, {u"--version"_qs});
proc.waitForFinished();
const auto nautilusVerStr = QString::fromLocal8Bit(proc.readLine()).remove(QRegularExpression(u"[^0-9.]"_qs));
const auto nautilusVerStr = QString::fromLocal8Bit(proc.readLine(lineMaxLength)).remove(QRegularExpression(u"[^0-9.]"_qs));
using NautilusVersion = Utils::Version<3>;
if (NautilusVersion::fromString(nautilusVerStr, {1, 0, 0}) > NautilusVersion(3, 28, 0))
proc.startDetached(u"nautilus"_qs, {(Fs::isDir(path) ? path.parentPath() : path).toString()});