aboutsummaryrefslogtreecommitdiffstats
path: root/pb_decode.c
AgeCommit message (Collapse)AuthorFilesLines
2016-06-06Protect against corrupted _count fields in pb_release().Petteri Aimonen1-0/+6
Fixes a potential security issue (#205). Only relevant if the user code writes untrusted data to _count fields, but this is allowed as per the security model.
2016-01-27Fix a few remaining bugs related to CHAR_BIT!=8 platforms.Petteri Aimonen1-25/+34
2016-01-27Replace uint8_t with a pb_byte_t typedef.Petteri Aimonen1-43/+47
This supports platforms where uint8_t does not exist. If you are using a custom pb_syshdr.h, this may require adding definitions for uint_least8_t etc.
2016-01-26Get rid of type punning in pb_encode_fixedXX().Petteri Aimonen1-28/+19
This was never very clean code, but it was fast. Hopefully compilers are smart enough to optimize it away, or the speed difference is not very large. This should be checked. However working code is always more important than fast code, and the previous way couldn't really work for platforms that do not have byte-sized memory access. Related to PR #191.
2015-12-16pb_istream_from_buffer: add const to prototypeAndrew Ruder1-5/+13
This commit changes the prototype for pb_istream_from_buffer from: pb_istream_t pb_istream_from_buffer(uint8_t *buf, size_t bufsize); to pb_istream_t pb_istream_from_buffer(const uint8_t *buf, size_t bufsize); This allows pb_istream_from_buffer users to point to const buffers without having to inspect code (to ensure practical const-ness) and then be forced to manually cast away const. In order to not break compatibility with existing programs (by introducing a const/non-const union in the pb_istream_t state) we simply cast away the const in pb_istream_from_buffer and re-apply it when possible in the callbacks. Unfortunately we lose any compiler help in the callbacks to ensure we are treating the buffer as const but manual inspection is easy enough.
2015-10-25Ignore null pointers in pb_release() (issue #183).Petteri Aimonen1-0/+3
2015-09-21decode: Fix compiler issue with gcc-5Kyle Manna1-1/+2
* gcc 5.0 and 5.1 appear to take issue with this line and generates the following error: /home/nitro/tmp/nanopb/pb_decode.c: In function ‘pb_decode_noinit’: /home/nitro/tmp/nanopb/pb_decode.c:889:60: error: conversion to ‘uint8_t {aka unsigned char}’ from ‘int’ may alter its value [-Werror=conversion] fields_seen[iter.required_field_index >> 3] |= (uint8_t)(1 << (iter.required_field_index & 7)); ^ * This seems like a compiler bug, but this workaround is harmless.
2015-04-03Clear callbacks for union fields.Petteri Aimonen1-0/+3
Update issue 148 Status: FixedInGit
2015-03-07Fix oneof submessage initialization bug.Petteri Aimonen1-0/+4
Update issue 149 Status: FixedInGit
2015-01-15Release memory when overwriting oneof fields.Petteri Aimonen1-0/+39
Update issue 131 Status: FixedInGit
2015-01-11Bugfixes for oneof support.Petteri Aimonen1-4/+13
Fixes crashes / memory leaks when using pointer type fields. Also fixes initialization of which_oneof fields.
2015-01-04Implement support for oneofs (C unions).Petteri Aimonen1-1/+11
Basic test included, should probably add an oneof to the AllTypes test also. Update issue 131 Status: Started
2015-01-04Detect too large varint values when decoding.Petteri Aimonen1-14/+36
Because Issue #139 now allows limiting integer fields, it is good to check the values received from other protobuf libraries against the lower limits.
2015-01-04Add int_size option for generator.Petteri Aimonen1-0/+4
This allows overriding the integer field types to e.g. uint8_t for saving RAM. Update issue 139 Status: FixedInGit
2014-12-26Fix memory leaks with PB_ENABLE_MALLOC and certain submessage type combinations.Petteri Aimonen1-20/+45
There was a memory leak when: 1) A statically allocated submessage or 2) an extension field submessage contained A) a pointer-type field or B) a submessage that further contained a pointer-type field. This was because pb_release() didn't recurse into non-pointer fields. Update issue 138 Status: FixedInGit
2014-12-26Initialize also extension fields to defaults in pb_decode().Petteri Aimonen1-54/+83
This makes the behaviour more consistent with non-extension fields, and also makes sure that all 'found' fields of extensions are initially false.
2014-12-26Add support for POINTER type in extensionsPetteri Aimonen1-0/+8
2014-09-11Protect against size_t overflows in pb_dec_bytes/pb_dec_string.Petteri Aimonen1-7/+13
Possible consequences of bug: 1) Denial of service by causing a crash Possible when all of the following apply: - Untrusted data is passed to pb_decode() - The top-level message contains a static string field as the first field. Causes a single write of '0' byte to 1 byte before the message struct. 2) Remote code execution Possible when all of the following apply: - 64-bit platform - The message or a submessage contains a static/pointer string field. - Decoding directly from a custom pb_istream_t - bytes_left on the stream is set to larger than 4 GB Causes a write of up to 4 GB of data past the string field. 3) Possible heap corruption or remote code execution Possible when all of the following apply: - less than 64-bit platform - The message or a submessage contains a pointer-type bytes field. Causes a write of sizeof(pb_size_t) bytes of data past a 0-byte long malloc()ed buffer. On many malloc() implementations, this causes at most a crash. However, remote code execution through a controlled jump cannot be ruled out. -- Detailed analysis follows In the following consideration, I define "platform bitness" as equal to number of bits in size_t datatype. Therefore most 8-bit platforms are regarded as 16-bit for the purposes of this discussion. 1. The overflow in pb_dec_string The overflow happens in this computation: uint32_t size; size_t alloc_size; alloc_size = size + 1; There are two ways in which the overflow can occur: In the uint32_t addition, or in the cast to size_t. This depends on the platform bitness. On 32- and 64-bit platforms, the size has to be UINT32_MAX for the overflow to occur. In that case alloc_size will be 0. On 16-bit platforms, overflow will happen whenever size is more than UINT16_MAX, and resulting alloc_size is attacker controlled. For static fields, the alloc_size value is just checked against the field data size. For pointer fields, the alloc_size value is passed to malloc(). End result in both cases is the same, the storage is 0 or just a few bytes in length. On 16-bit platforms, another overflow occurs in the call to pb_read(), when passing the original size. An attacker will want the passed value to be larger than the alloc_size, therefore the only reasonable choice is to have size = UINT16_MAX and alloc_size = 0. Any larger multiple will truncate to the same values. At this point we have read atleast the tag and the string length of the message, i.e. atleast 3 bytes. The maximum initial value for stream bytes_left is SIZE_MAX, thus at this point at most SIZE_MAX-3 bytes are remaining. On 32-bit and 16-bit platforms this means that the size passed to pb_read() is always larger than the number of remaining bytes. This causes pb_read() to fail immediately, before reading any bytes. On 64-bit platforms, it is possible for the bytes_left value to be set to a value larger than UINT32_MAX, which is the wraparound point in size calculation. In this case pb_read() will succeed and write up to 4 GB of attacker controlled data over the RAM that comes after the string field. On all platforms, there is an unconditional write of a terminating null byte. Because the size of size_t typically reflects the size of the processor address space, a write at UINT16_MAX or UINT32_MAX bytes after the string field actually wraps back to before the string field. Consequently, on 32-bit and 16-bit platforms, the bug causes a single write of '0' byte at one byte before the string field. If the string field is in the middle of a message, this will just corrupt other data in the message struct. Because the message contents is attacker controlled anyway, this is a non-issue. However, if the string field is the first field in the top-level message, it can corrupt other data on the stack/heap before it. Typically a single '0' write at a location not controlled by attacker is enough only for a denial-of-service attack. When using pointer fields and malloc(), the attacker controlled alloc_size will cause a 0-size allocation to happen. By the same logic as before, on 32-bit and 16-bit platforms this causes a '0' byte write only. On 64-bit platforms, however, it will again allow up to 4 GB of malicious data to be written over memory, if the stream length allows the read. 2. The overflow in pb_dec_bytes This overflow happens in the PB_BYTES_ARRAY_T_ALLOCSIZE macro: The computation is done in size_t data type this time. This means that an overflow is possible only when n is larger than SIZE_MAX - offsetof(..). The offsetof value in this case is equal to sizeof(pb_size_t) bytes. Because the incoming size value is limited to 32 bits, no overflow can happen here on 64-bit platforms. The size will be passed to pb_read(). Like before, on 32-bit and 16-bit platforms the read will always fail before writing anything. This leaves only the write of bdest->size as exploitable. On statically allocated fields, the size field will always be allocated, regardless of alloc_size. In this case, no buffer overflow is possible here, but user code could possibly use the attacker controlled size value and read past a buffer. If the field is allocated through malloc(), this will allow a write of sizeof(pb_size_t) attacker controlled bytes to past a 0-byte long buffer. In typical malloc implementations, this will either fit in unused alignment padding area, or cause a heap corruption and a crash. Under very exceptional situation it could allow attacker to influence the behaviour of malloc(), possibly jumping into an attacker-controlled location and thus leading to remote code execution.
2014-09-11Add just-to-be-sure check to allocate_field().Petteri Aimonen1-5/+11
This check will help to detect bugs earlier, and is quite lightweight compared to malloc() anyway.
2014-09-11Fix memory leak with duplicated fields and PB_ENABLE_MALLOC.Petteri Aimonen1-44/+60
If a required or optional field appeared twice in the message data, pb_decode will overwrite the old data with new one. That is fine, but with submessage fields, it didn't release the allocated subfields before overwriting. This bug can manifest if all of the following conditions are true: 1. There is a message with a "optional" or "required" submessage field that has type:FT_POINTER. 2. The submessage contains atleast one field with type:FT_POINTER. 3. The message data to be decoded has the submessage field twice in it.
2014-09-11Fix crash in pb_release() if called twice on same message.Petteri Aimonen1-10/+15
There was a double-free bug in pb_release() because it didn't set size fields to zero after deallocation. Most commonly this happens if pb_decode() fails, internally calls pb_release() and then application code also calls pb_release().
2014-08-18Rename UNUSED() and STATIC_ASSERT() macros with PB_ prefix.Petteri Aimonen1-4/+4
This avoids possible namespace conflicts with other macros.
2014-08-18Change the _count fields to use pb_size_t datatype.Petteri Aimonen1-11/+29
Update issue 82 Status: FixedInGit
2014-08-10Switch pb_encode to use the common iterator logic in pb_common.cPetteri Aimonen1-12/+10
Update issue 128 Status: FixedInGit
2014-08-10Separate field iterator logic from pb_decode to pb_common.Petteri Aimonen1-109/+31
2014-06-02Make clearer that size = 0 in allocate_field() is not allowed.Petteri Aimonen1-17/+12
Back in design phase the code used realloc() for freeing the memory also. However, this is not entirely portable, and therefore the finished implementation used free() separately. There were some remnants of the size = 0 code in the allocate_field() code, which made it somewhat confusing. This change makes it clearer that size = 0 is not allowed (and not used by nanopb).
2014-06-02Don't use SIZE_MAX macro, as it is not in C89.Petteri Aimonen1-1/+2
Update issue 120 Status: FixedInGit
2014-05-17Fix security issue with PB_ENABLE_MALLOC.Petteri Aimonen1-2/+22
The multiplication in allocate_field could potentially overflow, leading to allocating too little memory. This could subsequently allow an attacker to cause a write past the buffer, overwriting other memory contents. The attack is possible if untrusted message data is decoded using nanopb, and the message type includes a pointer-type string or bytes field, or a repeated numeric field. Submessage fields are not affected. This issue only affects systems that have been compiled with PB_ENABLE_MALLOC enabled. Only version nanopb-0.2.7 is affected, as prior versions do not include this functionality. Update issue 117 Status: FixedInGit
2014-04-05Add a 'found' field to pb_extension_t.Petteri Aimonen1-2/+1
Update issue 112 Status: FixedInGit
2014-04-02Add some missing 'static' specifiersPetteri Aimonen1-9/+8
Update issue 91 Status: FixedInGit
2014-04-02Fix splint warnings, add splint test casePetteri Aimonen1-8/+8
2014-03-17More configuration options for dynamic allocPetteri Aimonen1-3/+3
2014-03-16Documentation updatesPetteri Aimonen1-1/+9
2014-03-15Get rid of pb_bytes_ptr_t, just allocate pb_bytes_array_t dynamically.Petteri Aimonen1-41/+17
This makes the internal logic much simpler, and also keeps the datatypes more similar between STATIC/POINTER cases. It will still be a bit cumbersome to use because of variable length array member. Macros PB_BYTES_ARRAY_T(n) and PB_BYTES_ARRAY_T_ALLOCSIZE(n) have been added to make life a bit easier. This has the drawback that it is no longer as easy to use externally allocated byte array as input for bytes field in pointer mode. However, this is still easy to do using callbacks, so it shouldn't be a large issue.
2014-03-12Add pb_release() functionPetteri Aimonen1-18/+96
2014-03-10More fixes for dynamic allocationPetteri Aimonen1-41/+65
2014-02-25Bugfixes for dynamic allocationPetteri Aimonen1-13/+39
2014-02-24Beginnings of malloc support in pb_decodePetteri Aimonen1-5/+138
2013-12-21Add PB_LTYPE_UVARINT to fix encoding of negative int32 values.Petteri Aimonen1-3/+21
Apparently int32 values that are negative must be cast into int64 first before being encoded. Because uint32 still needs to be cast to uint64, the cases for int32 and uint32 had to be separated. Update issue 97 Status: FixedInGit
2013-11-14Optimize the common case of 1-byte reads for varints.Petteri Aimonen1-3/+23
For PB_BUFFER_ONLY configuration, this gives 20% speedup without increasing code size.
2013-10-29Remove the NANOPB_INTERNALS functions from public API.Petteri Aimonen1-0/+9
These have been deprecated since nanopb-0.1.6 (some since 0.1.3). Equivalent functions with better interface are available in the API. Update issue 91 Status: FixedInGit
2013-10-29Declare static functions before use.Petteri Aimonen1-12/+31
For compliance with MISRA C rules (issue 91).
2013-10-29Cleanup of comments.Petteri Aimonen1-7/+8
2013-10-29Rename some internal functions to have unique namesPetteri Aimonen1-2/+2
2013-07-17Extension support implemented for decoder.Petteri Aimonen1-2/+94
Testing is still needed. Also only 'optional' extension fields are supported now, 'repeated' fields are not yet supported.
2013-07-16Check for empty message type before incrementing required_field_index.Kent Ryhorchuk1-3/+3
If you have a message that defined as empty, but attempt to decode a message that has one or more unknown fields then pb_decode fails. The method used to count the number of required fields counts 1 required field because the default type of PB_LAST_FIELD is PB_HTYPE_REQUIRED.
2013-07-06Add pb_decode_delimited and pb_encode_delimited wrapper functions.Petteri Aimonen1-0/+13
Update issue 74 Status: FixedInGit
2013-04-14Fix bug with empty strings in repeated string callbacks.Petteri Aimonen1-2/+2
Fix suggested by Henrik Carlgren. Added also unit test for the bug. Update issue 73 Status: FixedInGit
2013-04-08Avoid maybe-uninitialized warningPetteri Aimonen1-4/+6
Patch from dch.
2013-04-02Change the callback function to use void**.Petteri Aimonen1-2/+8
NOTE: This change breaks backwards-compatibility by default. If you have old callback functions, you can define PB_OLD_CALLBACK_STYLE to retain the old behaviour. If you want to convert your old callbacks to new signature, you need to do the following: 1) Change decode callback argument to void **arg and encode callback argument to void * const *arg. 2) Change any reference to arg into *arg. The rationale for making the new behaviour the default is that it simplifies the common case of "allocate some memory in decode callback". Update issue 69 Status: FixedInGit