1 #include "libpldm/base.h" 2 #include "libpldm/file_io.h" 3 4 #include "libpldmresponder/file_io.hpp" 5 #include "libpldmresponder/file_io_by_type.hpp" 6 #include "libpldmresponder/file_io_type_cert.hpp" 7 #include "libpldmresponder/file_io_type_dump.hpp" 8 #include "libpldmresponder/file_io_type_lid.hpp" 9 #include "libpldmresponder/file_io_type_pel.hpp" 10 #include "libpldmresponder/file_table.hpp" 11 #include "xyz/openbmc_project/Common/error.hpp" 12 13 #include <nlohmann/json.hpp> 14 #include <phosphor-logging/elog-errors.hpp> 15 16 #include <filesystem> 17 #include <fstream> 18 19 #include <gmock/gmock-matchers.h> 20 #include <gmock/gmock.h> 21 #include <gtest/gtest.h> 22 23 namespace fs = std::filesystem; 24 using Json = nlohmann::json; 25 using namespace pldm::filetable; 26 using namespace pldm::responder; 27 28 class TestFileTable : public testing::Test 29 { 30 public: 31 void SetUp() override 32 { 33 // Create a temporary directory to hold the config file and files to 34 // populate the file table. 35 char tmppldm[] = "/tmp/pldm_fileio_table.XXXXXX"; 36 dir = fs::path(mkdtemp(tmppldm)); 37 38 // Copy the sample image files to the directory 39 fs::copy("./files", dir); 40 41 imageFile = dir / "NVRAM-IMAGE"; 42 auto jsonObjects = Json::array(); 43 auto obj = Json::object(); 44 obj["path"] = imageFile.c_str(); 45 obj["file_traits"] = 1; 46 47 jsonObjects.push_back(obj); 48 obj.clear(); 49 cksumFile = dir / "NVRAM-IMAGE-CKSUM"; 50 obj["path"] = cksumFile.c_str(); 51 obj["file_traits"] = 4; 52 jsonObjects.push_back(obj); 53 54 fileTableConfig = dir / "configFile.json"; 55 std::ofstream file(fileTableConfig.c_str()); 56 file << std::setw(4) << jsonObjects << std::endl; 57 } 58 59 void TearDown() override 60 { 61 fs::remove_all(dir); 62 } 63 64 fs::path dir; 65 fs::path imageFile; 66 fs::path cksumFile; 67 fs::path fileTableConfig; 68 69 // <4 bytes - File handle - 0 (0x00 0x00 0x00 0x00)>, 70 // <2 bytes - Filename length - 11 (0x0b 0x00> 71 // <11 bytes - Filename - ASCII for NVRAM-IMAGE> 72 // <4 bytes - File size - 1024 (0x00 0x04 0x00 0x00)> 73 // <4 bytes - File traits - 1 (0x01 0x00 0x00 0x00)> 74 // <4 bytes - File handle - 1 (0x01 0x00 0x00 0x00)>, 75 // <2 bytes - Filename length - 17 (0x11 0x00> 76 // <17 bytes - Filename - ASCII for NVRAM-IMAGE-CKSUM> 77 // <4 bytes - File size - 16 (0x0f 0x00 0x00 0x00)> 78 // <4 bytes - File traits - 4 (0x04 0x00 0x00 0x00)> 79 // No pad bytes added since the length for both the file entries in the 80 // table is 56, which is a multiple of 4. 81 // <4 bytes - Checksum - 2088303182(0x4e 0xfa 0x78 0x7c)> 82 Table attrTable = { 83 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x4e, 0x56, 0x52, 0x41, 0x4d, 0x2d, 84 0x49, 0x4d, 0x41, 0x47, 0x45, 0x00, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 85 0x00, 0x01, 0x00, 0x00, 0x00, 0x11, 0x00, 0x4e, 0x56, 0x52, 0x41, 0x4d, 86 0x2d, 0x49, 0x4d, 0x41, 0x47, 0x45, 0x2d, 0x43, 0x4b, 0x53, 0x55, 0x4d, 87 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x4e, 0xfa, 0x78, 0x7c}; 88 }; 89 90 namespace pldm 91 { 92 93 namespace responder 94 { 95 96 namespace dma 97 { 98 99 class MockDMA 100 { 101 public: 102 MOCK_METHOD5(transferDataHost, int(int fd, uint32_t offset, uint32_t length, 103 uint64_t address, bool upstream)); 104 }; 105 106 } // namespace dma 107 } // namespace responder 108 } // namespace pldm 109 using namespace pldm::responder; 110 using ::testing::_; 111 using ::testing::Return; 112 113 TEST(TransferDataHost, GoodPath) 114 { 115 using namespace pldm::responder::dma; 116 117 MockDMA dmaObj; 118 char tmpfile[] = "/tmp/pldm_fileio_table.XXXXXX"; 119 int fd = mkstemp(tmpfile); 120 close(fd); 121 fs::path path(tmpfile); 122 123 // Minimum length of 16 and expect transferDataHost to be called once 124 // returns the default value of 0 (the return type of transferDataHost is 125 // int, the default value for int is 0) 126 uint32_t length = minSize; 127 EXPECT_CALL(dmaObj, transferDataHost(_, 0, length, 0, true)).Times(1); 128 auto response = transferAll<MockDMA>(&dmaObj, PLDM_READ_FILE_INTO_MEMORY, 129 path, 0, length, 0, true, 0); 130 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 131 ASSERT_EQ(responsePtr->payload[0], PLDM_SUCCESS); 132 ASSERT_EQ(0, memcmp(responsePtr->payload + sizeof(responsePtr->payload[0]), 133 &length, sizeof(length))); 134 135 // maxsize of DMA 136 length = maxSize; 137 EXPECT_CALL(dmaObj, transferDataHost(_, 0, length, 0, true)).Times(1); 138 response = transferAll<MockDMA>(&dmaObj, PLDM_READ_FILE_INTO_MEMORY, path, 139 0, length, 0, true, 0); 140 responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 141 ASSERT_EQ(responsePtr->payload[0], PLDM_SUCCESS); 142 ASSERT_EQ(0, memcmp(responsePtr->payload + sizeof(responsePtr->payload[0]), 143 &length, sizeof(length))); 144 145 // length greater than maxsize of DMA 146 length = maxSize + minSize; 147 EXPECT_CALL(dmaObj, transferDataHost(_, 0, maxSize, 0, true)).Times(1); 148 EXPECT_CALL(dmaObj, transferDataHost(_, maxSize, minSize, maxSize, true)) 149 .Times(1); 150 response = transferAll<MockDMA>(&dmaObj, PLDM_READ_FILE_INTO_MEMORY, path, 151 0, length, 0, true, 0); 152 responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 153 ASSERT_EQ(responsePtr->payload[0], PLDM_SUCCESS); 154 ASSERT_EQ(0, memcmp(responsePtr->payload + sizeof(responsePtr->payload[0]), 155 &length, sizeof(length))); 156 157 // length greater than 2*maxsize of DMA 158 length = 3 * maxSize; 159 EXPECT_CALL(dmaObj, transferDataHost(_, _, _, _, true)).Times(3); 160 response = transferAll<MockDMA>(&dmaObj, PLDM_READ_FILE_INTO_MEMORY, path, 161 0, length, 0, true, 0); 162 responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 163 ASSERT_EQ(responsePtr->payload[0], PLDM_SUCCESS); 164 ASSERT_EQ(0, memcmp(responsePtr->payload + sizeof(responsePtr->payload[0]), 165 &length, sizeof(length))); 166 167 // check for downstream(copy data from host to BMC) parameter 168 length = minSize; 169 EXPECT_CALL(dmaObj, transferDataHost(_, 0, length, 0, false)).Times(1); 170 response = transferAll<MockDMA>(&dmaObj, PLDM_READ_FILE_INTO_MEMORY, path, 171 0, length, 0, false, 0); 172 responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 173 ASSERT_EQ(responsePtr->payload[0], PLDM_SUCCESS); 174 ASSERT_EQ(0, memcmp(responsePtr->payload + sizeof(responsePtr->payload[0]), 175 &length, sizeof(length))); 176 } 177 178 TEST(TransferDataHost, BadPath) 179 { 180 using namespace pldm::responder::dma; 181 182 MockDMA dmaObj; 183 char tmpfile[] = "/tmp/pldm_fileio_table.XXXXXX"; 184 int fd = mkstemp(tmpfile); 185 close(fd); 186 fs::path path(tmpfile); 187 188 // Minimum length of 16 and transferDataHost returning a negative errno 189 uint32_t length = minSize; 190 EXPECT_CALL(dmaObj, transferDataHost(_, _, _, _, _)).WillOnce(Return(-1)); 191 auto response = transferAll<MockDMA>(&dmaObj, PLDM_READ_FILE_INTO_MEMORY, 192 path, 0, length, 0, true, 0); 193 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 194 ASSERT_EQ(responsePtr->payload[0], PLDM_ERROR); 195 196 // length greater than maxsize of DMA and transferDataHost returning a 197 // negative errno 198 length = maxSize + minSize; 199 EXPECT_CALL(dmaObj, transferDataHost(_, _, _, _, _)).WillOnce(Return(-1)); 200 response = transferAll<MockDMA>(&dmaObj, PLDM_READ_FILE_INTO_MEMORY, path, 201 0, length, 0, true, 0); 202 responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 203 ASSERT_EQ(responsePtr->payload[0], PLDM_ERROR); 204 } 205 206 TEST(ReadFileIntoMemory, BadPath) 207 { 208 uint32_t fileHandle = 0; 209 uint32_t offset = 0; 210 uint32_t length = 10; 211 uint64_t address = 0; 212 213 std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_REQ_BYTES> 214 requestMsg{}; 215 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); 216 memcpy(request->payload, &fileHandle, sizeof(fileHandle)); 217 memcpy(request->payload + sizeof(fileHandle), &offset, sizeof(offset)); 218 memcpy(request->payload + sizeof(fileHandle) + sizeof(offset), &length, 219 sizeof(length)); 220 memcpy(request->payload + sizeof(fileHandle) + sizeof(offset) + 221 sizeof(length), 222 &address, sizeof(address)); 223 224 // Pass invalid payload length 225 std::unique_ptr<oem_platform::Handler> oemPlatformHandler{}; 226 oem_ibm::Handler handler(oemPlatformHandler.get()); 227 auto response = handler.readFileIntoMemory(request, 0); 228 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 229 ASSERT_EQ(responsePtr->payload[0], PLDM_ERROR_INVALID_LENGTH); 230 } 231 232 TEST_F(TestFileTable, ReadFileInvalidFileHandle) 233 { 234 // Invalid file handle in the file table 235 uint32_t fileHandle = 2; 236 uint32_t offset = 0; 237 uint32_t length = 0; 238 uint64_t address = 0; 239 240 std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_REQ_BYTES> 241 requestMsg{}; 242 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); 243 size_t requestPayloadLength = requestMsg.size() - sizeof(pldm_msg_hdr); 244 memcpy(request->payload, &fileHandle, sizeof(fileHandle)); 245 memcpy(request->payload + sizeof(fileHandle), &offset, sizeof(offset)); 246 memcpy(request->payload + sizeof(fileHandle) + sizeof(offset), &length, 247 sizeof(length)); 248 memcpy(request->payload + sizeof(fileHandle) + sizeof(offset) + 249 sizeof(length), 250 &address, sizeof(address)); 251 252 using namespace pldm::filetable; 253 // Initialise the file table with 2 valid file handles 0 & 1. 254 auto& table = buildFileTable(fileTableConfig.c_str()); 255 256 std::unique_ptr<oem_platform::Handler> oemPlatformHandler{}; 257 oem_ibm::Handler handler(oemPlatformHandler.get()); 258 auto response = handler.readFileIntoMemory(request, requestPayloadLength); 259 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 260 ASSERT_EQ(responsePtr->payload[0], PLDM_INVALID_FILE_HANDLE); 261 // Clear the file table contents. 262 table.clear(); 263 } 264 265 TEST_F(TestFileTable, ReadFileInvalidOffset) 266 { 267 uint32_t fileHandle = 0; 268 // The file size is 1024, so the offset is invalid 269 uint32_t offset = 1024; 270 uint32_t length = 0; 271 uint64_t address = 0; 272 273 std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_REQ_BYTES> 274 requestMsg{}; 275 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); 276 size_t requestPayloadLength = requestMsg.size() - sizeof(pldm_msg_hdr); 277 memcpy(request->payload, &fileHandle, sizeof(fileHandle)); 278 memcpy(request->payload + sizeof(fileHandle), &offset, sizeof(offset)); 279 memcpy(request->payload + sizeof(fileHandle) + sizeof(offset), &length, 280 sizeof(length)); 281 memcpy(request->payload + sizeof(fileHandle) + sizeof(offset) + 282 sizeof(length), 283 &address, sizeof(address)); 284 285 using namespace pldm::filetable; 286 auto& table = buildFileTable(fileTableConfig.c_str()); 287 288 std::unique_ptr<oem_platform::Handler> oemPlatformHandler{}; 289 oem_ibm::Handler handler(oemPlatformHandler.get()); 290 auto response = handler.readFileIntoMemory(request, requestPayloadLength); 291 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 292 ASSERT_EQ(responsePtr->payload[0], PLDM_DATA_OUT_OF_RANGE); 293 // Clear the file table contents. 294 table.clear(); 295 } 296 297 TEST_F(TestFileTable, ReadFileInvalidLength) 298 { 299 uint32_t fileHandle = 0; 300 uint32_t offset = 100; 301 // Length should be a multiple of dma min size(16) 302 uint32_t length = 10; 303 uint64_t address = 0; 304 305 std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_REQ_BYTES> 306 requestMsg{}; 307 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); 308 size_t requestPayloadLength = requestMsg.size() - sizeof(pldm_msg_hdr); 309 memcpy(request->payload, &fileHandle, sizeof(fileHandle)); 310 memcpy(request->payload + sizeof(fileHandle), &offset, sizeof(offset)); 311 memcpy(request->payload + sizeof(fileHandle) + sizeof(offset), &length, 312 sizeof(length)); 313 memcpy(request->payload + sizeof(fileHandle) + sizeof(offset) + 314 sizeof(length), 315 &address, sizeof(address)); 316 317 using namespace pldm::filetable; 318 auto& table = buildFileTable(fileTableConfig.c_str()); 319 320 std::unique_ptr<oem_platform::Handler> oemPlatformHandler{}; 321 oem_ibm::Handler handler(oemPlatformHandler.get()); 322 auto response = handler.readFileIntoMemory(request, requestPayloadLength); 323 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 324 ASSERT_EQ(responsePtr->payload[0], PLDM_ERROR_INVALID_LENGTH); 325 // Clear the file table contents. 326 table.clear(); 327 } 328 329 TEST_F(TestFileTable, ReadFileInvalidEffectiveLength) 330 { 331 uint32_t fileHandle = 0; 332 // valid offset 333 uint32_t offset = 100; 334 // length + offset exceeds the size, so effective length is 335 // filesize(1024) - offset(100). The effective length is not a multiple of 336 // DMA min size(16) 337 uint32_t length = 1024; 338 uint64_t address = 0; 339 340 std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_REQ_BYTES> 341 requestMsg{}; 342 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); 343 size_t requestPayloadLength = requestMsg.size() - sizeof(pldm_msg_hdr); 344 memcpy(request->payload, &fileHandle, sizeof(fileHandle)); 345 memcpy(request->payload + sizeof(fileHandle), &offset, sizeof(offset)); 346 memcpy(request->payload + sizeof(fileHandle) + sizeof(offset), &length, 347 sizeof(length)); 348 memcpy(request->payload + sizeof(fileHandle) + sizeof(offset) + 349 sizeof(length), 350 &address, sizeof(address)); 351 352 using namespace pldm::filetable; 353 auto& table = buildFileTable(fileTableConfig.c_str()); 354 355 std::unique_ptr<oem_platform::Handler> oemPlatformHandler{}; 356 oem_ibm::Handler handler(oemPlatformHandler.get()); 357 auto response = handler.readFileIntoMemory(request, requestPayloadLength); 358 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 359 ASSERT_EQ(responsePtr->payload[0], PLDM_ERROR_INVALID_LENGTH); 360 // Clear the file table contents. 361 table.clear(); 362 } 363 364 TEST(WriteFileFromMemory, BadPath) 365 { 366 uint32_t fileHandle = 0; 367 uint32_t offset = 0; 368 uint32_t length = 10; 369 uint64_t address = 0; 370 371 std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_REQ_BYTES> 372 requestMsg{}; 373 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); 374 size_t requestPayloadLength = requestMsg.size() - sizeof(pldm_msg_hdr); 375 memcpy(request->payload, &fileHandle, sizeof(fileHandle)); 376 memcpy(request->payload + sizeof(fileHandle), &offset, sizeof(offset)); 377 memcpy(request->payload + sizeof(fileHandle) + sizeof(offset), &length, 378 sizeof(length)); 379 memcpy(request->payload + sizeof(fileHandle) + sizeof(offset) + 380 sizeof(length), 381 &address, sizeof(address)); 382 383 // Pass invalid payload length 384 std::unique_ptr<oem_platform::Handler> oemPlatformHandler{}; 385 oem_ibm::Handler handler(oemPlatformHandler.get()); 386 auto response = handler.writeFileFromMemory(request, 0); 387 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 388 ASSERT_EQ(responsePtr->payload[0], PLDM_ERROR_INVALID_LENGTH); 389 390 // The length field is not a multiple of DMA minsize 391 response = handler.writeFileFromMemory(request, requestPayloadLength); 392 responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 393 ASSERT_EQ(responsePtr->payload[0], PLDM_ERROR_INVALID_LENGTH); 394 } 395 396 TEST_F(TestFileTable, WriteFileInvalidFileHandle) 397 { 398 // Invalid file handle in the file table 399 uint32_t fileHandle = 2; 400 uint32_t offset = 0; 401 uint32_t length = 16; 402 uint64_t address = 0; 403 404 std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_REQ_BYTES> 405 requestMsg{}; 406 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); 407 size_t requestPayloadLength = requestMsg.size() - sizeof(pldm_msg_hdr); 408 memcpy(request->payload, &fileHandle, sizeof(fileHandle)); 409 memcpy(request->payload + sizeof(fileHandle), &offset, sizeof(offset)); 410 memcpy(request->payload + sizeof(fileHandle) + sizeof(offset), &length, 411 sizeof(length)); 412 memcpy(request->payload + sizeof(fileHandle) + sizeof(offset) + 413 sizeof(length), 414 &address, sizeof(address)); 415 416 using namespace pldm::filetable; 417 // Initialise the file table with 2 valid file handles 0 & 1. 418 auto& table = buildFileTable(fileTableConfig.c_str()); 419 420 std::unique_ptr<oem_platform::Handler> oemPlatformHandler{}; 421 oem_ibm::Handler handler(oemPlatformHandler.get()); 422 auto response = handler.writeFileFromMemory(request, requestPayloadLength); 423 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 424 ASSERT_EQ(responsePtr->payload[0], PLDM_INVALID_FILE_HANDLE); 425 // Clear the file table contents. 426 table.clear(); 427 } 428 429 TEST_F(TestFileTable, WriteFileInvalidOffset) 430 { 431 uint32_t fileHandle = 0; 432 // The file size is 1024, so the offset is invalid 433 uint32_t offset = 1024; 434 uint32_t length = 16; 435 uint64_t address = 0; 436 437 std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_REQ_BYTES> 438 requestMsg{}; 439 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); 440 size_t requestPayloadLength = requestMsg.size() - sizeof(pldm_msg_hdr); 441 memcpy(request->payload, &fileHandle, sizeof(fileHandle)); 442 memcpy(request->payload + sizeof(fileHandle), &offset, sizeof(offset)); 443 memcpy(request->payload + sizeof(fileHandle) + sizeof(offset), &length, 444 sizeof(length)); 445 memcpy(request->payload + sizeof(fileHandle) + sizeof(offset) + 446 sizeof(length), 447 &address, sizeof(address)); 448 449 using namespace pldm::filetable; 450 // Initialise the file table with 2 valid file handles 0 & 1. 451 auto& table = buildFileTable(TestFileTable::fileTableConfig.c_str()); 452 453 std::unique_ptr<oem_platform::Handler> oemPlatformHandler{}; 454 oem_ibm::Handler handler(oemPlatformHandler.get()); 455 auto response = handler.writeFileFromMemory(request, requestPayloadLength); 456 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 457 ASSERT_EQ(responsePtr->payload[0], PLDM_DATA_OUT_OF_RANGE); 458 // Clear the file table contents. 459 table.clear(); 460 } 461 462 TEST(FileTable, ConfigNotExist) 463 { 464 FileTable tableObj(""); 465 EXPECT_EQ(tableObj.isEmpty(), true); 466 } 467 468 TEST_F(TestFileTable, ValidateFileEntry) 469 { 470 FileTable tableObj(fileTableConfig.c_str()); 471 472 // Test file handle 0, the file size is 1K bytes. 473 auto value = tableObj.at(0); 474 ASSERT_EQ(value.handle, 0); 475 ASSERT_EQ(strcmp(value.fsPath.c_str(), imageFile.c_str()), 0); 476 ASSERT_EQ(static_cast<uint32_t>(fs::file_size(value.fsPath)), 1024); 477 ASSERT_EQ(value.traits.value, 1); 478 ASSERT_EQ(true, fs::exists(value.fsPath)); 479 480 // Test file handle 1, the file size is 16 bytes 481 auto value1 = tableObj.at(1); 482 ASSERT_EQ(value1.handle, 1); 483 ASSERT_EQ(strcmp(value1.fsPath.c_str(), cksumFile.c_str()), 0); 484 ASSERT_EQ(static_cast<uint32_t>(fs::file_size(value1.fsPath)), 16); 485 ASSERT_EQ(value1.traits.value, 4); 486 ASSERT_EQ(true, fs::exists(value1.fsPath)); 487 488 // Test invalid file handle 489 ASSERT_THROW(tableObj.at(2), std::out_of_range); 490 } 491 492 TEST_F(TestFileTable, ValidateFileTable) 493 { 494 FileTable tableObj(fileTableConfig.c_str()); 495 496 // Validate file attribute table 497 auto table = tableObj(); 498 ASSERT_EQ(true, 499 std::equal(attrTable.begin(), attrTable.end(), table.begin())); 500 } 501 502 TEST_F(TestFileTable, GetFileTableCommand) 503 { 504 // Initialise the file table with a valid handle of 0 & 1 505 auto& table = buildFileTable(fileTableConfig.c_str()); 506 507 uint32_t transferHandle = 0; 508 uint8_t opFlag = 0; 509 uint8_t type = PLDM_FILE_ATTRIBUTE_TABLE; 510 uint32_t nextTransferHandle = 0; 511 uint8_t transferFlag = PLDM_START_AND_END; 512 513 std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_GET_FILE_TABLE_REQ_BYTES> 514 requestMsg{}; 515 auto requestMsgPtr = reinterpret_cast<pldm_msg*>(requestMsg.data()); 516 size_t requestPayloadLength = requestMsg.size() - sizeof(pldm_msg_hdr); 517 auto request = reinterpret_cast<pldm_get_file_table_req*>( 518 requestMsg.data() + sizeof(pldm_msg_hdr)); 519 request->transfer_handle = transferHandle; 520 request->operation_flag = opFlag; 521 request->table_type = type; 522 523 std::unique_ptr<oem_platform::Handler> oemPlatformHandler{}; 524 oem_ibm::Handler handler(oemPlatformHandler.get()); 525 auto response = handler.getFileTable(requestMsgPtr, requestPayloadLength); 526 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 527 ASSERT_EQ(responsePtr->payload[0], PLDM_SUCCESS); 528 size_t offsetSize = sizeof(responsePtr->payload[0]); 529 ASSERT_EQ(0, memcmp(responsePtr->payload + offsetSize, &nextTransferHandle, 530 sizeof(nextTransferHandle))); 531 offsetSize += sizeof(nextTransferHandle); 532 ASSERT_EQ(0, memcmp(responsePtr->payload + offsetSize, &transferFlag, 533 sizeof(transferFlag))); 534 offsetSize += sizeof(transferFlag); 535 ASSERT_EQ(0, memcmp(responsePtr->payload + offsetSize, attrTable.data(), 536 attrTable.size())); 537 table.clear(); 538 } 539 540 TEST_F(TestFileTable, GetFileTableCommandReqLengthMismatch) 541 { 542 std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_GET_FILE_TABLE_REQ_BYTES> 543 requestMsg{}; 544 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); 545 546 // Pass invalid command payload length 547 std::unique_ptr<oem_platform::Handler> oemPlatformHandler{}; 548 oem_ibm::Handler handler(oemPlatformHandler.get()); 549 auto response = handler.getFileTable(request, 0); 550 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 551 ASSERT_EQ(responsePtr->payload[0], PLDM_ERROR_INVALID_LENGTH); 552 } 553 554 TEST_F(TestFileTable, GetFileTableCommandOEMAttrTable) 555 { 556 uint32_t transferHandle = 0; 557 uint8_t opFlag = 0; 558 uint8_t type = PLDM_OEM_FILE_ATTRIBUTE_TABLE; 559 560 std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_GET_FILE_TABLE_REQ_BYTES> 561 requestMsg{}; 562 auto requestMsgPtr = reinterpret_cast<pldm_msg*>(requestMsg.data()); 563 size_t requestPayloadLength = requestMsg.size() - sizeof(pldm_msg_hdr); 564 auto request = reinterpret_cast<pldm_get_file_table_req*>( 565 requestMsg.data() + sizeof(pldm_msg_hdr)); 566 request->transfer_handle = transferHandle; 567 request->operation_flag = opFlag; 568 request->table_type = type; 569 570 std::unique_ptr<oem_platform::Handler> oemPlatformHandler{}; 571 oem_ibm::Handler handler(oemPlatformHandler.get()); 572 auto response = handler.getFileTable(requestMsgPtr, requestPayloadLength); 573 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 574 ASSERT_EQ(responsePtr->payload[0], PLDM_INVALID_FILE_TABLE_TYPE); 575 } 576 577 TEST_F(TestFileTable, ReadFileBadPath) 578 { 579 uint32_t fileHandle = 1; 580 uint32_t offset = 0; 581 uint32_t length = 0x4; 582 583 std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_READ_FILE_REQ_BYTES> 584 requestMsg{}; 585 auto requestMsgPtr = reinterpret_cast<pldm_msg*>(requestMsg.data()); 586 auto payload_length = requestMsg.size() - sizeof(pldm_msg_hdr); 587 auto request = reinterpret_cast<pldm_read_file_req*>(requestMsg.data() + 588 sizeof(pldm_msg_hdr)); 589 590 request->file_handle = fileHandle; 591 request->offset = offset; 592 request->length = length; 593 594 using namespace pldm::filetable; 595 // Initialise the file table with 2 valid file handles 0 & 1. 596 auto& table = buildFileTable(fileTableConfig.c_str()); 597 598 // Invalid payload length 599 std::unique_ptr<oem_platform::Handler> oemPlatformHandler{}; 600 oem_ibm::Handler handler(oemPlatformHandler.get()); 601 auto response = handler.readFile(requestMsgPtr, 0); 602 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 603 ASSERT_EQ(responsePtr->payload[0], PLDM_ERROR_INVALID_LENGTH); 604 605 // Data out of range. File size is 1024, offset = 1024 is invalid. 606 request->offset = 1024; 607 608 response = handler.readFile(requestMsgPtr, payload_length); 609 responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 610 ASSERT_EQ(responsePtr->payload[0], PLDM_DATA_OUT_OF_RANGE); 611 612 // Invalid file handle 613 request->file_handle = 2; 614 615 response = handler.readFile(requestMsgPtr, payload_length); 616 responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 617 ASSERT_EQ(responsePtr->payload[0], PLDM_INVALID_FILE_HANDLE); 618 619 table.clear(); 620 } 621 622 TEST_F(TestFileTable, ReadFileGoodPath) 623 { 624 uint32_t fileHandle = 0; 625 uint32_t offset = 0; 626 uint32_t length = 0x4; 627 628 std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_READ_FILE_REQ_BYTES> 629 requestMsg{}; 630 auto requestMsgPtr = reinterpret_cast<pldm_msg*>(requestMsg.data()); 631 auto payload_length = requestMsg.size() - sizeof(pldm_msg_hdr); 632 auto request = reinterpret_cast<pldm_read_file_req*>(requestMsg.data() + 633 sizeof(pldm_msg_hdr)); 634 635 request->file_handle = fileHandle; 636 request->offset = offset; 637 request->length = length; 638 639 using namespace pldm::filetable; 640 // Initialise the file table with 2 valid file handles 0 & 1. 641 auto& table = buildFileTable(fileTableConfig.c_str()); 642 FileEntry value{}; 643 value = table.at(fileHandle); 644 645 std::ifstream stream(value.fsPath, std::ios::in | std::ios::binary); 646 stream.seekg(offset); 647 std::vector<char> buffer(length); 648 stream.read(buffer.data(), length); 649 650 std::unique_ptr<oem_platform::Handler> oemPlatformHandler{}; 651 oem_ibm::Handler handler(oemPlatformHandler.get()); 652 auto responseMsg = handler.readFile(requestMsgPtr, payload_length); 653 auto response = reinterpret_cast<pldm_read_file_resp*>( 654 responseMsg.data() + sizeof(pldm_msg_hdr)); 655 ASSERT_EQ(response->completion_code, PLDM_SUCCESS); 656 ASSERT_EQ(response->length, length); 657 ASSERT_EQ(0, memcmp(response->file_data, buffer.data(), length)); 658 659 // Test condition offset + length > fileSize; 660 size_t fileSize = 1024; 661 request->offset = 1023; 662 request->length = 10; 663 664 stream.seekg(request->offset); 665 buffer.resize(fileSize - request->offset); 666 stream.read(buffer.data(), (fileSize - request->offset)); 667 668 responseMsg = handler.readFile(requestMsgPtr, payload_length); 669 response = reinterpret_cast<pldm_read_file_resp*>(responseMsg.data() + 670 sizeof(pldm_msg_hdr)); 671 ASSERT_EQ(response->completion_code, PLDM_SUCCESS); 672 ASSERT_EQ(response->length, (fileSize - request->offset)); 673 ASSERT_EQ(0, memcmp(response->file_data, buffer.data(), 674 (fileSize - request->offset))); 675 676 table.clear(); 677 } 678 679 TEST_F(TestFileTable, WriteFileBadPath) 680 { 681 uint32_t fileHandle = 0; 682 uint32_t offset = 0; 683 uint32_t length = 0x10; 684 685 std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) + 686 PLDM_WRITE_FILE_REQ_BYTES + length); 687 auto requestMsgPtr = reinterpret_cast<pldm_msg*>(requestMsg.data()); 688 auto payload_length = requestMsg.size() - sizeof(pldm_msg_hdr); 689 auto request = reinterpret_cast<pldm_write_file_req*>(requestMsg.data() + 690 sizeof(pldm_msg_hdr)); 691 692 using namespace pldm::filetable; 693 // Initialise the file table with 2 valid file handles 0 & 1. 694 auto& table = buildFileTable(fileTableConfig.c_str()); 695 696 request->file_handle = fileHandle; 697 request->offset = offset; 698 request->length = length; 699 700 // Invalid payload length 701 std::unique_ptr<oem_platform::Handler> oemPlatformHandler{}; 702 oem_ibm::Handler handler(oemPlatformHandler.get()); 703 auto response = handler.writeFile(requestMsgPtr, 0); 704 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 705 ASSERT_EQ(responsePtr->payload[0], PLDM_ERROR_INVALID_LENGTH); 706 707 // Data out of range. File size is 1024, offset = 1024 is invalid. 708 request->offset = 1024; 709 710 response = handler.writeFile(requestMsgPtr, payload_length); 711 responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 712 ASSERT_EQ(responsePtr->payload[0], PLDM_DATA_OUT_OF_RANGE); 713 714 // Invalid file handle 715 request->file_handle = 2; 716 717 response = handler.writeFile(requestMsgPtr, payload_length); 718 responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 719 ASSERT_EQ(responsePtr->payload[0], PLDM_INVALID_FILE_HANDLE); 720 721 table.clear(); 722 } 723 724 TEST_F(TestFileTable, WriteFileGoodPath) 725 { 726 uint32_t fileHandle = 1; 727 uint32_t offset = 0; 728 std::array<uint8_t, 4> fileData = {0x41, 0x42, 0x43, 0x44}; 729 uint32_t length = fileData.size(); 730 731 std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) + 732 PLDM_WRITE_FILE_REQ_BYTES + length); 733 auto requestMsgPtr = reinterpret_cast<pldm_msg*>(requestMsg.data()); 734 auto payload_length = requestMsg.size() - sizeof(pldm_msg_hdr); 735 auto request = reinterpret_cast<pldm_write_file_req*>(requestMsg.data() + 736 sizeof(pldm_msg_hdr)); 737 738 using namespace pldm::filetable; 739 // Initialise the file table with 2 valid file handles 0 & 1. 740 auto& table = buildFileTable(fileTableConfig.c_str()); 741 FileEntry value{}; 742 value = table.at(fileHandle); 743 744 request->file_handle = fileHandle; 745 request->offset = offset; 746 request->length = length; 747 memcpy(request->file_data, fileData.data(), fileData.size()); 748 749 std::unique_ptr<oem_platform::Handler> oemPlatformHandler{}; 750 oem_ibm::Handler handler(oemPlatformHandler.get()); 751 auto responseMsg = handler.writeFile(requestMsgPtr, payload_length); 752 auto response = reinterpret_cast<pldm_read_file_resp*>( 753 responseMsg.data() + sizeof(pldm_msg_hdr)); 754 755 std::ifstream stream(value.fsPath, std::ios::in | std::ios::binary); 756 stream.seekg(offset); 757 std::vector<char> buffer(length); 758 stream.read(buffer.data(), length); 759 760 ASSERT_EQ(response->completion_code, PLDM_SUCCESS); 761 ASSERT_EQ(response->length, length); 762 ASSERT_EQ(0, memcmp(fileData.data(), buffer.data(), length)); 763 764 table.clear(); 765 } 766 767 TEST(writeFileByTypeFromMemory, testBadPath) 768 { 769 const auto hdr_size = sizeof(pldm_msg_hdr); 770 std::array<uint8_t, hdr_size + PLDM_RW_FILE_BY_TYPE_MEM_REQ_BYTES> 771 requestMsg{}; 772 auto req = reinterpret_cast<pldm_msg*>(requestMsg.data()); 773 size_t requestPayloadLength = requestMsg.size() - hdr_size; 774 struct pldm_read_write_file_by_type_memory_req* request = 775 reinterpret_cast<struct pldm_read_write_file_by_type_memory_req*>( 776 req->payload); 777 request->file_type = PLDM_FILE_TYPE_PEL; 778 request->file_handle = 0xFFFFFFFF; 779 request->offset = 0; 780 request->length = 17; 781 request->address = 0; 782 783 std::unique_ptr<oem_platform::Handler> oemPlatformHandler{}; 784 oem_ibm::Handler handler(oemPlatformHandler.get()); 785 auto response = handler.writeFileByTypeFromMemory(req, 0); 786 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 787 788 struct pldm_read_write_file_by_type_memory_resp* resp = 789 reinterpret_cast<struct pldm_read_write_file_by_type_memory_resp*>( 790 responsePtr->payload); 791 ASSERT_EQ(PLDM_ERROR_INVALID_LENGTH, resp->completion_code); 792 793 response = handler.writeFileByTypeFromMemory(req, requestPayloadLength); 794 responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 795 796 resp = reinterpret_cast<struct pldm_read_write_file_by_type_memory_resp*>( 797 responsePtr->payload); 798 ASSERT_EQ(PLDM_ERROR_INVALID_LENGTH, resp->completion_code); 799 } 800 801 TEST(getHandlerByType, allPaths) 802 { 803 uint32_t fileHandle{}; 804 auto handler = getHandlerByType(PLDM_FILE_TYPE_PEL, fileHandle); 805 auto pelType = dynamic_cast<PelHandler*>(handler.get()); 806 ASSERT_TRUE(pelType != nullptr); 807 808 handler = getHandlerByType(PLDM_FILE_TYPE_LID_PERM, fileHandle); 809 auto lidType = dynamic_cast<LidHandler*>(handler.get()); 810 ASSERT_TRUE(lidType != nullptr); 811 pelType = dynamic_cast<PelHandler*>(handler.get()); 812 ASSERT_TRUE(pelType == nullptr); 813 handler = getHandlerByType(PLDM_FILE_TYPE_LID_TEMP, fileHandle); 814 lidType = dynamic_cast<LidHandler*>(handler.get()); 815 ASSERT_TRUE(lidType != nullptr); 816 817 handler = getHandlerByType(PLDM_FILE_TYPE_DUMP, fileHandle); 818 auto dumpType = dynamic_cast<DumpHandler*>(handler.get()); 819 ASSERT_TRUE(dumpType != nullptr); 820 821 handler = getHandlerByType(PLDM_FILE_TYPE_RESOURCE_DUMP_PARMS, fileHandle); 822 dumpType = dynamic_cast<DumpHandler*>(handler.get()); 823 ASSERT_TRUE(dumpType != nullptr); 824 825 handler = getHandlerByType(PLDM_FILE_TYPE_RESOURCE_DUMP, fileHandle); 826 dumpType = dynamic_cast<DumpHandler*>(handler.get()); 827 ASSERT_TRUE(dumpType != nullptr); 828 829 handler = getHandlerByType(PLDM_FILE_TYPE_CERT_SIGNING_REQUEST, fileHandle); 830 auto certType = dynamic_cast<CertHandler*>(handler.get()); 831 ASSERT_TRUE(certType != nullptr); 832 833 handler = getHandlerByType(PLDM_FILE_TYPE_SIGNED_CERT, fileHandle); 834 certType = dynamic_cast<CertHandler*>(handler.get()); 835 ASSERT_TRUE(certType != nullptr); 836 837 handler = getHandlerByType(PLDM_FILE_TYPE_ROOT_CERT, fileHandle); 838 certType = dynamic_cast<CertHandler*>(handler.get()); 839 ASSERT_TRUE(certType != nullptr); 840 841 using namespace sdbusplus::xyz::openbmc_project::Common::Error; 842 ASSERT_THROW(getHandlerByType(0xFFFF, fileHandle), InternalFailure); 843 } 844 845 TEST(readFileByTypeIntoMemory, testBadPath) 846 { 847 const auto hdr_size = sizeof(pldm_msg_hdr); 848 std::array<uint8_t, hdr_size + PLDM_RW_FILE_BY_TYPE_MEM_REQ_BYTES> 849 requestMsg{}; 850 auto req = reinterpret_cast<pldm_msg*>(requestMsg.data()); 851 struct pldm_read_write_file_by_type_memory_req* request = 852 reinterpret_cast<struct pldm_read_write_file_by_type_memory_req*>( 853 req->payload); 854 request->file_type = 0xFFFF; 855 request->file_handle = 0; 856 request->offset = 0; 857 request->length = 17; 858 request->address = 0; 859 860 std::unique_ptr<oem_platform::Handler> oemPlatformHandler{}; 861 oem_ibm::Handler handler(oemPlatformHandler.get()); 862 auto response = handler.readFileByTypeIntoMemory(req, 0); 863 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 864 struct pldm_read_write_file_by_type_memory_resp* resp = 865 reinterpret_cast<struct pldm_read_write_file_by_type_memory_resp*>( 866 responsePtr->payload); 867 ASSERT_EQ(PLDM_ERROR_INVALID_LENGTH, resp->completion_code); 868 869 response = handler.readFileByTypeIntoMemory( 870 req, PLDM_RW_FILE_BY_TYPE_MEM_REQ_BYTES); 871 responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 872 resp = reinterpret_cast<struct pldm_read_write_file_by_type_memory_resp*>( 873 responsePtr->payload); 874 ASSERT_EQ(PLDM_ERROR_INVALID_LENGTH, resp->completion_code); 875 876 request->length = 16; 877 response = handler.readFileByTypeIntoMemory( 878 req, PLDM_RW_FILE_BY_TYPE_MEM_REQ_BYTES); 879 responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 880 resp = reinterpret_cast<struct pldm_read_write_file_by_type_memory_resp*>( 881 responsePtr->payload); 882 ASSERT_EQ(PLDM_INVALID_FILE_TYPE, resp->completion_code); 883 } 884 885 TEST(readFileByType, testBadPath) 886 { 887 const auto hdr_size = sizeof(pldm_msg_hdr); 888 std::array<uint8_t, hdr_size + PLDM_RW_FILE_BY_TYPE_REQ_BYTES> requestMsg{}; 889 auto payloadLength = requestMsg.size() - hdr_size; 890 auto req = reinterpret_cast<pldm_msg*>(requestMsg.data()); 891 struct pldm_read_write_file_by_type_req* request = 892 reinterpret_cast<struct pldm_read_write_file_by_type_req*>( 893 req->payload); 894 request->file_type = 0xFFFF; 895 request->file_handle = 0; 896 request->offset = 0; 897 request->length = 13; 898 899 std::unique_ptr<oem_platform::Handler> oemPlatformHandler{}; 900 oem_ibm::Handler handler(oemPlatformHandler.get()); 901 auto response = handler.readFileByType(req, 0); 902 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 903 struct pldm_read_write_file_by_type_resp* resp = 904 reinterpret_cast<struct pldm_read_write_file_by_type_resp*>( 905 responsePtr->payload); 906 ASSERT_EQ(PLDM_ERROR_INVALID_LENGTH, resp->completion_code); 907 908 response = handler.readFileByType(req, payloadLength); 909 responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 910 resp = reinterpret_cast<struct pldm_read_write_file_by_type_resp*>( 911 responsePtr->payload); 912 ASSERT_EQ(PLDM_INVALID_FILE_TYPE, resp->completion_code); 913 } 914 915 TEST(readFileByType, testReadFile) 916 { 917 LidHandler handler(0, true); 918 Response response; 919 uint32_t length{}; 920 921 auto rc = handler.readFile({}, 0, length, response); 922 ASSERT_EQ(PLDM_INVALID_FILE_HANDLE, rc); 923 924 char tmplt[] = "/tmp/lid.XXXXXX"; 925 auto fd = mkstemp(tmplt); 926 std::vector<uint8_t> in = {100, 10, 56, 78, 34, 56, 79, 235, 111}; 927 write(fd, in.data(), in.size()); 928 close(fd); 929 length = in.size() + 1000; 930 rc = handler.readFile(tmplt, 0, length, response); 931 ASSERT_EQ(rc, PLDM_SUCCESS); 932 ASSERT_EQ(length, in.size()); 933 ASSERT_EQ(response.size(), in.size()); 934 ASSERT_EQ(std::equal(in.begin(), in.end(), response.begin()), true); 935 } 936