Make ExternalCommandHelper::getNonce() reentrant.

Store previously generated values of nonce, and remove them from
the container when they are used.

BUG: 396312
This commit is contained in:
Andrius Štikonas 2018-07-21 11:03:25 +01:00
parent c50e04c9d1
commit 938ec7fa8b
4 changed files with 46 additions and 25 deletions

View File

@ -142,8 +142,8 @@ bool ExternalCommand::start(int timeout)
bool rval = false; bool rval = false;
if (iface.isValid()) { if (iface.isValid()) {
QByteArray request; QByteArray request;
const quint64 nonce = getNonce(iface);
request.setNum(getNonce(iface)); request.setNum(nonce);
request.append(cmd.toUtf8()); request.append(cmd.toUtf8());
for (const auto &argument : qAsConst(d->m_Args)) for (const auto &argument : qAsConst(d->m_Args))
request.append(argument.toUtf8()); request.append(argument.toUtf8());
@ -154,6 +154,7 @@ bool ExternalCommand::start(int timeout)
QDBusPendingCall pcall = iface.asyncCall(QStringLiteral("start"), QDBusPendingCall pcall = iface.asyncCall(QStringLiteral("start"),
privateKey->signMessage(hash, QCA::EMSA3_Raw), privateKey->signMessage(hash, QCA::EMSA3_Raw),
nonce,
cmd, cmd,
args(), args(),
d->m_Input, d->m_Input,
@ -203,7 +204,8 @@ bool ExternalCommand::copyBlocks(CopySource& source, CopyTarget& target)
if (iface.isValid()) { if (iface.isValid()) {
QByteArray request; QByteArray request;
request.setNum(getNonce(iface)); const quint64 nonce = getNonce(iface);
request.setNum(nonce);
request.append(source.path().toUtf8()); request.append(source.path().toUtf8());
request.append(QByteArray::number(source.firstByte())); request.append(QByteArray::number(source.firstByte()));
request.append(QByteArray::number(source.length())); request.append(QByteArray::number(source.length()));
@ -214,8 +216,9 @@ bool ExternalCommand::copyBlocks(CopySource& source, CopyTarget& target)
QByteArray hash = QCryptographicHash::hash(request, QCryptographicHash::Sha512); QByteArray hash = QCryptographicHash::hash(request, QCryptographicHash::Sha512);
// Use asynchronous DBus calls, so that we can process reports and progress // Use asynchronous DBus calls, so that we can process reports and progress
QDBusPendingCall pcall= iface.asyncCall(QStringLiteral("copyblocks"), QDBusPendingCall pcall = iface.asyncCall(QStringLiteral("copyblocks"),
privateKey->signMessage(hash, QCA::EMSA3_Raw), privateKey->signMessage(hash, QCA::EMSA3_Raw),
nonce,
source.path(), source.firstByte(), source.length(), source.path(), source.firstByte(), source.length(),
target.path(), target.firstByte(), blockSize); target.path(), target.firstByte(), blockSize);
@ -410,16 +413,17 @@ void ExternalCommand::stopHelper()
QDBusInterface iface(QStringLiteral("org.kde.kpmcore.helperinterface"), QStringLiteral("/Helper"), QStringLiteral("org.kde.kpmcore.externalcommand"), QDBusConnection::systemBus()); QDBusInterface iface(QStringLiteral("org.kde.kpmcore.helperinterface"), QStringLiteral("/Helper"), QStringLiteral("org.kde.kpmcore.externalcommand"), QDBusConnection::systemBus());
if (iface.isValid()) { if (iface.isValid()) {
QByteArray request; QByteArray request;
request.setNum(getNonce(iface)); const quint64 nonce = getNonce(iface);
request.setNum(nonce);
QByteArray hash = QCryptographicHash::hash(request, QCryptographicHash::Sha512); QByteArray hash = QCryptographicHash::hash(request, QCryptographicHash::Sha512);
iface.call(QStringLiteral("exit"), privateKey->signMessage(hash, QCA::EMSA3_Raw)); iface.call(QStringLiteral("exit"), privateKey->signMessage(hash, QCA::EMSA3_Raw), nonce);
} }
delete privateKey; delete privateKey;
delete init; delete init;
} }
unsigned long long ExternalCommand::getNonce(QDBusInterface& iface) quint64 ExternalCommand::getNonce(QDBusInterface& iface)
{ {
QDBusPendingCall pcall = iface.asyncCall(QStringLiteral("getNonce")); QDBusPendingCall pcall = iface.asyncCall(QStringLiteral("getNonce"));
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pcall); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pcall);

View File

@ -130,13 +130,13 @@ private:
void onFinished(int exitCode, QProcess::ExitStatus exitStatus); void onFinished(int exitCode, QProcess::ExitStatus exitStatus);
void onReadOutput(); void onReadOutput();
static unsigned long long getNonce(QDBusInterface& iface); static quint64 getNonce(QDBusInterface& iface);
private: private:
std::unique_ptr<ExternalCommandPrivate> d; std::unique_ptr<ExternalCommandPrivate> d;
// KAuth stuff // KAuth
static unsigned long long m_Nonce; static quint64 m_Nonce;
static KAuth::ExecuteJob *m_job; static KAuth::ExecuteJob *m_job;
static QCA::Initializer *init; static QCA::Initializer *init;
static QCA::PrivateKey *privateKey; static QCA::PrivateKey *privateKey;

View File

@ -61,7 +61,6 @@ ActionReply ExternalCommandHelper::init(const QVariantMap& args)
} }
m_publicKey = QCA::PublicKey::fromDER(args[QStringLiteral("pubkey")].toByteArray()); m_publicKey = QCA::PublicKey::fromDER(args[QStringLiteral("pubkey")].toByteArray());
m_Nonce = m_Generator.generate();
HelperSupport::progressStep(QVariantMap()); HelperSupport::progressStep(QVariantMap());
auto timeout = [this] () { auto timeout = [this] () {
@ -93,10 +92,11 @@ ActionReply ExternalCommandHelper::init(const QVariantMap& args)
/** Generates cryptographic nonce /** Generates cryptographic nonce
* @return nonce * @return nonce
*/ */
unsigned long long ExternalCommandHelper::getNonce() quint64 ExternalCommandHelper::getNonce()
{ {
m_Nonce = m_Generator.generate(); quint64 nonce = m_Generator.generate();
return m_Nonce; m_Nonces.insert(nonce);
return nonce;
} }
/** Reads the given number of bytes from the sourceDevice into the given buffer. /** Reads the given number of bytes from the sourceDevice into the given buffer.
@ -156,11 +156,16 @@ bool ExternalCommandHelper::writeData(const QString &targetDevice, const QByteAr
return true; return true;
} }
bool ExternalCommandHelper::copyblocks(const QByteArray& signature, const QString& sourceDevice, const qint64 sourceFirstByte, const qint64 sourceLength, const QString& targetDevice, const qint64 targetFirstByte, const qint64 blockSize) bool 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)
{ {
if (m_Nonces.find(nonce) != m_Nonces.end())
m_Nonces.erase( nonce );
else
return false;
QByteArray request; QByteArray request;
request.setNum(m_Nonce); request.setNum(nonce);
request.append(sourceDevice.toUtf8()); request.append(sourceDevice.toUtf8());
request.append(QByteArray::number(sourceFirstByte)); request.append(QByteArray::number(sourceFirstByte));
request.append(QByteArray::number(sourceLength)); request.append(QByteArray::number(sourceLength));
@ -253,14 +258,21 @@ bool ExternalCommandHelper::copyblocks(const QByteArray& signature, const QStrin
return rval; return rval;
} }
QVariantMap ExternalCommandHelper::start(const QByteArray& signature, const QString& command, const QStringList& arguments, const QByteArray& input, const int processChannelMode) 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")); QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));
QVariantMap reply; QVariantMap reply;
reply[QStringLiteral("success")] = true; reply[QStringLiteral("success")] = true;
if (m_Nonces.find(nonce) != m_Nonces.end())
m_Nonces.erase( nonce );
else {
reply[QStringLiteral("success")] = false;
return reply;
}
QByteArray request; QByteArray request;
request.setNum(m_Nonce); request.setNum(nonce);
request.append(command.toUtf8()); request.append(command.toUtf8());
for (const auto &argument : arguments) for (const auto &argument : arguments)
request.append(argument.toUtf8()); request.append(argument.toUtf8());
@ -288,10 +300,13 @@ QVariantMap ExternalCommandHelper::start(const QByteArray& signature, const QStr
return reply; return reply;
} }
void ExternalCommandHelper::exit(const QByteArray& signature) void ExternalCommandHelper::exit(const QByteArray& signature, const quint64 nonce)
{ {
QByteArray request; QByteArray request;
request.setNum(m_Nonce); if (m_Nonces.find(nonce) == m_Nonces.end())
return;
request.setNum(nonce);
QByteArray hash = QCryptographicHash::hash(request, QCryptographicHash::Sha512); QByteArray hash = QCryptographicHash::hash(request, QCryptographicHash::Sha512);
if (!m_publicKey.verifyMessage(hash, signature, QCA::EMSA3_Raw)) { if (!m_publicKey.verifyMessage(hash, signature, QCA::EMSA3_Raw)) {
qCritical() << xi18n("Invalid cryptographic signature"); qCritical() << xi18n("Invalid cryptographic signature");

View File

@ -18,6 +18,8 @@
#ifndef KPMCORE_EXTERNALCOMMANDHELPER_H #ifndef KPMCORE_EXTERNALCOMMANDHELPER_H
#define KPMCORE_EXTERNALCOMMANDHELPER_H #define KPMCORE_EXTERNALCOMMANDHELPER_H
#include <unordered_set>
#include <KAuth> #include <KAuth>
#include <QEventLoop> #include <QEventLoop>
@ -44,10 +46,10 @@ public:
public Q_SLOTS: public Q_SLOTS:
ActionReply init(const QVariantMap& args); ActionReply init(const QVariantMap& args);
Q_SCRIPTABLE unsigned long long getNonce(); Q_SCRIPTABLE quint64 getNonce();
Q_SCRIPTABLE QVariantMap start(const QByteArray& signature, const QString& command, const QStringList& arguments, const QByteArray& input, const int processChannelMode); Q_SCRIPTABLE QVariantMap start(const QByteArray& signature, const quint64 nonce, const QString& command, const QStringList& arguments, const QByteArray& input, const int processChannelMode);
Q_SCRIPTABLE bool copyblocks(const QByteArray& signature, const QString& sourceDevice, const qint64 sourceFirstByte, const qint64 sourceLength, const QString& targetDevice, const qint64 targetFirstByte, const qint64 blockSize); Q_SCRIPTABLE bool 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 void exit(const QByteArray& signature); Q_SCRIPTABLE void exit(const QByteArray& signature, const quint64 nonce);
private: private:
void onReadOutput(); void onReadOutput();
@ -56,7 +58,7 @@ private:
QCA::Initializer initializer; QCA::Initializer initializer;
QCA::PublicKey m_publicKey; QCA::PublicKey m_publicKey;
QRandomGenerator64 m_Generator; QRandomGenerator64 m_Generator;
unsigned long long m_Nonce; std::unordered_set<quint64> m_Nonces;
QString m_command; QString m_command;
QString m_sourceDevice; QString m_sourceDevice;
QProcess m_cmd; QProcess m_cmd;