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

[BUG] Illegal Heap write in rawbuf when the capture has overflowed. #1517

Merged
merged 2 commits into from
Jul 6, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion src/IRrecv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -518,7 +518,9 @@ bool IRrecv::decode(decode_results *results, irparams_t *save,
// interrupt. decode() is not stored in ICACHE_RAM.
// Another better option would be to zero the entire irparams.rawbuf[] on
// resume() but that is a much more expensive operation compare to this.
params.rawbuf[params.rawlen] = 0;
// However, don't do this if rawbuf is already full as we stomp over the heap.
// See: https://github.com/crankyoldgit/IRremoteESP8266/issues/1516
if (!params.overflow) params.rawbuf[params.rawlen] = 0;

bool resumed = false; // Flag indicating if we have resumed.

Expand Down Expand Up @@ -1882,4 +1884,11 @@ uint16_t IRrecv::matchManchesterData(volatile const uint16_t *data_ptr,
*result_ptr = GETBITS64(data, 0, nbits);
return offset;
}

#if UNIT_TEST
/// Unit test helper to get access to the params structure.
volatile irparams_t *IRrecv::_getParamsPtr(void) {
return &params;
}
#endif // UNIT_TEST
// End of IRrecv class -------------------
3 changes: 3 additions & 0 deletions src/IRrecv.h
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,9 @@ class IRrecv {
#if DECODE_HASH
uint16_t _unknown_threshold;
#endif
#ifdef UNIT_TEST
volatile irparams_t *_getParamsPtr(void);
#endif // UNIT_TEST
// These are called by decode
uint8_t _validTolerance(const uint8_t percentage);
void copyIrParams(volatile irparams_t *src, irparams_t *dst);
Expand Down
43 changes: 43 additions & 0 deletions test/IRrecv_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,49 @@ TEST(TestIRrecv, IRrecvDestructor) {
delete irrecv_ptr;
}

TEST(TestIRrecv, DecodeHeapOverflow) {
// Check that we handle the rawbuf correctly when we fill it. e.g. overflow.
// Ref: https://github.com/crankyoldgit/IRremoteESP8266/issues/1516
IRrecv irrecv(1);
irrecv.enableIRIn();
ASSERT_EQ(kRawBuf, irrecv.getBufSize());
volatile irparams_t *params_ptr = irrecv._getParamsPtr();
// replace the buffer with a slightly bigger one to see if we go past the end
// accidentally.
params_ptr->rawbuf = new uint16_t[kRawBuf + 10];
ASSERT_EQ(kRawBuf, irrecv.getBufSize()); // Should not change.
// Fill the raw buffer with canaries
// Values of 100 for the proper buffer size, & values of 99 for the extras
for (uint16_t i = 0; i < irrecv.getBufSize() + 10; i++) {
params_ptr->rawbuf[i] = 100;
if (i >= irrecv.getBufSize()) params_ptr->rawbuf[i]--;
}
ASSERT_EQ(100, params_ptr->rawbuf[kRawBuf - 1]);
EXPECT_EQ(99, params_ptr->rawbuf[kRawBuf]);
EXPECT_EQ(99, params_ptr->rawbuf[kRawBuf + 1]);
ASSERT_EQ(kRawBuf, params_ptr->bufsize);
decode_results results;
// Mock up the rest of params like we've received a message that has used
// all the rawbuf.
params_ptr->rawlen = kRawBuf;
params_ptr->overflow = true;
params_ptr->rcvstate = kStopState;
// Need to tweak results structure too.
results.rawbuf = params_ptr->rawbuf;
results.rawlen = params_ptr->rawlen;
results.overflow = params_ptr->overflow;

// Do the decode.
ASSERT_TRUE(irrecv.decode(&results));
// Yay, nothing exploded! Now check everything is as we expect
// w.r.t. the buffer.
ASSERT_EQ(kRawBuf, params_ptr->rawlen);
ASSERT_TRUE(params_ptr->overflow);
ASSERT_EQ(100, params_ptr->rawbuf[params_ptr->rawlen - 1]);
EXPECT_EQ(99, params_ptr->rawbuf[params_ptr->rawlen]);
EXPECT_EQ(99, params_ptr->rawbuf[params_ptr->rawlen + 1]);
}

// Tests for copyIrParams()

TEST(TestCopyIrParams, CopyEmpty) {
Expand Down