PX4 / PX4-GPSDrivers

Platform independent GPS drivers

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

SBF driver

devbharat opened this issue · comments

if (_buf.length <= 4 || _buf.crc16 != crc16(reinterpret_cast<uint8_t *>(&_buf) + 4, _buf.length - 4)) {

If the length bytes are corrupt(_buf.Len is meaningless), the length arg to the crc16 call could overrun and cause hardfault. You can check it for %4 == 0 for sanity, and use _rxReadBytes instead of _buf.len to ensure you don’t go beyond sizeof(_buf)

fyi @skimslozo

@devbharat I don't quite understand it. When or how is _buf.length corrupt, or wrong? And how could that be caught?

From the SBF reference manual

B4F9FD3C-BE0C-4577-B2AB-08D937A7F1C5

The length bytes are the 7th and 8th bytes of the header. It’s similar to how the old sdlog2 used to work, you start parsing at the two sync bytes „$@„ then get 2 crc bytes, two packet type bytes followed by two length bytes and then the rest of the payload. All this goes into a fixed size buffer _buf (union) (allocated in the header if I remember) one by one from the serial stream. While copying the bytes from the stream, we are careful to not exceed the allocated size even if _buf.length tells us to (on this line) as one of the two or both bytes could be corrupted in transmission, but you can only know for sure after verifying the CRC. So until now it’s all good. The problem is, to tell CRC how many bytes to run through, we don’t use the variable representing how many bytes we read, which is ‚safe‘ against the size of _buf, but directly use the ‚interpreted value‘ of _buf.length formed out of the 7th and 8th bytes of the transmitted packet (starting from the stream). Imagine if they were FF FF.

A change like this below is safer

                if (_buf.length <= 4
		    || _buf.crc16 != crc16(reinterpret_cast<uint8_t *>(&_buf) + 4,
					   (_rx_payload_index > sizeof(_buf) ? sizeof(_buf) : _rx_payload_index) - 4)) {
			failure_cntr.crc_fail++;
			PX4_DEBUG("[SBF PARSER] crc_fail_cnt: %d", failure_cntr.crc_fail);
			return 1;
		}

@devbharat I gave this a try in #107, slightly different from your suggestion. I think it's simple enough and correct...