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