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.h"
18
19 #include <linux/dm-ioctl.h>
20 #include <sys/ioctl.h>
21 #include <sys/sysmacros.h>
22 #include <sys/types.h>
23 #include <sys/utsname.h>
24
25 #include <chrono>
26 #include <functional>
27 #include <string_view>
28 #include <thread>
29
30 #include <android-base/file.h>
31 #include <android-base/logging.h>
32 #include <android-base/macros.h>
33 #include <android-base/properties.h>
34 #include <android-base/strings.h>
35 #include <uuid/uuid.h>
36
37 #include "utility.h"
38
39 #ifndef DM_DEFERRED_REMOVE
40 #define DM_DEFERRED_REMOVE (1 << 17)
41 #endif
42 #ifndef DM_IMA_MEASUREMENT_FLAG
43 #define DM_IMA_MEASUREMENT_FLAG (1 << 19)
44 #endif
45
46 namespace android {
47 namespace dm {
48
49 using namespace std::literals;
50
DeviceMapper()51 DeviceMapper::DeviceMapper() : fd_(-1) {
52 fd_ = TEMP_FAILURE_RETRY(open("/dev/device-mapper", O_RDWR | O_CLOEXEC));
53 if (fd_ < 0) {
54 PLOG(ERROR) << "Failed to open device-mapper";
55 }
56 }
57
Instance()58 DeviceMapper& DeviceMapper::Instance() {
59 static DeviceMapper instance;
60 return instance;
61 }
62
63 // Creates a new device mapper device
CreateDevice(const std::string & name,const std::string & uuid)64 bool DeviceMapper::CreateDevice(const std::string& name, const std::string& uuid) {
65 if (name.empty()) {
66 LOG(ERROR) << "Unnamed device mapper device creation is not supported";
67 return false;
68 }
69 if (name.size() >= DM_NAME_LEN) {
70 LOG(ERROR) << "[" << name << "] is too long to be device mapper name";
71 return false;
72 }
73
74 struct dm_ioctl io;
75 InitIo(&io, name);
76 if (!uuid.empty()) {
77 snprintf(io.uuid, sizeof(io.uuid), "%s", uuid.c_str());
78 }
79
80 if (ioctl(fd_, DM_DEV_CREATE, &io)) {
81 PLOG(ERROR) << "DM_DEV_CREATE failed for [" << name << "]";
82 return false;
83 }
84
85 // Check to make sure the newly created device doesn't already have targets
86 // added or opened by someone
87 CHECK(io.target_count == 0) << "Unexpected targets for newly created [" << name << "] device";
88 CHECK(io.open_count == 0) << "Unexpected opens for newly created [" << name << "] device";
89
90 // Creates a new device mapper device with the name passed in
91 return true;
92 }
93
DeleteDeviceIfExists(const std::string & name,const std::chrono::milliseconds & timeout_ms)94 bool DeviceMapper::DeleteDeviceIfExists(const std::string& name,
95 const std::chrono::milliseconds& timeout_ms) {
96 if (GetState(name) == DmDeviceState::INVALID) {
97 return true;
98 }
99 return DeleteDevice(name, timeout_ms);
100 }
101
DeleteDeviceIfExists(const std::string & name)102 bool DeviceMapper::DeleteDeviceIfExists(const std::string& name) {
103 return DeleteDeviceIfExists(name, 0ms);
104 }
105
DeleteDevice(const std::string & name,const std::chrono::milliseconds & timeout_ms)106 bool DeviceMapper::DeleteDevice(const std::string& name,
107 const std::chrono::milliseconds& timeout_ms) {
108 std::string unique_path;
109 if (!GetDeviceUniquePath(name, &unique_path)) {
110 LOG(ERROR) << "Failed to get unique path for device " << name;
111 }
112 // Expect to have uevent generated if the unique path actually exists. This may not exist
113 // if the device was created but has never been activated before it gets deleted.
114 bool need_uevent = !unique_path.empty() && access(unique_path.c_str(), F_OK) == 0;
115
116 struct dm_ioctl io;
117 InitIo(&io, name);
118
119 if (ioctl(fd_, DM_DEV_REMOVE, &io)) {
120 PLOG(ERROR) << "DM_DEV_REMOVE failed for [" << name << "]";
121 return false;
122 }
123
124 // Check to make sure appropriate uevent is generated so ueventd will
125 // do the right thing and remove the corresponding device node and symlinks.
126 if (need_uevent && (io.flags & DM_UEVENT_GENERATED_FLAG) == 0) {
127 LOG(ERROR) << "Didn't generate uevent for [" << name << "] removal";
128 return false;
129 }
130
131 if (timeout_ms <= std::chrono::milliseconds::zero()) {
132 return true;
133 }
134 if (unique_path.empty()) {
135 return false;
136 }
137 if (!WaitForFileDeleted(unique_path, timeout_ms)) {
138 LOG(ERROR) << "Failed waiting for " << unique_path << " to be deleted";
139 return false;
140 }
141 return true;
142 }
143
DeleteDevice(const std::string & name)144 bool DeviceMapper::DeleteDevice(const std::string& name) {
145 return DeleteDevice(name, 0ms);
146 }
147
DeleteDeviceDeferred(const std::string & name)148 bool DeviceMapper::DeleteDeviceDeferred(const std::string& name) {
149 struct dm_ioctl io;
150 InitIo(&io, name);
151
152 io.flags |= DM_DEFERRED_REMOVE;
153 if (ioctl(fd_, DM_DEV_REMOVE, &io)) {
154 PLOG(ERROR) << "DM_DEV_REMOVE with DM_DEFERRED_REMOVE failed for [" << name << "]";
155 return false;
156 }
157 return true;
158 }
159
DeleteDeviceIfExistsDeferred(const std::string & name)160 bool DeviceMapper::DeleteDeviceIfExistsDeferred(const std::string& name) {
161 if (GetState(name) == DmDeviceState::INVALID) {
162 return true;
163 }
164 return DeleteDeviceDeferred(name);
165 }
166
GenerateUuid()167 static std::string GenerateUuid() {
168 uuid_t uuid_bytes;
169 uuid_generate(uuid_bytes);
170
171 char uuid_chars[37] = {};
172 uuid_unparse_lower(uuid_bytes, uuid_chars);
173
174 return std::string{uuid_chars};
175 }
176
IsRecovery()177 static bool IsRecovery() {
178 return access("/system/bin/recovery", F_OK) == 0;
179 }
180
CreateEmptyDevice(const std::string & name)181 bool DeviceMapper::CreateEmptyDevice(const std::string& name) {
182 std::string uuid = GenerateUuid();
183 return CreateDevice(name, uuid);
184 }
185
WaitForDevice(const std::string & name,const std::chrono::milliseconds & timeout_ms,std::string * path)186 bool DeviceMapper::WaitForDevice(const std::string& name,
187 const std::chrono::milliseconds& timeout_ms, std::string* path) {
188 // We use the unique path for testing whether the device is ready. After
189 // that, it's safe to use the dm-N path which is compatible with callers
190 // that expect it to be formatted as such.
191 std::string unique_path;
192 if (!GetDeviceUniquePath(name, &unique_path) || !GetDmDevicePathByName(name, path)) {
193 DeleteDevice(name);
194 return false;
195 }
196
197 if (timeout_ms <= std::chrono::milliseconds::zero()) {
198 return true;
199 }
200
201 if (IsRecovery()) {
202 bool non_ab_device = android::base::GetProperty("ro.build.ab_update", "").empty();
203 int sdk = android::base::GetIntProperty("ro.build.version.sdk", 0);
204 if (non_ab_device && sdk && sdk <= 29) {
205 LOG(INFO) << "Detected ueventd incompatibility, reverting to legacy libdm behavior.";
206 unique_path = *path;
207 }
208 }
209
210 if (!WaitForFile(unique_path, timeout_ms)) {
211 LOG(ERROR) << "Failed waiting for device path: " << unique_path;
212 DeleteDevice(name);
213 return false;
214 }
215 return true;
216 }
217
CreateDevice(const std::string & name,const DmTable & table,std::string * path,const std::chrono::milliseconds & timeout_ms)218 bool DeviceMapper::CreateDevice(const std::string& name, const DmTable& table, std::string* path,
219 const std::chrono::milliseconds& timeout_ms) {
220 if (!CreateEmptyDevice(name)) {
221 return false;
222 }
223
224 if (!LoadTableAndActivate(name, table)) {
225 DeleteDevice(name);
226 return false;
227 }
228
229 if (!WaitForDevice(name, timeout_ms, path)) {
230 DeleteDevice(name);
231 return false;
232 }
233
234 return true;
235 }
236
GetDeviceUniquePath(const std::string & name,std::string * path)237 bool DeviceMapper::GetDeviceUniquePath(const std::string& name, std::string* path) {
238 struct dm_ioctl io;
239 InitIo(&io, name);
240 if (ioctl(fd_, DM_DEV_STATUS, &io) < 0) {
241 PLOG(ERROR) << "Failed to get device path: " << name;
242 return false;
243 }
244
245 if (io.uuid[0] == '\0') {
246 LOG(ERROR) << "Device does not have a unique path: " << name;
247 return false;
248 }
249 *path = "/dev/block/mapper/by-uuid/"s + io.uuid;
250 return true;
251 }
252
GetDeviceNameAndUuid(dev_t dev,std::string * name,std::string * uuid)253 bool DeviceMapper::GetDeviceNameAndUuid(dev_t dev, std::string* name, std::string* uuid) {
254 struct dm_ioctl io;
255 InitIo(&io, {});
256 io.dev = dev;
257
258 if (ioctl(fd_, DM_DEV_STATUS, &io) < 0) {
259 PLOG(ERROR) << "Failed to find device dev: " << major(dev) << ":" << minor(dev);
260 return false;
261 }
262
263 if (name) {
264 *name = io.name;
265 }
266 if (uuid) {
267 *uuid = io.uuid;
268 }
269 return true;
270 }
271
GetDetailedInfo(const std::string & name) const272 std::optional<DeviceMapper::Info> DeviceMapper::GetDetailedInfo(const std::string& name) const {
273 struct dm_ioctl io;
274 InitIo(&io, name);
275 if (ioctl(fd_, DM_DEV_STATUS, &io) < 0) {
276 return std::nullopt;
277 }
278 return Info(io.flags);
279 }
280
GetState(const std::string & name) const281 DmDeviceState DeviceMapper::GetState(const std::string& name) const {
282 struct dm_ioctl io;
283 InitIo(&io, name);
284 if (ioctl(fd_, DM_DEV_STATUS, &io) < 0) {
285 return DmDeviceState::INVALID;
286 }
287 if ((io.flags & DM_ACTIVE_PRESENT_FLAG) && !(io.flags & DM_SUSPEND_FLAG)) {
288 return DmDeviceState::ACTIVE;
289 }
290 return DmDeviceState::SUSPENDED;
291 }
292
ChangeState(const std::string & name,DmDeviceState state)293 bool DeviceMapper::ChangeState(const std::string& name, DmDeviceState state) {
294 if (state != DmDeviceState::SUSPENDED && state != DmDeviceState::ACTIVE) {
295 return false;
296 }
297
298 struct dm_ioctl io;
299 InitIo(&io, name);
300
301 if (state == DmDeviceState::SUSPENDED) io.flags = DM_SUSPEND_FLAG;
302
303 if (ioctl(fd_, DM_DEV_SUSPEND, &io) < 0) {
304 PLOG(ERROR) << "DM_DEV_SUSPEND "
305 << (state == DmDeviceState::SUSPENDED ? "suspend" : "resume") << " failed";
306 return false;
307 }
308 return true;
309 }
310
CreateDevice(const std::string & name,const DmTable & table)311 bool DeviceMapper::CreateDevice(const std::string& name, const DmTable& table) {
312 std::string ignore_path;
313 if (!CreateDevice(name, table, &ignore_path, 0ms)) {
314 return false;
315 }
316 return true;
317 }
318
LoadTable(const std::string & name,const DmTable & table)319 bool DeviceMapper::LoadTable(const std::string& name, const DmTable& table) {
320 std::string ioctl_buffer(sizeof(struct dm_ioctl), 0);
321 ioctl_buffer += table.Serialize();
322
323 struct dm_ioctl* io = reinterpret_cast<struct dm_ioctl*>(&ioctl_buffer[0]);
324 InitIo(io, name);
325 io->data_size = ioctl_buffer.size();
326 io->data_start = sizeof(struct dm_ioctl);
327 io->target_count = static_cast<uint32_t>(table.num_targets());
328 if (table.readonly()) {
329 io->flags |= DM_READONLY_FLAG;
330 }
331 if (ioctl(fd_, DM_TABLE_LOAD, io)) {
332 PLOG(ERROR) << "DM_TABLE_LOAD failed";
333 return false;
334 }
335 return true;
336 }
337
LoadTableAndActivate(const std::string & name,const DmTable & table)338 bool DeviceMapper::LoadTableAndActivate(const std::string& name, const DmTable& table) {
339 if (!LoadTable(name, table)) {
340 return false;
341 }
342
343 struct dm_ioctl io;
344 InitIo(&io, name);
345 if (ioctl(fd_, DM_DEV_SUSPEND, &io)) {
346 PLOG(ERROR) << "DM_TABLE_SUSPEND resume failed";
347 return false;
348 }
349 return true;
350 }
351
352 // Reads all the available device mapper targets and their corresponding
353 // versions from the kernel and returns in a vector
GetAvailableTargets(std::vector<DmTargetTypeInfo> * targets)354 bool DeviceMapper::GetAvailableTargets(std::vector<DmTargetTypeInfo>* targets) {
355 targets->clear();
356
357 // calculate the space needed to read a maximum of kMaxPossibleDmTargets
358 uint32_t payload_size = sizeof(struct dm_target_versions);
359 payload_size += DM_MAX_TYPE_NAME;
360 // device mapper wants every target spec to be aligned at 8-byte boundary
361 payload_size = DM_ALIGN(payload_size);
362 payload_size *= kMaxPossibleDmTargets;
363
364 uint32_t data_size = sizeof(struct dm_ioctl) + payload_size;
365 auto buffer = std::unique_ptr<void, void (*)(void*)>(calloc(1, data_size), free);
366 if (buffer == nullptr) {
367 LOG(ERROR) << "failed to allocate memory";
368 return false;
369 }
370
371 // Sets appropriate data size and data_start to make sure we tell kernel
372 // about the total size of the buffer we are passing and where to start
373 // writing the list of targets.
374 struct dm_ioctl* io = reinterpret_cast<struct dm_ioctl*>(buffer.get());
375 InitIo(io);
376 io->data_size = data_size;
377 io->data_start = sizeof(*io);
378
379 if (ioctl(fd_, DM_LIST_VERSIONS, io)) {
380 PLOG(ERROR) << "DM_LIST_VERSIONS failed";
381 return false;
382 }
383
384 // If the provided buffer wasn't enough to list all targets, note that
385 // any data beyond sizeof(*io) must not be read in this case
386 if (io->flags & DM_BUFFER_FULL_FLAG) {
387 LOG(INFO) << data_size << " is not enough memory to list all dm targets";
388 return false;
389 }
390
391 // if there are no targets registered, return success with empty vector
392 if (io->data_size == sizeof(*io)) {
393 return true;
394 }
395
396 // Parse each target and list the name and version
397 // TODO(b/110035986): Templatize this
398 uint32_t next = sizeof(*io);
399 data_size = io->data_size - next;
400 struct dm_target_versions* vers =
401 reinterpret_cast<struct dm_target_versions*>(static_cast<char*>(buffer.get()) + next);
402 while (next && data_size) {
403 targets->emplace_back(vers);
404 if (vers->next == 0) {
405 break;
406 }
407 next += vers->next;
408 data_size -= vers->next;
409 vers = reinterpret_cast<struct dm_target_versions*>(static_cast<char*>(buffer.get()) +
410 next);
411 }
412
413 return true;
414 }
415
GetTargetByName(const std::string & name,DmTargetTypeInfo * info)416 bool DeviceMapper::GetTargetByName(const std::string& name, DmTargetTypeInfo* info) {
417 std::vector<DmTargetTypeInfo> targets;
418 if (!GetAvailableTargets(&targets)) {
419 return false;
420 }
421 for (const auto& target : targets) {
422 if (target.name() == name) {
423 if (info) *info = target;
424 return true;
425 }
426 }
427 return false;
428 }
429
GetAvailableDevices(std::vector<DmBlockDevice> * devices)430 bool DeviceMapper::GetAvailableDevices(std::vector<DmBlockDevice>* devices) {
431 devices->clear();
432
433 // calculate the space needed to read a maximum of 256 targets, each with
434 // name with maximum length of 16 bytes
435 uint32_t payload_size = sizeof(struct dm_name_list);
436 // 128-bytes for the name
437 payload_size += DM_NAME_LEN;
438 // dm wants every device spec to be aligned at 8-byte boundary
439 payload_size = DM_ALIGN(payload_size);
440 payload_size *= kMaxPossibleDmDevices;
441 uint32_t data_size = sizeof(struct dm_ioctl) + payload_size;
442 auto buffer = std::unique_ptr<void, void (*)(void*)>(calloc(1, data_size), free);
443 if (buffer == nullptr) {
444 LOG(ERROR) << "failed to allocate memory";
445 return false;
446 }
447
448 // Sets appropriate data size and data_start to make sure we tell kernel
449 // about the total size of the buffer we are passing and where to start
450 // writing the list of targets.
451 struct dm_ioctl* io = reinterpret_cast<struct dm_ioctl*>(buffer.get());
452 InitIo(io);
453 io->data_size = data_size;
454 io->data_start = sizeof(*io);
455
456 if (ioctl(fd_, DM_LIST_DEVICES, io)) {
457 PLOG(ERROR) << "DM_LIST_DEVICES failed";
458 return false;
459 }
460
461 // If the provided buffer wasn't enough to list all devices any data
462 // beyond sizeof(*io) must not be read.
463 if (io->flags & DM_BUFFER_FULL_FLAG) {
464 LOG(INFO) << data_size << " is not enough memory to list all dm devices";
465 return false;
466 }
467
468 // if there are no devices created yet, return success with empty vector
469 if (io->data_size == sizeof(*io)) {
470 return true;
471 }
472
473 // Parse each device and add a new DmBlockDevice to the vector
474 // created from the kernel data.
475 uint32_t next = sizeof(*io);
476 data_size = io->data_size - next;
477 struct dm_name_list* dm_dev =
478 reinterpret_cast<struct dm_name_list*>(static_cast<char*>(buffer.get()) + next);
479
480 while (next && data_size) {
481 devices->emplace_back((dm_dev));
482 if (dm_dev->next == 0) {
483 break;
484 }
485 next += dm_dev->next;
486 data_size -= dm_dev->next;
487 dm_dev = reinterpret_cast<struct dm_name_list*>(static_cast<char*>(buffer.get()) + next);
488 }
489
490 return true;
491 }
492
493 // Accepts a device mapper device name (like system_a, vendor_b etc) and
494 // returns the path to it's device node (or symlink to the device node)
GetDmDevicePathByName(const std::string & name,std::string * path)495 bool DeviceMapper::GetDmDevicePathByName(const std::string& name, std::string* path) {
496 struct dm_ioctl io;
497 InitIo(&io, name);
498 if (ioctl(fd_, DM_DEV_STATUS, &io) < 0) {
499 PLOG(WARNING) << "DM_DEV_STATUS failed for " << name;
500 return false;
501 }
502
503 uint32_t dev_num = minor(io.dev);
504 *path = "/dev/block/dm-" + std::to_string(dev_num);
505 return true;
506 }
507
508 // Accepts a device mapper device name (like system_a, vendor_b etc) and
509 // returns its UUID.
GetDmDeviceUuidByName(const std::string & name,std::string * uuid)510 bool DeviceMapper::GetDmDeviceUuidByName(const std::string& name, std::string* uuid) {
511 struct dm_ioctl io;
512 InitIo(&io, name);
513 if (ioctl(fd_, DM_DEV_STATUS, &io) < 0) {
514 PLOG(WARNING) << "DM_DEV_STATUS failed for " << name;
515 return false;
516 }
517
518 *uuid = std::string(io.uuid);
519 return true;
520 }
521
GetDeviceNumber(const std::string & name,dev_t * dev)522 bool DeviceMapper::GetDeviceNumber(const std::string& name, dev_t* dev) {
523 struct dm_ioctl io;
524 InitIo(&io, name);
525 if (ioctl(fd_, DM_DEV_STATUS, &io) < 0) {
526 PLOG(WARNING) << "DM_DEV_STATUS failed for " << name;
527 return false;
528 }
529 *dev = io.dev;
530 return true;
531 }
532
GetDeviceString(const std::string & name,std::string * dev)533 bool DeviceMapper::GetDeviceString(const std::string& name, std::string* dev) {
534 dev_t num;
535 if (!GetDeviceNumber(name, &num)) {
536 return false;
537 }
538 *dev = std::to_string(major(num)) + ":" + std::to_string(minor(num));
539 return true;
540 }
541
GetTableStatus(const std::string & name,std::vector<TargetInfo> * table)542 bool DeviceMapper::GetTableStatus(const std::string& name, std::vector<TargetInfo>* table) {
543 return GetTable(name, 0, table);
544 }
545
GetTableStatusIma(const std::string & name,std::vector<TargetInfo> * table)546 bool DeviceMapper::GetTableStatusIma(const std::string& name, std::vector<TargetInfo>* table) {
547 return GetTable(name, DM_IMA_MEASUREMENT_FLAG, table);
548 }
549
GetTableInfo(const std::string & name,std::vector<TargetInfo> * table)550 bool DeviceMapper::GetTableInfo(const std::string& name, std::vector<TargetInfo>* table) {
551 return GetTable(name, DM_STATUS_TABLE_FLAG, table);
552 }
553
554 // private methods of DeviceMapper
GetTable(const std::string & name,uint32_t flags,std::vector<TargetInfo> * table)555 bool DeviceMapper::GetTable(const std::string& name, uint32_t flags,
556 std::vector<TargetInfo>* table) {
557 std::vector<char> buffer;
558 struct dm_ioctl* io = nullptr;
559
560 for (buffer.resize(4096);; buffer.resize(buffer.size() * 2)) {
561 io = reinterpret_cast<struct dm_ioctl*>(&buffer[0]);
562
563 InitIo(io, name);
564 io->data_size = buffer.size();
565 io->data_start = sizeof(*io);
566 io->flags = flags;
567 if (ioctl(fd_, DM_TABLE_STATUS, io) < 0) {
568 PLOG(ERROR) << "DM_TABLE_STATUS failed for " << name;
569 return false;
570 }
571 if (!(io->flags & DM_BUFFER_FULL_FLAG)) break;
572 }
573
574 uint32_t cursor = io->data_start;
575 uint32_t data_end = std::min(io->data_size, uint32_t(buffer.size()));
576 for (uint32_t i = 0; i < io->target_count; i++) {
577 if (cursor + sizeof(struct dm_target_spec) > data_end) {
578 break;
579 }
580 // After each dm_target_spec is a status string. spec->next is an
581 // offset from |io->data_start|, and we clamp it to the size of our
582 // buffer.
583 struct dm_target_spec* spec = reinterpret_cast<struct dm_target_spec*>(&buffer[cursor]);
584 uint32_t data_offset = cursor + sizeof(dm_target_spec);
585 uint32_t next_cursor = std::min(io->data_start + spec->next, data_end);
586
587 std::string data;
588 if (next_cursor > data_offset) {
589 // Note: we use c_str() to eliminate any extra trailing 0s.
590 data = std::string(&buffer[data_offset], next_cursor - data_offset).c_str();
591 }
592 table->emplace_back(*spec, data);
593 cursor = next_cursor;
594 }
595 return true;
596 }
597
InitIo(struct dm_ioctl * io,const std::string & name) const598 void DeviceMapper::InitIo(struct dm_ioctl* io, const std::string& name) const {
599 CHECK(io != nullptr) << "nullptr passed to dm_ioctl initialization";
600 memset(io, 0, sizeof(*io));
601
602 io->version[0] = DM_VERSION0;
603 io->version[1] = DM_VERSION1;
604 io->version[2] = DM_VERSION2;
605 io->data_size = sizeof(*io);
606 io->data_start = 0;
607 if (!name.empty()) {
608 snprintf(io->name, sizeof(io->name), "%s", name.c_str());
609 }
610 }
611
GetTargetType(const struct dm_target_spec & spec)612 std::string DeviceMapper::GetTargetType(const struct dm_target_spec& spec) {
613 if (const void* p = memchr(spec.target_type, '\0', sizeof(spec.target_type))) {
614 ptrdiff_t length = reinterpret_cast<const char*>(p) - spec.target_type;
615 return std::string{spec.target_type, static_cast<size_t>(length)};
616 }
617 return std::string{spec.target_type, sizeof(spec.target_type)};
618 }
619
ExtractBlockDeviceName(const std::string & path)620 std::optional<std::string> ExtractBlockDeviceName(const std::string& path) {
621 static constexpr std::string_view kDevBlockPrefix("/dev/block/");
622 std::string real_path;
623 if (!android::base::Realpath(path, &real_path)) {
624 real_path = path;
625 }
626 if (android::base::StartsWith(real_path, kDevBlockPrefix)) {
627 return real_path.substr(kDevBlockPrefix.length());
628 }
629 return {};
630 }
631
IsDmBlockDevice(const std::string & path)632 bool DeviceMapper::IsDmBlockDevice(const std::string& path) {
633 std::optional<std::string> name = ExtractBlockDeviceName(path);
634 return name && android::base::StartsWith(*name, "dm-");
635 }
636
GetDmDeviceNameByPath(const std::string & path)637 std::optional<std::string> DeviceMapper::GetDmDeviceNameByPath(const std::string& path) {
638 std::optional<std::string> name = ExtractBlockDeviceName(path);
639 if (!name) {
640 LOG(WARNING) << path << " is not a block device";
641 return std::nullopt;
642 }
643 if (!android::base::StartsWith(*name, "dm-")) {
644 LOG(WARNING) << path << " is not a dm device";
645 return std::nullopt;
646 }
647 std::string dm_name_file = "/sys/block/" + *name + "/dm/name";
648 std::string dm_name;
649 if (!android::base::ReadFileToString(dm_name_file, &dm_name)) {
650 PLOG(ERROR) << "Failed to read file " << dm_name_file;
651 return std::nullopt;
652 }
653 dm_name = android::base::Trim(dm_name);
654 return dm_name;
655 }
656
GetParentBlockDeviceByPath(const std::string & path)657 std::optional<std::string> DeviceMapper::GetParentBlockDeviceByPath(const std::string& path) {
658 std::optional<std::string> name = ExtractBlockDeviceName(path);
659 if (!name) {
660 LOG(WARNING) << path << " is not a block device";
661 return std::nullopt;
662 }
663 if (!android::base::StartsWith(*name, "dm-")) {
664 // Reached bottom of the device mapper stack.
665 return std::nullopt;
666 }
667 auto slaves_dir = "/sys/block/" + *name + "/slaves";
668 auto dir = std::unique_ptr<DIR, decltype(&closedir)>(opendir(slaves_dir.c_str()), closedir);
669 if (dir == nullptr) {
670 PLOG(ERROR) << "Failed to open: " << slaves_dir;
671 return std::nullopt;
672 }
673 std::string sub_device_name = "";
674 for (auto entry = readdir(dir.get()); entry; entry = readdir(dir.get())) {
675 if (entry->d_type != DT_LNK) continue;
676 if (!sub_device_name.empty()) {
677 LOG(ERROR) << "Too many slaves in " << slaves_dir;
678 return std::nullopt;
679 }
680 sub_device_name = entry->d_name;
681 }
682 if (sub_device_name.empty()) {
683 LOG(ERROR) << "No slaves in " << slaves_dir;
684 return std::nullopt;
685 }
686 return "/dev/block/" + sub_device_name;
687 }
688
IsOverflowSnapshot() const689 bool DeviceMapper::TargetInfo::IsOverflowSnapshot() const {
690 return spec.target_type == "snapshot"s && data == "Overflow"s;
691 }
692
693 // Find directories in format of "/sys/block/dm-X".
DmNameFilter(const dirent * de)694 static int DmNameFilter(const dirent* de) {
695 if (android::base::StartsWith(de->d_name, "dm-")) {
696 return 1;
697 }
698 return 0;
699 }
700
FindDmPartitions()701 std::map<std::string, std::string> DeviceMapper::FindDmPartitions() {
702 static constexpr auto DM_PATH_PREFIX = "/sys/block/";
703 dirent** namelist;
704 int n = scandir(DM_PATH_PREFIX, &namelist, DmNameFilter, alphasort);
705 if (n == -1) {
706 PLOG(ERROR) << "Failed to scan dir " << DM_PATH_PREFIX;
707 return {};
708 }
709 if (n == 0) {
710 LOG(ERROR) << "No dm block device found.";
711 free(namelist);
712 return {};
713 }
714
715 static constexpr auto DM_PATH_SUFFIX = "/dm/name";
716 static constexpr auto DEV_PATH = "/dev/block/";
717 std::map<std::string, std::string> dm_block_devices;
718 while (n--) {
719 std::string path = DM_PATH_PREFIX + std::string(namelist[n]->d_name) + DM_PATH_SUFFIX;
720 std::string content;
721 if (!android::base::ReadFileToString(path, &content)) {
722 PLOG(WARNING) << "Failed to read " << path;
723 } else {
724 std::string dm_block_name = android::base::Trim(content);
725 // AVB is using 'vroot' for the root block device but we're expecting 'system'.
726 if (dm_block_name == "vroot") {
727 dm_block_name = "system";
728 } else if (android::base::EndsWith(dm_block_name, "-verity")) {
729 auto npos = dm_block_name.rfind("-verity");
730 dm_block_name = dm_block_name.substr(0, npos);
731 } else if (!android::base::GetProperty("ro.boot.avb_version", "").empty()) {
732 // Verified Boot 1.0 doesn't add a -verity suffix. On AVB 2 devices,
733 // if DAP is enabled, then a -verity suffix must be used to
734 // differentiate between dm-linear and dm-verity devices. If we get
735 // here, we're AVB 2 and looking at a non-verity partition.
736 free(namelist[n]);
737 continue;
738 }
739
740 dm_block_devices.emplace(dm_block_name, DEV_PATH + std::string(namelist[n]->d_name));
741 }
742 free(namelist[n]);
743 }
744 free(namelist);
745
746 return dm_block_devices;
747 }
748
CreatePlaceholderDevice(const std::string & name)749 bool DeviceMapper::CreatePlaceholderDevice(const std::string& name) {
750 if (!CreateEmptyDevice(name)) {
751 return false;
752 }
753
754 struct utsname uts;
755 unsigned int major, minor;
756 if (uname(&uts) != 0 || sscanf(uts.release, "%u.%u", &major, &minor) != 2) {
757 LOG(ERROR) << "Could not parse the kernel version from uname";
758 return true;
759 }
760
761 // On Linux 5.15+, there is no uevent until DM_TABLE_LOAD.
762 if (major > 5 || (major == 5 && minor >= 15)) {
763 DmTable table;
764 table.Emplace<DmTargetError>(0, 1);
765 if (!LoadTable(name, table)) {
766 return false;
767 }
768 }
769 return true;
770 }
771
SendMessage(const std::string & name,uint64_t sector,const std::string & message)772 bool DeviceMapper::SendMessage(const std::string& name, uint64_t sector,
773 const std::string& message) {
774 std::string ioctl_buffer(sizeof(struct dm_ioctl) + sizeof(struct dm_target_msg), 0);
775 ioctl_buffer += message;
776 ioctl_buffer.push_back('\0');
777
778 struct dm_ioctl* io = reinterpret_cast<struct dm_ioctl*>(&ioctl_buffer[0]);
779 InitIo(io, name);
780 io->data_size = ioctl_buffer.size();
781 io->data_start = sizeof(struct dm_ioctl);
782 struct dm_target_msg* msg =
783 reinterpret_cast<struct dm_target_msg*>(&ioctl_buffer[sizeof(struct dm_ioctl)]);
784 msg->sector = sector;
785 if (ioctl(fd_, DM_TARGET_MSG, io)) {
786 PLOG(ERROR) << "DM_TARGET_MSG failed";
787 return false;
788 }
789 return true;
790 }
791
792 } // namespace dm
793 } // namespace android
794