1 #include "estoraged_test.hpp"
2
3 #include "estoraged.hpp"
4 #include "estoraged_conf.hpp"
5
6 #include <linux/mmc/core.h>
7 #include <linux/mmc/ioctl.h>
8 #include <linux/mmc/mmc.h>
9 #include <unistd.h>
10
11 #include <boost/asio/io_context.hpp>
12 #include <sdbusplus/asio/connection.hpp>
13 #include <sdbusplus/asio/object_server.hpp>
14 #include <stdplus/fd/gmock.hpp>
15 #include <xyz/openbmc_project/Common/error.hpp>
16 #include <xyz/openbmc_project/Inventory/Item/Volume/server.hpp>
17
18 #include <array>
19 #include <exception>
20 #include <filesystem>
21 #include <fstream>
22 #include <iterator>
23 #include <memory>
24 #include <span>
25 #include <string>
26 #include <vector>
27
28 #include <gmock/gmock.h>
29 #include <gtest/gtest.h>
30
31 namespace estoraged_test
32 {
33
34 using sdbusplus::server::xyz::openbmc_project::inventory::item::Volume;
35 using sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
36 using sdbusplus::xyz::openbmc_project::Common::Error::ResourceNotFound;
37 using std::filesystem::path;
38 using stdplus::fd::FdMock;
39 using ::testing::_;
40 using ::testing::ElementsAreArray;
41 using ::testing::Return;
42 using ::testing::StrEq;
43
44 class EStoragedTest : public testing::Test
45 {
46 public:
47 const char* testFileName = "testfile";
48 const char* testLuksDevName = "testfile_luksDev";
49 const char* testCryptDir = "/tmp";
50 const std::string testConfigPath =
51 "/xyz/openbmc_project/inventory/system/board/test_board/test_emmc";
52 const uint64_t testSize = 24;
53 const uint8_t testLifeTime = 25;
54 const std::string testPartNumber = "12345678";
55 const std::string testSerialNumber = "ABCDEF1234";
56 const std::string testLocationCode = "U102020";
57 const std::string testDriveType = "SSD";
58 const std::string testDriveProtocol = "eMMC";
59 std::ofstream testFile;
60 std::string passwordString;
61 std::vector<uint8_t> password;
62 MockCryptsetupInterface* mockCryptIface{};
63 static const constexpr std::array<const char*, 2> options = {
64 "-E", "discard"};
65 MockFilesystemInterface* mockFsIface{};
66 boost::asio::io_context io;
67 std::shared_ptr<sdbusplus::asio::connection> conn;
68 std::unique_ptr<sdbusplus::asio::object_server> objectServer;
69 std::unique_ptr<estoraged::EStoraged> esObject;
70
EStoragedTest()71 EStoragedTest() :
72 passwordString("password"),
73 password(passwordString.begin(), passwordString.end())
74 {}
75
SetUp()76 void SetUp() override
77 {
78 /* Create an empty file that we'll pretend is a 'storage device'. */
79 testFile.open(testFileName,
80 std::ios::out | std::ios::binary | std::ios::trunc);
81 testFile.close();
82 if (testFile.fail())
83 {
84 throw std::runtime_error("Failed to open test file");
85 }
86
87 std::unique_ptr<MockCryptsetupInterface> cryptIface =
88 std::make_unique<MockCryptsetupInterface>();
89 mockCryptIface = cryptIface.get();
90 std::unique_ptr<MockFilesystemInterface> fsIface =
91 std::make_unique<MockFilesystemInterface>();
92 mockFsIface = fsIface.get();
93
94 /* Set up location of dummy mapped crypt file. */
95 EXPECT_CALL(*cryptIface, cryptGetDir).WillOnce(Return(testCryptDir));
96
97 conn = std::make_shared<sdbusplus::asio::connection>(io);
98 // request D-Bus server name.
99 conn->request_name("xyz.openbmc_project.eStoraged.test");
100 objectServer = std::make_unique<sdbusplus::asio::object_server>(conn);
101
102 std::unique_ptr<FdMock> mockFd = std::make_unique<FdMock>();
103 esObject = std::make_unique<estoraged::EStoraged>(
104 std::move(mockFd), *objectServer, testConfigPath, testFileName,
105 testLuksDevName, testSize, testLifeTime, testPartNumber,
106 testSerialNumber, testLocationCode, ERASE_MAX_GEOMETRY,
107 ERASE_MIN_GEOMETRY, testDriveType, testDriveProtocol,
108 std::move(cryptIface), std::move(fsIface));
109 }
110
TearDown()111 void TearDown() override
112 {
113 EXPECT_EQ(0, unlink(testFileName));
114 }
115 };
116
117 const char* mappedDevicePath = "/tmp/testfile_luksDev";
118 std::ofstream mappedDevice;
119
createMappedDev()120 int createMappedDev()
121 {
122 mappedDevice.open(mappedDevicePath,
123 std::ios::out | std::ios::binary | std::ios::trunc);
124 mappedDevice.close();
125 if (mappedDevice.fail())
126 {
127 throw std::runtime_error("Failed to open test mapped device");
128 }
129
130 return 0;
131 }
132
removeMappedDev()133 int removeMappedDev()
134 {
135 EXPECT_EQ(0, unlink(mappedDevicePath));
136
137 return 0;
138 }
139
140 /* Test case to format and then lock the LUKS device. */
TEST_F(EStoragedTest,FormatPass)141 TEST_F(EStoragedTest, FormatPass)
142 {
143 EXPECT_CALL(*mockCryptIface, cryptFormat(_, _, _, _, _, _, _, _)).Times(1);
144
145 EXPECT_CALL(*mockCryptIface, cryptKeyslotAddByVolumeKey(_, _, _, _, _, _))
146 .Times(1);
147
148 EXPECT_CALL(*mockCryptIface, cryptLoad(_, _, _)).Times(1);
149
150 EXPECT_CALL(*mockCryptIface, cryptActivateByPassphrase(_, _, _, _, _, _))
151 .WillOnce(&createMappedDev);
152
153 EXPECT_CALL(*mockFsIface, runMkfs(StrEq(esObject->getCryptDevicePath()),
154 ElementsAreArray(EStoragedTest::options)))
155 .WillOnce(Return(0));
156
157 EXPECT_CALL(*mockFsIface, runFsck(StrEq(esObject->getCryptDevicePath()),
158 StrEq("-t ext4 -p")))
159 .WillOnce(Return(0));
160
161 EXPECT_CALL(*mockFsIface, directoryExists(path(esObject->getMountPoint())))
162 .WillOnce(Return(false));
163
164 EXPECT_CALL(*mockFsIface, createDirectory(path(esObject->getMountPoint())))
165 .WillOnce(Return(true));
166
167 EXPECT_CALL(*mockFsIface,
168 doMount(StrEq(esObject->getCryptDevicePath()),
169 StrEq(esObject->getMountPoint()), _, _, _))
170 .WillOnce(Return(0));
171
172 EXPECT_CALL(*mockFsIface, doUnmount(StrEq(esObject->getMountPoint())))
173 .WillOnce(Return(0));
174
175 EXPECT_CALL(*mockFsIface, removeDirectory(path(esObject->getMountPoint())))
176 .WillOnce(Return(true));
177
178 EXPECT_CALL(*mockCryptIface, cryptDeactivate(_, _))
179 .WillOnce(&removeMappedDev);
180
181 /* Format the encrypted device. */
182 esObject->formatLuks(password, Volume::FilesystemType::ext4);
183 EXPECT_FALSE(esObject->isLocked());
184
185 esObject->lock();
186 EXPECT_TRUE(esObject->isLocked());
187 }
188
189 /*
190 * Test case where the mount point directory already exists, so it shouldn't
191 * try to create it.
192 */
TEST_F(EStoragedTest,MountPointExistsPass)193 TEST_F(EStoragedTest, MountPointExistsPass)
194 {
195 EXPECT_CALL(*mockCryptIface, cryptFormat(_, _, _, _, _, _, _, _)).Times(1);
196
197 EXPECT_CALL(*mockCryptIface, cryptKeyslotAddByVolumeKey(_, _, _, _, _, _))
198 .Times(1);
199
200 EXPECT_CALL(*mockCryptIface, cryptLoad(_, _, _)).Times(1);
201
202 EXPECT_CALL(*mockCryptIface, cryptActivateByPassphrase(_, _, _, _, _, _))
203 .WillOnce(&createMappedDev);
204
205 EXPECT_CALL(*mockFsIface, runMkfs(StrEq(esObject->getCryptDevicePath()),
206 ElementsAreArray(EStoragedTest::options)))
207 .WillOnce(Return(0));
208
209 EXPECT_CALL(*mockFsIface, runFsck(StrEq(esObject->getCryptDevicePath()),
210 StrEq("-t ext4 -p")))
211 .WillOnce(Return(0));
212
213 EXPECT_CALL(*mockFsIface, directoryExists(path(esObject->getMountPoint())))
214 .WillOnce(Return(true));
215
216 EXPECT_CALL(*mockFsIface, createDirectory(path(esObject->getMountPoint())))
217 .Times(0);
218
219 EXPECT_CALL(*mockFsIface,
220 doMount(StrEq(esObject->getCryptDevicePath()),
221 StrEq(esObject->getMountPoint()), _, _, _))
222 .WillOnce(Return(0));
223
224 EXPECT_CALL(*mockFsIface, doUnmount(StrEq(esObject->getMountPoint())))
225 .WillOnce(Return(0));
226
227 EXPECT_CALL(*mockFsIface, removeDirectory(path(esObject->getMountPoint())))
228 .WillOnce(Return(true));
229
230 EXPECT_CALL(*mockCryptIface, cryptDeactivate(_, _))
231 .WillOnce(&removeMappedDev);
232
233 /* Format the encrypted device. */
234 esObject->formatLuks(password, Volume::FilesystemType::ext4);
235 EXPECT_FALSE(esObject->isLocked());
236
237 esObject->lock();
238 EXPECT_TRUE(esObject->isLocked());
239 }
240
241 /* Test case where the device/file doesn't exist. */
TEST_F(EStoragedTest,FormatNoDeviceFail)242 TEST_F(EStoragedTest, FormatNoDeviceFail)
243 {
244 /* Delete the test file. */
245 EXPECT_EQ(0, unlink(testFileName));
246
247 EXPECT_THROW(esObject->formatLuks(password, Volume::FilesystemType::ext4),
248 ResourceNotFound);
249 EXPECT_TRUE(esObject->isLocked());
250
251 /* Create the test file again, so that the TearDown function works. */
252 testFile.open(testFileName,
253 std::ios::out | std::ios::binary | std::ios::trunc);
254 testFile.close();
255 }
256
257 /* Test case where we fail to format the LUKS device. */
TEST_F(EStoragedTest,FormatFail)258 TEST_F(EStoragedTest, FormatFail)
259 {
260 EXPECT_CALL(*mockCryptIface, cryptFormat(_, _, _, _, _, _, _, _))
261 .WillOnce(Return(-1));
262
263 EXPECT_THROW(esObject->formatLuks(password, Volume::FilesystemType::ext4),
264 InternalFailure);
265 EXPECT_TRUE(esObject->isLocked());
266 }
267
268 /* Test case where we fail to set the password for the LUKS device. */
TEST_F(EStoragedTest,AddKeyslotFail)269 TEST_F(EStoragedTest, AddKeyslotFail)
270 {
271 EXPECT_CALL(*mockCryptIface, cryptFormat(_, _, _, _, _, _, _, _)).Times(1);
272
273 EXPECT_CALL(*mockCryptIface, cryptKeyslotAddByVolumeKey(_, _, _, _, _, _))
274 .WillOnce(Return(-1));
275
276 EXPECT_THROW(esObject->formatLuks(password, Volume::FilesystemType::ext4),
277 InternalFailure);
278 EXPECT_TRUE(esObject->isLocked());
279 }
280
281 /* Test case where we fail to load the LUKS header. */
TEST_F(EStoragedTest,LoadLuksHeaderFail)282 TEST_F(EStoragedTest, LoadLuksHeaderFail)
283 {
284 EXPECT_CALL(*mockCryptIface, cryptFormat(_, _, _, _, _, _, _, _)).Times(1);
285
286 EXPECT_CALL(*mockCryptIface, cryptKeyslotAddByVolumeKey(_, _, _, _, _, _))
287 .Times(1);
288
289 EXPECT_CALL(*mockCryptIface, cryptLoad(_, _, _)).WillOnce(Return(-1));
290
291 EXPECT_THROW(esObject->formatLuks(password, Volume::FilesystemType::ext4),
292 InternalFailure);
293 EXPECT_TRUE(esObject->isLocked());
294 }
295
296 /* Test case where we fail to activate the LUKS device. */
TEST_F(EStoragedTest,ActivateFail)297 TEST_F(EStoragedTest, ActivateFail)
298 {
299 EXPECT_CALL(*mockCryptIface, cryptFormat(_, _, _, _, _, _, _, _)).Times(1);
300
301 EXPECT_CALL(*mockCryptIface, cryptKeyslotAddByVolumeKey(_, _, _, _, _, _))
302 .Times(1);
303
304 EXPECT_CALL(*mockCryptIface, cryptLoad(_, _, _)).Times(1);
305
306 EXPECT_CALL(*mockCryptIface, cryptActivateByPassphrase(_, _, _, _, _, _))
307 .WillOnce(Return(-1));
308
309 EXPECT_THROW(esObject->formatLuks(password, Volume::FilesystemType::ext4),
310 InternalFailure);
311 EXPECT_TRUE(esObject->isLocked());
312 }
313
314 /* Test case where we fail to create the filesystem. */
TEST_F(EStoragedTest,CreateFilesystemFail)315 TEST_F(EStoragedTest, CreateFilesystemFail)
316 {
317 EXPECT_CALL(*mockCryptIface, cryptFormat(_, _, _, _, _, _, _, _)).Times(1);
318
319 EXPECT_CALL(*mockCryptIface, cryptKeyslotAddByVolumeKey(_, _, _, _, _, _))
320 .Times(1);
321
322 EXPECT_CALL(*mockCryptIface, cryptLoad(_, _, _)).Times(1);
323
324 EXPECT_CALL(*mockCryptIface, cryptActivateByPassphrase(_, _, _, _, _, _))
325 .WillOnce(&createMappedDev);
326
327 EXPECT_CALL(*mockFsIface, runMkfs(StrEq(esObject->getCryptDevicePath()),
328 ElementsAreArray(EStoragedTest::options)))
329 .WillOnce(Return(-1));
330
331 EXPECT_THROW(esObject->formatLuks(password, Volume::FilesystemType::ext4),
332 InternalFailure);
333 EXPECT_FALSE(esObject->isLocked());
334
335 EXPECT_EQ(0, removeMappedDev());
336 }
337
338 /* Test case where we fail to create the mount point. */
TEST_F(EStoragedTest,CreateMountPointFail)339 TEST_F(EStoragedTest, CreateMountPointFail)
340 {
341 EXPECT_CALL(*mockCryptIface, cryptFormat(_, _, _, _, _, _, _, _)).Times(1);
342
343 EXPECT_CALL(*mockCryptIface, cryptKeyslotAddByVolumeKey(_, _, _, _, _, _))
344 .Times(1);
345
346 EXPECT_CALL(*mockCryptIface, cryptLoad(_, _, _)).Times(1);
347
348 EXPECT_CALL(*mockCryptIface, cryptActivateByPassphrase(_, _, _, _, _, _))
349 .WillOnce(&createMappedDev);
350
351 EXPECT_CALL(*mockFsIface, runMkfs(StrEq(esObject->getCryptDevicePath()),
352 ElementsAreArray(EStoragedTest::options)))
353 .WillOnce(Return(0));
354
355 EXPECT_CALL(*mockFsIface, runFsck(StrEq(esObject->getCryptDevicePath()),
356 StrEq("-t ext4 -p")))
357 .WillOnce(Return(0));
358
359 EXPECT_CALL(*mockFsIface, directoryExists(path(esObject->getMountPoint())))
360 .WillOnce(Return(false));
361
362 EXPECT_CALL(*mockFsIface, createDirectory(path(esObject->getMountPoint())))
363 .WillOnce(Return(false));
364
365 EXPECT_THROW(esObject->formatLuks(password, Volume::FilesystemType::ext4),
366 InternalFailure);
367 EXPECT_FALSE(esObject->isLocked());
368
369 EXPECT_EQ(0, removeMappedDev());
370 }
371
372 /* Test case where we fail to mount the filesystem. */
TEST_F(EStoragedTest,MountFail)373 TEST_F(EStoragedTest, MountFail)
374 {
375 EXPECT_CALL(*mockCryptIface, cryptFormat(_, _, _, _, _, _, _, _)).Times(1);
376
377 EXPECT_CALL(*mockCryptIface, cryptKeyslotAddByVolumeKey(_, _, _, _, _, _))
378 .Times(1);
379
380 EXPECT_CALL(*mockCryptIface, cryptLoad(_, _, _)).Times(1);
381
382 EXPECT_CALL(*mockCryptIface, cryptActivateByPassphrase(_, _, _, _, _, _))
383 .WillOnce(&createMappedDev);
384
385 EXPECT_CALL(*mockFsIface, runMkfs(StrEq(esObject->getCryptDevicePath()),
386 ElementsAreArray(EStoragedTest::options)))
387 .WillOnce(Return(0));
388
389 EXPECT_CALL(*mockFsIface, runFsck(StrEq(esObject->getCryptDevicePath()),
390 StrEq("-t ext4 -p")))
391 .WillOnce(Return(0));
392
393 EXPECT_CALL(*mockFsIface, directoryExists(path(esObject->getMountPoint())))
394 .WillOnce(Return(false));
395
396 EXPECT_CALL(*mockFsIface, createDirectory(path(esObject->getMountPoint())))
397 .WillOnce(Return(true));
398
399 EXPECT_CALL(*mockFsIface,
400 doMount(StrEq(esObject->getCryptDevicePath()),
401 StrEq(esObject->getMountPoint()), _, _, _))
402 .WillOnce(Return(-1));
403
404 EXPECT_CALL(*mockFsIface, removeDirectory(path(esObject->getMountPoint())))
405 .WillOnce(Return(true));
406
407 EXPECT_THROW(esObject->formatLuks(password, Volume::FilesystemType::ext4),
408 InternalFailure);
409 EXPECT_FALSE(esObject->isLocked());
410
411 EXPECT_EQ(0, removeMappedDev());
412 }
413
414 /* Test case where we fail to unmount the filesystem. */
TEST_F(EStoragedTest,UnmountFail)415 TEST_F(EStoragedTest, UnmountFail)
416 {
417 EXPECT_CALL(*mockCryptIface, cryptFormat(_, _, _, _, _, _, _, _)).Times(1);
418
419 EXPECT_CALL(*mockCryptIface, cryptKeyslotAddByVolumeKey(_, _, _, _, _, _))
420 .Times(1);
421
422 EXPECT_CALL(*mockCryptIface, cryptLoad(_, _, _)).Times(1);
423
424 EXPECT_CALL(*mockCryptIface, cryptActivateByPassphrase(_, _, _, _, _, _))
425 .WillOnce(&createMappedDev);
426
427 EXPECT_CALL(*mockFsIface, runMkfs(StrEq(esObject->getCryptDevicePath()),
428 ElementsAreArray(EStoragedTest::options)))
429 .WillOnce(Return(0));
430
431 EXPECT_CALL(*mockFsIface, runFsck(StrEq(esObject->getCryptDevicePath()),
432 StrEq("-t ext4 -p")))
433 .WillOnce(Return(0));
434
435 EXPECT_CALL(*mockFsIface, directoryExists(path(esObject->getMountPoint())))
436 .WillOnce(Return(false));
437
438 EXPECT_CALL(*mockFsIface, createDirectory(path(esObject->getMountPoint())))
439 .WillOnce(Return(true));
440
441 EXPECT_CALL(*mockFsIface,
442 doMount(StrEq(esObject->getCryptDevicePath()),
443 StrEq(esObject->getMountPoint()), _, _, _))
444 .WillOnce(Return(0));
445
446 EXPECT_CALL(*mockFsIface, doUnmount(StrEq(esObject->getMountPoint())))
447 .WillOnce(Return(-1));
448
449 esObject->formatLuks(password, Volume::FilesystemType::ext4);
450 EXPECT_FALSE(esObject->isLocked());
451
452 EXPECT_THROW(esObject->lock(), InternalFailure);
453 EXPECT_FALSE(esObject->isLocked());
454
455 EXPECT_EQ(0, removeMappedDev());
456 }
457
458 /* Test case where we fail to remove the mount point. */
TEST_F(EStoragedTest,RemoveMountPointFail)459 TEST_F(EStoragedTest, RemoveMountPointFail)
460 {
461 EXPECT_CALL(*mockCryptIface, cryptFormat(_, _, _, _, _, _, _, _)).Times(1);
462
463 EXPECT_CALL(*mockCryptIface, cryptKeyslotAddByVolumeKey(_, _, _, _, _, _))
464 .Times(1);
465
466 EXPECT_CALL(*mockCryptIface, cryptLoad(_, _, _)).Times(1);
467
468 EXPECT_CALL(*mockCryptIface, cryptActivateByPassphrase(_, _, _, _, _, _))
469 .WillOnce(&createMappedDev);
470
471 EXPECT_CALL(*mockFsIface, runMkfs(StrEq(esObject->getCryptDevicePath()),
472 ElementsAreArray(EStoragedTest::options)))
473 .WillOnce(Return(0));
474
475 EXPECT_CALL(*mockFsIface, runFsck(StrEq(esObject->getCryptDevicePath()),
476 StrEq("-t ext4 -p")))
477 .WillOnce(Return(0));
478
479 EXPECT_CALL(*mockFsIface, directoryExists(path(esObject->getMountPoint())))
480 .WillOnce(Return(false));
481
482 EXPECT_CALL(*mockFsIface, createDirectory(path(esObject->getMountPoint())))
483 .WillOnce(Return(true));
484
485 EXPECT_CALL(*mockFsIface,
486 doMount(StrEq(esObject->getCryptDevicePath()),
487 StrEq(esObject->getMountPoint()), _, _, _))
488 .WillOnce(Return(0));
489
490 EXPECT_CALL(*mockFsIface, doUnmount(StrEq(esObject->getMountPoint())))
491 .WillOnce(Return(0));
492
493 EXPECT_CALL(*mockFsIface, removeDirectory(path(esObject->getMountPoint())))
494 .WillOnce(Return(false));
495
496 esObject->formatLuks(password, Volume::FilesystemType::ext4);
497 EXPECT_FALSE(esObject->isLocked());
498
499 /* This will fail to remove the mount point. */
500 EXPECT_THROW(esObject->lock(), InternalFailure);
501 EXPECT_FALSE(esObject->isLocked());
502
503 EXPECT_EQ(0, removeMappedDev());
504 }
505
506 /* Test case where we fail to deactivate the LUKS device. */
TEST_F(EStoragedTest,DeactivateFail)507 TEST_F(EStoragedTest, DeactivateFail)
508 {
509 EXPECT_CALL(*mockCryptIface, cryptFormat(_, _, _, _, _, _, _, _)).Times(1);
510
511 EXPECT_CALL(*mockCryptIface, cryptKeyslotAddByVolumeKey(_, _, _, _, _, _))
512 .Times(1);
513
514 EXPECT_CALL(*mockCryptIface, cryptLoad(_, _, _)).Times(1);
515
516 EXPECT_CALL(*mockCryptIface, cryptActivateByPassphrase(_, _, _, _, _, _))
517 .WillOnce(&createMappedDev);
518
519 EXPECT_CALL(*mockFsIface, runMkfs(StrEq(esObject->getCryptDevicePath()),
520 ElementsAreArray(EStoragedTest::options)))
521 .WillOnce(Return(0));
522
523 EXPECT_CALL(*mockFsIface, runFsck(StrEq(esObject->getCryptDevicePath()),
524 StrEq("-t ext4 -p")))
525 .WillOnce(Return(0));
526
527 EXPECT_CALL(*mockFsIface, directoryExists(path(esObject->getMountPoint())))
528 .WillOnce(Return(false));
529
530 EXPECT_CALL(*mockFsIface, createDirectory(path(esObject->getMountPoint())))
531 .WillOnce(Return(true));
532
533 EXPECT_CALL(*mockFsIface,
534 doMount(StrEq(esObject->getCryptDevicePath()),
535 StrEq(esObject->getMountPoint()), _, _, _))
536 .WillOnce(Return(0));
537
538 EXPECT_CALL(*mockFsIface, doUnmount(StrEq(esObject->getMountPoint())))
539 .WillOnce(Return(0));
540
541 EXPECT_CALL(*mockFsIface, removeDirectory(path(esObject->getMountPoint())))
542 .WillOnce(Return(true));
543
544 EXPECT_CALL(*mockCryptIface, cryptDeactivate(_, _)).WillOnce(Return(-1));
545
546 /* Format the encrypted device. */
547 esObject->formatLuks(password, Volume::FilesystemType::ext4);
548 EXPECT_FALSE(esObject->isLocked());
549
550 EXPECT_THROW(esObject->lock(), InternalFailure);
551 EXPECT_FALSE(esObject->isLocked());
552
553 EXPECT_EQ(0, removeMappedDev());
554 }
555
556 /* Test case where we successfully change the password. */
TEST_F(EStoragedTest,ChangePasswordSuccess)557 TEST_F(EStoragedTest, ChangePasswordSuccess)
558 {
559 std::string newPasswordString("newPassword");
560 std::vector<uint8_t> newPassword(newPasswordString.begin(),
561 newPasswordString.end());
562
563 EXPECT_CALL(*mockCryptIface, cryptLoad(_, _, _)).Times(1);
564
565 EXPECT_CALL(*mockCryptIface,
566 cryptKeyslotChangeByPassphrase(
567 _, _, _, reinterpret_cast<const char*>(password.data()),
568 password.size(),
569 reinterpret_cast<const char*>(newPassword.data()),
570 newPassword.size()))
571 .WillOnce(Return(0));
572
573 /* Change the password for the LUKS-encrypted device. */
574 esObject->changePassword(password, newPassword);
575 }
576
577 /* Test case where we fail to change the password. */
TEST_F(EStoragedTest,ChangePasswordFail)578 TEST_F(EStoragedTest, ChangePasswordFail)
579 {
580 std::string newPasswordString("newPassword");
581 std::vector<uint8_t> newPassword(newPasswordString.begin(),
582 newPasswordString.end());
583
584 EXPECT_CALL(*mockCryptIface, cryptLoad(_, _, _)).Times(1);
585
586 EXPECT_CALL(*mockCryptIface,
587 cryptKeyslotChangeByPassphrase(
588 _, _, _, reinterpret_cast<const char*>(password.data()),
589 password.size(),
590 reinterpret_cast<const char*>(newPassword.data()),
591 newPassword.size()))
592 .WillOnce(Return(-1));
593
594 EXPECT_THROW(esObject->changePassword(password, newPassword),
595 InternalFailure);
596 }
597
TEST(EMMCBackgroundOperation,IoCtlFailure)598 TEST(EMMCBackgroundOperation, IoCtlFailure)
599 {
600 std::unique_ptr<FdMock> mockFd = std::make_unique<FdMock>();
601
602 EXPECT_CALL(*mockFd, ioctl(MMC_IOC_CMD, testing::_)).WillOnce(Return(1));
603 EXPECT_THROW(estoraged::EStoraged::enableBackgroundOperation(
604 std::move(mockFd), "/dev/test"),
605 estoraged::BkopsIoctlFailure);
606 }
607
TEST(EMMCBackgroundOperation,BkOpsNotSupported)608 TEST(EMMCBackgroundOperation, BkOpsNotSupported)
609 {
610 std::unique_ptr<FdMock> mockFd = std::make_unique<FdMock>();
611
612 EXPECT_CALL(*mockFd, ioctl(MMC_IOC_CMD, testing::_)).WillOnce(Return(0));
613 EXPECT_FALSE(estoraged::EStoraged::enableBackgroundOperation(
614 std::move(mockFd), "/dev/test"));
615 }
616
TEST(EMMCBackgroundOperation,EnableFailure)617 TEST(EMMCBackgroundOperation, EnableFailure)
618 {
619 std::unique_ptr<FdMock> mockFd = std::make_unique<FdMock>();
620
621 EXPECT_CALL(*mockFd, ioctl(MMC_IOC_CMD, testing::_))
622 .WillOnce(testing::Invoke([](unsigned long, void* data) {
623 struct mmc_ioc_cmd* idata = static_cast<struct mmc_ioc_cmd*>(data);
624 EXPECT_EQ(idata->opcode, MMC_SEND_EXT_CSD);
625 EXPECT_EQ(idata->blksz, 512);
626 EXPECT_EQ(idata->flags, MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC);
627
628 // Set specific bytes to simulate a hardware state
629 // NOLINTNEXTLINE(performance-no-int-to-ptr)
630 *reinterpret_cast<uint8_t*>(idata->data_ptr + 502) =
631 0x01; // BKOPS_SUPPORT = Supported
632 // NOLINTNEXTLINE(performance-no-int-to-ptr)
633 *reinterpret_cast<uint8_t*>(idata->data_ptr + 163) =
634 0x00; // BKOPS_EN = Disabled
635 return 0; // Success
636 }))
637 .WillOnce(Return(1));
638 EXPECT_THROW(estoraged::EStoraged::enableBackgroundOperation(
639 std::move(mockFd), "/dev/test"),
640 estoraged::BkopsEnableFailure);
641 }
642
TEST(EMMCBackgroundOperation,AlreadyEnabled)643 TEST(EMMCBackgroundOperation, AlreadyEnabled)
644 {
645 std::unique_ptr<FdMock> mockFd = std::make_unique<FdMock>();
646
647 EXPECT_CALL(*mockFd, ioctl(MMC_IOC_CMD, testing::_))
648 .WillOnce(testing::Invoke([](unsigned long, void* data) {
649 struct mmc_ioc_cmd* idata = static_cast<struct mmc_ioc_cmd*>(data);
650 EXPECT_EQ(idata->opcode, MMC_SEND_EXT_CSD);
651 EXPECT_EQ(idata->blksz, 512);
652 EXPECT_EQ(idata->flags, MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC);
653
654 // Set specific bytes to simulate a hardware state
655 // NOLINTNEXTLINE(performance-no-int-to-ptr)
656 *reinterpret_cast<uint8_t*>(idata->data_ptr + 502) =
657 0x01; // BKOPS_SUPPORT = Supported
658 // NOLINTNEXTLINE(performance-no-int-to-ptr)
659 *reinterpret_cast<uint8_t*>(idata->data_ptr + 163) =
660 EXT_CSD_MANUAL_BKOPS_MASK; // BKOPS_EN = Manual Mode
661 return 0; // Success
662 }));
663 EXPECT_FALSE(estoraged::EStoraged::enableBackgroundOperation(
664 std::move(mockFd), "/dev/test"));
665 }
666
TEST(EMMCBackgroundOperation,EnableSuccess)667 TEST(EMMCBackgroundOperation, EnableSuccess)
668 {
669 std::unique_ptr<FdMock> mockFd = std::make_unique<FdMock>();
670
671 EXPECT_CALL(*mockFd, ioctl(MMC_IOC_CMD, testing::_))
672 .WillOnce(testing::Invoke([](unsigned long, void* data) {
673 struct mmc_ioc_cmd* idata = static_cast<struct mmc_ioc_cmd*>(data);
674 EXPECT_EQ(idata->opcode, MMC_SEND_EXT_CSD);
675 EXPECT_EQ(idata->blksz, 512);
676 EXPECT_EQ(idata->flags, MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC);
677
678 // Set specific bytes to simulate a hardware state
679 // NOLINTNEXTLINE(performance-no-int-to-ptr)
680 *reinterpret_cast<uint8_t*>(idata->data_ptr + 502) =
681 0x01; // BKOPS_SUPPORT = Supported
682 // NOLINTNEXTLINE(performance-no-int-to-ptr)
683 *reinterpret_cast<uint8_t*>(idata->data_ptr + 163) =
684 0x00; // BKOPS_EN = Disabled
685 return 0; // Success
686 }))
687 .WillOnce(testing::Invoke([](unsigned long, void* data) {
688 struct mmc_ioc_cmd* idata = static_cast<struct mmc_ioc_cmd*>(data);
689 EXPECT_EQ(idata->opcode, MMC_SWITCH);
690 EXPECT_EQ(idata->arg, (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
691 (EXT_CSD_BKOPS_EN << 16) |
692 (EXT_CSD_MANUAL_BKOPS_MASK << 8) |
693 EXT_CSD_CMD_SET_NORMAL);
694 EXPECT_EQ(idata->flags, MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC);
695 return 0; // Success
696 }));
697 EXPECT_TRUE(estoraged::EStoraged::enableBackgroundOperation(
698 std::move(mockFd), "/dev/test"));
699 }
700
701 } // namespace estoraged_test
702