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