In the context of protocol buffers, security comes into play when decoding untrusted data. Naturally, if the attacker can modify the contents of a protocol buffers message, he can feed the application any values possible. Therefore the application itself must be prepared to receive untrusted values.
Where nanopb plays a part is preventing the attacker from running arbitrary code on the target system. Mostly this means that there must not be any possibility to cause buffer overruns, memory corruption or invalid pointers by the means of crafting a malicious message.
The following data is regarded as trusted. It must be under the control of the application writer. Malicious data in these structures could cause security issues, such as execution of arbitrary code:
pb_msgdesc_t
.pb_istream_t
and pb_ostream_t
structures (this does not mean the contents of the stream itself, just the stream definition).The following data is regarded as untrusted. Invalid/malicious data in these will cause “garbage in, garbage out” behaviour. It will not cause buffer overflows, information disclosure or other security problems:
pb_istream_t
.pb_callback_t
structures)_count
fields for pointerspb_extension_t
structures)The following invariants are maintained during operation, even if the untrusted data has been maliciously crafted:
bytes_left
bytes from pb_istream_t
.max_size
bytes to pb_ostream_t
.pb_decode()
returns successfully, the message structure will be internally consistent:
count
fields of arrays will not exceed the array size.size
field of bytes will not exceed the allocated size.NULL
or point to valid datapb_encode()
returns successfully, the resulting message is a valid protocol buffers message. (Except if user-defined callbacks write incorrect data.)pb_decode()
will be released by a subsequent call to pb_release()
on the same message.Even if the nanopb library is free of any security issues, there are still several possible attack vectors that the application author must consider. The following list is not comprehensive:
pb_istream_t
to stop a denial of service attack from using an infinite message.malloc()
support, some method of limiting memory use should be employed. This can be done by defining custom pb_realloc()
function. Nanopb will properly detect and handle failed memory allocations.