1 #pragma once 2 3 #include "cryptsetupInterface.hpp" 4 #include "filesystemInterface.hpp" 5 #include "util.hpp" 6 7 #include <libcryptsetup.h> 8 9 #include <sdbusplus/asio/object_server.hpp> 10 #include <sdbusplus/bus.hpp> 11 #include <sdbusplus/exception.hpp> 12 #include <sdbusplus/server/object.hpp> 13 #include <stdplus/fd/create.hpp> 14 #include <stdplus/fd/managed.hpp> 15 #include <util.hpp> 16 #include <xyz/openbmc_project/Inventory/Item/Drive/server.hpp> 17 #include <xyz/openbmc_project/Inventory/Item/Volume/server.hpp> 18 19 #include <filesystem> 20 #include <format> 21 #include <memory> 22 #include <stdexcept> 23 #include <string> 24 #include <string_view> 25 #include <vector> 26 27 namespace estoraged 28 { 29 using estoraged::Cryptsetup; 30 using estoraged::Filesystem; 31 using sdbusplus::xyz::openbmc_project::Inventory::Item::server::Drive; 32 using sdbusplus::xyz::openbmc_project::Inventory::Item::server::Volume; 33 34 class BkopsError : public std::runtime_error 35 { 36 using std::runtime_error::runtime_error; 37 }; 38 39 class BkopsEnableFailure : public BkopsError 40 { 41 public: BkopsEnableFailure(std::string_view dev)42 BkopsEnableFailure(std::string_view dev) : 43 BkopsError(std::format("Failed to enable BKOPS on {}", dev)) 44 {} 45 }; 46 47 class BkopsIoctlFailure : public BkopsError 48 { 49 public: BkopsIoctlFailure(std::string_view dev,std::string_view msg)50 BkopsIoctlFailure(std::string_view dev, std::string_view msg) : 51 BkopsError(std::format("Failed to run ioctl on {}: {}", dev, msg)) 52 {} 53 }; 54 55 class HsModeError : public std::runtime_error 56 { 57 public: HsModeError(std::string_view dev)58 HsModeError(std::string_view dev) : 59 std::runtime_error(std::format("Failed to set HS mode on {}", dev)) 60 {} 61 }; 62 63 /** @class eStoraged 64 * @brief eStoraged object to manage a LUKS encrypted storage device. 65 */ 66 class EStoraged 67 { 68 public: 69 /** @brief Constructor for eStoraged 70 * 71 * @param[in] fd - mmc ioc fd 72 * @param[in] server - sdbusplus asio object server 73 * @param[in] configPath - path of the config object from Entity Manager 74 * @param[in] devPath - path to device file, e.g. /dev/mmcblk0 75 * @param[in] luksName - name for the LUKS container 76 * @param[in] size - size of the drive in bytes 77 * @param[in] lifeTime - percent of lifetime remaining for a drive 78 * @param[in] partNumber - part number for the storage device 79 * @param[in] serialNumber - serial number for the storage device 80 * @param[in] locationCode - location code for the storage device 81 * @param[in] eraseMaxGeometry - max geometry to erase if it's specified 82 * @param[in] eraseMinGeometry - min geometry to erase if it's specified 83 * @param[in] driveType - type of drive, e.g. HDD vs SSD 84 * @param[in] driveProtocol - protocol used to communicate with drive 85 * @param[in] cryptInterface - (optional) pointer to CryptsetupInterface 86 * object 87 * @param[in] fsInterface - (optional) pointer to FilesystemInterface 88 * object 89 */ 90 EStoraged(std::unique_ptr<stdplus::Fd> fd, 91 sdbusplus::asio::object_server& server, 92 const std::string& configPath, const std::string& devPath, 93 const std::string& luksName, uint64_t size, uint8_t lifeTime, 94 const std::string& partNumber, const std::string& serialNumber, 95 const std::string& locationCode, uint64_t eraseMaxGeometry, 96 uint64_t eraseMinGeometry, const std::string& driveType, 97 const std::string& driveProtocol, 98 std::unique_ptr<CryptsetupInterface> cryptInterface = 99 std::make_unique<Cryptsetup>(), 100 std::unique_ptr<FilesystemInterface> fsInterface = 101 std::make_unique<Filesystem>()); 102 103 /** @brief Destructor for eStoraged. */ 104 ~EStoraged(); 105 106 EStoraged& operator=(const EStoraged&) = delete; 107 EStoraged(const EStoraged&) = delete; 108 EStoraged(EStoraged&&) = default; 109 EStoraged& operator=(EStoraged&&) = delete; 110 111 /** @brief Format the LUKS encrypted device and create empty filesystem. 112 * 113 * @param[in] password - password to set for the LUKS device. 114 * @param[in] type - filesystem type, e.g. ext4 115 */ 116 void formatLuks(const std::vector<uint8_t>& password, 117 Volume::FilesystemType type); 118 119 /** @brief Erase the contents of the storage device. 120 * 121 * @param[in] eraseType - type of erase operation. 122 */ 123 void erase(Volume::EraseMethod eraseType); 124 125 /** @brief Unmount filesystem and lock the LUKS device. 126 */ 127 void lock(); 128 129 /** @brief Unlock device and mount the filesystem. 130 * 131 * @param[in] password - password for the LUKS device. 132 */ 133 void unlock(std::vector<uint8_t> password); 134 135 /** @brief Change the password for the LUKS device. 136 * 137 * @param[in] oldPassword - old password for the LUKS device. 138 * @param[in] newPassword - new password for the LUKS device. 139 */ 140 void changePassword(const std::vector<uint8_t>& oldPassword, 141 const std::vector<uint8_t>& newPassword); 142 143 /** @brief Check if the LUKS device is currently locked. */ 144 bool isLocked() const; 145 146 /** @brief Get the mount point for the filesystem on the LUKS device. */ 147 std::string_view getMountPoint() const; 148 149 /** @brief Get the path to the mapped crypt device. */ 150 std::string_view getCryptDevicePath() const; 151 152 /** @brief Enable eMMC background operations 153 * @param[in] fd - mmc ioc fd 154 * @param[in] devPath - mmc device path 155 * 156 * @details This enables the BKOPS flag on the eMMC device and set it to 157 * manual mode. 158 * 159 * @throw BkopsUnsupported BKOPS not support for the MMC 160 * @throw BkopsEnableFailure Failed to enable BKOPS on the MMC 161 * 162 * @returns true if we enabled the BKOPS on the MMC 163 */ 164 static bool enableBackgroundOperation(std::unique_ptr<stdplus::Fd> fd, 165 std::string_view devPath); 166 167 /** @brief Enable eMMC HS Timeing Mode 168 * @param[in] fd - mmc ioc fd 169 * @param[in] devPath - mmc device path 170 * 171 * @details This enables the the High-Speed (HS) Timing modes and Drive 172 * Strength settings, allowing the card to operate at faster interfaces 173 * 174 * @throw HsModeError HS timing mode is not set properly 175 * 176 * @returns true if we enabled the HS timing mode on the MMC 177 */ 178 static bool changeHsTiming(stdplus::Fd* fd, std::string_view devPath); 179 180 /** @brief Enable eMMC HS Timeing Mode if it is the applied parts 181 * @param[in] fd - mmc ioc fd 182 * @param[in] devPath - mmc device path 183 * @param[in] partNumber - part number to check if this feature shuold be 184 * enabled 185 * 186 * @throw HsModeError HS timing mode is not set properly 187 * 188 * @details This checks the part number to see if we want to enable the HS 189 * timing mode. 190 * 191 * @returns true if we enabled the HS timeing mode on the MMC 192 */ 193 static bool changeHsTimingIfNeeded( 194 stdplus::Fd* fd, std::string_view devPath, std::string_view partNumber); 195 196 private: 197 /** @brief Full path of the device file, e.g. /dev/mmcblk0. */ 198 std::string devPath; 199 200 /** @brief Name of the LUKS container. */ 201 std::string containerName; 202 203 /** @brief Mount point for the filesystem. */ 204 std::string mountPoint; 205 206 /** @brief Max geometry to erase. */ 207 uint64_t eraseMaxGeometry; 208 209 /** @brief Min geometry to erase. */ 210 uint64_t eraseMinGeometry; 211 212 /** @brief Indicates whether the LUKS device is currently locked. */ 213 bool lockedProperty{false}; 214 215 /** @brief Pointer to cryptsetup interface object. 216 * @details This is used to mock out the cryptsetup functions. 217 */ 218 std::unique_ptr<CryptsetupInterface> cryptIface; 219 220 /** @brief Pointer to filesystem interface object. 221 * @details This is used to mock out filesystem operations. 222 */ 223 std::unique_ptr<FilesystemInterface> fsIface; 224 225 /** @brief Path where the mapped crypt device gets created. */ 226 const std::string cryptDevicePath; 227 228 /** @brief D-Bus object server. */ 229 sdbusplus::asio::object_server& objectServer; 230 231 /** @brief D-Bus interface for the logical volume. */ 232 std::shared_ptr<sdbusplus::asio::dbus_interface> volumeInterface; 233 234 /** @brief D-Bus interface for the physical drive. */ 235 std::shared_ptr<sdbusplus::asio::dbus_interface> driveInterface; 236 237 /** @brief D-Bus interface for the location type of the drive. */ 238 std::shared_ptr<sdbusplus::asio::dbus_interface> embeddedLocationInterface; 239 240 /** @brief D-Bus interface for the location code of the drive. */ 241 std::shared_ptr<sdbusplus::asio::dbus_interface> locationCodeInterface; 242 243 /** @brief D-Bus interface for the asset information. */ 244 std::shared_ptr<sdbusplus::asio::dbus_interface> assetInterface; 245 246 /** @brief Association between chassis and drive. */ 247 std::shared_ptr<sdbusplus::asio::dbus_interface> association; 248 249 /** @brief Indicates whether the LUKS header is on the disk. */ 250 Drive::DriveEncryptionState encryptionStatus{ 251 Drive::DriveEncryptionState::Unknown}; 252 253 /** @brief Format LUKS encrypted device. 254 * 255 * @param[in] password - password to set for the LUKS device. 256 */ 257 void formatLuksDev(std::vector<uint8_t> password); 258 259 /** @brief check the LUKS header, for devPath 260 * 261 * @returns a CryptHandle to the LUKS drive 262 */ 263 CryptHandle loadLuksHeader(); 264 265 /** @brief Unlock the device. 266 * 267 * @param[in] password - password to activate the LUKS device. 268 */ 269 270 Drive::DriveEncryptionState findEncryptionStatus(); 271 272 void activateLuksDev(std::vector<uint8_t> password); 273 274 /** @brief Create the filesystem on the LUKS device. 275 * @details The LUKS device should already be activated, i.e. unlocked. 276 */ 277 void createFilesystem(); 278 279 /** @brief Deactivate the LUKS device. 280 * @details The filesystem is assumed to be unmounted already. 281 */ 282 void deactivateLuksDev(); 283 284 /** @brief Mount the filesystem. 285 * @details The filesystem should already exist and the LUKS device should 286 * be unlocked already. 287 */ 288 void mountFilesystem(); 289 290 /** @brief Unmount the filesystem. */ 291 void unmountFilesystem(); 292 }; 293 294 } // namespace estoraged 295