• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "libdm/dm_target.h"
18 
19 #include <inttypes.h>
20 #include <stdio.h>
21 #include <sys/types.h>
22 
23 #include <android-base/logging.h>
24 #include <android-base/macros.h>
25 #include <android-base/parseint.h>
26 #include <android-base/strings.h>
27 
28 #include <libdm/dm.h>
29 
30 namespace android {
31 namespace dm {
32 
Serialize() const33 std::string DmTarget::Serialize() const {
34     // Create a string containing a dm_target_spec, parameter data, and an
35     // explicit null terminator.
36     std::string data(sizeof(dm_target_spec), '\0');
37     data += GetParameterString();
38     data.push_back('\0');
39 
40     // The kernel expects each target to be 8-byte aligned.
41     size_t padding = DM_ALIGN(data.size()) - data.size();
42     for (size_t i = 0; i < padding; i++) {
43         data.push_back('\0');
44     }
45 
46     // Finally fill in the dm_target_spec.
47     struct dm_target_spec* spec = reinterpret_cast<struct dm_target_spec*>(&data[0]);
48     spec->sector_start = start();
49     spec->length = size();
50     snprintf(spec->target_type, sizeof(spec->target_type), "%s", name().c_str());
51     spec->next = (uint32_t)data.size();
52     return data;
53 }
54 
GetParameterString() const55 std::string DmTargetZero::GetParameterString() const {
56     // The zero target type has no additional parameters.
57     return "";
58 }
59 
GetParameterString() const60 std::string DmTargetLinear::GetParameterString() const {
61     return block_device_ + " " + std::to_string(physical_sector_);
62 }
63 
GetParameterString() const64 std::string DmTargetStripe::GetParameterString() const {
65     return "2 " + std::to_string(chunksize) + " " + block_device0_ + " 0 " + block_device1_ + " 0";
66 }
67 
DmTargetVerity(uint64_t start,uint64_t length,uint32_t version,const std::string & block_device,const std::string & hash_device,uint32_t data_block_size,uint32_t hash_block_size,uint32_t num_data_blocks,uint32_t hash_start_block,const std::string & hash_algorithm,const std::string & root_digest,const std::string & salt)68 DmTargetVerity::DmTargetVerity(uint64_t start, uint64_t length, uint32_t version,
69                                const std::string& block_device, const std::string& hash_device,
70                                uint32_t data_block_size, uint32_t hash_block_size,
71                                uint32_t num_data_blocks, uint32_t hash_start_block,
72                                const std::string& hash_algorithm, const std::string& root_digest,
73                                const std::string& salt)
74     : DmTarget(start, length), valid_(true) {
75     base_args_ = {
76             std::to_string(version),
77             block_device,
78             hash_device,
79             std::to_string(data_block_size),
80             std::to_string(hash_block_size),
81             std::to_string(num_data_blocks),
82             std::to_string(hash_start_block),
83             hash_algorithm,
84             root_digest,
85             salt,
86     };
87 }
88 
UseFec(const std::string & device,uint32_t num_roots,uint32_t num_blocks,uint32_t start)89 void DmTargetVerity::UseFec(const std::string& device, uint32_t num_roots, uint32_t num_blocks,
90                             uint32_t start) {
91     optional_args_.emplace_back("use_fec_from_device");
92     optional_args_.emplace_back(device);
93     optional_args_.emplace_back("fec_roots");
94     optional_args_.emplace_back(std::to_string(num_roots));
95     optional_args_.emplace_back("fec_blocks");
96     optional_args_.emplace_back(std::to_string(num_blocks));
97     optional_args_.emplace_back("fec_start");
98     optional_args_.emplace_back(std::to_string(start));
99 }
100 
SetVerityMode(const std::string & mode)101 void DmTargetVerity::SetVerityMode(const std::string& mode) {
102     if (mode != "panic_on_corruption" &&
103         mode != "restart_on_corruption" &&
104         mode != "ignore_corruption") {
105         LOG(ERROR) << "Unknown verity mode: " << mode;
106         valid_ = false;
107         return;
108     }
109     optional_args_.emplace_back(mode);
110 }
111 
IgnoreZeroBlocks()112 void DmTargetVerity::IgnoreZeroBlocks() {
113     optional_args_.emplace_back("ignore_zero_blocks");
114 }
115 
CheckAtMostOnce()116 void DmTargetVerity::CheckAtMostOnce() {
117     optional_args_.emplace_back("check_at_most_once");
118 }
119 
GetParameterString() const120 std::string DmTargetVerity::GetParameterString() const {
121     std::string base = android::base::Join(base_args_, " ");
122     if (optional_args_.empty()) {
123         return base;
124     }
125     std::string optional = android::base::Join(optional_args_, " ");
126     return base + " " + std::to_string(optional_args_.size()) + " " + optional;
127 }
128 
GetParameterString() const129 std::string DmTargetAndroidVerity::GetParameterString() const {
130     return keyid_ + " " + block_device_;
131 }
132 
GetParameterString() const133 std::string DmTargetBow::GetParameterString() const {
134     if (!block_size_) return target_string_;
135     return target_string_ + " 1 block_size:" + std::to_string(block_size_);
136 }
137 
name() const138 std::string DmTargetSnapshot::name() const {
139     if (mode_ == SnapshotStorageMode::Merge) {
140         return "snapshot-merge";
141     }
142     return "snapshot";
143 }
144 
GetParameterString() const145 std::string DmTargetSnapshot::GetParameterString() const {
146     std::string mode;
147     switch (mode_) {
148         case SnapshotStorageMode::Persistent:
149         case SnapshotStorageMode::Merge:
150             // Note: "O" lets us query for overflow in the status message. This
151             // is only supported on kernels 4.4+. On earlier kernels, an overflow
152             // will be reported as "Invalid" in the status string.
153             mode = "P";
154             if (ReportsOverflow(name())) {
155                 mode += "O";
156             }
157             break;
158         case SnapshotStorageMode::Transient:
159             mode = "N";
160             break;
161         default:
162             LOG(ERROR) << "DmTargetSnapshot unknown mode";
163             break;
164     }
165     return base_device_ + " " + cow_device_ + " " + mode + " " + std::to_string(chunk_size_);
166 }
167 
168 // Computes the percentage of complition for snapshot status.
169 // @sectors_initial is the number of sectors_allocated stored right before
170 // starting the merge.
MergePercent(const DmTargetSnapshot::Status & status,uint64_t sectors_initial)171 double DmTargetSnapshot::MergePercent(const DmTargetSnapshot::Status& status,
172                                       uint64_t sectors_initial) {
173     uint64_t s = status.sectors_allocated;
174     uint64_t t = status.total_sectors;
175     uint64_t m = status.metadata_sectors;
176     uint64_t i = sectors_initial == 0 ? t : sectors_initial;
177 
178     if (t <= s || i <= s) {
179         return 0.0;
180     }
181     if (s == 0 || t == 0 || s <= m) {
182         return 100.0;
183     }
184     return 100.0 / (i - m) * (i - s);
185 }
186 
ReportsOverflow(const std::string & target_type)187 bool DmTargetSnapshot::ReportsOverflow(const std::string& target_type) {
188     DeviceMapper& dm = DeviceMapper::Instance();
189     DmTargetTypeInfo info;
190     if (!dm.GetTargetByName(target_type, &info)) {
191         return false;
192     }
193     if (target_type == "snapshot") {
194         return info.IsAtLeast(1, 15, 0);
195     }
196     if (target_type == "snapshot-merge") {
197         return info.IsAtLeast(1, 4, 0);
198     }
199     return false;
200 }
201 
ParseStatusText(const std::string & text,Status * status)202 bool DmTargetSnapshot::ParseStatusText(const std::string& text, Status* status) {
203     // Try to parse the line as it should be
204     int args = sscanf(text.c_str(), "%" PRIu64 "/%" PRIu64 " %" PRIu64, &status->sectors_allocated,
205                       &status->total_sectors, &status->metadata_sectors);
206     if (args == 3) {
207         return true;
208     }
209     auto sections = android::base::Split(text, " ");
210     if (sections.size() == 0) {
211         LOG(ERROR) << "could not parse empty status";
212         return false;
213     }
214     // Error codes are: "Invalid", "Overflow" and "Merge failed"
215     if (sections.size() == 1) {
216         if (text == "Invalid" || text == "Overflow") {
217             status->error = text;
218             return true;
219         }
220     } else if (sections.size() == 2 && text == "Merge failed") {
221         status->error = text;
222         return true;
223     }
224     LOG(ERROR) << "could not parse snapshot status: wrong format";
225     return false;
226 }
227 
GetDevicesFromParams(const std::string & params,std::string * base_device,std::string * cow_device)228 bool DmTargetSnapshot::GetDevicesFromParams(const std::string& params, std::string* base_device,
229                                             std::string* cow_device) {
230     auto pieces = android::base::Split(params, " ");
231     if (pieces.size() < 2) {
232         LOG(ERROR) << "Parameter string is invalid: " << params;
233         return false;
234     }
235     *base_device = pieces[0];
236     *cow_device = pieces[1];
237     return true;
238 }
239 
GetParameterString() const240 std::string DmTargetCrypt::GetParameterString() const {
241     std::vector<std::string> argv = {
242             cipher_,
243             key_,
244             std::to_string(iv_sector_offset_),
245             device_,
246             std::to_string(device_sector_),
247     };
248 
249     std::vector<std::string> extra_argv;
250     if (allow_discards_) extra_argv.emplace_back("allow_discards");
251     if (allow_encrypt_override_) extra_argv.emplace_back("allow_encrypt_override");
252     if (iv_large_sectors_) extra_argv.emplace_back("iv_large_sectors");
253     if (sector_size_) extra_argv.emplace_back("sector_size:" + std::to_string(sector_size_));
254 
255     if (!extra_argv.empty()) argv.emplace_back(std::to_string(extra_argv.size()));
256 
257     argv.insert(argv.end(), extra_argv.begin(), extra_argv.end());
258     return android::base::Join(argv, " ");
259 }
260 
Valid() const261 bool DmTargetDefaultKey::Valid() const {
262     if (!use_legacy_options_format_ && !set_dun_) return false;
263     return true;
264 }
265 
GetParameterString() const266 std::string DmTargetDefaultKey::GetParameterString() const {
267     std::vector<std::string> argv;
268     argv.emplace_back(cipher_);
269     argv.emplace_back(key_);
270     if (!use_legacy_options_format_) {
271         argv.emplace_back("0");  // iv_offset
272     }
273     argv.emplace_back(blockdev_);
274     argv.push_back(std::to_string(start_sector_));
275     std::vector<std::string> extra_argv;
276     if (use_legacy_options_format_) {
277         if (set_dun_) {  // v2 always sets the DUN.
278             extra_argv.emplace_back("set_dun");
279         }
280     } else {
281         extra_argv.emplace_back("allow_discards");
282         extra_argv.emplace_back("sector_size:4096");
283         extra_argv.emplace_back("iv_large_sectors");
284         if (is_hw_wrapped_) extra_argv.emplace_back("wrappedkey_v0");
285     }
286     if (!extra_argv.empty()) {
287         argv.emplace_back(std::to_string(extra_argv.size()));
288         argv.insert(argv.end(), extra_argv.begin(), extra_argv.end());
289     }
290     return android::base::Join(argv, " ");
291 }
292 
GetParameterString() const293 std::string DmTargetUser::GetParameterString() const {
294     std::vector<std::string> argv;
295     argv.push_back(std::to_string(start()));
296     argv.push_back(std::to_string(size()));
297     argv.push_back(control_device());
298     return android::base::Join(argv, " ");
299 }
300 
DmTargetThinPool(uint64_t start,uint64_t length,const std::string & metadata_dev,const std::string & data_dev,uint64_t data_block_size,uint64_t low_water_mark)301 DmTargetThinPool::DmTargetThinPool(uint64_t start, uint64_t length, const std::string& metadata_dev,
302                                    const std::string& data_dev, uint64_t data_block_size,
303                                    uint64_t low_water_mark)
304     : DmTarget(start, length),
305       metadata_dev_(metadata_dev),
306       data_dev_(data_dev),
307       data_block_size_(data_block_size),
308       low_water_mark_(low_water_mark) {}
309 
GetParameterString() const310 std::string DmTargetThinPool::GetParameterString() const {
311     std::vector<std::string> args{
312             metadata_dev_,
313             data_dev_,
314             std::to_string(data_block_size_),
315             std::to_string(low_water_mark_),
316     };
317     return android::base::Join(args, " ");
318 }
319 
Valid() const320 bool DmTargetThinPool::Valid() const {
321     // data_block_size: must be between 128 (64KB) and 2097152 (1GB) and a multiple of 128 (64KB)
322     if (data_block_size_ < 128 || data_block_size_ > 2097152) return false;
323     if (data_block_size_ % 128) return false;
324     return true;
325 }
326 
DmTargetThin(uint64_t start,uint64_t length,const std::string & pool_dev,uint64_t dev_id)327 DmTargetThin::DmTargetThin(uint64_t start, uint64_t length, const std::string& pool_dev,
328                            uint64_t dev_id)
329     : DmTarget(start, length), pool_dev_(pool_dev), dev_id_(dev_id) {}
330 
GetParameterString() const331 std::string DmTargetThin::GetParameterString() const {
332     std::vector<std::string> args{
333             pool_dev_,
334             std::to_string(dev_id_),
335     };
336     return android::base::Join(args, " ");
337 }
338 
339 }  // namespace dm
340 }  // namespace android
341