xref: /openbmc/estoraged/include/estoraged.hpp (revision 30bfe8efd252bee31f919d61bbe94af6619fb39b)
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