xref: /aosp_15_r20/system/core/fs_mgr/libdm/dm.cpp (revision 00c7fec1bb09f3284aad6a6f96d2f63dfc3650ad)
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 
RedactTableInfo(const struct dm_target_spec & spec,std::string * data)554 void RedactTableInfo(const struct dm_target_spec& spec, std::string* data) {
555     if (DeviceMapper::GetTargetType(spec) == "crypt") {
556         auto parts = android::base::Split(*data, " ");
557         if (parts.size() < 2) {
558             return;
559         }
560         parts[1] = "redacted";
561         *data = android::base::Join(parts, " ");
562     }
563 }
564 
565 // private methods of DeviceMapper
GetTable(const std::string & name,uint32_t flags,std::vector<TargetInfo> * table)566 bool DeviceMapper::GetTable(const std::string& name, uint32_t flags,
567                             std::vector<TargetInfo>* table) {
568     std::vector<char> buffer;
569     struct dm_ioctl* io = nullptr;
570 
571     for (buffer.resize(4096);; buffer.resize(buffer.size() * 2)) {
572         io = reinterpret_cast<struct dm_ioctl*>(&buffer[0]);
573 
574         InitIo(io, name);
575         io->data_size = buffer.size();
576         io->data_start = sizeof(*io);
577         io->flags = flags;
578         if (ioctl(fd_, DM_TABLE_STATUS, io) < 0) {
579             PLOG(ERROR) << "DM_TABLE_STATUS failed for " << name;
580             return false;
581         }
582         if (!(io->flags & DM_BUFFER_FULL_FLAG)) break;
583     }
584 
585     uint32_t cursor = io->data_start;
586     uint32_t data_end = std::min(io->data_size, uint32_t(buffer.size()));
587     for (uint32_t i = 0; i < io->target_count; i++) {
588         if (cursor + sizeof(struct dm_target_spec) > data_end) {
589             break;
590         }
591         // After each dm_target_spec is a status string. spec->next is an
592         // offset from |io->data_start|, and we clamp it to the size of our
593         // buffer.
594         struct dm_target_spec* spec = reinterpret_cast<struct dm_target_spec*>(&buffer[cursor]);
595         uint32_t data_offset = cursor + sizeof(dm_target_spec);
596         uint32_t next_cursor = std::min(io->data_start + spec->next, data_end);
597 
598         std::string data;
599         if (next_cursor > data_offset) {
600             // Note: we use c_str() to eliminate any extra trailing 0s.
601             data = std::string(&buffer[data_offset], next_cursor - data_offset).c_str();
602         }
603         if (flags & DM_STATUS_TABLE_FLAG) {
604             RedactTableInfo(*spec, &data);
605         }
606         table->emplace_back(*spec, data);
607         cursor = next_cursor;
608     }
609     return true;
610 }
611 
InitIo(struct dm_ioctl * io,const std::string & name) const612 void DeviceMapper::InitIo(struct dm_ioctl* io, const std::string& name) const {
613     CHECK(io != nullptr) << "nullptr passed to dm_ioctl initialization";
614     memset(io, 0, sizeof(*io));
615 
616     io->version[0] = DM_VERSION0;
617     io->version[1] = DM_VERSION1;
618     io->version[2] = DM_VERSION2;
619     io->data_size = sizeof(*io);
620     io->data_start = 0;
621     if (!name.empty()) {
622         snprintf(io->name, sizeof(io->name), "%s", name.c_str());
623     }
624 }
625 
GetTargetType(const struct dm_target_spec & spec)626 std::string DeviceMapper::GetTargetType(const struct dm_target_spec& spec) {
627     if (const void* p = memchr(spec.target_type, '\0', sizeof(spec.target_type))) {
628         ptrdiff_t length = reinterpret_cast<const char*>(p) - spec.target_type;
629         return std::string{spec.target_type, static_cast<size_t>(length)};
630     }
631     return std::string{spec.target_type, sizeof(spec.target_type)};
632 }
633 
ExtractBlockDeviceName(const std::string & path)634 std::optional<std::string> ExtractBlockDeviceName(const std::string& path) {
635     static constexpr std::string_view kDevBlockPrefix("/dev/block/");
636     std::string real_path;
637     if (!android::base::Realpath(path, &real_path)) {
638         real_path = path;
639     }
640     if (android::base::StartsWith(real_path, kDevBlockPrefix)) {
641         return real_path.substr(kDevBlockPrefix.length());
642     }
643     return {};
644 }
645 
IsDmBlockDevice(const std::string & path)646 bool DeviceMapper::IsDmBlockDevice(const std::string& path) {
647     std::optional<std::string> name = ExtractBlockDeviceName(path);
648     return name && android::base::StartsWith(*name, "dm-");
649 }
650 
GetDmDeviceNameByPath(const std::string & path)651 std::optional<std::string> DeviceMapper::GetDmDeviceNameByPath(const std::string& path) {
652     std::optional<std::string> name = ExtractBlockDeviceName(path);
653     if (!name) {
654         LOG(WARNING) << path << " is not a block device";
655         return std::nullopt;
656     }
657     if (!android::base::StartsWith(*name, "dm-")) {
658         LOG(WARNING) << path << " is not a dm device";
659         return std::nullopt;
660     }
661     std::string dm_name_file = "/sys/block/" + *name + "/dm/name";
662     std::string dm_name;
663     if (!android::base::ReadFileToString(dm_name_file, &dm_name)) {
664         PLOG(ERROR) << "Failed to read file " << dm_name_file;
665         return std::nullopt;
666     }
667     dm_name = android::base::Trim(dm_name);
668     return dm_name;
669 }
670 
GetParentBlockDeviceByPath(const std::string & path)671 std::optional<std::string> DeviceMapper::GetParentBlockDeviceByPath(const std::string& path) {
672     std::optional<std::string> name = ExtractBlockDeviceName(path);
673     if (!name) {
674         LOG(WARNING) << path << " is not a block device";
675         return std::nullopt;
676     }
677     if (!android::base::StartsWith(*name, "dm-")) {
678         // Reached bottom of the device mapper stack.
679         return std::nullopt;
680     }
681     auto slaves_dir = "/sys/block/" + *name + "/slaves";
682     auto dir = std::unique_ptr<DIR, decltype(&closedir)>(opendir(slaves_dir.c_str()), closedir);
683     if (dir == nullptr) {
684         PLOG(ERROR) << "Failed to open: " << slaves_dir;
685         return std::nullopt;
686     }
687     std::string sub_device_name = "";
688     for (auto entry = readdir(dir.get()); entry; entry = readdir(dir.get())) {
689         if (entry->d_type != DT_LNK) continue;
690         if (!sub_device_name.empty()) {
691             LOG(ERROR) << "Too many slaves in " << slaves_dir;
692             return std::nullopt;
693         }
694         sub_device_name = entry->d_name;
695     }
696     if (sub_device_name.empty()) {
697         LOG(ERROR) << "No slaves in " << slaves_dir;
698         return std::nullopt;
699     }
700     return "/dev/block/" + sub_device_name;
701 }
702 
IsOverflowSnapshot() const703 bool DeviceMapper::TargetInfo::IsOverflowSnapshot() const {
704     return spec.target_type == "snapshot"s && data == "Overflow"s;
705 }
706 
707 // Find directories in format of "/sys/block/dm-X".
DmNameFilter(const dirent * de)708 static int DmNameFilter(const dirent* de) {
709     if (android::base::StartsWith(de->d_name, "dm-")) {
710         return 1;
711     }
712     return 0;
713 }
714 
FindDmPartitions()715 std::map<std::string, std::string> DeviceMapper::FindDmPartitions() {
716     static constexpr auto DM_PATH_PREFIX = "/sys/block/";
717     dirent** namelist;
718     int n = scandir(DM_PATH_PREFIX, &namelist, DmNameFilter, alphasort);
719     if (n == -1) {
720         PLOG(ERROR) << "Failed to scan dir " << DM_PATH_PREFIX;
721         return {};
722     }
723     if (n == 0) {
724         LOG(ERROR) << "No dm block device found.";
725         free(namelist);
726         return {};
727     }
728 
729     static constexpr auto DM_PATH_SUFFIX = "/dm/name";
730     static constexpr auto DEV_PATH = "/dev/block/";
731     std::map<std::string, std::string> dm_block_devices;
732     while (n--) {
733         std::string path = DM_PATH_PREFIX + std::string(namelist[n]->d_name) + DM_PATH_SUFFIX;
734         std::string content;
735         if (!android::base::ReadFileToString(path, &content)) {
736             PLOG(WARNING) << "Failed to read " << path;
737         } else {
738             std::string dm_block_name = android::base::Trim(content);
739             // AVB is using 'vroot' for the root block device but we're expecting 'system'.
740             if (dm_block_name == "vroot") {
741                 dm_block_name = "system";
742             } else if (android::base::EndsWith(dm_block_name, "-verity")) {
743                 auto npos = dm_block_name.rfind("-verity");
744                 dm_block_name = dm_block_name.substr(0, npos);
745             } else if (!android::base::GetProperty("ro.boot.avb_version", "").empty()) {
746                 // Verified Boot 1.0 doesn't add a -verity suffix. On AVB 2 devices,
747                 // if DAP is enabled, then a -verity suffix must be used to
748                 // differentiate between dm-linear and dm-verity devices. If we get
749                 // here, we're AVB 2 and looking at a non-verity partition.
750                 free(namelist[n]);
751                 continue;
752             }
753 
754             dm_block_devices.emplace(dm_block_name, DEV_PATH + std::string(namelist[n]->d_name));
755         }
756         free(namelist[n]);
757     }
758     free(namelist);
759 
760     return dm_block_devices;
761 }
762 
CreatePlaceholderDevice(const std::string & name)763 bool DeviceMapper::CreatePlaceholderDevice(const std::string& name) {
764     if (!CreateEmptyDevice(name)) {
765         return false;
766     }
767 
768     struct utsname uts;
769     unsigned int major, minor;
770     if (uname(&uts) != 0 || sscanf(uts.release, "%u.%u", &major, &minor) != 2) {
771         LOG(ERROR) << "Could not parse the kernel version from uname";
772         return true;
773     }
774 
775     // On Linux 5.15+, there is no uevent until DM_TABLE_LOAD.
776     if (major > 5 || (major == 5 && minor >= 15)) {
777         DmTable table;
778         table.Emplace<DmTargetError>(0, 1);
779         if (!LoadTable(name, table)) {
780             return false;
781         }
782     }
783     return true;
784 }
785 
SendMessage(const std::string & name,uint64_t sector,const std::string & message)786 bool DeviceMapper::SendMessage(const std::string& name, uint64_t sector,
787                                const std::string& message) {
788     std::string ioctl_buffer(sizeof(struct dm_ioctl) + sizeof(struct dm_target_msg), 0);
789     ioctl_buffer += message;
790     ioctl_buffer.push_back('\0');
791 
792     struct dm_ioctl* io = reinterpret_cast<struct dm_ioctl*>(&ioctl_buffer[0]);
793     InitIo(io, name);
794     io->data_size = ioctl_buffer.size();
795     io->data_start = sizeof(struct dm_ioctl);
796     struct dm_target_msg* msg =
797             reinterpret_cast<struct dm_target_msg*>(&ioctl_buffer[sizeof(struct dm_ioctl)]);
798     msg->sector = sector;
799     if (ioctl(fd_, DM_TARGET_MSG, io)) {
800         PLOG(ERROR) << "DM_TARGET_MSG failed";
801         return false;
802     }
803     return true;
804 }
805 
806 }  // namespace dm
807 }  // namespace android
808