blob: a243aeff2a7b38bdebe3c533a5a3878cf4543b94 [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"
John Edward Broadbent7f2ab642021-11-11 21:00:38 -08006#include "pattern.hpp"
John Edward Broadbent605085a2021-11-05 13:45:45 -07007#include "sanitize.hpp"
John Edward Broadbente6ffe702021-10-14 14:03:11 -07008#include "verifyDriveGeometry.hpp"
John Edward Broadbent4bc8a102021-12-30 16:11:49 -08009#include "zero.hpp"
John Edward Broadbent4e13b0a2021-11-15 15:21:59 -080010
John Wedigb810c922021-11-17 16:38:03 -080011#include <libcryptsetup.h>
Willy Tuda5aa612025-12-18 07:32:34 +000012#include <linux/mmc/core.h>
13#include <linux/mmc/ioctl.h>
14#include <linux/mmc/mmc.h>
John Wedigb810c922021-11-17 16:38:03 -080015#include <openssl/rand.h>
Willy Tuda5aa612025-12-18 07:32:34 +000016#include <sys/ioctl.h>
John Wedigb810c922021-11-17 16:38:03 -080017
18#include <phosphor-logging/lg2.hpp>
John Wedig67a47442022-04-05 17:21:29 -070019#include <sdbusplus/asio/object_server.hpp>
Willy Tuda5aa612025-12-18 07:32:34 +000020#include <stdplus/fd/create.hpp>
21#include <stdplus/fd/managed.hpp>
John Wedig972c3fa2021-12-29 17:30:41 -080022#include <xyz/openbmc_project/Common/error.hpp>
John Wedigb810c922021-11-17 16:38:03 -080023
Ed Tanous82897c32022-02-21 14:11:59 -080024#include <cstdlib>
John Wedigb810c922021-11-17 16:38:03 -080025#include <filesystem>
John Wedig2098dab2021-09-14 13:56:28 -070026#include <iostream>
John Wedig67a47442022-04-05 17:21:29 -070027#include <string>
John Wedigb810c922021-11-17 16:38:03 -080028#include <string_view>
John Wedig67a47442022-04-05 17:21:29 -070029#include <utility>
John Wedig2098dab2021-09-14 13:56:28 -070030#include <vector>
31
32namespace estoraged
33{
34
John Wedig6c0d8ce2022-04-22 14:00:43 -070035using Association = std::tuple<std::string, std::string, std::string>;
John Wedig1755d1b2025-07-21 22:26:30 +000036using sdbusplus::asio::PropertyPermission;
John Wedig972c3fa2021-12-29 17:30:41 -080037using sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
John Wedig972c3fa2021-12-29 17:30:41 -080038using sdbusplus::xyz::openbmc_project::Common::Error::UnsupportedRequest;
John Edward Broadbent91c1ec12022-05-20 16:51:43 -070039using sdbusplus::xyz::openbmc_project::Inventory::Item::server::Drive;
John Wedig67a47442022-04-05 17:21:29 -070040using sdbusplus::xyz::openbmc_project::Inventory::Item::server::Volume;
John Wedigb810c922021-11-17 16:38:03 -080041
Patrick Williams15b63e12024-08-16 15:22:01 -040042EStoraged::EStoraged(
Willy Tuda5aa612025-12-18 07:32:34 +000043 std::unique_ptr<stdplus::Fd> fd, sdbusplus::asio::object_server& server,
44 const std::string& configPath, const std::string& devPath,
45 const std::string& luksName, uint64_t size, uint8_t lifeTime,
46 const std::string& partNumber, const std::string& serialNumber,
47 const std::string& locationCode, uint64_t eraseMaxGeometry,
48 uint64_t eraseMinGeometry, const std::string& driveType,
49 const std::string& driveProtocol,
Patrick Williams15b63e12024-08-16 15:22:01 -040050 std::unique_ptr<CryptsetupInterface> cryptInterface,
51 std::unique_ptr<FilesystemInterface> fsInterface) :
52 devPath(devPath), containerName(luksName),
53 mountPoint("/mnt/" + luksName + "_fs"), eraseMaxGeometry(eraseMaxGeometry),
54 eraseMinGeometry(eraseMinGeometry), cryptIface(std::move(cryptInterface)),
55 fsIface(std::move(fsInterface)),
John Wedig2443a022023-03-17 13:42:32 -070056 cryptDevicePath(cryptIface->cryptGetDir() + "/" + luksName),
John Edward Broadbent6771c692022-06-22 19:49:27 -070057 objectServer(server)
John Wedig67a47442022-04-05 17:21:29 -070058{
Willy Tuda5aa612025-12-18 07:32:34 +000059 try
60 {
61 enableBackgroundOperation(std::move(fd), devPath);
62 }
63 catch (const BkopsError& e)
64 {
65 lg2::error("Failed to enable background operation for {PATH}: {ERROR}",
66 "PATH", devPath, "ERROR", e.what());
67 }
68
John Wedig67a47442022-04-05 17:21:29 -070069 /* Get the filename of the device (without "/dev/"). */
70 std::string deviceName = std::filesystem::path(devPath).filename().string();
71 /* DBus object path */
Patrick Williams15b63e12024-08-16 15:22:01 -040072 std::string objectPath =
73 "/xyz/openbmc_project/inventory/storage/" + deviceName;
John Wedig67a47442022-04-05 17:21:29 -070074
75 /* Add Volume interface. */
76 volumeInterface = objectServer.add_interface(
John Wedig6c0d8ce2022-04-22 14:00:43 -070077 objectPath, "xyz.openbmc_project.Inventory.Item.Volume");
John Wedig67a47442022-04-05 17:21:29 -070078 volumeInterface->register_method(
79 "FormatLuks", [this](const std::vector<uint8_t>& password,
80 Volume::FilesystemType type) {
Patrick Williams15b63e12024-08-16 15:22:01 -040081 this->formatLuks(password, type);
82 });
Patrick Williamsff1b64f2023-10-20 11:19:56 -050083 volumeInterface->register_method(
84 "Erase",
85 [this](Volume::EraseMethod eraseType) { this->erase(eraseType); });
John Wedig67a47442022-04-05 17:21:29 -070086 volumeInterface->register_method("Lock", [this]() { this->lock(); });
Patrick Williamsff1b64f2023-10-20 11:19:56 -050087 volumeInterface->register_method(
88 "Unlock",
89 [this](std::vector<uint8_t>& password) { this->unlock(password); });
John Wedig67a47442022-04-05 17:21:29 -070090 volumeInterface->register_method(
91 "ChangePassword", [this](const std::vector<uint8_t>& oldPassword,
92 const std::vector<uint8_t>& newPassword) {
Patrick Williams15b63e12024-08-16 15:22:01 -040093 this->changePassword(oldPassword, newPassword);
94 });
John Wedig67a47442022-04-05 17:21:29 -070095 volumeInterface->register_property_r(
96 "Locked", lockedProperty, sdbusplus::vtable::property_::emits_change,
97 [this](bool& value) {
Patrick Williams15b63e12024-08-16 15:22:01 -040098 value = this->isLocked();
99 return value;
100 });
John Wedig67a47442022-04-05 17:21:29 -0700101
102 /* Add Drive interface. */
103 driveInterface = objectServer.add_interface(
John Wedig6c0d8ce2022-04-22 14:00:43 -0700104 objectPath, "xyz.openbmc_project.Inventory.Item.Drive");
John Wedig67a47442022-04-05 17:21:29 -0700105 driveInterface->register_property("Capacity", size);
John Wedig1755d1b2025-07-21 22:26:30 +0000106 /* The lifetime property is read/write only for testing purposes. */
107 driveInterface->register_property("PredictedMediaLifeLeftPercent", lifeTime,
108 PropertyPermission::readWrite);
John Wedigd7be42b2024-01-19 16:07:19 -0800109 driveInterface->register_property(
110 "Type",
111 "xyz.openbmc_project.Inventory.Item.Drive.DriveType." + driveType);
John Wedigc0d66eb2024-02-26 15:54:47 -0800112 driveInterface->register_property(
113 "Protocol", "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol." +
114 driveProtocol);
John Edward Broadbent14aee772022-04-20 13:46:48 -0700115 /* This registers the Locked property for the Drives interface.
116 * Now it is the same as the volume Locked property */
117 driveInterface->register_property_r(
118 "Locked", lockedProperty, sdbusplus::vtable::property_::emits_change,
119 [this](bool& value) {
Patrick Williams15b63e12024-08-16 15:22:01 -0400120 value = this->isLocked();
121 return value;
122 });
John Wedig67a47442022-04-05 17:21:29 -0700123
John Edward Broadbent91c1ec12022-05-20 16:51:43 -0700124 driveInterface->register_property_r(
125 "EncryptionStatus", encryptionStatus,
126 sdbusplus::vtable::property_::emits_change,
127 [this](Drive::DriveEncryptionState& value) {
Patrick Williams15b63e12024-08-16 15:22:01 -0400128 value = this->findEncryptionStatus();
129 return value;
130 });
John Edward Broadbent91c1ec12022-05-20 16:51:43 -0700131
John Edward Broadbent49796412022-06-22 18:31:52 -0700132 embeddedLocationInterface = objectServer.add_interface(
133 objectPath, "xyz.openbmc_project.Inventory.Connector.Embedded");
John Edward Broadbent740e94b2022-06-10 19:42:30 -0700134
Rahul Kapoor19825052023-05-27 01:52:23 +0000135 if (!locationCode.empty())
136 {
137 locationCodeInterface = objectServer.add_interface(
138 objectPath, "xyz.openbmc_project.Inventory.Decorator.LocationCode");
139 locationCodeInterface->register_property("LocationCode", locationCode);
140 locationCodeInterface->initialize();
141 }
142
John Wedigb4838302022-07-22 13:51:16 -0700143 /* Add Asset interface. */
144 assetInterface = objectServer.add_interface(
145 objectPath, "xyz.openbmc_project.Inventory.Decorator.Asset");
146 assetInterface->register_property("PartNumber", partNumber);
147 assetInterface->register_property("SerialNumber", serialNumber);
148
John Wedig67a47442022-04-05 17:21:29 -0700149 volumeInterface->initialize();
150 driveInterface->initialize();
John Edward Broadbent49796412022-06-22 18:31:52 -0700151 embeddedLocationInterface->initialize();
John Wedigb4838302022-07-22 13:51:16 -0700152 assetInterface->initialize();
John Wedig6c0d8ce2022-04-22 14:00:43 -0700153
154 /* Set up the association between chassis and drive. */
155 association = objectServer.add_interface(
156 objectPath, "xyz.openbmc_project.Association.Definitions");
157
158 std::vector<Association> associations;
159 associations.emplace_back("chassis", "drive",
160 std::filesystem::path(configPath).parent_path());
161 association->register_property("Associations", associations);
162 association->initialize();
John Wedig67a47442022-04-05 17:21:29 -0700163}
164
165EStoraged::~EStoraged()
166{
167 objectServer.remove_interface(volumeInterface);
168 objectServer.remove_interface(driveInterface);
John Edward Broadbent49796412022-06-22 18:31:52 -0700169 objectServer.remove_interface(embeddedLocationInterface);
John Wedigb4838302022-07-22 13:51:16 -0700170 objectServer.remove_interface(assetInterface);
John Wedig6c0d8ce2022-04-22 14:00:43 -0700171 objectServer.remove_interface(association);
Rahul Kapoor19825052023-05-27 01:52:23 +0000172
173 if (locationCodeInterface != nullptr)
174 {
175 objectServer.remove_interface(locationCodeInterface);
176 }
John Wedig67a47442022-04-05 17:21:29 -0700177}
178
179void EStoraged::formatLuks(const std::vector<uint8_t>& password,
180 Volume::FilesystemType type)
John Wedig2098dab2021-09-14 13:56:28 -0700181{
John Edward Broadbent4e13b0a2021-11-15 15:21:59 -0800182 std::string msg = "OpenBMC.0.1.DriveFormat";
183 lg2::info("Starting format", "REDFISH_MESSAGE_ID", msg);
John Wedigb810c922021-11-17 16:38:03 -0800184
John Wedig67a47442022-04-05 17:21:29 -0700185 if (type != Volume::FilesystemType::ext4)
John Wedig972c3fa2021-12-29 17:30:41 -0800186 {
187 lg2::error("Only ext4 filesystems are supported currently",
188 "REDFISH_MESSAGE_ID", std::string("OpenBMC.0.1.FormatFail"));
189 throw UnsupportedRequest();
190 }
191
John Edward Broadbentb2c86be2022-04-15 11:45:53 -0700192 formatLuksDev(password);
193 activateLuksDev(password);
John Wedigb810c922021-11-17 16:38:03 -0800194
195 createFilesystem();
196 mountFilesystem();
John Wedig2098dab2021-09-14 13:56:28 -0700197}
198
John Wedig67a47442022-04-05 17:21:29 -0700199void EStoraged::erase(Volume::EraseMethod inEraseMethod)
John Wedig2098dab2021-09-14 13:56:28 -0700200{
201 std::cerr << "Erasing encrypted eMMC" << std::endl;
John Edward Broadbente6ffe702021-10-14 14:03:11 -0700202 lg2::info("Starting erase", "REDFISH_MESSAGE_ID",
203 std::string("OpenBMC.0.1.DriveErase"));
204 switch (inEraseMethod)
205 {
John Wedig67a47442022-04-05 17:21:29 -0700206 case Volume::EraseMethod::CryptoErase:
John Edward Broadbente6ffe702021-10-14 14:03:11 -0700207 {
John Edward Broadbent59dffa62022-01-13 17:41:32 -0800208 CryptErase myCryptErase(devPath);
209 myCryptErase.doErase();
John Edward Broadbente6ffe702021-10-14 14:03:11 -0700210 break;
211 }
John Wedig67a47442022-04-05 17:21:29 -0700212 case Volume::EraseMethod::VerifyGeometry:
John Edward Broadbente6ffe702021-10-14 14:03:11 -0700213 {
214 VerifyDriveGeometry myVerifyGeometry(devPath);
Tom Tung043af592023-11-24 13:37:05 +0800215 myVerifyGeometry.geometryOkay(eraseMaxGeometry, eraseMinGeometry);
John Edward Broadbente6ffe702021-10-14 14:03:11 -0700216 break;
217 }
John Wedig67a47442022-04-05 17:21:29 -0700218 case Volume::EraseMethod::LogicalOverWrite:
John Edward Broadbente6ffe702021-10-14 14:03:11 -0700219 {
John Edward Broadbent7f2ab642021-11-11 21:00:38 -0800220 Pattern myErasePattern(devPath);
John Edward Broadbenta6e3b992022-03-17 14:33:15 -0700221 myErasePattern.writePattern();
John Edward Broadbente6ffe702021-10-14 14:03:11 -0700222 break;
223 }
John Wedig67a47442022-04-05 17:21:29 -0700224 case Volume::EraseMethod::LogicalVerify:
John Edward Broadbente6ffe702021-10-14 14:03:11 -0700225 {
John Edward Broadbent7f2ab642021-11-11 21:00:38 -0800226 Pattern myErasePattern(devPath);
John Edward Broadbenta6e3b992022-03-17 14:33:15 -0700227 myErasePattern.verifyPattern();
John Edward Broadbente6ffe702021-10-14 14:03:11 -0700228 break;
229 }
John Wedig67a47442022-04-05 17:21:29 -0700230 case Volume::EraseMethod::VendorSanitize:
John Edward Broadbente6ffe702021-10-14 14:03:11 -0700231 {
John Edward Broadbent605085a2021-11-05 13:45:45 -0700232 Sanitize mySanitize(devPath);
233 mySanitize.doSanitize();
John Edward Broadbente6ffe702021-10-14 14:03:11 -0700234 break;
235 }
John Wedig67a47442022-04-05 17:21:29 -0700236 case Volume::EraseMethod::ZeroOverWrite:
John Edward Broadbente6ffe702021-10-14 14:03:11 -0700237 {
John Edward Broadbent4bc8a102021-12-30 16:11:49 -0800238 Zero myZero(devPath);
John Edward Broadbenta6e3b992022-03-17 14:33:15 -0700239 myZero.writeZero();
John Edward Broadbente6ffe702021-10-14 14:03:11 -0700240 break;
241 }
John Wedig67a47442022-04-05 17:21:29 -0700242 case Volume::EraseMethod::ZeroVerify:
John Edward Broadbente6ffe702021-10-14 14:03:11 -0700243 {
John Edward Broadbent4bc8a102021-12-30 16:11:49 -0800244 Zero myZero(devPath);
John Edward Broadbenta6e3b992022-03-17 14:33:15 -0700245 myZero.verifyZero();
John Edward Broadbente6ffe702021-10-14 14:03:11 -0700246 break;
247 }
John Wedig67a47442022-04-05 17:21:29 -0700248 case Volume::EraseMethod::SecuredLocked:
John Edward Broadbente6ffe702021-10-14 14:03:11 -0700249 {
John Wedig47cd7992022-10-05 15:45:11 -0700250 if (!isLocked())
John Edward Broadbentf59b7292022-02-15 15:07:15 -0800251 {
252 lock();
253 }
254 // TODO: implement hardware locking
255 // Until that is done, we can lock using eStoraged::lock()
John Edward Broadbente6ffe702021-10-14 14:03:11 -0700256 break;
257 }
258 }
John Wedig2098dab2021-09-14 13:56:28 -0700259}
260
Ed Tanous82897c32022-02-21 14:11:59 -0800261void EStoraged::lock()
John Wedig2098dab2021-09-14 13:56:28 -0700262{
John Edward Broadbent4e13b0a2021-11-15 15:21:59 -0800263 std::string msg = "OpenBMC.0.1.DriveLock";
264 lg2::info("Starting lock", "REDFISH_MESSAGE_ID", msg);
John Wedigb810c922021-11-17 16:38:03 -0800265
266 unmountFilesystem();
267 deactivateLuksDev();
John Wedig2098dab2021-09-14 13:56:28 -0700268}
269
Ed Tanous82897c32022-02-21 14:11:59 -0800270void EStoraged::unlock(std::vector<uint8_t> password)
John Wedig2098dab2021-09-14 13:56:28 -0700271{
John Edward Broadbent4e13b0a2021-11-15 15:21:59 -0800272 std::string msg = "OpenBMC.0.1.DriveUnlock";
273 lg2::info("Starting unlock", "REDFISH_MESSAGE_ID", msg);
John Wedigb810c922021-11-17 16:38:03 -0800274
John Edward Broadbentb2c86be2022-04-15 11:45:53 -0700275 activateLuksDev(std::move(password));
John Wedigb810c922021-11-17 16:38:03 -0800276 mountFilesystem();
John Wedig2098dab2021-09-14 13:56:28 -0700277}
278
John Wedig8d5a3a02022-09-29 15:25:58 -0700279void EStoraged::changePassword(const std::vector<uint8_t>& oldPassword,
280 const std::vector<uint8_t>& newPassword)
John Wedig2098dab2021-09-14 13:56:28 -0700281{
John Edward Broadbente6ffe702021-10-14 14:03:11 -0700282 lg2::info("Starting change password", "REDFISH_MESSAGE_ID",
283 std::string("OpenBMC.0.1.DrivePasswordChanged"));
John Wedig8d5a3a02022-09-29 15:25:58 -0700284
285 CryptHandle cryptHandle = loadLuksHeader();
286
287 int retval = cryptIface->cryptKeyslotChangeByPassphrase(
288 cryptHandle.get(), CRYPT_ANY_SLOT, CRYPT_ANY_SLOT,
289 reinterpret_cast<const char*>(oldPassword.data()), oldPassword.size(),
290 reinterpret_cast<const char*>(newPassword.data()), newPassword.size());
291 if (retval < 0)
292 {
293 lg2::error("Failed to change password", "REDFISH_MESSAGE_ID",
294 std::string("OpenBMC.0.1.DrivePasswordChangeFail"));
295 throw InternalFailure();
296 }
297
298 lg2::info("Successfully changed password for {DEV}", "DEV", devPath,
299 "REDFISH_MESSAGE_ID",
300 std::string("OpenBMC.0.1.DrivePasswordChangeSuccess"));
John Wedig2098dab2021-09-14 13:56:28 -0700301}
302
Ed Tanous82897c32022-02-21 14:11:59 -0800303bool EStoraged::isLocked() const
John Wedigb810c922021-11-17 16:38:03 -0800304{
John Wedig2443a022023-03-17 13:42:32 -0700305 /*
306 * Check if the mapped virtual device exists. If it exists, the LUKS volume
307 * is unlocked.
308 */
309 try
310 {
311 std::filesystem::path mappedDevicePath(cryptDevicePath);
312 return (std::filesystem::exists(mappedDevicePath) == false);
313 }
314 catch (const std::exception& e)
315 {
316 lg2::error("Failed to query locked status: {EXCEPT}", "EXCEPT",
317 e.what(), "REDFISH_MESSAGE_ID",
318 std::string("OpenBMC.0.1.IsLockedFail"));
319 /* If we couldn't query the filesystem path, assume unlocked. */
320 return false;
321 }
John Wedigb810c922021-11-17 16:38:03 -0800322}
323
Ed Tanous82897c32022-02-21 14:11:59 -0800324std::string_view EStoraged::getMountPoint() const
John Wedigb810c922021-11-17 16:38:03 -0800325{
326 return mountPoint;
327}
328
John Edward Broadbentb2c86be2022-04-15 11:45:53 -0700329void EStoraged::formatLuksDev(std::vector<uint8_t> password)
John Wedigb810c922021-11-17 16:38:03 -0800330{
331 lg2::info("Formatting device {DEV}", "DEV", devPath, "REDFISH_MESSAGE_ID",
332 std::string("OpenBMC.0.1.FormatLuksDev"));
333
334 /* Generate the volume key. */
335 const std::size_t keySize = 64;
336 std::vector<uint8_t> volumeKey(keySize);
337 if (RAND_bytes(volumeKey.data(), keySize) != 1)
338 {
339 lg2::error("Failed to create volume key", "REDFISH_MESSAGE_ID",
340 std::string("OpenBMC.0.1.FormatLuksDevFail"));
John Wedig972c3fa2021-12-29 17:30:41 -0800341 throw InternalFailure();
John Wedigb810c922021-11-17 16:38:03 -0800342 }
John Edward Broadbentb2c86be2022-04-15 11:45:53 -0700343
344 /* Create the handle. */
345 CryptHandle cryptHandle(devPath);
346
John Wedigb810c922021-11-17 16:38:03 -0800347 /* Format the LUKS encrypted device. */
John Edward Broadbentb2c86be2022-04-15 11:45:53 -0700348 int retval = cryptIface->cryptFormat(
349 cryptHandle.get(), CRYPT_LUKS2, "aes", "xts-plain64", nullptr,
350 reinterpret_cast<const char*>(volumeKey.data()), volumeKey.size(),
351 nullptr);
John Wedigb810c922021-11-17 16:38:03 -0800352 if (retval < 0)
353 {
354 lg2::error("Failed to format encrypted device: {RETVAL}", "RETVAL",
355 retval, "REDFISH_MESSAGE_ID",
356 std::string("OpenBMC.0.1.FormatLuksDevFail"));
John Wedig972c3fa2021-12-29 17:30:41 -0800357 throw InternalFailure();
John Wedigb810c922021-11-17 16:38:03 -0800358 }
359
John Wedigb810c922021-11-17 16:38:03 -0800360 /* Set the password. */
361 retval = cryptIface->cryptKeyslotAddByVolumeKey(
John Edward Broadbentb2c86be2022-04-15 11:45:53 -0700362 cryptHandle.get(), CRYPT_ANY_SLOT, nullptr, 0,
John Wedigb810c922021-11-17 16:38:03 -0800363 reinterpret_cast<const char*>(password.data()), password.size());
364
365 if (retval < 0)
366 {
367 lg2::error("Failed to set encryption password", "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
372 lg2::info("Encrypted device {DEV} successfully formatted", "DEV", devPath,
373 "REDFISH_MESSAGE_ID",
374 std::string("OpenBMC.0.1.FormatLuksDevSuccess"));
375}
376
John Edward Broadbent91c1ec12022-05-20 16:51:43 -0700377CryptHandle EStoraged::loadLuksHeader()
John Wedigb810c922021-11-17 16:38:03 -0800378{
John Edward Broadbentb2c86be2022-04-15 11:45:53 -0700379 CryptHandle cryptHandle(devPath);
380
381 int retval = cryptIface->cryptLoad(cryptHandle.get(), CRYPT_LUKS2, nullptr);
John Wedigb810c922021-11-17 16:38:03 -0800382 if (retval < 0)
383 {
384 lg2::error("Failed to load LUKS header: {RETVAL}", "RETVAL", retval,
385 "REDFISH_MESSAGE_ID",
386 std::string("OpenBMC.0.1.ActivateLuksDevFail"));
John Wedig972c3fa2021-12-29 17:30:41 -0800387 throw InternalFailure();
John Wedigb810c922021-11-17 16:38:03 -0800388 }
John Edward Broadbent91c1ec12022-05-20 16:51:43 -0700389 return cryptHandle;
390}
John Wedigb810c922021-11-17 16:38:03 -0800391
John Edward Broadbent91c1ec12022-05-20 16:51:43 -0700392Drive::DriveEncryptionState EStoraged::findEncryptionStatus()
393{
394 try
395 {
396 loadLuksHeader();
397 return Drive::DriveEncryptionState::Encrypted;
398 }
399 catch (...)
400 {
Hao Zhou0cec4282024-03-12 22:16:16 +0000401 return Drive::DriveEncryptionState::Unencrypted;
John Edward Broadbent91c1ec12022-05-20 16:51:43 -0700402 }
403}
404
405void EStoraged::activateLuksDev(std::vector<uint8_t> password)
406{
407 lg2::info("Activating LUKS dev {DEV}", "DEV", devPath, "REDFISH_MESSAGE_ID",
408 std::string("OpenBMC.0.1.ActivateLuksDev"));
409
410 /* Create the handle. */
411 CryptHandle cryptHandle = loadLuksHeader();
412
413 int retval = cryptIface->cryptActivateByPassphrase(
John Edward Broadbentb2c86be2022-04-15 11:45:53 -0700414 cryptHandle.get(), containerName.c_str(), CRYPT_ANY_SLOT,
Rom Lemarchand530ce1e2025-12-16 21:45:08 +0000415 reinterpret_cast<const char*>(password.data()), password.size(),
416 CRYPT_ACTIVATE_ALLOW_DISCARDS);
John Wedigb810c922021-11-17 16:38:03 -0800417
418 if (retval < 0)
419 {
420 lg2::error("Failed to activate LUKS dev: {RETVAL}", "RETVAL", retval,
421 "REDFISH_MESSAGE_ID",
422 std::string("OpenBMC.0.1.ActivateLuksDevFail"));
John Wedig972c3fa2021-12-29 17:30:41 -0800423 throw InternalFailure();
John Wedigb810c922021-11-17 16:38:03 -0800424 }
425
John Wedigb810c922021-11-17 16:38:03 -0800426 lg2::info("Successfully activated LUKS dev {DEV}", "DEV", devPath,
427 "REDFISH_MESSAGE_ID",
428 std::string("OpenBMC.0.1.ActivateLuksDevSuccess"));
429}
430
Ed Tanous82897c32022-02-21 14:11:59 -0800431void EStoraged::createFilesystem()
John Wedigb810c922021-11-17 16:38:03 -0800432{
433 /* Run the command to create the filesystem. */
Rom Lemarchand530ce1e2025-12-16 21:45:08 +0000434 int retval = fsIface->runMkfs(cryptDevicePath, {"-E", "discard"});
Ed Tanous82897c32022-02-21 14:11:59 -0800435 if (retval != 0)
John Wedigb810c922021-11-17 16:38:03 -0800436 {
437 lg2::error("Failed to create filesystem: {RETVAL}", "RETVAL", retval,
438 "REDFISH_MESSAGE_ID",
439 std::string("OpenBMC.0.1.CreateFilesystemFail"));
John Wedig972c3fa2021-12-29 17:30:41 -0800440 throw InternalFailure();
John Wedigb810c922021-11-17 16:38:03 -0800441 }
John Wedig2443a022023-03-17 13:42:32 -0700442 lg2::info("Successfully created filesystem for {CONTAINER}", "CONTAINER",
443 cryptDevicePath, "REDFISH_MESSAGE_ID",
John Wedigb810c922021-11-17 16:38:03 -0800444 std::string("OpenBMC.0.1.CreateFilesystemSuccess"));
445}
446
Ed Tanous82897c32022-02-21 14:11:59 -0800447void EStoraged::mountFilesystem()
John Wedigb810c922021-11-17 16:38:03 -0800448{
John Wedigb17f8252022-01-12 14:24:26 -0800449 /*
John Wedig1d6665f2025-12-04 19:08:06 +0000450 * Before mounting, run fsck to check for and resolve any filesystem errors.
451 */
452 int retval = fsIface->runFsck(cryptDevicePath, "-t ext4 -p");
453 if (retval != 0)
454 {
455 lg2::error("The fsck command failed: {RETVAL}", "RETVAL", retval,
456 "REDFISH_MESSAGE_ID",
457 std::string("OpenBMC.0.1.FixFilesystemFail"));
458 /* We'll still try to mount the filesystem, though. */
459 }
460
461 /*
John Wedigb17f8252022-01-12 14:24:26 -0800462 * Create directory for the filesystem, if it's not already present. It
463 * might already exist if, for example, the BMC reboots after creating the
464 * directory.
465 */
466 if (!fsIface->directoryExists(std::filesystem::path(mountPoint)))
John Wedigb810c922021-11-17 16:38:03 -0800467 {
John Wedigb17f8252022-01-12 14:24:26 -0800468 bool success =
469 fsIface->createDirectory(std::filesystem::path(mountPoint));
470 if (!success)
471 {
472 lg2::error("Failed to create mount point: {DIR}", "DIR", mountPoint,
473 "REDFISH_MESSAGE_ID",
474 std::string("OpenBMC.0.1.MountFilesystemFail"));
475 throw InternalFailure();
476 }
John Wedigb810c922021-11-17 16:38:03 -0800477 }
478
479 /* Run the command to mount the filesystem. */
John Wedig1d6665f2025-12-04 19:08:06 +0000480 retval = fsIface->doMount(cryptDevicePath.c_str(), mountPoint.c_str(),
481 "ext4", 0, nullptr);
Ed Tanous82897c32022-02-21 14:11:59 -0800482 if (retval != 0)
John Wedigb810c922021-11-17 16:38:03 -0800483 {
484 lg2::error("Failed to mount filesystem: {RETVAL}", "RETVAL", retval,
485 "REDFISH_MESSAGE_ID",
486 std::string("OpenBMC.0.1.MountFilesystemFail"));
487 bool removeSuccess =
488 fsIface->removeDirectory(std::filesystem::path(mountPoint));
489 if (!removeSuccess)
490 {
491 lg2::error("Failed to remove mount point: {DIR}", "DIR", mountPoint,
492 "REDFISH_MESSAGE_ID",
493 std::string("OpenBMC.0.1.MountFilesystemFail"));
494 }
John Wedig972c3fa2021-12-29 17:30:41 -0800495 throw InternalFailure();
John Wedigb810c922021-11-17 16:38:03 -0800496 }
497
498 lg2::info("Successfully mounted filesystem at {DIR}", "DIR", mountPoint,
499 "REDFISH_MESSAGE_ID",
500 std::string("OpenBMC.0.1.MountFilesystemSuccess"));
501}
502
Ed Tanous82897c32022-02-21 14:11:59 -0800503void EStoraged::unmountFilesystem()
John Wedigb810c922021-11-17 16:38:03 -0800504{
505 int retval = fsIface->doUnmount(mountPoint.c_str());
Ed Tanous82897c32022-02-21 14:11:59 -0800506 if (retval != 0)
John Wedigb810c922021-11-17 16:38:03 -0800507 {
508 lg2::error("Failed to unmount filesystem: {RETVAL}", "RETVAL", retval,
509 "REDFISH_MESSAGE_ID",
510 std::string("OpenBMC.0.1.UnmountFilesystemFail"));
John Wedig972c3fa2021-12-29 17:30:41 -0800511 throw InternalFailure();
John Wedigb810c922021-11-17 16:38:03 -0800512 }
513
514 /* Remove the mount point. */
515 bool success = fsIface->removeDirectory(std::filesystem::path(mountPoint));
516 if (!success)
517 {
518 lg2::error("Failed to remove mount point {DIR}", "DIR", mountPoint,
519 "REDFISH_MESSAGE_ID",
520 std::string("OpenBMC.0.1.UnmountFilesystemFail"));
John Wedig972c3fa2021-12-29 17:30:41 -0800521 throw InternalFailure();
John Wedigb810c922021-11-17 16:38:03 -0800522 }
523
524 lg2::info("Successfully unmounted filesystem at {DIR}", "DIR", mountPoint,
525 "REDFISH_MESSAGE_ID",
526 std::string("OpenBMC.0.1.MountFilesystemSuccess"));
527}
528
Ed Tanous82897c32022-02-21 14:11:59 -0800529void EStoraged::deactivateLuksDev()
John Wedigb810c922021-11-17 16:38:03 -0800530{
531 lg2::info("Deactivating LUKS device {DEV}", "DEV", devPath,
532 "REDFISH_MESSAGE_ID",
533 std::string("OpenBMC.0.1.DeactivateLuksDev"));
534
535 int retval = cryptIface->cryptDeactivate(nullptr, containerName.c_str());
536 if (retval < 0)
537 {
538 lg2::error("Failed to deactivate crypt device: {RETVAL}", "RETVAL",
539 retval, "REDFISH_MESSAGE_ID",
540 std::string("OpenBMC.0.1.DeactivateLuksDevFail"));
John Wedig972c3fa2021-12-29 17:30:41 -0800541 throw InternalFailure();
John Wedigb810c922021-11-17 16:38:03 -0800542 }
543
John Wedigb810c922021-11-17 16:38:03 -0800544 lg2::info("Successfully deactivated LUKS device {DEV}", "DEV", devPath,
545 "REDFISH_MESSAGE_ID",
546 std::string("OpenBMC.0.1.DeactivateLuksDevSuccess"));
547}
548
John Wedig2443a022023-03-17 13:42:32 -0700549std::string_view EStoraged::getCryptDevicePath() const
John Wedig67a47442022-04-05 17:21:29 -0700550{
John Wedig2443a022023-03-17 13:42:32 -0700551 return cryptDevicePath;
John Wedig67a47442022-04-05 17:21:29 -0700552}
553
Willy Tuda5aa612025-12-18 07:32:34 +0000554bool EStoraged::enableBackgroundOperation(std::unique_ptr<stdplus::Fd> fd,
555 std::string_view devPath)
556{
557 struct mmc_ioc_cmd idata{};
558 memset(&idata, 0, sizeof(idata));
559 // Extended Device Specific Data. Contains information about the Device
560 // capabilities and selected modes.
561 std::array<uint8_t, /*EXT_CSD*/ 512> extCsd{};
562 idata.write_flag = 0;
563 idata.opcode = MMC_SEND_EXT_CSD;
564 idata.arg = 0;
565 idata.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
566 idata.blksz = extCsd.size();
567 idata.blocks = 1;
568 mmc_ioc_cmd_set_data(idata, extCsd.data());
569 if (fd->ioctl(MMC_IOC_CMD, &idata) != 0)
570 {
571 throw BkopsIoctlFailure(devPath,
572 "Failed to get Extended Device Specific Data");
573 }
574
575 if ((extCsd[EXT_CSD_BKOPS_SUPPORT] & 0x1) == 0)
576 {
577 lg2::info("BKOPS is not supported for {DEV}", "DEV", devPath);
578 return false;
579 }
580 lg2::info("BKOPS is supported for {DEV}", "DEV", devPath);
581
582 if ((extCsd[EXT_CSD_BKOPS_EN] &
583 (EXT_CSD_MANUAL_BKOPS_MASK | EXT_CSD_AUTO_BKOPS_MASK)) != 0)
584 {
585 lg2::info("BKOPS is already enabled for {DEV}: Mode: {MODE}", "DEV",
586 devPath, "MODE", extCsd[EXT_CSD_BKOPS_EN]);
587 return false;
588 }
589
590 // Clear the input data.
591 memset(&idata, 0, sizeof(idata));
592 idata.write_flag = 1;
593 idata.opcode = MMC_SWITCH;
594 idata.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | (EXT_CSD_BKOPS_EN << 16) |
595 (EXT_CSD_MANUAL_BKOPS_MASK << 8) | EXT_CSD_CMD_SET_NORMAL;
596 idata.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
597 if (fd->ioctl(MMC_IOC_CMD, &idata) != 0)
598 {
599 throw BkopsEnableFailure(devPath);
600 }
601
602 lg2::info("Successfully enable BKOPS for {DEV}", "DEV", devPath);
603 return true;
604}
605
John Wedig2098dab2021-09-14 13:56:28 -0700606} // namespace estoraged