batt_smbus: fix potential hardfault by checking buffer sizes (#15789)

* Added buffer length check to SMBus::block_read (triggered hardfault in batt_smbus module by writing beyond buffer end due to device returning longer byte_count than requested/expected)

Co-authored-by: Florian Olbrich <florian.olbrich@scarabot.de>
Co-authored-by: Daniel Agar <daniel@agar.ca>
Co-authored-by: BazookaJoe1900 <BazookaJoe1900@gmail.com>
Co-authored-by: Beat Küng <beat-kueng@gmx.net>
This commit is contained in:
flochir
2020-09-28 09:41:40 +02:00
committed by GitHub
parent 6a08e16351
commit ec7108892b
+5 -3
View File
@@ -45,6 +45,7 @@
*/ */
#include "SMBus.hpp" #include "SMBus.hpp"
#include <mathlib/mathlib.h>
SMBus::SMBus(int bus_num, uint16_t address) : SMBus::SMBus(int bus_num, uint16_t address) :
I2C(DRV_BAT_DEVTYPE_SMBUS, MODULE_NAME, bus_num, address, 100000) I2C(DRV_BAT_DEVTYPE_SMBUS, MODULE_NAME, bus_num, address, 100000)
@@ -106,7 +107,7 @@ int SMBus::write_word(const uint8_t cmd_code, uint16_t data)
int SMBus::block_read(const uint8_t cmd_code, void *data, const uint8_t length, const bool use_pec) int SMBus::block_read(const uint8_t cmd_code, void *data, const uint8_t length, const bool use_pec)
{ {
unsigned byte_count = 0; uint8_t byte_count = 0;
// addr(wr), cmd_code, addr(r), byte_count, data (32 bytes max), pec // addr(wr), cmd_code, addr(r), byte_count, data (32 bytes max), pec
uint8_t rx_data[32 + 5]; uint8_t rx_data[32 + 5];
@@ -121,9 +122,10 @@ int SMBus::block_read(const uint8_t cmd_code, void *data, const uint8_t length,
rx_data[0] = (device_address << 1) | 0x00; rx_data[0] = (device_address << 1) | 0x00;
rx_data[1] = cmd_code; rx_data[1] = cmd_code;
rx_data[2] = (device_address << 1) | 0x01; rx_data[2] = (device_address << 1) | 0x01;
byte_count = rx_data[3]; byte_count = math::min(rx_data[3], (uint8_t)32);
memcpy(data, &rx_data[4], byte_count); // ensure data is not longer than given buffer
memcpy(data, &rx_data[4], math::min(byte_count, length));
if (use_pec) { if (use_pec) {
uint8_t pec = get_pec(rx_data, byte_count + 4); uint8_t pec = get_pec(rx_data, byte_count + 4);