blob_handler: Add check to avoid OOB memory access
There's a potential for OOB memory access in statGeneric if
sendIpmiPayload returns a small or empty respones. Added a check to guard
against it and added unit tests.
Change-Id: I224cd3cb391c2f8bbde87aec478bf4042fbdfd47
Signed-off-by: Brandon Kim <brandonkim@google.com>
diff --git a/test/tools_blob_unittest.cpp b/test/tools_blob_unittest.cpp
index 3b64d57..a9ec639 100644
--- a/test/tools_blob_unittest.cpp
+++ b/test/tools_blob_unittest.cpp
@@ -1,3 +1,4 @@
+#include <ipmiblob/blob_errors.hpp>
#include <ipmiblob/blob_handler.hpp>
#include <ipmiblob/test/crc_mock.hpp>
#include <ipmiblob/test/ipmi_interface_mock.hpp>
@@ -214,6 +215,41 @@
EXPECT_EQ(metadata, meta.metadata);
}
+TEST_F(BlobHandlerTest, getStatWithWrongMetadataLength)
+{
+ /* Stat fails when wrong metadata length is received */
+ auto ipmi = CreateIpmiMock();
+ IpmiInterfaceMock* ipmiMock =
+ reinterpret_cast<IpmiInterfaceMock*>(ipmi.get());
+ BlobHandler blob(std::move(ipmi));
+
+ std::vector<std::uint8_t> request = {
+ 0xcf, 0xc2,
+ 0x00, static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobStat),
+ 0x00, 0x00,
+ 'a', 'b',
+ 'c', 'd',
+ 0x00};
+
+ /* return blob_state: 0xffff, size: 0x00, len: 1, metadata 0x3445 */
+ std::vector<std::uint8_t> resp = {0xcf, 0xc2, 0x00, 0x00, 0x00, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x34, 0x45};
+
+ std::vector<std::uint8_t> reqCrc = {'a', 'b', 'c', 'd', 0x00};
+ std::vector<std::uint8_t> respCrc = {0xff, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x34, 0x45};
+ EXPECT_CALL(crcMock, generateCrc(ContainerEq(reqCrc)))
+ .WillOnce(Return(0x00));
+ EXPECT_CALL(crcMock, generateCrc(ContainerEq(respCrc)))
+ .WillOnce(Return(0x00));
+
+ EXPECT_CALL(*ipmiMock,
+ sendPacket(ipmiOEMNetFn, ipmiOEMBlobCmd, ContainerEq(request)))
+ .WillOnce(Return(resp));
+
+ EXPECT_THROW(blob.getStat("abcd"), BlobException);
+}
+
TEST_F(BlobHandlerTest, getStatNoMetadata)
{
/* Stat received no metadata. */
@@ -230,7 +266,7 @@
'c', 'd',
0x00};
- /* return blob_state: 0xffff, size: 0x00, metadata 0x3445 */
+ /* return blob_state: 0xffff, size: 0x00, metadata 0x0000 */
std::vector<std::uint8_t> resp = {0xcf, 0xc2, 0x00, 0x00, 0x00, 0xff,
0xff, 0x00, 0x00, 0x00, 0x00, 0x00};
@@ -268,7 +304,7 @@
0x00, 0x00,
0x01, 0x00};
- /* return blob_state: 0xffff, size: 0x00, metadata 0x3445 */
+ /* return blob_state: 0xffff, size: 0x00, metadata 0x0000 */
std::vector<std::uint8_t> resp = {0xcf, 0xc2, 0x00, 0x00, 0x00, 0xff,
0xff, 0x00, 0x00, 0x00, 0x00, 0x00};
@@ -292,6 +328,62 @@
EXPECT_EQ(metadata, meta.metadata);
}
+TEST_F(BlobHandlerTest, getSessionStatEmptyResp)
+{
+ /* The get session stat fails after getting empty response */
+ auto ipmi = CreateIpmiMock();
+ IpmiInterfaceMock* ipmiMock =
+ reinterpret_cast<IpmiInterfaceMock*>(ipmi.get());
+ BlobHandler blob(std::move(ipmi));
+
+ std::vector<std::uint8_t> request = {
+ 0xcf, 0xc2,
+ 0x00, static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobSessionStat),
+ 0x00, 0x00,
+ 0x01, 0x00};
+
+ std::vector<std::uint8_t> resp;
+ std::vector<std::uint8_t> reqCrc = {0x01, 0x00};
+
+ EXPECT_CALL(crcMock, generateCrc(ContainerEq(reqCrc)))
+ .WillOnce(Return(0x00));
+
+ EXPECT_CALL(*ipmiMock,
+ sendPacket(ipmiOEMNetFn, ipmiOEMBlobCmd, ContainerEq(request)))
+ .WillOnce(Return(resp));
+
+ EXPECT_THROW(blob.getStat(0x0001), BlobException);
+}
+
+TEST_F(BlobHandlerTest, getSessionStatInvalidHeader)
+{
+ /* The get session stat fails after getting a response shorter than the
+ * expected headersize but with the expected OEN
+ */
+ auto ipmi = CreateIpmiMock();
+ IpmiInterfaceMock* ipmiMock =
+ reinterpret_cast<IpmiInterfaceMock*>(ipmi.get());
+ BlobHandler blob(std::move(ipmi));
+
+ std::vector<std::uint8_t> request = {
+ 0xcf, 0xc2,
+ 0x00, static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobSessionStat),
+ 0x00, 0x00,
+ 0x01, 0x00};
+
+ std::vector<std::uint8_t> resp = {0xcf, 0xc2, 0x00, 0x00};
+ std::vector<std::uint8_t> reqCrc = {0x01, 0x00};
+
+ EXPECT_CALL(crcMock, generateCrc(ContainerEq(reqCrc)))
+ .WillOnce(Return(0x00));
+
+ EXPECT_CALL(*ipmiMock,
+ sendPacket(ipmiOEMNetFn, ipmiOEMBlobCmd, ContainerEq(request)))
+ .WillOnce(Return(resp));
+
+ EXPECT_THROW(blob.getStat(0x0001), BlobException);
+}
+
TEST_F(BlobHandlerTest, openBlobSucceeds)
{
/* The open blob succeeds. */