Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix freeze and high CPU usage on invalid STDIN data #1628

Merged
merged 1 commit into from
Mar 6, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 17 additions & 9 deletions src/browser/NativeMessagingHost.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,18 +107,26 @@ void NativeMessagingHost::readLength()

void NativeMessagingHost::readStdIn(const quint32 length)
{
if (length > 0) {
QByteArray arr;
arr.reserve(length);
if (length <= 0) {
return;
}

for (quint32 i = 0; i < length; ++i) {
arr.append(getchar());
}
QByteArray arr;
arr.reserve(length);

if (arr.length() > 0) {
QMutexLocker locker(&m_mutex);
sendReply(m_browserClients.readResponse(arr));
QMutexLocker locker(&m_mutex);

for (quint32 i = 0; i < length; ++i) {
int c = std::getchar();
if (c == EOF) {
// message ended prematurely, ignore it and return
return;
}
arr.append(static_cast<char>(c));
}

if (arr.length() > 0) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't we lock at the beginning of the function or the beginning of the sendReply function?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why lock the mutex at the beginning when the first time any members (that need locking) are used is at this point?

Copy link
Member Author

@phoerious phoerious Mar 6, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't change anything here, but yes, it's weird.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, I had a quick look at it. On *nix it should be perfectly safe to remove the mutex, but on Windows, there is a weird mix of threads and signal/slot connections. I don't have the time right now to investigate where it's really needed and where it isn't. I'd prefer we just leave it as is for now.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Defer to the 2.4 epic to cleanup this code

sendReply(m_browserClients.readResponse(arr));
}
}

Expand Down
13 changes: 8 additions & 5 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -143,12 +143,15 @@ int main(int argc, char** argv)

const bool pwstdin = parser.isSet(pwstdinOption);
for (const QString& filename: fileNames) {
QString password;
if (pwstdin) {
// we always need consume a line of STDIN if --pw-stdin is set to clear out the
// buffer for native messaging, even if the specified file does not exist
static QTextStream in(stdin, QIODevice::ReadOnly);
password = in.readLine();
}

if (!filename.isEmpty() && QFile::exists(filename) && !filename.endsWith(".json", Qt::CaseInsensitive)) {
QString password;
if (pwstdin) {
static QTextStream in(stdin, QIODevice::ReadOnly);
password = in.readLine();
}
mainWindow.openDatabase(filename, password, parser.value(keyfileOption));
}
}
Expand Down
25 changes: 16 additions & 9 deletions src/proxy/NativeMessagingHost.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,18 +51,25 @@ void NativeMessagingHost::readLength()

void NativeMessagingHost::readStdIn(const quint32 length)
{
if (length > 0) {
QByteArray arr;
arr.reserve(length);
if (length <= 0) {
return;
}

for (quint32 i = 0; i < length; ++i) {
arr.append(getchar());
}
QByteArray arr;
arr.reserve(length);

if (arr.length() > 0 && m_localSocket && m_localSocket->state() == QLocalSocket::ConnectedState) {
m_localSocket->write(arr.constData(), arr.length());
m_localSocket->flush();
for (quint32 i = 0; i < length; ++i) {
int c = std::getchar();
if (c == EOF) {
// message ended prematurely, ignore it and return
return;
}
arr.append(static_cast<char>(c));
}

if (arr.length() > 0 && m_localSocket && m_localSocket->state() == QLocalSocket::ConnectedState) {
m_localSocket->write(arr.constData(), arr.length());
m_localSocket->flush();
}
}

Expand Down