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