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