[MME][Memory] Enable UBSAN for debug builds and resolve unaligned memory access issues#5262
[MME][Memory] Enable UBSAN for debug builds and resolve unaligned memory access issues#5262talkhasib merged 1 commit intomagma:masterfrom
Conversation
…ory access issues Signed-off-by: Tariq Al-Khasib <[email protected]>
Codecov Report
@@ Coverage Diff @@
## master #5262 +/- ##
==========================================
- Coverage 63.61% 63.61% -0.01%
==========================================
Files 301 301
Lines 20300 20300
==========================================
- Hits 12914 12913 -1
- Misses 5485 5486 +1
Partials 1901 1901
Continue to review full report at Codecov.
|
| size += sizeof(uint8_t) + sizeof(uint16_t) | ||
| do { \ | ||
| uint32_t n_value = htonl(value); \ | ||
| memcpy(buffer, (unsigned char*) &n_value, sizeof(uint32_t)); \ |
There was a problem hiding this comment.
should not we just copy 3 bytes?
There was a problem hiding this comment.
This macro is a bit odd too - because as far as I can see in code search, it always receives a uint32_t and then packs all four bytes here. So it's really not an ENCODE_U24 its an ENCODE_U32... At least for the call sites I am spotting.
There was a problem hiding this comment.
I noticed the oddness of this and kept the logic intact for the purpose of this PR
There was a problem hiding this comment.
It does that, but size is incremented by 3 bytes. So the last byte will be overwritten. For that reason I commented that we should make the copy for the 3 bytes as well to avoid any confusion and also avoid potential buffer overflow if this happens to be the last 3 bytes of space in the allocated buffer.
electronjoe
left a comment
There was a problem hiding this comment.
As a top level concern, my experience with our CMake configs has me worried that other libraries that may be handling these buffers may not have UBSAN turned on - and it's possible that we might be fixing the issue in some MAGMA code but not detecting it at root cause / in other areas of the codebase. CMake badly needs to be fixed up IMO. See questions in review!
| assert(msg_frame); | ||
| MessageDef* received_message_p = (MessageDef*) zframe_data(msg_frame); | ||
| int rc = 0; | ||
| MessageDef* received_message_p = receive_msg(reader); |
There was a problem hiding this comment.
Do we understand why this buffer is unaligned? By fixing it here are we fixing it everywhere? Or is it possibly unaligned in a third party library etc? Wondering if this is hiding the root cause (maybe not, but asking the question).
There was a problem hiding this comment.
ZMQ does not care about the data structure and treats it as a byte buffer. Thus, alignment is not an issue inside ZMQ.
When we cast back to the message structure at the receiving end. That caused the misalignment. Copying the data resolves this issue.
|
|
||
| case TERMINATE_MESSAGE: { | ||
| itti_free_msg_content(received_message_p); | ||
| zframe_destroy(&msg_frame); |
There was a problem hiding this comment.
Here and elsewhere. Are we certain that zframe_destroy can be substituted with free() here? I think without a comment that's not clear to me. E.g. our Bstring library b_destroy actually frees two allocations - and if we moved to free() we would leak.
There was a problem hiding this comment.
free does not replace zframe_destroy(). We still do a zframe_destroy()
inside the receive_msg function after we copy the message body. We free the message that receive_msg() created.
itti_free_msg_content() handels freeing second level data allocations inside messages. Thats why we need to call both.
|
|
||
| #define DECODE_U16(bUFFER, vALUE, sIZE) \ | ||
| vALUE = ntohs(*(uint16_t*) (bUFFER)); \ | ||
| memcpy((unsigned char*) &vALUE, bUFFER, sizeof(uint16_t)); \ |
There was a problem hiding this comment.
Same question as above - do we expect that these buffers might be unaligned? If so then no surprises here and great. In this particular fixup I could see it being less surprising - if this is say parsing a uint16_t that came after a type field that was a byte or whatever.
There was a problem hiding this comment.
Buffers are mainly packed data (IEs) received over the wire. Thus, no guarantee on alignment
| size += sizeof(uint8_t) + sizeof(uint16_t) | ||
| do { \ | ||
| uint32_t n_value = htonl(value); \ | ||
| memcpy(buffer, (unsigned char*) &n_value, sizeof(uint32_t)); \ |
There was a problem hiding this comment.
This macro is a bit odd too - because as far as I can see in code search, it always receives a uint32_t and then packs all four bytes here. So it's really not an ENCODE_U24 its an ENCODE_U32... At least for the call sites I am spotting.
| sizeof(uint32_t) * ((stream_cipher->blength >> 5) + 1)); | ||
|
|
||
| /* copy message to avoid memory alignment issues */ | ||
| memcpy(message, stream_cipher->message, ceil(stream_cipher->blength / 8.0)); |
There was a problem hiding this comment.
Again, wondering if alignment issue here was expected or not?
There was a problem hiding this comment.
Same here, input is a stream of bytes that guarantees no alignment
…ory access issues (#5262) Signed-off-by: Tariq Al-Khasib <[email protected]>
…ory access issues (#5262) Signed-off-by: Tariq Al-Khasib <[email protected]>
…ory access issues (magma#5262) Signed-off-by: Tariq Al-Khasib <[email protected]>
Signed-off-by: Tariq Al-Khasib [email protected]
Summary
Enable UBSAN for debug builds (sanitize=undefined)
Once enabled, it uncovered many unaligned memory access problems.
sample logs
Test Plan
fab integ_test