-
Notifications
You must be signed in to change notification settings - Fork 107
fix(network): Prevent buffer overflows for incoming messages in NetPacket #1668
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
base: main
Are you sure you want to change the base?
Conversation
TODO Fix numerous out of bound reads which may lead to crashes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I looked at code and I think we can fix and simplify these functions like so:
NetCommandMsg * NetPacket::readFileMessage(UnsignedByte *data, Int &i) {
NetFileCommandMsg *msg = newInstance(NetFileCommandMsg);
// file name
AsciiString filename(reinterpret_cast<const char*>(data)); // data is expected to be zero terminated
msg->setPortableFilename(filename); // it's transferred as a portable filename
i += filename.getByteCount();
// file size
UnsignedInt dataLength = 0;
memcpy(&dataLength, data + i, sizeof(dataLength));
i += sizeof(dataLength);
// file data
UnsignedByte *buf = NEW UnsignedByte[dataLength];
memcpy(buf, data + i, dataLength);
i += dataLength;
msg->setFileData(buf, dataLength);
return msg;
}
Alternatively I was thinking doing
...
// file name
const size_t filenameLength = std::min<size_t>(MAX_PATH, strlen(reinterpret_cast<const char*>(data)));
AsciiString filename(reinterpret_cast<const char*>(data), filenameLength);
msg->setPortableFilename(filename); // it's transferred as a portable filename
i += filename.getByteCount();
...
but this would perhaps not help against cases where a malicious sender would send a short message that is not 0 terminated. So we do not need this. I think all messages need to be zero terminated before processing to be safe.
Hi, as you noted yourself this would not prevent out of bounds read (when the packet is not null-terminated) and could therefore still result in a crash, albeit a read access violation rather than a stack buffer overflow. Your code could work if you were to use |
There are a few messages that expect null terminated strings, so I think we need to always null terminate incoming packet data, to guarantee that no malicious sender can send non 0 terminated data and cause us some mayhem. So perhaps this is good: NetPacket::NetPacket(TransportMessage *msg) {
init();
m_packetLen = std::min<Int>(msg->length, MAX_PACKET_SIZE);
memcpy(m_packet, msg->data, m_packetLen);
memset(m_packet + m_packetLen, 0, ARRAY_SIZE(m_packet) - m_packetLen);
m_numCommands = -1;
m_addr = msg->addr;
m_port = msg->port;
} Not sure if it is worth it to memset the whole rest to 0. I think it is zero anyway because of the Game Memory Allocator. I checked |
In theory that's fine. Not sure if you care about "zero-copy" but this would add a copy (I assume). Additionally I'd note, just in case, that |
I forgot to mention, |
It would resolve out of bounds access ascii string reading logic ( |
Edit: having the packet zero-terminated and using |
But then still there's |
This could also be: strlcpy(filename, data, _MAX_PATH) which will ensure null termination. |
Ah yes, |
Will this change see additional revisions? |
I can make modifications if you like, but so far my PR seems less intrusive than the other suggestions mentioned above (e.g., by not requiring buf to be nul-terminated). |
TODO Fix numerous out of bound reads which may lead to crashes.