From 09e4d47e0711a800be858fdd6691f59838bc3003 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrius=20=C5=A0tikonas?= Date: Sun, 25 Nov 2018 20:50:22 +0000 Subject: [PATCH] Do not use external process dd. BUG: 398154 --- src/fs/fat12.cpp | 8 ++--- src/fs/fat32.cpp | 11 +++---- src/fs/ntfs.cpp | 7 ++-- src/util/externalcommand.cpp | 49 ++++++++++++++++++++++++++++ src/util/externalcommand.h | 1 + src/util/externalcommand_whitelist.h | 1 - src/util/externalcommandhelper.cpp | 30 ++++++++++++++++- src/util/externalcommandhelper.h | 1 + 8 files changed, 90 insertions(+), 18 deletions(-) diff --git a/src/fs/fat12.cpp b/src/fs/fat12.cpp index 8124c4a..dbad427 100644 --- a/src/fs/fat12.cpp +++ b/src/fs/fat12.cpp @@ -157,7 +157,7 @@ bool fat12::create(Report& report, const QString& deviceNode) bool fat12::updateUUID(Report& report, const QString& deviceNode) const { - qint64 t = time(nullptr); + long int t = time(nullptr); char uuid[4]; for (auto &u : uuid) { @@ -165,9 +165,7 @@ bool fat12::updateUUID(Report& report, const QString& deviceNode) const t >>= 8; } - ExternalCommand cmd(report, QStringLiteral("dd"), { QStringLiteral("of=") + deviceNode , QStringLiteral("bs=1"), QStringLiteral("count=4"), QStringLiteral("seek=39") }); - - cmd.write(QByteArray(uuid, sizeof(uuid))); - return cmd.start(); + ExternalCommand cmd; + return cmd.writeData(report, QByteArray(uuid, sizeof(uuid)), deviceNode, 39); } } diff --git a/src/fs/fat32.cpp b/src/fs/fat32.cpp index b54e4fa..2bb6b34 100644 --- a/src/fs/fat32.cpp +++ b/src/fs/fat32.cpp @@ -14,6 +14,7 @@ * You should have received a copy of the GNU General Public License * * along with this program. If not, see .* *************************************************************************/ + #include "fs/fat32.h" #include "util/externalcommand.h" @@ -48,7 +49,8 @@ bool fat32::create(Report& report, const QString& deviceNode) bool fat32::updateUUID(Report& report, const QString& deviceNode) const { - qint64 t = time(nullptr); + // HACK: replace this hack with fatlabel "-i" (dosfstools 4.2) + long int t = time(nullptr); char uuid[4]; for (auto &u : uuid) { @@ -56,10 +58,7 @@ bool fat32::updateUUID(Report& report, const QString& deviceNode) const t >>= 8; } - // HACK: replace this hack with fatlabel "-i" (dosfstools 4.2) - ExternalCommand cmd(report, QStringLiteral("dd"), { QStringLiteral("of=") + deviceNode, QStringLiteral("bs=1"), QStringLiteral("count=4"), QStringLiteral("seek=67") }); - - cmd.write(QByteArray(uuid, sizeof(uuid))); - return cmd.start(); + ExternalCommand cmd; + return cmd.writeData(report, QByteArray(uuid, sizeof(uuid)), deviceNode, 67); } } diff --git a/src/fs/ntfs.cpp b/src/fs/ntfs.cpp index 471638a..0c08c6c 100644 --- a/src/fs/ntfs.cpp +++ b/src/fs/ntfs.cpp @@ -29,7 +29,6 @@ #include #include #include -#include #include #include @@ -188,10 +187,8 @@ bool ntfs::updateBootSector(Report& report, const QString& deviceNode) const std::swap(s[1], s[2]); #endif - ExternalCommand cmd(report, QStringLiteral("dd"), { QStringLiteral("of=") + deviceNode , QStringLiteral("bs=1"), QStringLiteral("count=4"), QStringLiteral("seek=28") }); - - cmd.write(QByteArray(s, sizeof(s))); - if (!cmd.start()) { + ExternalCommand cmd; + if (!cmd.writeData(report, QByteArray(s, sizeof(s)), deviceNode, 28)) { Log() << xi18nc("@info:progress", "Could not write new start sector to partition %1 when trying to update the NTFS boot sector.", deviceNode); return false; } diff --git a/src/util/externalcommand.cpp b/src/util/externalcommand.cpp index 76b480c..72b1b14 100644 --- a/src/util/externalcommand.cpp +++ b/src/util/externalcommand.cpp @@ -241,6 +241,55 @@ bool ExternalCommand::copyBlocks(CopySource& source, CopyTarget& target) return rval; } +bool ExternalCommand::writeData(Report& commandReport, const QByteArray& buffer, const QString& deviceNode, const quint64 firstByte) +{ + d->m_Report = commandReport.newChild(); + if (report()) + report()->setCommand(xi18nc("@info:status", "Command: %1 %2", command(), args().join(QStringLiteral(" ")))); + + bool rval = true; + + if (!QDBusConnection::systemBus().isConnected()) { + qWarning() << "Could not connect to DBus system bus"; + return false; + } + + auto *interface = new org::kde::kpmcore::externalcommand(QStringLiteral("org.kde.kpmcore.externalcommand"), + QStringLiteral("/Helper"), QDBusConnection::systemBus(), this); + interface->setTimeout(10 * 24 * 3600 * 1000); // 10 days + QByteArray request; + + const quint64 nonce = interface->getNonce(); + request.setNum(nonce); + request.append(buffer); + request.append(deviceNode.toUtf8()); + request.append(QByteArray::number(firstByte)); + + QByteArray hash = QCryptographicHash::hash(request, QCryptographicHash::Sha512); + + QDBusPendingCall pcall = interface->writeData(privateKey->signMessage(hash, QCA::EMSA3_Raw), nonce, + buffer, deviceNode, firstByte); + + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pcall, this); + QEventLoop loop; + + auto exitLoop = [&] (QDBusPendingCallWatcher *watcher) { + loop.exit(); + if (watcher->isError()) + qWarning() << watcher->error(); + else { + QDBusPendingReply reply = *watcher; + rval = reply.argumentAt<0>(); + } + setExitCode(!rval); + }; + + connect(watcher, &QDBusPendingCallWatcher::finished, exitLoop); + loop.exec(); + + return rval; +} + bool ExternalCommand::write(const QByteArray& input) { diff --git a/src/util/externalcommand.h b/src/util/externalcommand.h index 35b1a81..c1abba2 100644 --- a/src/util/externalcommand.h +++ b/src/util/externalcommand.h @@ -69,6 +69,7 @@ public: public: bool copyBlocks(CopySource& source, CopyTarget& target); + bool writeData(Report& report, const QByteArray& buffer, const QString& deviceNode, const quint64 firstByte); // same as copyBlocks but from QByteArray /**< @param cmd the command to run */ void setCommand(const QString& cmd); diff --git a/src/util/externalcommand_whitelist.h b/src/util/externalcommand_whitelist.h index 79160aa..7ae4240 100644 --- a/src/util/externalcommand_whitelist.h +++ b/src/util/externalcommand_whitelist.h @@ -21,7 +21,6 @@ QString allowedCommands[] = { // TODO try to remove these later QStringLiteral("mv"), -QStringLiteral("dd"), // TODO no root needed QStringLiteral("lsblk"), diff --git a/src/util/externalcommandhelper.cpp b/src/util/externalcommandhelper.cpp index 87edade..c5687cf 100644 --- a/src/util/externalcommandhelper.cpp +++ b/src/util/externalcommandhelper.cpp @@ -152,6 +152,7 @@ bool ExternalCommandHelper::writeData(const QString &targetDevice, const QByteAr return true; } +// If targetDevice is empty then return QByteArray with data that was read from disk. QVariantMap ExternalCommandHelper::copyblocks(const QByteArray& signature, const quint64 nonce, const QString& sourceDevice, const qint64 sourceFirstByte, const qint64 sourceLength, const QString& targetDevice, const qint64 targetFirstByte, const qint64 blockSize) { QVariantMap reply; @@ -213,7 +214,7 @@ QVariantMap ExternalCommandHelper::copyblocks(const QByteArray& signature, const bool rval = true; - while (blocksCopied < blocksToCopy) { + while (blocksCopied < blocksToCopy && !targetDevice.isEmpty()) { if (!(rval = readData(sourceDevice, buffer, readOffset + blockSize * blocksCopied * copyDirection, blockSize))) break; @@ -265,6 +266,33 @@ QVariantMap ExternalCommandHelper::copyblocks(const QByteArray& signature, const return reply; } +bool ExternalCommandHelper::writeData(const QByteArray& signature, const quint64 nonce, const QByteArray buffer, const QString& targetDevice, const qint64 targetFirstByte) +{ + if (m_Nonces.find(nonce) != m_Nonces.end()) + m_Nonces.erase( nonce ); + else + return false; + + QByteArray request; + request.setNum(nonce); + request.append(buffer); + request.append(targetDevice.toUtf8()); + request.append(QByteArray::number(targetFirstByte)); + + // Do not allow using this helper for writing to arbitrary location + if ( targetDevice.left(5) != QStringLiteral("/dev/") && !targetDevice.contains(QStringLiteral("/etc/fstab"))) + return false; + + QByteArray hash = QCryptographicHash::hash(request, QCryptographicHash::Sha512); + if (!m_publicKey.verifyMessage(hash, signature, QCA::EMSA3_Raw)) { + qCritical() << xi18n("Invalid cryptographic signature"); + return false; + } + + return writeData(targetDevice, buffer, targetFirstByte); +} + + QVariantMap ExternalCommandHelper::start(const QByteArray& signature, const quint64 nonce, const QString& command, const QStringList& arguments, const QByteArray& input, const int processChannelMode) { QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8")); diff --git a/src/util/externalcommandhelper.h b/src/util/externalcommandhelper.h index 3f7959c..d73d085 100644 --- a/src/util/externalcommandhelper.h +++ b/src/util/externalcommandhelper.h @@ -50,6 +50,7 @@ public Q_SLOTS: Q_SCRIPTABLE quint64 getNonce(); Q_SCRIPTABLE QVariantMap start(const QByteArray& signature, const quint64 nonce, const QString& command, const QStringList& arguments, const QByteArray& input, const int processChannelMode); Q_SCRIPTABLE QVariantMap copyblocks(const QByteArray& signature, const quint64 nonce, const QString& sourceDevice, const qint64 sourceFirstByte, const qint64 sourceLength, const QString& targetDevice, const qint64 targetFirstByte, const qint64 blockSize); + Q_SCRIPTABLE bool writeData(const QByteArray& signature, const quint64 nonce, const QByteArray buffer, const QString& targetDevice, const qint64 targetFirstByte); Q_SCRIPTABLE void exit(const QByteArray& signature, const quint64 nonce); private: