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