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 uint8_t host_eid = 0; 213 int hostSocketFd = 0; 214 215 std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_REQ_BYTES> 216 requestMsg{}; 217 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); 218 memcpy(request->payload, &fileHandle, sizeof(fileHandle)); 219 memcpy(request->payload + sizeof(fileHandle), &offset, sizeof(offset)); 220 memcpy(request->payload + sizeof(fileHandle) + sizeof(offset), &length, 221 sizeof(length)); 222 memcpy(request->payload + sizeof(fileHandle) + sizeof(offset) + 223 sizeof(length), 224 &address, sizeof(address)); 225 226 // Pass invalid payload length 227 std::unique_ptr<oem_platform::Handler> oemPlatformHandler{}; 228 oem_ibm::Handler handler(oemPlatformHandler.get(), hostSocketFd, host_eid, 229 nullptr, nullptr); 230 auto response = handler.readFileIntoMemory(request, 0); 231 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 232 ASSERT_EQ(responsePtr->payload[0], PLDM_ERROR_INVALID_LENGTH); 233 } 234 235 TEST_F(TestFileTable, ReadFileInvalidFileHandle) 236 { 237 // Invalid file handle in the file table 238 uint32_t fileHandle = 2; 239 uint32_t offset = 0; 240 uint32_t length = 0; 241 uint64_t address = 0; 242 uint8_t host_eid = 0; 243 int hostSocketFd = 0; 244 245 std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_REQ_BYTES> 246 requestMsg{}; 247 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); 248 size_t requestPayloadLength = requestMsg.size() - sizeof(pldm_msg_hdr); 249 memcpy(request->payload, &fileHandle, sizeof(fileHandle)); 250 memcpy(request->payload + sizeof(fileHandle), &offset, sizeof(offset)); 251 memcpy(request->payload + sizeof(fileHandle) + sizeof(offset), &length, 252 sizeof(length)); 253 memcpy(request->payload + sizeof(fileHandle) + sizeof(offset) + 254 sizeof(length), 255 &address, sizeof(address)); 256 257 using namespace pldm::filetable; 258 // Initialise the file table with 2 valid file handles 0 & 1. 259 auto& table = buildFileTable(fileTableConfig.c_str()); 260 261 std::unique_ptr<oem_platform::Handler> oemPlatformHandler{}; 262 oem_ibm::Handler handler(oemPlatformHandler.get(), hostSocketFd, host_eid, 263 nullptr, nullptr); 264 auto response = handler.readFileIntoMemory(request, requestPayloadLength); 265 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 266 ASSERT_EQ(responsePtr->payload[0], PLDM_INVALID_FILE_HANDLE); 267 // Clear the file table contents. 268 table.clear(); 269 } 270 271 TEST_F(TestFileTable, ReadFileInvalidOffset) 272 { 273 uint32_t fileHandle = 0; 274 // The file size is 1024, so the offset is invalid 275 uint32_t offset = 1024; 276 uint32_t length = 0; 277 uint64_t address = 0; 278 uint8_t host_eid = 0; 279 int hostSocketFd = 0; 280 281 std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_REQ_BYTES> 282 requestMsg{}; 283 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); 284 size_t requestPayloadLength = requestMsg.size() - sizeof(pldm_msg_hdr); 285 memcpy(request->payload, &fileHandle, sizeof(fileHandle)); 286 memcpy(request->payload + sizeof(fileHandle), &offset, sizeof(offset)); 287 memcpy(request->payload + sizeof(fileHandle) + sizeof(offset), &length, 288 sizeof(length)); 289 memcpy(request->payload + sizeof(fileHandle) + sizeof(offset) + 290 sizeof(length), 291 &address, sizeof(address)); 292 293 using namespace pldm::filetable; 294 auto& table = buildFileTable(fileTableConfig.c_str()); 295 296 std::unique_ptr<oem_platform::Handler> oemPlatformHandler{}; 297 oem_ibm::Handler handler(oemPlatformHandler.get(), hostSocketFd, host_eid, 298 nullptr, nullptr); 299 auto response = handler.readFileIntoMemory(request, requestPayloadLength); 300 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 301 ASSERT_EQ(responsePtr->payload[0], PLDM_DATA_OUT_OF_RANGE); 302 // Clear the file table contents. 303 table.clear(); 304 } 305 306 TEST_F(TestFileTable, ReadFileInvalidLength) 307 { 308 uint32_t fileHandle = 0; 309 uint32_t offset = 100; 310 // Length should be a multiple of dma min size(16) 311 uint32_t length = 10; 312 uint64_t address = 0; 313 uint8_t host_eid = 0; 314 int hostSocketFd = 0; 315 316 std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_REQ_BYTES> 317 requestMsg{}; 318 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); 319 size_t requestPayloadLength = requestMsg.size() - sizeof(pldm_msg_hdr); 320 memcpy(request->payload, &fileHandle, sizeof(fileHandle)); 321 memcpy(request->payload + sizeof(fileHandle), &offset, sizeof(offset)); 322 memcpy(request->payload + sizeof(fileHandle) + sizeof(offset), &length, 323 sizeof(length)); 324 memcpy(request->payload + sizeof(fileHandle) + sizeof(offset) + 325 sizeof(length), 326 &address, sizeof(address)); 327 328 using namespace pldm::filetable; 329 auto& table = buildFileTable(fileTableConfig.c_str()); 330 331 std::unique_ptr<oem_platform::Handler> oemPlatformHandler{}; 332 oem_ibm::Handler handler(oemPlatformHandler.get(), hostSocketFd, host_eid, 333 nullptr, nullptr); 334 auto response = handler.readFileIntoMemory(request, requestPayloadLength); 335 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 336 ASSERT_EQ(responsePtr->payload[0], PLDM_ERROR_INVALID_LENGTH); 337 // Clear the file table contents. 338 table.clear(); 339 } 340 341 TEST_F(TestFileTable, ReadFileInvalidEffectiveLength) 342 { 343 uint32_t fileHandle = 0; 344 // valid offset 345 uint32_t offset = 100; 346 // length + offset exceeds the size, so effective length is 347 // filesize(1024) - offset(100). The effective length is not a multiple of 348 // DMA min size(16) 349 uint32_t length = 1024; 350 uint64_t address = 0; 351 uint8_t host_eid = 0; 352 int hostSocketFd = 0; 353 354 std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_REQ_BYTES> 355 requestMsg{}; 356 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); 357 size_t requestPayloadLength = requestMsg.size() - sizeof(pldm_msg_hdr); 358 memcpy(request->payload, &fileHandle, sizeof(fileHandle)); 359 memcpy(request->payload + sizeof(fileHandle), &offset, sizeof(offset)); 360 memcpy(request->payload + sizeof(fileHandle) + sizeof(offset), &length, 361 sizeof(length)); 362 memcpy(request->payload + sizeof(fileHandle) + sizeof(offset) + 363 sizeof(length), 364 &address, sizeof(address)); 365 366 using namespace pldm::filetable; 367 auto& table = buildFileTable(fileTableConfig.c_str()); 368 369 std::unique_ptr<oem_platform::Handler> oemPlatformHandler{}; 370 oem_ibm::Handler handler(oemPlatformHandler.get(), hostSocketFd, host_eid, 371 nullptr, nullptr); 372 auto response = handler.readFileIntoMemory(request, requestPayloadLength); 373 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 374 ASSERT_EQ(responsePtr->payload[0], PLDM_ERROR_INVALID_LENGTH); 375 // Clear the file table contents. 376 table.clear(); 377 } 378 379 TEST(WriteFileFromMemory, BadPath) 380 { 381 uint32_t fileHandle = 0; 382 uint32_t offset = 0; 383 uint32_t length = 10; 384 uint64_t address = 0; 385 uint8_t host_eid = 0; 386 int hostSocketFd = 0; 387 388 std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_REQ_BYTES> 389 requestMsg{}; 390 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); 391 size_t requestPayloadLength = requestMsg.size() - sizeof(pldm_msg_hdr); 392 memcpy(request->payload, &fileHandle, sizeof(fileHandle)); 393 memcpy(request->payload + sizeof(fileHandle), &offset, sizeof(offset)); 394 memcpy(request->payload + sizeof(fileHandle) + sizeof(offset), &length, 395 sizeof(length)); 396 memcpy(request->payload + sizeof(fileHandle) + sizeof(offset) + 397 sizeof(length), 398 &address, sizeof(address)); 399 400 // Pass invalid payload length 401 std::unique_ptr<oem_platform::Handler> oemPlatformHandler{}; 402 oem_ibm::Handler handler(oemPlatformHandler.get(), hostSocketFd, host_eid, 403 nullptr, nullptr); 404 auto response = handler.writeFileFromMemory(request, 0); 405 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 406 ASSERT_EQ(responsePtr->payload[0], PLDM_ERROR_INVALID_LENGTH); 407 408 // The length field is not a multiple of DMA minsize 409 response = handler.writeFileFromMemory(request, requestPayloadLength); 410 responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 411 ASSERT_EQ(responsePtr->payload[0], PLDM_ERROR_INVALID_LENGTH); 412 } 413 414 TEST_F(TestFileTable, WriteFileInvalidFileHandle) 415 { 416 // Invalid file handle in the file table 417 uint32_t fileHandle = 2; 418 uint32_t offset = 0; 419 uint32_t length = 16; 420 uint64_t address = 0; 421 uint8_t host_eid = 0; 422 int hostSocketFd = 0; 423 424 std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_REQ_BYTES> 425 requestMsg{}; 426 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); 427 size_t requestPayloadLength = requestMsg.size() - sizeof(pldm_msg_hdr); 428 memcpy(request->payload, &fileHandle, sizeof(fileHandle)); 429 memcpy(request->payload + sizeof(fileHandle), &offset, sizeof(offset)); 430 memcpy(request->payload + sizeof(fileHandle) + sizeof(offset), &length, 431 sizeof(length)); 432 memcpy(request->payload + sizeof(fileHandle) + sizeof(offset) + 433 sizeof(length), 434 &address, sizeof(address)); 435 436 using namespace pldm::filetable; 437 // Initialise the file table with 2 valid file handles 0 & 1. 438 auto& table = buildFileTable(fileTableConfig.c_str()); 439 440 std::unique_ptr<oem_platform::Handler> oemPlatformHandler{}; 441 oem_ibm::Handler handler(oemPlatformHandler.get(), hostSocketFd, host_eid, 442 nullptr, nullptr); 443 auto response = handler.writeFileFromMemory(request, requestPayloadLength); 444 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 445 ASSERT_EQ(responsePtr->payload[0], PLDM_INVALID_FILE_HANDLE); 446 // Clear the file table contents. 447 table.clear(); 448 } 449 450 TEST_F(TestFileTable, WriteFileInvalidOffset) 451 { 452 uint32_t fileHandle = 0; 453 // The file size is 1024, so the offset is invalid 454 uint32_t offset = 1024; 455 uint32_t length = 16; 456 uint64_t address = 0; 457 uint8_t host_eid = 0; 458 int hostSocketFd = 0; 459 460 std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_REQ_BYTES> 461 requestMsg{}; 462 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); 463 size_t requestPayloadLength = requestMsg.size() - sizeof(pldm_msg_hdr); 464 memcpy(request->payload, &fileHandle, sizeof(fileHandle)); 465 memcpy(request->payload + sizeof(fileHandle), &offset, sizeof(offset)); 466 memcpy(request->payload + sizeof(fileHandle) + sizeof(offset), &length, 467 sizeof(length)); 468 memcpy(request->payload + sizeof(fileHandle) + sizeof(offset) + 469 sizeof(length), 470 &address, sizeof(address)); 471 472 using namespace pldm::filetable; 473 // Initialise the file table with 2 valid file handles 0 & 1. 474 auto& table = buildFileTable(TestFileTable::fileTableConfig.c_str()); 475 476 std::unique_ptr<oem_platform::Handler> oemPlatformHandler{}; 477 oem_ibm::Handler handler(oemPlatformHandler.get(), hostSocketFd, host_eid, 478 nullptr, nullptr); 479 auto response = handler.writeFileFromMemory(request, requestPayloadLength); 480 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 481 ASSERT_EQ(responsePtr->payload[0], PLDM_DATA_OUT_OF_RANGE); 482 // Clear the file table contents. 483 table.clear(); 484 } 485 486 TEST(FileTable, ConfigNotExist) 487 { 488 FileTable tableObj(""); 489 EXPECT_EQ(tableObj.isEmpty(), true); 490 } 491 492 TEST_F(TestFileTable, ValidateFileEntry) 493 { 494 FileTable tableObj(fileTableConfig.c_str()); 495 496 // Test file handle 0, the file size is 1K bytes. 497 auto value = tableObj.at(0); 498 ASSERT_EQ(value.handle, 0); 499 ASSERT_EQ(strcmp(value.fsPath.c_str(), imageFile.c_str()), 0); 500 ASSERT_EQ(static_cast<uint32_t>(fs::file_size(value.fsPath)), 1024); 501 ASSERT_EQ(value.traits.value, 1); 502 ASSERT_EQ(true, fs::exists(value.fsPath)); 503 504 // Test file handle 1, the file size is 16 bytes 505 auto value1 = tableObj.at(1); 506 ASSERT_EQ(value1.handle, 1); 507 ASSERT_EQ(strcmp(value1.fsPath.c_str(), cksumFile.c_str()), 0); 508 ASSERT_EQ(static_cast<uint32_t>(fs::file_size(value1.fsPath)), 16); 509 ASSERT_EQ(value1.traits.value, 4); 510 ASSERT_EQ(true, fs::exists(value1.fsPath)); 511 512 // Test invalid file handle 513 ASSERT_THROW(tableObj.at(2), std::out_of_range); 514 } 515 516 TEST_F(TestFileTable, ValidateFileTable) 517 { 518 FileTable tableObj(fileTableConfig.c_str()); 519 520 // Validate file attribute table 521 auto table = tableObj(); 522 ASSERT_EQ(true, 523 std::equal(attrTable.begin(), attrTable.end(), table.begin())); 524 } 525 526 TEST_F(TestFileTable, GetFileTableCommand) 527 { 528 // Initialise the file table with a valid handle of 0 & 1 529 auto& table = buildFileTable(fileTableConfig.c_str()); 530 531 uint32_t transferHandle = 0; 532 uint8_t opFlag = 0; 533 uint8_t type = PLDM_FILE_ATTRIBUTE_TABLE; 534 uint32_t nextTransferHandle = 0; 535 uint8_t transferFlag = PLDM_START_AND_END; 536 uint8_t host_eid = 0; 537 int hostSocketFd = 0; 538 539 std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_GET_FILE_TABLE_REQ_BYTES> 540 requestMsg{}; 541 auto requestMsgPtr = reinterpret_cast<pldm_msg*>(requestMsg.data()); 542 size_t requestPayloadLength = requestMsg.size() - sizeof(pldm_msg_hdr); 543 auto request = reinterpret_cast<pldm_get_file_table_req*>( 544 requestMsg.data() + sizeof(pldm_msg_hdr)); 545 request->transfer_handle = transferHandle; 546 request->operation_flag = opFlag; 547 request->table_type = type; 548 549 std::unique_ptr<oem_platform::Handler> oemPlatformHandler{}; 550 oem_ibm::Handler handler(oemPlatformHandler.get(), hostSocketFd, host_eid, 551 nullptr, nullptr); 552 auto response = handler.getFileTable(requestMsgPtr, requestPayloadLength); 553 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 554 ASSERT_EQ(responsePtr->payload[0], PLDM_SUCCESS); 555 size_t offsetSize = sizeof(responsePtr->payload[0]); 556 ASSERT_EQ(0, memcmp(responsePtr->payload + offsetSize, &nextTransferHandle, 557 sizeof(nextTransferHandle))); 558 offsetSize += sizeof(nextTransferHandle); 559 ASSERT_EQ(0, memcmp(responsePtr->payload + offsetSize, &transferFlag, 560 sizeof(transferFlag))); 561 offsetSize += sizeof(transferFlag); 562 ASSERT_EQ(0, memcmp(responsePtr->payload + offsetSize, attrTable.data(), 563 attrTable.size())); 564 table.clear(); 565 } 566 567 TEST_F(TestFileTable, GetFileTableCommandReqLengthMismatch) 568 { 569 uint8_t host_eid = 0; 570 int hostSocketFd = 0; 571 std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_GET_FILE_TABLE_REQ_BYTES> 572 requestMsg{}; 573 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); 574 575 // Pass invalid command payload length 576 std::unique_ptr<oem_platform::Handler> oemPlatformHandler{}; 577 oem_ibm::Handler handler(oemPlatformHandler.get(), hostSocketFd, host_eid, 578 nullptr, nullptr); 579 auto response = handler.getFileTable(request, 0); 580 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 581 ASSERT_EQ(responsePtr->payload[0], PLDM_ERROR_INVALID_LENGTH); 582 } 583 584 TEST_F(TestFileTable, GetFileTableCommandOEMAttrTable) 585 { 586 uint32_t transferHandle = 0; 587 uint8_t opFlag = 0; 588 uint8_t type = PLDM_OEM_FILE_ATTRIBUTE_TABLE; 589 uint8_t host_eid = 0; 590 int hostSocketFd = 0; 591 592 std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_GET_FILE_TABLE_REQ_BYTES> 593 requestMsg{}; 594 auto requestMsgPtr = reinterpret_cast<pldm_msg*>(requestMsg.data()); 595 size_t requestPayloadLength = requestMsg.size() - sizeof(pldm_msg_hdr); 596 auto request = reinterpret_cast<pldm_get_file_table_req*>( 597 requestMsg.data() + sizeof(pldm_msg_hdr)); 598 request->transfer_handle = transferHandle; 599 request->operation_flag = opFlag; 600 request->table_type = type; 601 602 std::unique_ptr<oem_platform::Handler> oemPlatformHandler{}; 603 oem_ibm::Handler handler(oemPlatformHandler.get(), hostSocketFd, host_eid, 604 nullptr, nullptr); 605 auto response = handler.getFileTable(requestMsgPtr, requestPayloadLength); 606 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 607 ASSERT_EQ(responsePtr->payload[0], PLDM_INVALID_FILE_TABLE_TYPE); 608 } 609 610 TEST_F(TestFileTable, ReadFileBadPath) 611 { 612 uint32_t fileHandle = 1; 613 uint32_t offset = 0; 614 uint32_t length = 0x4; 615 uint8_t host_eid = 0; 616 int hostSocketFd = 0; 617 618 std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_READ_FILE_REQ_BYTES> 619 requestMsg{}; 620 auto requestMsgPtr = reinterpret_cast<pldm_msg*>(requestMsg.data()); 621 auto payload_length = requestMsg.size() - sizeof(pldm_msg_hdr); 622 auto request = reinterpret_cast<pldm_read_file_req*>(requestMsg.data() + 623 sizeof(pldm_msg_hdr)); 624 625 request->file_handle = fileHandle; 626 request->offset = offset; 627 request->length = length; 628 629 using namespace pldm::filetable; 630 // Initialise the file table with 2 valid file handles 0 & 1. 631 auto& table = buildFileTable(fileTableConfig.c_str()); 632 633 // Invalid payload length 634 std::unique_ptr<oem_platform::Handler> oemPlatformHandler{}; 635 oem_ibm::Handler handler(oemPlatformHandler.get(), hostSocketFd, host_eid, 636 nullptr, nullptr); 637 auto response = handler.readFile(requestMsgPtr, 0); 638 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 639 ASSERT_EQ(responsePtr->payload[0], PLDM_ERROR_INVALID_LENGTH); 640 641 // Data out of range. File size is 1024, offset = 1024 is invalid. 642 request->offset = 1024; 643 644 response = handler.readFile(requestMsgPtr, payload_length); 645 responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 646 ASSERT_EQ(responsePtr->payload[0], PLDM_DATA_OUT_OF_RANGE); 647 648 // Invalid file handle 649 request->file_handle = 2; 650 651 response = handler.readFile(requestMsgPtr, payload_length); 652 responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 653 ASSERT_EQ(responsePtr->payload[0], PLDM_INVALID_FILE_HANDLE); 654 655 table.clear(); 656 } 657 658 TEST_F(TestFileTable, ReadFileGoodPath) 659 { 660 uint32_t fileHandle = 0; 661 uint32_t offset = 0; 662 uint32_t length = 0x4; 663 uint8_t host_eid = 0; 664 int hostSocketFd = 0; 665 666 std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_READ_FILE_REQ_BYTES> 667 requestMsg{}; 668 auto requestMsgPtr = reinterpret_cast<pldm_msg*>(requestMsg.data()); 669 auto payload_length = requestMsg.size() - sizeof(pldm_msg_hdr); 670 auto request = reinterpret_cast<pldm_read_file_req*>(requestMsg.data() + 671 sizeof(pldm_msg_hdr)); 672 673 request->file_handle = fileHandle; 674 request->offset = offset; 675 request->length = length; 676 677 using namespace pldm::filetable; 678 // Initialise the file table with 2 valid file handles 0 & 1. 679 auto& table = buildFileTable(fileTableConfig.c_str()); 680 FileEntry value{}; 681 value = table.at(fileHandle); 682 683 std::ifstream stream(value.fsPath, std::ios::in | std::ios::binary); 684 stream.seekg(offset); 685 std::vector<char> buffer(length); 686 stream.read(buffer.data(), length); 687 688 std::unique_ptr<oem_platform::Handler> oemPlatformHandler{}; 689 oem_ibm::Handler handler(oemPlatformHandler.get(), hostSocketFd, host_eid, 690 nullptr, nullptr); 691 auto responseMsg = handler.readFile(requestMsgPtr, payload_length); 692 auto response = reinterpret_cast<pldm_read_file_resp*>( 693 responseMsg.data() + sizeof(pldm_msg_hdr)); 694 ASSERT_EQ(response->completion_code, PLDM_SUCCESS); 695 ASSERT_EQ(response->length, length); 696 ASSERT_EQ(0, memcmp(response->file_data, buffer.data(), length)); 697 698 // Test condition offset + length > fileSize; 699 size_t fileSize = 1024; 700 request->offset = 1023; 701 request->length = 10; 702 703 stream.seekg(request->offset); 704 buffer.resize(fileSize - request->offset); 705 stream.read(buffer.data(), (fileSize - request->offset)); 706 707 responseMsg = handler.readFile(requestMsgPtr, payload_length); 708 response = reinterpret_cast<pldm_read_file_resp*>(responseMsg.data() + 709 sizeof(pldm_msg_hdr)); 710 ASSERT_EQ(response->completion_code, PLDM_SUCCESS); 711 ASSERT_EQ(response->length, (fileSize - request->offset)); 712 ASSERT_EQ(0, memcmp(response->file_data, buffer.data(), 713 (fileSize - request->offset))); 714 715 table.clear(); 716 } 717 718 TEST_F(TestFileTable, WriteFileBadPath) 719 { 720 uint32_t fileHandle = 0; 721 uint32_t offset = 0; 722 uint32_t length = 0x10; 723 uint8_t host_eid = 0; 724 int hostSocketFd = 0; 725 726 std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) + 727 PLDM_WRITE_FILE_REQ_BYTES + length); 728 auto requestMsgPtr = reinterpret_cast<pldm_msg*>(requestMsg.data()); 729 auto payload_length = requestMsg.size() - sizeof(pldm_msg_hdr); 730 auto request = reinterpret_cast<pldm_write_file_req*>(requestMsg.data() + 731 sizeof(pldm_msg_hdr)); 732 733 using namespace pldm::filetable; 734 // Initialise the file table with 2 valid file handles 0 & 1. 735 auto& table = buildFileTable(fileTableConfig.c_str()); 736 737 request->file_handle = fileHandle; 738 request->offset = offset; 739 request->length = length; 740 741 // Invalid payload length 742 std::unique_ptr<oem_platform::Handler> oemPlatformHandler{}; 743 oem_ibm::Handler handler(oemPlatformHandler.get(), hostSocketFd, host_eid, 744 nullptr, nullptr); 745 auto response = handler.writeFile(requestMsgPtr, 0); 746 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 747 ASSERT_EQ(responsePtr->payload[0], PLDM_ERROR_INVALID_LENGTH); 748 749 // Data out of range. File size is 1024, offset = 1024 is invalid. 750 request->offset = 1024; 751 752 response = handler.writeFile(requestMsgPtr, payload_length); 753 responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 754 ASSERT_EQ(responsePtr->payload[0], PLDM_DATA_OUT_OF_RANGE); 755 756 // Invalid file handle 757 request->file_handle = 2; 758 759 response = handler.writeFile(requestMsgPtr, payload_length); 760 responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 761 ASSERT_EQ(responsePtr->payload[0], PLDM_INVALID_FILE_HANDLE); 762 763 table.clear(); 764 } 765 766 TEST_F(TestFileTable, WriteFileGoodPath) 767 { 768 uint32_t fileHandle = 1; 769 uint32_t offset = 0; 770 std::array<uint8_t, 4> fileData = {0x41, 0x42, 0x43, 0x44}; 771 uint32_t length = fileData.size(); 772 uint8_t host_eid = 0; 773 int hostSocketFd = 0; 774 775 std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) + 776 PLDM_WRITE_FILE_REQ_BYTES + length); 777 auto requestMsgPtr = reinterpret_cast<pldm_msg*>(requestMsg.data()); 778 auto payload_length = requestMsg.size() - sizeof(pldm_msg_hdr); 779 auto request = reinterpret_cast<pldm_write_file_req*>(requestMsg.data() + 780 sizeof(pldm_msg_hdr)); 781 782 using namespace pldm::filetable; 783 // Initialise the file table with 2 valid file handles 0 & 1. 784 auto& table = buildFileTable(fileTableConfig.c_str()); 785 FileEntry value{}; 786 value = table.at(fileHandle); 787 788 request->file_handle = fileHandle; 789 request->offset = offset; 790 request->length = length; 791 memcpy(request->file_data, fileData.data(), fileData.size()); 792 793 std::unique_ptr<oem_platform::Handler> oemPlatformHandler{}; 794 oem_ibm::Handler handler(oemPlatformHandler.get(), hostSocketFd, host_eid, 795 nullptr, nullptr); 796 auto responseMsg = handler.writeFile(requestMsgPtr, payload_length); 797 auto response = reinterpret_cast<pldm_read_file_resp*>( 798 responseMsg.data() + sizeof(pldm_msg_hdr)); 799 800 std::ifstream stream(value.fsPath, std::ios::in | std::ios::binary); 801 stream.seekg(offset); 802 std::vector<char> buffer(length); 803 stream.read(buffer.data(), length); 804 805 ASSERT_EQ(response->completion_code, PLDM_SUCCESS); 806 ASSERT_EQ(response->length, length); 807 ASSERT_EQ(0, memcmp(fileData.data(), buffer.data(), length)); 808 809 table.clear(); 810 } 811 812 TEST(writeFileByTypeFromMemory, testBadPath) 813 { 814 uint8_t host_eid = 0; 815 int hostSocketFd = 0; 816 817 const auto hdr_size = sizeof(pldm_msg_hdr); 818 std::array<uint8_t, hdr_size + PLDM_RW_FILE_BY_TYPE_MEM_REQ_BYTES> 819 requestMsg{}; 820 auto req = reinterpret_cast<pldm_msg*>(requestMsg.data()); 821 size_t requestPayloadLength = requestMsg.size() - hdr_size; 822 struct pldm_read_write_file_by_type_memory_req* request = 823 reinterpret_cast<struct pldm_read_write_file_by_type_memory_req*>( 824 req->payload); 825 request->file_type = PLDM_FILE_TYPE_PEL; 826 request->file_handle = 0xFFFFFFFF; 827 request->offset = 0; 828 request->length = 17; 829 request->address = 0; 830 831 std::unique_ptr<oem_platform::Handler> oemPlatformHandler{}; 832 oem_ibm::Handler handler(oemPlatformHandler.get(), hostSocketFd, host_eid, 833 nullptr, nullptr); 834 auto response = handler.writeFileByTypeFromMemory(req, 0); 835 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 836 837 struct pldm_read_write_file_by_type_memory_resp* resp = 838 reinterpret_cast<struct pldm_read_write_file_by_type_memory_resp*>( 839 responsePtr->payload); 840 ASSERT_EQ(PLDM_ERROR_INVALID_LENGTH, resp->completion_code); 841 842 response = handler.writeFileByTypeFromMemory(req, requestPayloadLength); 843 responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 844 845 resp = reinterpret_cast<struct pldm_read_write_file_by_type_memory_resp*>( 846 responsePtr->payload); 847 ASSERT_EQ(PLDM_ERROR_INVALID_LENGTH, resp->completion_code); 848 } 849 850 TEST(getHandlerByType, allPaths) 851 { 852 uint32_t fileHandle{}; 853 auto handler = getHandlerByType(PLDM_FILE_TYPE_PEL, fileHandle); 854 auto pelType = dynamic_cast<PelHandler*>(handler.get()); 855 ASSERT_TRUE(pelType != nullptr); 856 857 handler = getHandlerByType(PLDM_FILE_TYPE_LID_PERM, fileHandle); 858 auto lidType = dynamic_cast<LidHandler*>(handler.get()); 859 ASSERT_TRUE(lidType != nullptr); 860 pelType = dynamic_cast<PelHandler*>(handler.get()); 861 ASSERT_TRUE(pelType == nullptr); 862 handler = getHandlerByType(PLDM_FILE_TYPE_LID_TEMP, fileHandle); 863 lidType = dynamic_cast<LidHandler*>(handler.get()); 864 ASSERT_TRUE(lidType != nullptr); 865 866 handler = getHandlerByType(PLDM_FILE_TYPE_DUMP, fileHandle); 867 auto dumpType = dynamic_cast<DumpHandler*>(handler.get()); 868 ASSERT_TRUE(dumpType != nullptr); 869 870 handler = getHandlerByType(PLDM_FILE_TYPE_RESOURCE_DUMP_PARMS, fileHandle); 871 dumpType = dynamic_cast<DumpHandler*>(handler.get()); 872 ASSERT_TRUE(dumpType != nullptr); 873 874 handler = getHandlerByType(PLDM_FILE_TYPE_RESOURCE_DUMP, fileHandle); 875 dumpType = dynamic_cast<DumpHandler*>(handler.get()); 876 ASSERT_TRUE(dumpType != nullptr); 877 878 handler = getHandlerByType(PLDM_FILE_TYPE_CERT_SIGNING_REQUEST, fileHandle); 879 auto certType = dynamic_cast<CertHandler*>(handler.get()); 880 ASSERT_TRUE(certType != nullptr); 881 882 handler = getHandlerByType(PLDM_FILE_TYPE_SIGNED_CERT, fileHandle); 883 certType = dynamic_cast<CertHandler*>(handler.get()); 884 ASSERT_TRUE(certType != nullptr); 885 886 handler = getHandlerByType(PLDM_FILE_TYPE_ROOT_CERT, fileHandle); 887 certType = dynamic_cast<CertHandler*>(handler.get()); 888 ASSERT_TRUE(certType != nullptr); 889 890 using namespace sdbusplus::xyz::openbmc_project::Common::Error; 891 ASSERT_THROW(getHandlerByType(0xFFFF, fileHandle), InternalFailure); 892 } 893 894 TEST(readFileByTypeIntoMemory, testBadPath) 895 { 896 uint8_t host_eid = 0; 897 int hostSocketFd = 0; 898 const auto hdr_size = sizeof(pldm_msg_hdr); 899 std::array<uint8_t, hdr_size + PLDM_RW_FILE_BY_TYPE_MEM_REQ_BYTES> 900 requestMsg{}; 901 auto req = reinterpret_cast<pldm_msg*>(requestMsg.data()); 902 struct pldm_read_write_file_by_type_memory_req* request = 903 reinterpret_cast<struct pldm_read_write_file_by_type_memory_req*>( 904 req->payload); 905 request->file_type = 0xFFFF; 906 request->file_handle = 0; 907 request->offset = 0; 908 request->length = 17; 909 request->address = 0; 910 911 std::unique_ptr<oem_platform::Handler> oemPlatformHandler{}; 912 oem_ibm::Handler handler(oemPlatformHandler.get(), hostSocketFd, host_eid, 913 nullptr, nullptr); 914 auto response = handler.readFileByTypeIntoMemory(req, 0); 915 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 916 struct pldm_read_write_file_by_type_memory_resp* resp = 917 reinterpret_cast<struct pldm_read_write_file_by_type_memory_resp*>( 918 responsePtr->payload); 919 ASSERT_EQ(PLDM_ERROR_INVALID_LENGTH, resp->completion_code); 920 921 response = handler.readFileByTypeIntoMemory( 922 req, PLDM_RW_FILE_BY_TYPE_MEM_REQ_BYTES); 923 responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 924 resp = reinterpret_cast<struct pldm_read_write_file_by_type_memory_resp*>( 925 responsePtr->payload); 926 ASSERT_EQ(PLDM_ERROR_INVALID_LENGTH, resp->completion_code); 927 928 request->length = 16; 929 response = handler.readFileByTypeIntoMemory( 930 req, PLDM_RW_FILE_BY_TYPE_MEM_REQ_BYTES); 931 responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 932 resp = reinterpret_cast<struct pldm_read_write_file_by_type_memory_resp*>( 933 responsePtr->payload); 934 ASSERT_EQ(PLDM_INVALID_FILE_TYPE, resp->completion_code); 935 } 936 937 TEST(readFileByType, testBadPath) 938 { 939 uint8_t host_eid = 0; 940 int hostSocketFd = 0; 941 const auto hdr_size = sizeof(pldm_msg_hdr); 942 std::array<uint8_t, hdr_size + PLDM_RW_FILE_BY_TYPE_REQ_BYTES> requestMsg{}; 943 auto payloadLength = requestMsg.size() - hdr_size; 944 auto req = reinterpret_cast<pldm_msg*>(requestMsg.data()); 945 struct pldm_read_write_file_by_type_req* request = 946 reinterpret_cast<struct pldm_read_write_file_by_type_req*>( 947 req->payload); 948 request->file_type = 0xFFFF; 949 request->file_handle = 0; 950 request->offset = 0; 951 request->length = 13; 952 953 std::unique_ptr<oem_platform::Handler> oemPlatformHandler{}; 954 oem_ibm::Handler handler(oemPlatformHandler.get(), hostSocketFd, host_eid, 955 nullptr, nullptr); 956 auto response = handler.readFileByType(req, 0); 957 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 958 struct pldm_read_write_file_by_type_resp* resp = 959 reinterpret_cast<struct pldm_read_write_file_by_type_resp*>( 960 responsePtr->payload); 961 ASSERT_EQ(PLDM_ERROR_INVALID_LENGTH, resp->completion_code); 962 963 response = handler.readFileByType(req, payloadLength); 964 responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 965 resp = reinterpret_cast<struct pldm_read_write_file_by_type_resp*>( 966 responsePtr->payload); 967 ASSERT_EQ(PLDM_INVALID_FILE_TYPE, resp->completion_code); 968 } 969 970 TEST(readFileByType, testReadFile) 971 { 972 LidHandler handler(0, true); 973 Response response; 974 uint32_t length{}; 975 976 auto rc = handler.readFile({}, 0, length, response); 977 ASSERT_EQ(PLDM_INVALID_FILE_HANDLE, rc); 978 979 char tmplt[] = "/tmp/lid.XXXXXX"; 980 auto fd = mkstemp(tmplt); 981 std::vector<uint8_t> in = {100, 10, 56, 78, 34, 56, 79, 235, 111}; 982 rc = write(fd, in.data(), in.size()); 983 close(fd); 984 length = in.size() + 1000; 985 rc = handler.readFile(tmplt, 0, length, response); 986 ASSERT_EQ(rc, PLDM_SUCCESS); 987 ASSERT_EQ(length, in.size()); 988 ASSERT_EQ(response.size(), in.size()); 989 ASSERT_EQ(std::equal(in.begin(), in.end(), response.begin()), true); 990 } 991