fix potential DoS vulnerability (through memory exhaustion) by restricting maximum line length

This commit is contained in:
Guenter Obiltschnig
2017-01-24 13:13:13 +01:00
parent 3577724efd
commit 4392f13b9c
2 changed files with 16 additions and 10 deletions

View File

@@ -22,6 +22,7 @@
#include "Poco/Net/Net.h" #include "Poco/Net/Net.h"
#include "Poco/Net/StreamSocket.h" #include "Poco/Net/StreamSocket.h"
#include <cstdlib>
namespace Poco { namespace Poco {
@@ -189,13 +190,14 @@ public:
protected: protected:
void allocBuffer(); void allocBuffer();
void refill(); void refill();
bool receiveLine(std::string& line); bool receiveLine(std::string& line, std::size_t lineLengthLimit = 0);
int receiveStatusLine(std::string& line); int receiveStatusLine(std::string& line, std::size_t lineLengthLimit = 0);
private: private:
enum enum
{ {
RECEIVE_BUFFER_SIZE = 1024, RECEIVE_BUFFER_SIZE = 1024,
MAX_LINE_LENGTH = 4096,
EOF_CHAR = -1 EOF_CHAR = -1
}; };

View File

@@ -15,6 +15,7 @@
#include "Poco/Net/DialogSocket.h" #include "Poco/Net/DialogSocket.h"
#include "Poco/Exception.h"
#include "Poco/Ascii.h" #include "Poco/Ascii.h"
#include <cstring> #include <cstring>
@@ -149,20 +150,20 @@ void DialogSocket::sendMessage(const std::string& message, const std::string& ar
bool DialogSocket::receiveMessage(std::string& message) bool DialogSocket::receiveMessage(std::string& message)
{ {
message.clear(); message.clear();
return receiveLine(message); return receiveLine(message, MAX_LINE_LENGTH);
} }
int DialogSocket::receiveStatusMessage(std::string& message) int DialogSocket::receiveStatusMessage(std::string& message)
{ {
message.clear(); message.clear();
int status = receiveStatusLine(message); int status = receiveStatusLine(message, MAX_LINE_LENGTH);
if (status < 0) if (status < 0)
{ {
while (status <= 0) while (status <= 0)
{ {
message += '\n'; message += '\n';
status = receiveStatusLine(message); status = receiveStatusLine(message, MAX_LINE_LENGTH);
} }
} }
return status; return status;
@@ -236,14 +237,17 @@ void DialogSocket::allocBuffer()
} }
bool DialogSocket::receiveLine(std::string& line) bool DialogSocket::receiveLine(std::string& line, std::size_t lineLengthLimit)
{ {
// An old wisdom goes: be strict in what you emit // An old wisdom goes: be strict in what you emit
// and generous in what you accept. // and generous in what you accept.
int ch = get(); int ch = get();
while (ch != EOF_CHAR && ch != '\r' && ch != '\n') while (ch != EOF_CHAR && ch != '\r' && ch != '\n')
{ {
line += (char) ch; if (lineLengthLimit == 0 || line.size() < lineLengthLimit)
line += (char) ch;
else
throw Poco::IOException("Line too long");
ch = get(); ch = get();
} }
if (ch == '\r' && peek() == '\n') if (ch == '\r' && peek() == '\n')
@@ -254,7 +258,7 @@ bool DialogSocket::receiveLine(std::string& line)
} }
int DialogSocket::receiveStatusLine(std::string& line) int DialogSocket::receiveStatusLine(std::string& line, std::size_t lineLengthLimit)
{ {
int status = 0; int status = 0;
int ch = get(); int ch = get();
@@ -274,7 +278,7 @@ int DialogSocket::receiveStatusLine(std::string& line)
status = -status; status = -status;
} }
else status = 0; else status = 0;
if (ch != EOF_CHAR) receiveLine(line); if (ch != EOF_CHAR) receiveLine(line, lineLengthLimit);
return status; return status;
} }