Skip to content
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

Fix buffering of user payloads #243

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open

Conversation

TMRh20
Copy link
Member

@TMRh20 TMRh20 commented Jan 7, 2025

Per #242 fix buffer overrun

Per #242 fix buffer overrun
@TMRh20 TMRh20 requested a review from 2bndy5 January 7, 2025 13:08
@2bndy5
Copy link
Member

2bndy5 commented Jan 7, 2025

Just to be sure, did you see this debug message before the changes here?

IF_RF24NETWORK_DEBUG(printf_P(PSTR("NET **Drop Payload** Buffer Full")));

@TMRh20
Copy link
Member Author

TMRh20 commented Jan 7, 2025 via email

RF24Network.cpp Outdated
Comment on lines 518 to 521
if (message_size + (next_frame - frame_queue) <= MAIN_BUFFER_SIZE) {
if (message_size + (next_frame - frame_queue) <= MAX_PAYLOAD_SIZE) {
memcpy(next_frame, &frame_buffer, 8);
memcpy(next_frame + 8, &message_size, 2);
memcpy(next_frame + 10, frame_buffer + 8, message_size);
Copy link
Member

@2bndy5 2bndy5 Jan 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at these lines, I feel like the header (8 bytes) and message size (2 bytes) are not accounted for in the conditional statement. Given that,

uint8_t frame_queue[MAIN_BUFFER_SIZE]; /** Space for a small set of frames that need to be delivered to the app layer */

Where
#define MAIN_BUFFER_SIZE (MAX_PAYLOAD_SIZE + FRAME_HEADER_SIZE)

I think that MAIN_BUFFER_SIZE is the right choice for the condition's sentinel.

To prevent overflow, I'd 10 + message_size and use MAIN_BUFFER_SIZE:

-    if (message_size + (next_frame - frame_queue) <= MAIN_BUFFER_SIZE) {
+    if (message_size + 10 + (next_frame - frame_queue) <= MAIN_BUFFER_SIZE) {

I haven't tested this though.

Its important we calculate "if all the data would fit in frame_queue", not just the message's size, because of how we advance next_frame.

RF24Network/RF24Network.cpp

Lines 525 to 530 in b9095a7

next_frame += (message_size + 10);
#if !defined(ARDUINO_ARCH_AVR)
if (uint8_t padding = (message_size + 10) % 4) {
next_frame += 4 - padding;
}
#endif

Hmm, the conditional padding may have to be calculated before entering the conditional block, so it can be ifdef'd into the condition.

So, here's what I came up with in review:

diff --git a/RF24Network.cpp b/RF24Network.cpp
index c468ef4..12c9498 100644
--- a/RF24Network.cpp
+++ b/RF24Network.cpp
@@ -515,7 +515,17 @@ uint8_t ESBNetwork<radio_t>::enqueue(RF24NetworkHeader* header)
     return 0;
 }
     #else // !defined(DISABLE_USER_PAYLOADS)
-    if (message_size + (next_frame - frame_queue) <= MAX_PAYLOAD_SIZE) {
+
+        #if !defined(ARDUINO_ARCH_AVR)
+    uint8_t padding = (message_size + 10) % 4;
+    padding = padding ? 4 - padding : 0;
+    if (padding +
+        #else
+    if (
+        #endif
+            message_size + 10 + (next_frame - frame_queue)
+        <= MAIN_BUFFER_SIZE)
+    {
         memcpy(next_frame, &frame_buffer, 8);
         memcpy(next_frame + 8, &message_size, 2);
         memcpy(next_frame + 10, frame_buffer + 8, message_size);
@@ -524,9 +534,7 @@ uint8_t ESBNetwork<radio_t>::enqueue(RF24NetworkHeader* header)

         next_frame += (message_size + 10);
         #if !defined(ARDUINO_ARCH_AVR)
-        if (uint8_t padding = (message_size + 10) % 4) {
-            next_frame += 4 - padding;
-        }
+        next_frame += padding;
         #endif
         //IF_RF24NETWORK_DEBUG_FRAGMENTATION( Serial.print("Enq "); Serial.println(next_frame-frame_queue); );//printf_P(PSTR("enq %d\n"),next_frame-frame_queue); );

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I didn't really analyze this much, just threw in what I though was the fix. I see you have thought things through a bit more. I will have to take some time to understand your changes and make sure we have it right this time, but in the mean time I will test it out.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Its similar to what you propose. Instead of subtracting from one side of the <=, I added to the other side.

You knew I'd make it more complicated. 😜

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WTF u reading my mind now @2bndy5 ? I was literally going to say something about u making it more complicated...

Tests ok in my limited tests, and seems to all make sense.

Copy link
Member

@2bndy5 2bndy5 Jan 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I went through any code that altered next_frame. The only other blocks that do, aside from what was discussed here, are when the last frag is received or when network.read() is called. Both instances seem fine to me, but pointers are hard.

FWIW, I don't have to worry about this low-level tediousness in rust. Instead, the rust compiler complains about tracking data ownership, which is still easier to cope with.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants