Skip to content

Commit 5f464ee

Browse files
committed
fix: Validate frame size in QModbusAduRtu and QModbusAduTcp classes
1 parent de787c8 commit 5f464ee

2 files changed

Lines changed: 60 additions & 12 deletions

File tree

src/qmodbusadurtu.h

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
class QModbusAduRtu : public QModbusAdu
1111
{
1212
public:
13+
/// Minimum RTU frame size: address(1) + function(1) + data(0+) + CRC(2)
14+
static constexpr int MinRtuFrameSize = 4;
15+
1316
explicit QModbusAduRtu(const QByteArray& rawData)
1417
: QModbusAdu()
1518
{
@@ -21,6 +24,8 @@ class QModbusAduRtu : public QModbusAdu
2124
/// \return
2225
///
2326
bool isValid() const override {
27+
if (_data.size() < MinRtuFrameSize)
28+
return false;
2429
return matchingChecksum() && _pdu.isValid();
2530
}
2631

@@ -30,15 +35,23 @@ class QModbusAduRtu : public QModbusAdu
3035
///
3136
void setRawData(const QByteArray& data) override {
3237
_data = data;
33-
_pdu.setFunctionCode(QModbusPdu::FunctionCode((quint8)_data[1]));
34-
_pdu.setData(_data.mid(2, _data.size() - 4));
38+
if (_data.size() >= MinRtuFrameSize) {
39+
_pdu.setFunctionCode(QModbusPdu::FunctionCode(quint8(_data[1])));
40+
_pdu.setData(_data.mid(2, _data.size() - MinRtuFrameSize));
41+
} else {
42+
_pdu.setFunctionCode(QModbusPdu::Invalid); // reset to invalid state
43+
_pdu.setData(QByteArray());
44+
}
3545
}
3646

3747
///
3848
/// \brief serverAddress
3949
/// \return
4050
///
4151
quint8 serverAddress() const override {
52+
if (_data.isEmpty())
53+
return 0;
54+
4255
return quint8(_data[0]);
4356
}
4457

@@ -47,17 +60,23 @@ class QModbusAduRtu : public QModbusAdu
4760
/// \return
4861
///
4962
quint16 checksum() const {
50-
return makeUInt16(_data[_data.size() - 1], _data[_data.size() - 2], ByteOrder::Direct);
63+
if (_data.size() >= MinRtuFrameSize) {
64+
return makeUInt16(_data[_data.size() - 1], _data[_data.size() - 2], ByteOrder::Direct);
65+
}
66+
return 0;
5167
}
5268

5369
///
5470
/// \brief calcChecksum
5571
/// \return
5672
///
5773
quint16 calcChecksum() const {
58-
const auto size = _data.size() - 2; // two bytes, CRC
59-
const auto data = _data.left(size);
60-
return calculateCRC(data, size);
74+
if (_data.size() < MinRtuFrameSize)
75+
return 0;
76+
77+
const int crcDataSize = _data.size() - 2;
78+
const QByteArray crcData = _data.left(crcDataSize);
79+
return calculateCRC(crcData.constData(), crcDataSize);
6180
}
6281

6382
///
@@ -68,7 +87,10 @@ class QModbusAduRtu : public QModbusAdu
6887
return checksum() == calcChecksum();
6988
}
7089

71-
inline static quint16 calculateCRC(const char* data, qint32 len){
90+
inline static quint16 calculateCRC(const char* data, qint32 len) {
91+
if (len <= 0 || data == nullptr)
92+
return 0;
93+
7294
quint16 crc = 0xFFFF;
7395
while (len--) {
7496
const quint8 c = *data++;
@@ -82,12 +104,12 @@ class QModbusAduRtu : public QModbusAdu
82104
}
83105
crc &= 0xFFFF;
84106
}
85-
crc = crc_reflect(crc & 0xFFFF, 16) ^ 0x0000;
86-
return (crc >> 8) | (crc << 8); // swap bytes
107+
crc = crc_reflect(crc, 16);
108+
return (crc >> 8) | (crc << 8); // swap bytes
87109
}
88110

89111
private:
90-
inline static quint16 crc_reflect(quint16 data, qint32 len){
112+
inline static quint16 crc_reflect(quint16 data, qint32 len) {
91113
quint16 ret = data & 0x01;
92114
for (qint32 i = 1; i < len; i++) {
93115
data >>= 1;

src/qmodbusadutcp.h

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
class QModbusAduTcp : public QModbusAdu
1111
{
1212
public:
13+
/// Minimum TCP frame size: header(6) + unitId(1) + function(1) = 8 bytes
14+
static constexpr int MinTcpFrameSize = 8;
15+
1316
explicit QModbusAduTcp(const QByteArray& rawData)
1417
: QModbusAdu()
1518
{
@@ -21,6 +24,9 @@ class QModbusAduTcp : public QModbusAdu
2124
/// \return
2225
///
2326
bool isValid() const override {
27+
if (_data.size() < MinTcpFrameSize)
28+
return false;
29+
2430
return _pdu.isValid() && length() == _pdu.size() + 1;
2531
}
2632

@@ -30,15 +36,23 @@ class QModbusAduTcp : public QModbusAdu
3036
///
3137
void setRawData(const QByteArray& data) override {
3238
_data = data;
33-
_pdu.setFunctionCode(QModbusPdu::FunctionCode((quint8)_data[7]));
34-
_pdu.setData(_data.mid(8));
39+
if (_data.size() >= MinTcpFrameSize) {
40+
_pdu.setFunctionCode(QModbusPdu::FunctionCode(quint8(_data[7])));
41+
_pdu.setData(_data.mid(8, _data.size() - MinTcpFrameSize));
42+
} else {
43+
_pdu.setFunctionCode(QModbusPdu::Invalid); // reset to invalid state
44+
_pdu.setData(QByteArray());
45+
}
3546
}
3647

3748
///
3849
/// \brief transactionId
3950
/// \return
4051
///
4152
quint16 transactionId() const {
53+
if (_data.size() < MinTcpFrameSize)
54+
return 0;
55+
4256
return makeUInt16(_data[1], _data[0], ByteOrder::Direct);
4357
}
4458

@@ -47,6 +61,9 @@ class QModbusAduTcp : public QModbusAdu
4761
/// \param id
4862
///
4963
void setTransactionId(quint16 id) {
64+
if (_data.size() < MinTcpFrameSize)
65+
return;
66+
5067
quint8 lo,hi;
5168
breakUInt16(id, lo, hi, ByteOrder::Direct);
5269
_data[1] = lo; _data[0] = hi;
@@ -57,6 +74,9 @@ class QModbusAduTcp : public QModbusAdu
5774
/// \return
5875
///
5976
quint16 protocolId() const {
77+
if (_data.size() < MinTcpFrameSize)
78+
return 0;
79+
6080
return makeUInt16(_data[3], _data[2], ByteOrder::Direct);
6181
}
6282

@@ -65,6 +85,9 @@ class QModbusAduTcp : public QModbusAdu
6585
/// \return
6686
///
6787
quint16 length() const {
88+
if (_data.size() < MinTcpFrameSize)
89+
return 0;
90+
6891
return makeUInt16(_data[5], _data[4], ByteOrder::Direct);
6992
}
7093

@@ -73,6 +96,9 @@ class QModbusAduTcp : public QModbusAdu
7396
/// \return
7497
///
7598
quint8 serverAddress() const override {
99+
if (_data.size() < MinTcpFrameSize)
100+
return 0;
101+
76102
return quint8(_data[6]);
77103
}
78104

0 commit comments

Comments
 (0)