blob: adad5abd07d5fa2956088f8ca43d20eb961afe2d [file] [log] [blame]
John Wedig2098dab2021-09-14 13:56:28 -07001
2#include "estoraged.hpp"
3
John Edward Broadbent59dffa62022-01-13 17:41:32 -08004#include "cryptErase.hpp"
John Wedigb810c922021-11-17 16:38:03 -08005#include "cryptsetupInterface.hpp"
Willy Tu30bfe8e2025-12-30 19:47:52 +00006#include "estoraged_conf.hpp"
John Edward Broadbent7f2ab642021-11-11 21:00:38 -08007#include "pattern.hpp"
John Edward Broadbent605085a2021-11-05 13:45:45 -07008#include "sanitize.hpp"
John Edward Broadbente6ffe702021-10-14 14:03:11 -07009#include "verifyDriveGeometry.hpp"
John Edward Broadbent4bc8a102021-12-30 16:11:49 -080010#include "zero.hpp"
John Edward Broadbent4e13b0a2021-11-15 15:21:59 -080011
John Wedigb810c922021-11-17 16:38:03 -080012#include <libcryptsetup.h>
Willy Tuda5aa612025-12-18 07:32:34 +000013#include <linux/mmc/core.h>
14#include <linux/mmc/ioctl.h>
15#include <linux/mmc/mmc.h>
John Wedigb810c922021-11-17 16:38:03 -080016#include <openssl/rand.h>
Willy Tuda5aa612025-12-18 07:32:34 +000017#include <sys/ioctl.h>
John Wedigb810c922021-11-17 16:38:03 -080018
19#include <phosphor-logging/lg2.hpp>
John Wedig67a47442022-04-05 17:21:29 -070020#include <sdbusplus/asio/object_server.hpp>
Willy Tuda5aa612025-12-18 07:32:34 +000021#include <stdplus/fd/create.hpp>
22#include <stdplus/fd/managed.hpp>
John Wedig972c3fa2021-12-29 17:30:41 -080023#include <xyz/openbmc_project/Common/error.hpp>
John Wedigb810c922021-11-17 16:38:03 -080024
Ed Tanous82897c32022-02-21 14:11:59 -080025#include <cstdlib>
John Wedigb810c922021-11-17 16:38:03 -080026#include <filesystem>
John Wedig2098dab2021-09-14 13:56:28 -070027#include <iostream>
John Wedig67a47442022-04-05 17:21:29 -070028#include <string>
John Wedigb810c922021-11-17 16:38:03 -080029#include <string_view>
John Wedig67a47442022-04-05 17:21:29 -070030#include <utility>
John Wedig2098dab2021-09-14 13:56:28 -070031#include <vector>
32
33namespace estoraged
34{
35
John Wedig6c0d8ce2022-04-22 14:00:43 -070036using Association = std::tuple<std::string, std::string, std::string>;
John Wedig1755d1b2025-07-21 22:26:30 +000037using sdbusplus::asio::PropertyPermission;
John Wedig972c3fa2021-12-29 17:30:41 -080038using sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
John Wedig972c3fa2021-12-29 17:30:41 -080039using sdbusplus::xyz::openbmc_project::Common::Error::UnsupportedRequest;
John Edward Broadbent91c1ec12022-05-20 16:51:43 -070040using sdbusplus::xyz::openbmc_project::Inventory::Item::server::Drive;
John Wedig67a47442022-04-05 17:21:29 -070041using sdbusplus::xyz::openbmc_project::Inventory::Item::server::Volume;
John Wedigb810c922021-11-17 16:38:03 -080042
Patrick Williams15b63e12024-08-16 15:22:01 -040043EStoraged::EStoraged(
Willy Tuda5aa612025-12-18 07:32:34 +000044 std::unique_ptr<stdplus::Fd> fd, sdbusplus::asio::object_server& server,
45 const std::string& configPath, const std::string& devPath,
46 const std::string& luksName, uint64_t size, uint8_t lifeTime,
47 const std::string& partNumber, const std::string& serialNumber,
48 const std::string& locationCode, uint64_t eraseMaxGeometry,
49 uint64_t eraseMinGeometry, const std::string& driveType,
50 const std::string& driveProtocol,
Patrick Williams15b63e12024-08-16 15:22:01 -040051 std::unique_ptr<CryptsetupInterface> cryptInterface,
52 std::unique_ptr<FilesystemInterface> fsInterface) :
53 devPath(devPath), containerName(luksName),
54 mountPoint("/mnt/" + luksName + "_fs"), eraseMaxGeometry(eraseMaxGeometry),
55 eraseMinGeometry(eraseMinGeometry), cryptIface(std::move(cryptInterface)),
56 fsIface(std::move(fsInterface)),
John Wedig2443a022023-03-17 13:42:32 -070057 cryptDevicePath(cryptIface->cryptGetDir() + "/" + luksName),
John Edward Broadbent6771c692022-06-22 19:49:27 -070058 objectServer(server)
John Wedig67a47442022-04-05 17:21:29 -070059{
Willy Tuda5aa612025-12-18 07:32:34 +000060 try
61 {
Willy Tu30bfe8e2025-12-30 19:47:52 +000062 changeHsTimingIfNeeded(fd.get(), devPath, partNumber);
63 lg2::info("Change HS_TIMING for {DEV} with {PARTNUMBER}", "DEV",
64 devPath, "PARTNUMBER", partNumber);
65 }
66 catch (const HsModeError& e)
67 {
68 lg2::error(e.what());
69 }
70
71 try
72 {
Willy Tuda5aa612025-12-18 07:32:34 +000073 enableBackgroundOperation(std::move(fd), devPath);
74 }
75 catch (const BkopsError& e)
76 {
77 lg2::error("Failed to enable background operation for {PATH}: {ERROR}",
78 "PATH", devPath, "ERROR", e.what());
79 }
80
John Wedig67a47442022-04-05 17:21:29 -070081 /* Get the filename of the device (without "/dev/"). */
82 std::string deviceName = std::filesystem::path(devPath).filename().string();
83 /* DBus object path */
Patrick Williams15b63e12024-08-16 15:22:01 -040084 std::string objectPath =
85 "/xyz/openbmc_project/inventory/storage/" + deviceName;
John Wedig67a47442022-04-05 17:21:29 -070086
87 /* Add Volume interface. */
88 volumeInterface = objectServer.add_interface(
John Wedig6c0d8ce2022-04-22 14:00:43 -070089 objectPath, "xyz.openbmc_project.Inventory.Item.Volume");
John Wedig67a47442022-04-05 17:21:29 -070090 volumeInterface->register_method(
91 "FormatLuks", [this](const std::vector<uint8_t>& password,
92 Volume::FilesystemType type) {
Patrick Williams15b63e12024-08-16 15:22:01 -040093 this->formatLuks(password, type);
94 });
Patrick Williamsff1b64f2023-10-20 11:19:56 -050095 volumeInterface->register_method(
96 "Erase",
97 [this](Volume::EraseMethod eraseType) { this->erase(eraseType); });
John Wedig67a47442022-04-05 17:21:29 -070098 volumeInterface->register_method("Lock", [this]() { this->lock(); });
Patrick Williamsff1b64f2023-10-20 11:19:56 -050099 volumeInterface->register_method(
100 "Unlock",
101 [this](std::vector<uint8_t>& password) { this->unlock(password); });
John Wedig67a47442022-04-05 17:21:29 -0700102 volumeInterface->register_method(
103 "ChangePassword", [this](const std::vector<uint8_t>& oldPassword,
104 const std::vector<uint8_t>& newPassword) {
Patrick Williams15b63e12024-08-16 15:22:01 -0400105 this->changePassword(oldPassword, newPassword);
106 });
John Wedig67a47442022-04-05 17:21:29 -0700107 volumeInterface->register_property_r(
108 "Locked", lockedProperty, sdbusplus::vtable::property_::emits_change,
109 [this](bool& value) {
Patrick Williams15b63e12024-08-16 15:22:01 -0400110 value = this->isLocked();
111 return value;
112 });
John Wedig67a47442022-04-05 17:21:29 -0700113
114 /* Add Drive interface. */
115 driveInterface = objectServer.add_interface(
John Wedig6c0d8ce2022-04-22 14:00:43 -0700116 objectPath, "xyz.openbmc_project.Inventory.Item.Drive");
John Wedig67a47442022-04-05 17:21:29 -0700117 driveInterface->register_property("Capacity", size);
John Wedig1755d1b2025-07-21 22:26:30 +0000118 /* The lifetime property is read/write only for testing purposes. */
119 driveInterface->register_property("PredictedMediaLifeLeftPercent", lifeTime,
120 PropertyPermission::readWrite);
John Wedigd7be42b2024-01-19 16:07:19 -0800121 driveInterface->register_property(
122 "Type",
123 "xyz.openbmc_project.Inventory.Item.Drive.DriveType." + driveType);
John Wedigc0d66eb2024-02-26 15:54:47 -0800124 driveInterface->register_property(
125 "Protocol", "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol." +
126 driveProtocol);
John Edward Broadbent14aee772022-04-20 13:46:48 -0700127 /* This registers the Locked property for the Drives interface.
128 * Now it is the same as the volume Locked property */
129 driveInterface->register_property_r(
130 "Locked", lockedProperty, sdbusplus::vtable::property_::emits_change,
131 [this](bool& value) {
Patrick Williams15b63e12024-08-16 15:22:01 -0400132 value = this->isLocked();
133 return value;
134 });
John Wedig67a47442022-04-05 17:21:29 -0700135
John Edward Broadbent91c1ec12022-05-20 16:51:43 -0700136 driveInterface->register_property_r(
137 "EncryptionStatus", encryptionStatus,
138 sdbusplus::vtable::property_::emits_change,
139 [this](Drive::DriveEncryptionState& value) {
Patrick Williams15b63e12024-08-16 15:22:01 -0400140 value = this->findEncryptionStatus();
141 return value;
142 });
John Edward Broadbent91c1ec12022-05-20 16:51:43 -0700143
John Edward Broadbent49796412022-06-22 18:31:52 -0700144 embeddedLocationInterface = objectServer.add_interface(
145 objectPath, "xyz.openbmc_project.Inventory.Connector.Embedded");
John Edward Broadbent740e94b2022-06-10 19:42:30 -0700146
Rahul Kapoor19825052023-05-27 01:52:23 +0000147 if (!locationCode.empty())
148 {
149 locationCodeInterface = objectServer.add_interface(
150 objectPath, "xyz.openbmc_project.Inventory.Decorator.LocationCode");
151 locationCodeInterface->register_property("LocationCode", locationCode);
152 locationCodeInterface->initialize();
153 }
154
John Wedigb4838302022-07-22 13:51:16 -0700155 /* Add Asset interface. */
156 assetInterface = objectServer.add_interface(
157 objectPath, "xyz.openbmc_project.Inventory.Decorator.Asset");
158 assetInterface->register_property("PartNumber", partNumber);
159 assetInterface->register_property("SerialNumber", serialNumber);
160
John Wedig67a47442022-04-05 17:21:29 -0700161 volumeInterface->initialize();
162 driveInterface->initialize();
John Edward Broadbent49796412022-06-22 18:31:52 -0700163 embeddedLocationInterface->initialize();
John Wedigb4838302022-07-22 13:51:16 -0700164 assetInterface->initialize();
John Wedig6c0d8ce2022-04-22 14:00:43 -0700165
166 /* Set up the association between chassis and drive. */
167 association = objectServer.add_interface(
168 objectPath, "xyz.openbmc_project.Association.Definitions");
169
170 std::vector<Association> associations;
171 associations.emplace_back("chassis", "drive",
172 std::filesystem::path(configPath).parent_path());
173 association->register_property("Associations", associations);
174 association->initialize();
John Wedig67a47442022-04-05 17:21:29 -0700175}
176
177EStoraged::~EStoraged()
178{
179 objectServer.remove_interface(volumeInterface);
180 objectServer.remove_interface(driveInterface);
John Edward Broadbent49796412022-06-22 18:31:52 -0700181 objectServer.remove_interface(embeddedLocationInterface);
John Wedigb4838302022-07-22 13:51:16 -0700182 objectServer.remove_interface(assetInterface);
John Wedig6c0d8ce2022-04-22 14:00:43 -0700183 objectServer.remove_interface(association);
Rahul Kapoor19825052023-05-27 01:52:23 +0000184
185 if (locationCodeInterface != nullptr)
186 {
187 objectServer.remove_interface(locationCodeInterface);
188 }
John Wedig67a47442022-04-05 17:21:29 -0700189}
190
191void EStoraged::formatLuks(const std::vector<uint8_t>& password,
192 Volume::FilesystemType type)
John Wedig2098dab2021-09-14 13:56:28 -0700193{
John Edward Broadbent4e13b0a2021-11-15 15:21:59 -0800194 std::string msg = "OpenBMC.0.1.DriveFormat";
195 lg2::info("Starting format", "REDFISH_MESSAGE_ID", msg);
John Wedigb810c922021-11-17 16:38:03 -0800196
John Wedig67a47442022-04-05 17:21:29 -0700197 if (type != Volume::FilesystemType::ext4)
John Wedig972c3fa2021-12-29 17:30:41 -0800198 {
199 lg2::error("Only ext4 filesystems are supported currently",
200 "REDFISH_MESSAGE_ID", std::string("OpenBMC.0.1.FormatFail"));
201 throw UnsupportedRequest();
202 }
203
John Edward Broadbentb2c86be2022-04-15 11:45:53 -0700204 formatLuksDev(password);
205 activateLuksDev(password);
John Wedigb810c922021-11-17 16:38:03 -0800206
207 createFilesystem();
208 mountFilesystem();
John Wedig2098dab2021-09-14 13:56:28 -0700209}
210
John Wedig67a47442022-04-05 17:21:29 -0700211void EStoraged::erase(Volume::EraseMethod inEraseMethod)
John Wedig2098dab2021-09-14 13:56:28 -0700212{
213 std::cerr << "Erasing encrypted eMMC" << std::endl;
John Edward Broadbente6ffe702021-10-14 14:03:11 -0700214 lg2::info("Starting erase", "REDFISH_MESSAGE_ID",
215 std::string("OpenBMC.0.1.DriveErase"));
216 switch (inEraseMethod)
217 {
John Wedig67a47442022-04-05 17:21:29 -0700218 case Volume::EraseMethod::CryptoErase:
John Edward Broadbente6ffe702021-10-14 14:03:11 -0700219 {
John Edward Broadbent59dffa62022-01-13 17:41:32 -0800220 CryptErase myCryptErase(devPath);
221 myCryptErase.doErase();
John Edward Broadbente6ffe702021-10-14 14:03:11 -0700222 break;
223 }
John Wedig67a47442022-04-05 17:21:29 -0700224 case Volume::EraseMethod::VerifyGeometry:
John Edward Broadbente6ffe702021-10-14 14:03:11 -0700225 {
226 VerifyDriveGeometry myVerifyGeometry(devPath);
Tom Tung043af592023-11-24 13:37:05 +0800227 myVerifyGeometry.geometryOkay(eraseMaxGeometry, eraseMinGeometry);
John Edward Broadbente6ffe702021-10-14 14:03:11 -0700228 break;
229 }
John Wedig67a47442022-04-05 17:21:29 -0700230 case Volume::EraseMethod::LogicalOverWrite:
John Edward Broadbente6ffe702021-10-14 14:03:11 -0700231 {
John Edward Broadbent7f2ab642021-11-11 21:00:38 -0800232 Pattern myErasePattern(devPath);
John Edward Broadbenta6e3b992022-03-17 14:33:15 -0700233 myErasePattern.writePattern();
John Edward Broadbente6ffe702021-10-14 14:03:11 -0700234 break;
235 }
John Wedig67a47442022-04-05 17:21:29 -0700236 case Volume::EraseMethod::LogicalVerify:
John Edward Broadbente6ffe702021-10-14 14:03:11 -0700237 {
John Edward Broadbent7f2ab642021-11-11 21:00:38 -0800238 Pattern myErasePattern(devPath);
John Edward Broadbenta6e3b992022-03-17 14:33:15 -0700239 myErasePattern.verifyPattern();
John Edward Broadbente6ffe702021-10-14 14:03:11 -0700240 break;
241 }
John Wedig67a47442022-04-05 17:21:29 -0700242 case Volume::EraseMethod::VendorSanitize:
John Edward Broadbente6ffe702021-10-14 14:03:11 -0700243 {
John Edward Broadbent605085a2021-11-05 13:45:45 -0700244 Sanitize mySanitize(devPath);
245 mySanitize.doSanitize();
John Edward Broadbente6ffe702021-10-14 14:03:11 -0700246 break;
247 }
John Wedig67a47442022-04-05 17:21:29 -0700248 case Volume::EraseMethod::ZeroOverWrite:
John Edward Broadbente6ffe702021-10-14 14:03:11 -0700249 {
John Edward Broadbent4bc8a102021-12-30 16:11:49 -0800250 Zero myZero(devPath);
John Edward Broadbenta6e3b992022-03-17 14:33:15 -0700251 myZero.writeZero();
John Edward Broadbente6ffe702021-10-14 14:03:11 -0700252 break;
253 }
John Wedig67a47442022-04-05 17:21:29 -0700254 case Volume::EraseMethod::ZeroVerify:
John Edward Broadbente6ffe702021-10-14 14:03:11 -0700255 {
John Edward Broadbent4bc8a102021-12-30 16:11:49 -0800256 Zero myZero(devPath);
John Edward Broadbenta6e3b992022-03-17 14:33:15 -0700257 myZero.verifyZero();
John Edward Broadbente6ffe702021-10-14 14:03:11 -0700258 break;
259 }
John Wedig67a47442022-04-05 17:21:29 -0700260 case Volume::EraseMethod::SecuredLocked:
John Edward Broadbente6ffe702021-10-14 14:03:11 -0700261 {
John Wedig47cd7992022-10-05 15:45:11 -0700262 if (!isLocked())
John Edward Broadbentf59b7292022-02-15 15:07:15 -0800263 {
264 lock();
265 }
266 // TODO: implement hardware locking
267 // Until that is done, we can lock using eStoraged::lock()
John Edward Broadbente6ffe702021-10-14 14:03:11 -0700268 break;
269 }
270 }
John Wedig2098dab2021-09-14 13:56:28 -0700271}
272
Ed Tanous82897c32022-02-21 14:11:59 -0800273void EStoraged::lock()
John Wedig2098dab2021-09-14 13:56:28 -0700274{
John Edward Broadbent4e13b0a2021-11-15 15:21:59 -0800275 std::string msg = "OpenBMC.0.1.DriveLock";
276 lg2::info("Starting lock", "REDFISH_MESSAGE_ID", msg);
John Wedigb810c922021-11-17 16:38:03 -0800277
278 unmountFilesystem();
279 deactivateLuksDev();
John Wedig2098dab2021-09-14 13:56:28 -0700280}
281
Ed Tanous82897c32022-02-21 14:11:59 -0800282void EStoraged::unlock(std::vector<uint8_t> password)
John Wedig2098dab2021-09-14 13:56:28 -0700283{
John Edward Broadbent4e13b0a2021-11-15 15:21:59 -0800284 std::string msg = "OpenBMC.0.1.DriveUnlock";
285 lg2::info("Starting unlock", "REDFISH_MESSAGE_ID", msg);
John Wedigb810c922021-11-17 16:38:03 -0800286
John Edward Broadbentb2c86be2022-04-15 11:45:53 -0700287 activateLuksDev(std::move(password));
John Wedigb810c922021-11-17 16:38:03 -0800288 mountFilesystem();
John Wedig2098dab2021-09-14 13:56:28 -0700289}
290
John Wedig8d5a3a02022-09-29 15:25:58 -0700291void EStoraged::changePassword(const std::vector<uint8_t>& oldPassword,
292 const std::vector<uint8_t>& newPassword)
John Wedig2098dab2021-09-14 13:56:28 -0700293{
John Edward Broadbente6ffe702021-10-14 14:03:11 -0700294 lg2::info("Starting change password", "REDFISH_MESSAGE_ID",
295 std::string("OpenBMC.0.1.DrivePasswordChanged"));
John Wedig8d5a3a02022-09-29 15:25:58 -0700296
297 CryptHandle cryptHandle = loadLuksHeader();
298
299 int retval = cryptIface->cryptKeyslotChangeByPassphrase(
300 cryptHandle.get(), CRYPT_ANY_SLOT, CRYPT_ANY_SLOT,
301 reinterpret_cast<const char*>(oldPassword.data()), oldPassword.size(),
302 reinterpret_cast<const char*>(newPassword.data()), newPassword.size());
303 if (retval < 0)
304 {
305 lg2::error("Failed to change password", "REDFISH_MESSAGE_ID",
306 std::string("OpenBMC.0.1.DrivePasswordChangeFail"));
307 throw InternalFailure();
308 }
309
310 lg2::info("Successfully changed password for {DEV}", "DEV", devPath,
311 "REDFISH_MESSAGE_ID",
312 std::string("OpenBMC.0.1.DrivePasswordChangeSuccess"));
John Wedig2098dab2021-09-14 13:56:28 -0700313}
314
Ed Tanous82897c32022-02-21 14:11:59 -0800315bool EStoraged::isLocked() const
John Wedigb810c922021-11-17 16:38:03 -0800316{
John Wedig2443a022023-03-17 13:42:32 -0700317 /*
318 * Check if the mapped virtual device exists. If it exists, the LUKS volume
319 * is unlocked.
320 */
321 try
322 {
323 std::filesystem::path mappedDevicePath(cryptDevicePath);
324 return (std::filesystem::exists(mappedDevicePath) == false);
325 }
326 catch (const std::exception& e)
327 {
328 lg2::error("Failed to query locked status: {EXCEPT}", "EXCEPT",
329 e.what(), "REDFISH_MESSAGE_ID",
330 std::string("OpenBMC.0.1.IsLockedFail"));
331 /* If we couldn't query the filesystem path, assume unlocked. */
332 return false;
333 }
John Wedigb810c922021-11-17 16:38:03 -0800334}
335
Ed Tanous82897c32022-02-21 14:11:59 -0800336std::string_view EStoraged::getMountPoint() const
John Wedigb810c922021-11-17 16:38:03 -0800337{
338 return mountPoint;
339}
340
John Edward Broadbentb2c86be2022-04-15 11:45:53 -0700341void EStoraged::formatLuksDev(std::vector<uint8_t> password)
John Wedigb810c922021-11-17 16:38:03 -0800342{
343 lg2::info("Formatting device {DEV}", "DEV", devPath, "REDFISH_MESSAGE_ID",
344 std::string("OpenBMC.0.1.FormatLuksDev"));
345
346 /* Generate the volume key. */
347 const std::size_t keySize = 64;
348 std::vector<uint8_t> volumeKey(keySize);
349 if (RAND_bytes(volumeKey.data(), keySize) != 1)
350 {
351 lg2::error("Failed to create volume key", "REDFISH_MESSAGE_ID",
352 std::string("OpenBMC.0.1.FormatLuksDevFail"));
John Wedig972c3fa2021-12-29 17:30:41 -0800353 throw InternalFailure();
John Wedigb810c922021-11-17 16:38:03 -0800354 }
John Edward Broadbentb2c86be2022-04-15 11:45:53 -0700355
356 /* Create the handle. */
357 CryptHandle cryptHandle(devPath);
358
John Wedigb810c922021-11-17 16:38:03 -0800359 /* Format the LUKS encrypted device. */
John Edward Broadbentb2c86be2022-04-15 11:45:53 -0700360 int retval = cryptIface->cryptFormat(
361 cryptHandle.get(), CRYPT_LUKS2, "aes", "xts-plain64", nullptr,
362 reinterpret_cast<const char*>(volumeKey.data()), volumeKey.size(),
363 nullptr);
John Wedigb810c922021-11-17 16:38:03 -0800364 if (retval < 0)
365 {
366 lg2::error("Failed to format encrypted device: {RETVAL}", "RETVAL",
367 retval, "REDFISH_MESSAGE_ID",
368 std::string("OpenBMC.0.1.FormatLuksDevFail"));
John Wedig972c3fa2021-12-29 17:30:41 -0800369 throw InternalFailure();
John Wedigb810c922021-11-17 16:38:03 -0800370 }
371
John Wedigb810c922021-11-17 16:38:03 -0800372 /* Set the password. */
373 retval = cryptIface->cryptKeyslotAddByVolumeKey(
John Edward Broadbentb2c86be2022-04-15 11:45:53 -0700374 cryptHandle.get(), CRYPT_ANY_SLOT, nullptr, 0,
John Wedigb810c922021-11-17 16:38:03 -0800375 reinterpret_cast<const char*>(password.data()), password.size());
376
377 if (retval < 0)
378 {
379 lg2::error("Failed to set encryption password", "REDFISH_MESSAGE_ID",
380 std::string("OpenBMC.0.1.FormatLuksDevFail"));
John Wedig972c3fa2021-12-29 17:30:41 -0800381 throw InternalFailure();
John Wedigb810c922021-11-17 16:38:03 -0800382 }
383
384 lg2::info("Encrypted device {DEV} successfully formatted", "DEV", devPath,
385 "REDFISH_MESSAGE_ID",
386 std::string("OpenBMC.0.1.FormatLuksDevSuccess"));
387}
388
John Edward Broadbent91c1ec12022-05-20 16:51:43 -0700389CryptHandle EStoraged::loadLuksHeader()
John Wedigb810c922021-11-17 16:38:03 -0800390{
John Edward Broadbentb2c86be2022-04-15 11:45:53 -0700391 CryptHandle cryptHandle(devPath);
392
393 int retval = cryptIface->cryptLoad(cryptHandle.get(), CRYPT_LUKS2, nullptr);
John Wedigb810c922021-11-17 16:38:03 -0800394 if (retval < 0)
395 {
396 lg2::error("Failed to load LUKS header: {RETVAL}", "RETVAL", retval,
397 "REDFISH_MESSAGE_ID",
398 std::string("OpenBMC.0.1.ActivateLuksDevFail"));
John Wedig972c3fa2021-12-29 17:30:41 -0800399 throw InternalFailure();
John Wedigb810c922021-11-17 16:38:03 -0800400 }
John Edward Broadbent91c1ec12022-05-20 16:51:43 -0700401 return cryptHandle;
402}
John Wedigb810c922021-11-17 16:38:03 -0800403
John Edward Broadbent91c1ec12022-05-20 16:51:43 -0700404Drive::DriveEncryptionState EStoraged::findEncryptionStatus()
405{
406 try
407 {
408 loadLuksHeader();
409 return Drive::DriveEncryptionState::Encrypted;
410 }
411 catch (...)
412 {
Hao Zhou0cec4282024-03-12 22:16:16 +0000413 return Drive::DriveEncryptionState::Unencrypted;
John Edward Broadbent91c1ec12022-05-20 16:51:43 -0700414 }
415}
416
417void EStoraged::activateLuksDev(std::vector<uint8_t> password)
418{
419 lg2::info("Activating LUKS dev {DEV}", "DEV", devPath, "REDFISH_MESSAGE_ID",
420 std::string("OpenBMC.0.1.ActivateLuksDev"));
421
422 /* Create the handle. */
423 CryptHandle cryptHandle = loadLuksHeader();
424
425 int retval = cryptIface->cryptActivateByPassphrase(
John Edward Broadbentb2c86be2022-04-15 11:45:53 -0700426 cryptHandle.get(), containerName.c_str(), CRYPT_ANY_SLOT,
Rom Lemarchand530ce1e2025-12-16 21:45:08 +0000427 reinterpret_cast<const char*>(password.data()), password.size(),
428 CRYPT_ACTIVATE_ALLOW_DISCARDS);
John Wedigb810c922021-11-17 16:38:03 -0800429
430 if (retval < 0)
431 {
432 lg2::error("Failed to activate LUKS dev: {RETVAL}", "RETVAL", retval,
433 "REDFISH_MESSAGE_ID",
434 std::string("OpenBMC.0.1.ActivateLuksDevFail"));
John Wedig972c3fa2021-12-29 17:30:41 -0800435 throw InternalFailure();
John Wedigb810c922021-11-17 16:38:03 -0800436 }
437
John Wedigb810c922021-11-17 16:38:03 -0800438 lg2::info("Successfully activated LUKS dev {DEV}", "DEV", devPath,
439 "REDFISH_MESSAGE_ID",
440 std::string("OpenBMC.0.1.ActivateLuksDevSuccess"));
441}
442
Ed Tanous82897c32022-02-21 14:11:59 -0800443void EStoraged::createFilesystem()
John Wedigb810c922021-11-17 16:38:03 -0800444{
445 /* Run the command to create the filesystem. */
Rom Lemarchand530ce1e2025-12-16 21:45:08 +0000446 int retval = fsIface->runMkfs(cryptDevicePath, {"-E", "discard"});
Ed Tanous82897c32022-02-21 14:11:59 -0800447 if (retval != 0)
John Wedigb810c922021-11-17 16:38:03 -0800448 {
449 lg2::error("Failed to create filesystem: {RETVAL}", "RETVAL", retval,
450 "REDFISH_MESSAGE_ID",
451 std::string("OpenBMC.0.1.CreateFilesystemFail"));
John Wedig972c3fa2021-12-29 17:30:41 -0800452 throw InternalFailure();
John Wedigb810c922021-11-17 16:38:03 -0800453 }
John Wedig2443a022023-03-17 13:42:32 -0700454 lg2::info("Successfully created filesystem for {CONTAINER}", "CONTAINER",
455 cryptDevicePath, "REDFISH_MESSAGE_ID",
John Wedigb810c922021-11-17 16:38:03 -0800456 std::string("OpenBMC.0.1.CreateFilesystemSuccess"));
457}
458
Ed Tanous82897c32022-02-21 14:11:59 -0800459void EStoraged::mountFilesystem()
John Wedigb810c922021-11-17 16:38:03 -0800460{
John Wedigb17f8252022-01-12 14:24:26 -0800461 /*
John Wedig1d6665f2025-12-04 19:08:06 +0000462 * Before mounting, run fsck to check for and resolve any filesystem errors.
463 */
464 int retval = fsIface->runFsck(cryptDevicePath, "-t ext4 -p");
465 if (retval != 0)
466 {
467 lg2::error("The fsck command failed: {RETVAL}", "RETVAL", retval,
468 "REDFISH_MESSAGE_ID",
469 std::string("OpenBMC.0.1.FixFilesystemFail"));
470 /* We'll still try to mount the filesystem, though. */
471 }
472
473 /*
John Wedigb17f8252022-01-12 14:24:26 -0800474 * Create directory for the filesystem, if it's not already present. It
475 * might already exist if, for example, the BMC reboots after creating the
476 * directory.
477 */
478 if (!fsIface->directoryExists(std::filesystem::path(mountPoint)))
John Wedigb810c922021-11-17 16:38:03 -0800479 {
John Wedigb17f8252022-01-12 14:24:26 -0800480 bool success =
481 fsIface->createDirectory(std::filesystem::path(mountPoint));
482 if (!success)
483 {
484 lg2::error("Failed to create mount point: {DIR}", "DIR", mountPoint,
485 "REDFISH_MESSAGE_ID",
486 std::string("OpenBMC.0.1.MountFilesystemFail"));
487 throw InternalFailure();
488 }
John Wedigb810c922021-11-17 16:38:03 -0800489 }
490
491 /* Run the command to mount the filesystem. */
John Wedig1d6665f2025-12-04 19:08:06 +0000492 retval = fsIface->doMount(cryptDevicePath.c_str(), mountPoint.c_str(),
493 "ext4", 0, nullptr);
Ed Tanous82897c32022-02-21 14:11:59 -0800494 if (retval != 0)
John Wedigb810c922021-11-17 16:38:03 -0800495 {
496 lg2::error("Failed to mount filesystem: {RETVAL}", "RETVAL", retval,
497 "REDFISH_MESSAGE_ID",
498 std::string("OpenBMC.0.1.MountFilesystemFail"));
499 bool removeSuccess =
500 fsIface->removeDirectory(std::filesystem::path(mountPoint));
501 if (!removeSuccess)
502 {
503 lg2::error("Failed to remove mount point: {DIR}", "DIR", mountPoint,
504 "REDFISH_MESSAGE_ID",
505 std::string("OpenBMC.0.1.MountFilesystemFail"));
506 }
John Wedig972c3fa2021-12-29 17:30:41 -0800507 throw InternalFailure();
John Wedigb810c922021-11-17 16:38:03 -0800508 }
509
510 lg2::info("Successfully mounted filesystem at {DIR}", "DIR", mountPoint,
511 "REDFISH_MESSAGE_ID",
512 std::string("OpenBMC.0.1.MountFilesystemSuccess"));
513}
514
Ed Tanous82897c32022-02-21 14:11:59 -0800515void EStoraged::unmountFilesystem()
John Wedigb810c922021-11-17 16:38:03 -0800516{
517 int retval = fsIface->doUnmount(mountPoint.c_str());
Ed Tanous82897c32022-02-21 14:11:59 -0800518 if (retval != 0)
John Wedigb810c922021-11-17 16:38:03 -0800519 {
520 lg2::error("Failed to unmount filesystem: {RETVAL}", "RETVAL", retval,
521 "REDFISH_MESSAGE_ID",
522 std::string("OpenBMC.0.1.UnmountFilesystemFail"));
John Wedig972c3fa2021-12-29 17:30:41 -0800523 throw InternalFailure();
John Wedigb810c922021-11-17 16:38:03 -0800524 }
525
526 /* Remove the mount point. */
527 bool success = fsIface->removeDirectory(std::filesystem::path(mountPoint));
528 if (!success)
529 {
530 lg2::error("Failed to remove mount point {DIR}", "DIR", mountPoint,
531 "REDFISH_MESSAGE_ID",
532 std::string("OpenBMC.0.1.UnmountFilesystemFail"));
John Wedig972c3fa2021-12-29 17:30:41 -0800533 throw InternalFailure();
John Wedigb810c922021-11-17 16:38:03 -0800534 }
535
536 lg2::info("Successfully unmounted filesystem at {DIR}", "DIR", mountPoint,
537 "REDFISH_MESSAGE_ID",
538 std::string("OpenBMC.0.1.MountFilesystemSuccess"));
539}
540
Ed Tanous82897c32022-02-21 14:11:59 -0800541void EStoraged::deactivateLuksDev()
John Wedigb810c922021-11-17 16:38:03 -0800542{
543 lg2::info("Deactivating LUKS device {DEV}", "DEV", devPath,
544 "REDFISH_MESSAGE_ID",
545 std::string("OpenBMC.0.1.DeactivateLuksDev"));
546
547 int retval = cryptIface->cryptDeactivate(nullptr, containerName.c_str());
548 if (retval < 0)
549 {
550 lg2::error("Failed to deactivate crypt device: {RETVAL}", "RETVAL",
551 retval, "REDFISH_MESSAGE_ID",
552 std::string("OpenBMC.0.1.DeactivateLuksDevFail"));
John Wedig972c3fa2021-12-29 17:30:41 -0800553 throw InternalFailure();
John Wedigb810c922021-11-17 16:38:03 -0800554 }
555
John Wedigb810c922021-11-17 16:38:03 -0800556 lg2::info("Successfully deactivated LUKS device {DEV}", "DEV", devPath,
557 "REDFISH_MESSAGE_ID",
558 std::string("OpenBMC.0.1.DeactivateLuksDevSuccess"));
559}
560
John Wedig2443a022023-03-17 13:42:32 -0700561std::string_view EStoraged::getCryptDevicePath() const
John Wedig67a47442022-04-05 17:21:29 -0700562{
John Wedig2443a022023-03-17 13:42:32 -0700563 return cryptDevicePath;
John Wedig67a47442022-04-05 17:21:29 -0700564}
565
Willy Tuda5aa612025-12-18 07:32:34 +0000566bool EStoraged::enableBackgroundOperation(std::unique_ptr<stdplus::Fd> fd,
567 std::string_view devPath)
568{
569 struct mmc_ioc_cmd idata{};
570 memset(&idata, 0, sizeof(idata));
571 // Extended Device Specific Data. Contains information about the Device
572 // capabilities and selected modes.
573 std::array<uint8_t, /*EXT_CSD*/ 512> extCsd{};
574 idata.write_flag = 0;
575 idata.opcode = MMC_SEND_EXT_CSD;
576 idata.arg = 0;
577 idata.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
578 idata.blksz = extCsd.size();
579 idata.blocks = 1;
580 mmc_ioc_cmd_set_data(idata, extCsd.data());
581 if (fd->ioctl(MMC_IOC_CMD, &idata) != 0)
582 {
583 throw BkopsIoctlFailure(devPath,
584 "Failed to get Extended Device Specific Data");
585 }
586
587 if ((extCsd[EXT_CSD_BKOPS_SUPPORT] & 0x1) == 0)
588 {
589 lg2::info("BKOPS is not supported for {DEV}", "DEV", devPath);
590 return false;
591 }
592 lg2::info("BKOPS is supported for {DEV}", "DEV", devPath);
593
594 if ((extCsd[EXT_CSD_BKOPS_EN] &
595 (EXT_CSD_MANUAL_BKOPS_MASK | EXT_CSD_AUTO_BKOPS_MASK)) != 0)
596 {
597 lg2::info("BKOPS is already enabled for {DEV}: Mode: {MODE}", "DEV",
598 devPath, "MODE", extCsd[EXT_CSD_BKOPS_EN]);
599 return false;
600 }
601
602 // Clear the input data.
603 memset(&idata, 0, sizeof(idata));
604 idata.write_flag = 1;
605 idata.opcode = MMC_SWITCH;
606 idata.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | (EXT_CSD_BKOPS_EN << 16) |
607 (EXT_CSD_MANUAL_BKOPS_MASK << 8) | EXT_CSD_CMD_SET_NORMAL;
608 idata.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
609 if (fd->ioctl(MMC_IOC_CMD, &idata) != 0)
610 {
611 throw BkopsEnableFailure(devPath);
612 }
613
614 lg2::info("Successfully enable BKOPS for {DEV}", "DEV", devPath);
615 return true;
616}
617
Willy Tu30bfe8e2025-12-30 19:47:52 +0000618bool EStoraged::changeHsTiming(stdplus::Fd* fd, std::string_view devPath)
619{
620 if (fd == nullptr)
621 {
622 return false;
623 }
624 struct mmc_ioc_cmd cmd = {};
625 cmd.write_flag = 1;
626 cmd.opcode = MMC_SWITCH;
627 cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | (EXT_CSD_HS_TIMING << 16) |
628 (EXT_CSD_TIMING_HS400 << 8);
629 cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
630 if (fd->ioctl(MMC_IOC_CMD, &cmd) != 0)
631 {
632 throw HsModeError(devPath);
633 }
634 return true;
635}
636
637bool EStoraged::changeHsTimingIfNeeded(
638 stdplus::Fd* fd, std::string_view devPath, std::string_view partNumber)
639{
640 if (fd == nullptr)
641 {
642 return false;
643 }
644 if (std::ranges::contains(highSpeedMMC, partNumber))
645 {
646 return changeHsTiming(fd, devPath);
647 }
648 return false;
649}
650
John Wedig2098dab2021-09-14 13:56:28 -0700651} // namespace estoraged