libp2p / cpp-libp2p

C++17 implementation of libp2p
Apache License 2.0
346 stars 97 forks source link

Segmentation fault when receiving empty protobuf message #199

Closed asmie closed 1 year ago

asmie commented 1 year ago

The problem occurs when there is a need to receive message like (protobuf definition):

message BlockResponse {
    repeated bytes block_data = 1;
}

and block_data has zero length. According to protobuf standard 'repeated' means zero or more occurs so it is possible for message with only one repeated field to have no data.

Such correct message is read in MessageReadWriterUvarint::read (message_read_writer_uvarint.cpp). If there is no error during read, that method check if message length is zero and if so, it calls callback with ResultType:

cb(ResultType{});

But the result type is: using ResultType = std::shared_ptr<std::vector<uint8_t>>;

In fact, the previous callback execution is done using shared pointer that contain nullptr inside.

Read method of ProtobufMessageReadWriter (protobuf_message_read_writer.hpp) contains lambda called from MessageReadWriter, which checks if result is correct and if so it executes the following code:

auto &&buf = res.value();
ProtoMsgType msg;
msg.ParseFromArray(buf->data(), buf->size());

So right after getting shared pointer (res.value()) it's dereferenced without checking if it's empty (buf->data(), buf->size()). This causes segmentation fault.

Above behaviour can lead to DoS attack as potential attacker can prepare empty messages (if there are suitable proto structures) to crash any application using this library. So potential attacker can crash application remotely just by sending appropriate formatted messages that will be parsed by protobuf.

asmie commented 1 year ago

Fixing commit (0cf9827) merged.