xref: /aosp_15_r20/external/libbrillo/brillo/blkdev_utils/device_mapper.cc (revision 1a96fba65179ea7d3f56207137718607415c5953)
1*1a96fba6SXin Li // Copyright 2018 The Chromium OS Authors. All rights reserved.
2*1a96fba6SXin Li // Use of this source code is governed by a BSD-style license that can be
3*1a96fba6SXin Li // found in the LICENSE file.
4*1a96fba6SXin Li 
5*1a96fba6SXin Li #include <brillo/blkdev_utils/device_mapper.h>
6*1a96fba6SXin Li 
7*1a96fba6SXin Li #include <libdevmapper.h>
8*1a96fba6SXin Li #include <algorithm>
9*1a96fba6SXin Li #include <utility>
10*1a96fba6SXin Li 
11*1a96fba6SXin Li #include <base/files/file_util.h>
12*1a96fba6SXin Li #include <base/strings/string_number_conversions.h>
13*1a96fba6SXin Li #include <base/strings/string_tokenizer.h>
14*1a96fba6SXin Li #include <base/strings/stringprintf.h>
15*1a96fba6SXin Li #include <brillo/blkdev_utils/device_mapper_task.h>
16*1a96fba6SXin Li #include <brillo/secure_blob.h>
17*1a96fba6SXin Li 
18*1a96fba6SXin Li namespace brillo {
19*1a96fba6SXin Li 
20*1a96fba6SXin Li // Use a tokenizer to parse string data stored in SecureBlob.
21*1a96fba6SXin Li // The tokenizer does not store internal state so it should be
22*1a96fba6SXin Li // okay to use with SecureBlobs.
23*1a96fba6SXin Li // DO NOT USE .toker() as that leaks contents of the SecureBlob.
24*1a96fba6SXin Li using SecureBlobTokenizer =
25*1a96fba6SXin Li     base::StringTokenizerT<std::string, SecureBlob::const_iterator>;
26*1a96fba6SXin Li 
DevmapperTable(uint64_t start,uint64_t size,const std::string & type,const SecureBlob & parameters)27*1a96fba6SXin Li DevmapperTable::DevmapperTable(uint64_t start,
28*1a96fba6SXin Li                                uint64_t size,
29*1a96fba6SXin Li                                const std::string& type,
30*1a96fba6SXin Li                                const SecureBlob& parameters)
31*1a96fba6SXin Li     : start_(start), size_(size), type_(type), parameters_(parameters) {}
32*1a96fba6SXin Li 
ToSecureBlob()33*1a96fba6SXin Li SecureBlob DevmapperTable::ToSecureBlob() {
34*1a96fba6SXin Li   SecureBlob table_blob(base::StringPrintf("%" PRIu64 " %" PRIu64 " %s ",
35*1a96fba6SXin Li                                            start_, size_, type_.c_str()));
36*1a96fba6SXin Li 
37*1a96fba6SXin Li   return SecureBlob::Combine(table_blob, parameters_);
38*1a96fba6SXin Li }
39*1a96fba6SXin Li 
CreateTableFromSecureBlob(const SecureBlob & table)40*1a96fba6SXin Li DevmapperTable DevmapperTable::CreateTableFromSecureBlob(
41*1a96fba6SXin Li     const SecureBlob& table) {
42*1a96fba6SXin Li   uint64_t start, size;
43*1a96fba6SXin Li   std::string type;
44*1a96fba6SXin Li   DevmapperTable invalid_table(0, 0, "", SecureBlob());
45*1a96fba6SXin Li 
46*1a96fba6SXin Li   SecureBlobTokenizer tokenizer(table.begin(), table.end(), " ");
47*1a96fba6SXin Li 
48*1a96fba6SXin Li   // First parameter is start.
49*1a96fba6SXin Li   if (!tokenizer.GetNext() ||
50*1a96fba6SXin Li       !base::StringToUint64(
51*1a96fba6SXin Li           std::string(tokenizer.token_begin(), tokenizer.token_end()), &start))
52*1a96fba6SXin Li     return invalid_table;
53*1a96fba6SXin Li 
54*1a96fba6SXin Li   // Second parameter is size of the dm device.
55*1a96fba6SXin Li   if (!tokenizer.GetNext() ||
56*1a96fba6SXin Li       !base::StringToUint64(
57*1a96fba6SXin Li           std::string(tokenizer.token_begin(), tokenizer.token_end()), &size))
58*1a96fba6SXin Li     return invalid_table;
59*1a96fba6SXin Li 
60*1a96fba6SXin Li   // Third parameter is type of dm device.
61*1a96fba6SXin Li   if (!tokenizer.GetNext())
62*1a96fba6SXin Li     return invalid_table;
63*1a96fba6SXin Li 
64*1a96fba6SXin Li   type = std::string(tokenizer.token_begin(), tokenizer.token_end());
65*1a96fba6SXin Li 
66*1a96fba6SXin Li   // The remaining string is the parameters.
67*1a96fba6SXin Li   if (!tokenizer.GetNext())
68*1a96fba6SXin Li     return invalid_table;
69*1a96fba6SXin Li 
70*1a96fba6SXin Li   // The remaining part is the parameters passed to the device.
71*1a96fba6SXin Li   SecureBlob target = SecureBlob(tokenizer.token_begin(), table.end());
72*1a96fba6SXin Li 
73*1a96fba6SXin Li   return DevmapperTable(start, size, type, target);
74*1a96fba6SXin Li }
75*1a96fba6SXin Li 
CryptGetKey()76*1a96fba6SXin Li SecureBlob DevmapperTable::CryptGetKey() {
77*1a96fba6SXin Li   SecureBlobTokenizer tokenizer(parameters_.begin(), parameters_.end(), " ");
78*1a96fba6SXin Li 
79*1a96fba6SXin Li   // First field is the cipher.
80*1a96fba6SXin Li   if (!tokenizer.GetNext())
81*1a96fba6SXin Li     return SecureBlob();
82*1a96fba6SXin Li 
83*1a96fba6SXin Li   // The key is stored in the second field.
84*1a96fba6SXin Li   if (!tokenizer.GetNext())
85*1a96fba6SXin Li     return SecureBlob();
86*1a96fba6SXin Li 
87*1a96fba6SXin Li   SecureBlob hex_key(tokenizer.token_begin(), tokenizer.token_end());
88*1a96fba6SXin Li 
89*1a96fba6SXin Li   SecureBlob key = SecureHexToSecureBlob(hex_key);
90*1a96fba6SXin Li 
91*1a96fba6SXin Li   if (key.empty()) {
92*1a96fba6SXin Li     LOG(ERROR) << "CryptExtractKey: HexStringToBytes failed";
93*1a96fba6SXin Li     return SecureBlob();
94*1a96fba6SXin Li   }
95*1a96fba6SXin Li 
96*1a96fba6SXin Li   return key;
97*1a96fba6SXin Li }
98*1a96fba6SXin Li 
99*1a96fba6SXin Li // In order to not leak the encryption key to non-SecureBlob managed memory,
100*1a96fba6SXin Li // create the parameter blobs in three parts and combine.
CryptCreateParameters(const std::string & cipher,const SecureBlob & encryption_key,const int iv_offset,const base::FilePath & device,int device_offset,bool allow_discard)101*1a96fba6SXin Li SecureBlob DevmapperTable::CryptCreateParameters(
102*1a96fba6SXin Li     const std::string& cipher,
103*1a96fba6SXin Li     const SecureBlob& encryption_key,
104*1a96fba6SXin Li     const int iv_offset,
105*1a96fba6SXin Li     const base::FilePath& device,
106*1a96fba6SXin Li     int device_offset,
107*1a96fba6SXin Li     bool allow_discard) {
108*1a96fba6SXin Li   // First field is the cipher.
109*1a96fba6SXin Li   SecureBlob parameter_parts[3];
110*1a96fba6SXin Li 
111*1a96fba6SXin Li   parameter_parts[0] = SecureBlob(cipher + " ");
112*1a96fba6SXin Li   parameter_parts[1] = SecureBlobToSecureHex(encryption_key);
113*1a96fba6SXin Li   parameter_parts[2] = SecureBlob(base::StringPrintf(
114*1a96fba6SXin Li       " %d %s %d%s", iv_offset, device.value().c_str(), device_offset,
115*1a96fba6SXin Li       (allow_discard ? " 1 allow_discards" : "")));
116*1a96fba6SXin Li 
117*1a96fba6SXin Li   SecureBlob parameters;
118*1a96fba6SXin Li   for (auto param_part : parameter_parts)
119*1a96fba6SXin Li     parameters = SecureBlob::Combine(parameters, param_part);
120*1a96fba6SXin Li 
121*1a96fba6SXin Li   return parameters;
122*1a96fba6SXin Li }
123*1a96fba6SXin Li 
CreateDevmapperTask(int type)124*1a96fba6SXin Li std::unique_ptr<DevmapperTask> CreateDevmapperTask(int type) {
125*1a96fba6SXin Li   return std::make_unique<DevmapperTaskImpl>(type);
126*1a96fba6SXin Li }
127*1a96fba6SXin Li 
DeviceMapper()128*1a96fba6SXin Li DeviceMapper::DeviceMapper() {
129*1a96fba6SXin Li   dm_task_factory_ = base::Bind(&CreateDevmapperTask);
130*1a96fba6SXin Li }
131*1a96fba6SXin Li 
DeviceMapper(const DevmapperTaskFactory & factory)132*1a96fba6SXin Li DeviceMapper::DeviceMapper(const DevmapperTaskFactory& factory)
133*1a96fba6SXin Li     : dm_task_factory_(factory) {}
134*1a96fba6SXin Li 
Setup(const std::string & name,const DevmapperTable & table)135*1a96fba6SXin Li bool DeviceMapper::Setup(const std::string& name, const DevmapperTable& table) {
136*1a96fba6SXin Li   auto task = dm_task_factory_.Run(DM_DEVICE_CREATE);
137*1a96fba6SXin Li 
138*1a96fba6SXin Li   if (!task->SetName(name)) {
139*1a96fba6SXin Li     LOG(ERROR) << "Setup: SetName failed.";
140*1a96fba6SXin Li     return false;
141*1a96fba6SXin Li   }
142*1a96fba6SXin Li 
143*1a96fba6SXin Li   if (!task->AddTarget(table.GetStart(), table.GetSize(), table.GetType(),
144*1a96fba6SXin Li                        table.GetParameters())) {
145*1a96fba6SXin Li     LOG(ERROR) << "Setup: AddTarget failed";
146*1a96fba6SXin Li     return false;
147*1a96fba6SXin Li   }
148*1a96fba6SXin Li 
149*1a96fba6SXin Li   if (!task->Run(true /* udev sync */)) {
150*1a96fba6SXin Li     LOG(ERROR) << "Setup: Run failed.";
151*1a96fba6SXin Li     return false;
152*1a96fba6SXin Li   }
153*1a96fba6SXin Li 
154*1a96fba6SXin Li   return true;
155*1a96fba6SXin Li }
156*1a96fba6SXin Li 
Remove(const std::string & name)157*1a96fba6SXin Li bool DeviceMapper::Remove(const std::string& name) {
158*1a96fba6SXin Li   auto task = dm_task_factory_.Run(DM_DEVICE_REMOVE);
159*1a96fba6SXin Li 
160*1a96fba6SXin Li   if (!task->SetName(name)) {
161*1a96fba6SXin Li     LOG(ERROR) << "Remove: SetName failed.";
162*1a96fba6SXin Li     return false;
163*1a96fba6SXin Li   }
164*1a96fba6SXin Li 
165*1a96fba6SXin Li   if (!task->Run(true /* udev_sync */)) {
166*1a96fba6SXin Li     LOG(ERROR) << "Remove: Teardown failed.";
167*1a96fba6SXin Li     return false;
168*1a96fba6SXin Li   }
169*1a96fba6SXin Li 
170*1a96fba6SXin Li   return true;
171*1a96fba6SXin Li }
172*1a96fba6SXin Li 
GetTable(const std::string & name)173*1a96fba6SXin Li DevmapperTable DeviceMapper::GetTable(const std::string& name) {
174*1a96fba6SXin Li   auto task = dm_task_factory_.Run(DM_DEVICE_TABLE);
175*1a96fba6SXin Li   uint64_t start, size;
176*1a96fba6SXin Li   std::string type;
177*1a96fba6SXin Li   SecureBlob parameters;
178*1a96fba6SXin Li 
179*1a96fba6SXin Li   if (!task->SetName(name)) {
180*1a96fba6SXin Li     LOG(ERROR) << "GetTable: SetName failed.";
181*1a96fba6SXin Li     return DevmapperTable(0, 0, "", SecureBlob());
182*1a96fba6SXin Li   }
183*1a96fba6SXin Li 
184*1a96fba6SXin Li   if (!task->Run()) {
185*1a96fba6SXin Li     LOG(ERROR) << "GetTable: Run failed.";
186*1a96fba6SXin Li     return DevmapperTable(0, 0, "", SecureBlob());
187*1a96fba6SXin Li   }
188*1a96fba6SXin Li 
189*1a96fba6SXin Li   task->GetNextTarget(&start, &size, &type, &parameters);
190*1a96fba6SXin Li 
191*1a96fba6SXin Li   return DevmapperTable(start, size, type, parameters);
192*1a96fba6SXin Li }
193*1a96fba6SXin Li 
WipeTable(const std::string & name)194*1a96fba6SXin Li bool DeviceMapper::WipeTable(const std::string& name) {
195*1a96fba6SXin Li   auto size_task = dm_task_factory_.Run(DM_DEVICE_TABLE);
196*1a96fba6SXin Li 
197*1a96fba6SXin Li   if (!size_task->SetName(name)) {
198*1a96fba6SXin Li     LOG(ERROR) << "WipeTable: SetName failed.";
199*1a96fba6SXin Li     return false;
200*1a96fba6SXin Li   }
201*1a96fba6SXin Li 
202*1a96fba6SXin Li   if (!size_task->Run()) {
203*1a96fba6SXin Li     LOG(ERROR) << "WipeTable: RunTask failed.";
204*1a96fba6SXin Li     return false;
205*1a96fba6SXin Li   }
206*1a96fba6SXin Li 
207*1a96fba6SXin Li   // Arguments for fetching dm target.
208*1a96fba6SXin Li   bool ret = false;
209*1a96fba6SXin Li   uint64_t start = 0, size = 0, total_size = 0;
210*1a96fba6SXin Li   std::string type;
211*1a96fba6SXin Li   SecureBlob parameters;
212*1a96fba6SXin Li 
213*1a96fba6SXin Li   // Get maximum size of the device to be wiped.
214*1a96fba6SXin Li   do {
215*1a96fba6SXin Li     ret = size_task->GetNextTarget(&start, &size, &type, &parameters);
216*1a96fba6SXin Li     total_size = std::max(start + size, total_size);
217*1a96fba6SXin Li   } while (ret);
218*1a96fba6SXin Li 
219*1a96fba6SXin Li   // Setup wipe task.
220*1a96fba6SXin Li   auto wipe_task = dm_task_factory_.Run(DM_DEVICE_RELOAD);
221*1a96fba6SXin Li 
222*1a96fba6SXin Li   if (!wipe_task->SetName(name)) {
223*1a96fba6SXin Li     LOG(ERROR) << "WipeTable: SetName failed.";
224*1a96fba6SXin Li     return false;
225*1a96fba6SXin Li   }
226*1a96fba6SXin Li 
227*1a96fba6SXin Li   if (!wipe_task->AddTarget(0, total_size, "error", SecureBlob())) {
228*1a96fba6SXin Li     LOG(ERROR) << "WipeTable: AddTarget failed.";
229*1a96fba6SXin Li     return false;
230*1a96fba6SXin Li   }
231*1a96fba6SXin Li 
232*1a96fba6SXin Li   if (!wipe_task->Run()) {
233*1a96fba6SXin Li     LOG(ERROR) << "WipeTable: RunTask failed.";
234*1a96fba6SXin Li     return false;
235*1a96fba6SXin Li   }
236*1a96fba6SXin Li 
237*1a96fba6SXin Li   return true;
238*1a96fba6SXin Li }
239*1a96fba6SXin Li 
240*1a96fba6SXin Li }  // namespace brillo
241