summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'init/first_stage_mount.cpp')
-rw-r--r--init/first_stage_mount.cpp598
1 files changed, 598 insertions, 0 deletions
diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp
new file mode 100644
index 000000000..8ded87373
--- /dev/null
+++ b/init/first_stage_mount.cpp
@@ -0,0 +1,598 @@
1/*
2 * Copyright (C) 2017 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 "first_stage_mount.h"
18
19#include <stdlib.h>
20#include <unistd.h>
21
22#include <chrono>
23#include <memory>
24#include <set>
25#include <string>
26#include <vector>
27
28#include <android-base/chrono_utils.h>
29#include <android-base/file.h>
30#include <android-base/logging.h>
31#include <android-base/strings.h>
32#include <liblp/metadata_format.h>
33
34#include "devices.h"
35#include "fs_mgr.h"
36#include "fs_mgr_avb.h"
37#include "fs_mgr_dm_linear.h"
38#include "uevent.h"
39#include "uevent_listener.h"
40#include "util.h"
41
42using android::base::Timer;
43
44namespace android {
45namespace init {
46
47// Class Declarations
48// ------------------
49class FirstStageMount {
50 public:
51 FirstStageMount();
52 virtual ~FirstStageMount() = default;
53
54 // The factory method to create either FirstStageMountVBootV1 or FirstStageMountVBootV2
55 // based on device tree configurations.
56 static std::unique_ptr<FirstStageMount> Create();
57 bool DoFirstStageMount(); // Mounts fstab entries read from device tree.
58 bool InitDevices();
59
60 protected:
61 ListenerAction HandleBlockDevice(const std::string& name, const Uevent&);
62 bool InitRequiredDevices();
63 bool InitMappedDevice(const std::string& verity_device);
64 bool CreateLogicalPartitions();
65 bool MountPartitions();
66 bool GetBackingDmLinearDevices();
67
68 virtual ListenerAction UeventCallback(const Uevent& uevent);
69
70 // Pure virtual functions.
71 virtual bool GetDmVerityDevices() = 0;
72 virtual bool SetUpDmVerity(fstab_rec* fstab_rec) = 0;
73
74 bool need_dm_verity_;
75
76 std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> device_tree_fstab_;
77 std::string lp_metadata_partition_;
78 std::vector<fstab_rec*> mount_fstab_recs_;
79 std::set<std::string> required_devices_partition_names_;
80 std::unique_ptr<DeviceHandler> device_handler_;
81 UeventListener uevent_listener_;
82};
83
84class FirstStageMountVBootV1 : public FirstStageMount {
85 public:
86 FirstStageMountVBootV1() = default;
87 ~FirstStageMountVBootV1() override = default;
88
89 protected:
90 bool GetDmVerityDevices() override;
91 bool SetUpDmVerity(fstab_rec* fstab_rec) override;
92};
93
94class FirstStageMountVBootV2 : public FirstStageMount {
95 public:
96 friend void SetInitAvbVersionInRecovery();
97
98 FirstStageMountVBootV2();
99 ~FirstStageMountVBootV2() override = default;
100
101 protected:
102 ListenerAction UeventCallback(const Uevent& uevent) override;
103 bool GetDmVerityDevices() override;
104 bool SetUpDmVerity(fstab_rec* fstab_rec) override;
105 bool InitAvbHandle();
106
107 std::string device_tree_vbmeta_parts_;
108 FsManagerAvbUniquePtr avb_handle_;
109 ByNameSymlinkMap by_name_symlink_map_;
110};
111
112// Static Functions
113// ----------------
114static inline bool IsDtVbmetaCompatible() {
115 return is_android_dt_value_expected("vbmeta/compatible", "android,vbmeta");
116}
117
118static bool inline IsRecoveryMode() {
119 return access("/sbin/recovery", F_OK) == 0;
120}
121
122static inline bool IsDmLinearEnabled() {
123 static bool checked = false;
124 static bool enabled = false;
125 if (checked) {
126 return enabled;
127 }
128 import_kernel_cmdline(false,
129 [](const std::string& key, const std::string& value, bool in_qemu) {
130 if (key == "androidboot.logical_partitions" && value == "1") {
131 enabled = true;
132 }
133 });
134 checked = true;
135 return enabled;
136}
137
138// Class Definitions
139// -----------------
140FirstStageMount::FirstStageMount()
141 : need_dm_verity_(false), device_tree_fstab_(fs_mgr_read_fstab_dt(), fs_mgr_free_fstab) {
142 if (device_tree_fstab_) {
143 // Stores device_tree_fstab_->recs[] into mount_fstab_recs_ (vector<fstab_rec*>)
144 // for easier manipulation later, e.g., range-base for loop.
145 for (int i = 0; i < device_tree_fstab_->num_entries; i++) {
146 mount_fstab_recs_.push_back(&device_tree_fstab_->recs[i]);
147 }
148 } else {
149 LOG(INFO) << "Failed to read fstab from device tree";
150 }
151
152 auto boot_devices = fs_mgr_get_boot_devices();
153 device_handler_ = std::make_unique<DeviceHandler>(
154 std::vector<Permissions>{}, std::vector<SysfsPermissions>{}, std::vector<Subsystem>{},
155 std::move(boot_devices), false);
156}
157
158std::unique_ptr<FirstStageMount> FirstStageMount::Create() {
159 if (IsDtVbmetaCompatible()) {
160 return std::make_unique<FirstStageMountVBootV2>();
161 } else {
162 return std::make_unique<FirstStageMountVBootV1>();
163 }
164}
165
166bool FirstStageMount::DoFirstStageMount() {
167 if (!IsDmLinearEnabled() && mount_fstab_recs_.empty()) {
168 // Nothing to mount.
169 LOG(INFO) << "First stage mount skipped (missing/incompatible/empty fstab in device tree)";
170 return true;
171 }
172
173 if (!InitDevices()) return false;
174
175 if (!CreateLogicalPartitions()) return false;
176
177 if (!MountPartitions()) return false;
178
179 return true;
180}
181
182bool FirstStageMount::InitDevices() {
183 return GetBackingDmLinearDevices() && GetDmVerityDevices() && InitRequiredDevices();
184}
185
186bool FirstStageMount::GetBackingDmLinearDevices() {
187 // Add any additional devices required for dm-linear mappings.
188 if (!IsDmLinearEnabled()) {
189 return true;
190 }
191
192 required_devices_partition_names_.emplace(LP_METADATA_PARTITION_NAME);
193 return true;
194}
195
196// Creates devices with uevent->partition_name matching one in the member variable
197// required_devices_partition_names_. Found partitions will then be removed from it
198// for the subsequent member function to check which devices are NOT created.
199bool FirstStageMount::InitRequiredDevices() {
200 if (required_devices_partition_names_.empty()) {
201 return true;
202 }
203
204 if (IsDmLinearEnabled() || need_dm_verity_) {
205 const std::string dm_path = "/devices/virtual/misc/device-mapper";
206 bool found = false;
207 auto dm_callback = [this, &dm_path, &found](const Uevent& uevent) {
208 if (uevent.path == dm_path) {
209 device_handler_->HandleDeviceEvent(uevent);
210 found = true;
211 return ListenerAction::kStop;
212 }
213 return ListenerAction::kContinue;
214 };
215 uevent_listener_.RegenerateUeventsForPath("/sys" + dm_path, dm_callback);
216 if (!found) {
217 LOG(INFO) << "device-mapper device not found in /sys, waiting for its uevent";
218 Timer t;
219 uevent_listener_.Poll(dm_callback, 10s);
220 LOG(INFO) << "Wait for device-mapper returned after " << t;
221 }
222 if (!found) {
223 LOG(ERROR) << "device-mapper device not found after polling timeout";
224 return false;
225 }
226 }
227
228 auto uevent_callback = [this](const Uevent& uevent) { return UeventCallback(uevent); };
229 uevent_listener_.RegenerateUevents(uevent_callback);
230
231 // UeventCallback() will remove found partitions from required_devices_partition_names_.
232 // So if it isn't empty here, it means some partitions are not found.
233 if (!required_devices_partition_names_.empty()) {
234 LOG(INFO) << __PRETTY_FUNCTION__
235 << ": partition(s) not found in /sys, waiting for their uevent(s): "
236 << android::base::Join(required_devices_partition_names_, ", ");
237 Timer t;
238 uevent_listener_.Poll(uevent_callback, 10s);
239 LOG(INFO) << "Wait for partitions returned after " << t;
240 }
241
242 if (!required_devices_partition_names_.empty()) {
243 LOG(ERROR) << __PRETTY_FUNCTION__ << ": partition(s) not found after polling timeout: "
244 << android::base::Join(required_devices_partition_names_, ", ");
245 return false;
246 }
247
248 return true;
249}
250
251bool FirstStageMount::CreateLogicalPartitions() {
252 if (!IsDmLinearEnabled()) {
253 return true;
254 }
255
256 if (lp_metadata_partition_.empty()) {
257 LOG(ERROR) << "Could not locate logical partition tables in partition "
258 << LP_METADATA_PARTITION_NAME;
259 return false;
260 }
261 return android::fs_mgr::CreateLogicalPartitions(lp_metadata_partition_);
262}
263
264ListenerAction FirstStageMount::HandleBlockDevice(const std::string& name, const Uevent& uevent) {
265 // Matches partition name to create device nodes.
266 // Both required_devices_partition_names_ and uevent->partition_name have A/B
267 // suffix when A/B is used.
268 auto iter = required_devices_partition_names_.find(name);
269 if (iter != required_devices_partition_names_.end()) {
270 LOG(VERBOSE) << __PRETTY_FUNCTION__ << ": found partition: " << *iter;
271 if (IsDmLinearEnabled() && name == LP_METADATA_PARTITION_NAME) {
272 std::vector<std::string> links = device_handler_->GetBlockDeviceSymlinks(uevent);
273 lp_metadata_partition_ = links[0];
274 }
275 required_devices_partition_names_.erase(iter);
276 device_handler_->HandleDeviceEvent(uevent);
277 if (required_devices_partition_names_.empty()) {
278 return ListenerAction::kStop;
279 } else {
280 return ListenerAction::kContinue;
281 }
282 }
283 return ListenerAction::kContinue;
284}
285
286ListenerAction FirstStageMount::UeventCallback(const Uevent& uevent) {
287 // Ignores everything that is not a block device.
288 if (uevent.subsystem != "block") {
289 return ListenerAction::kContinue;
290 }
291
292 if (!uevent.partition_name.empty()) {
293 return HandleBlockDevice(uevent.partition_name, uevent);
294 } else {
295 size_t base_idx = uevent.path.rfind('/');
296 if (base_idx != std::string::npos) {
297 return HandleBlockDevice(uevent.path.substr(base_idx + 1), uevent);
298 }
299 }
300 // Not found a partition or find an unneeded partition, continue to find others.
301 return ListenerAction::kContinue;
302}
303
304// Creates "/dev/block/dm-XX" for dm-verity by running coldboot on /sys/block/dm-XX.
305bool FirstStageMount::InitMappedDevice(const std::string& dm_device) {
306 const std::string device_name(basename(dm_device.c_str()));
307 const std::string syspath = "/sys/block/" + device_name;
308 bool found = false;
309
310 auto verity_callback = [&device_name, &dm_device, this, &found](const Uevent& uevent) {
311 if (uevent.device_name == device_name) {
312 LOG(VERBOSE) << "Creating device-mapper device : " << dm_device;
313 device_handler_->HandleDeviceEvent(uevent);
314 found = true;
315 return ListenerAction::kStop;
316 }
317 return ListenerAction::kContinue;
318 };
319
320 uevent_listener_.RegenerateUeventsForPath(syspath, verity_callback);
321 if (!found) {
322 LOG(INFO) << "dm-verity device not found in /sys, waiting for its uevent";
323 Timer t;
324 uevent_listener_.Poll(verity_callback, 10s);
325 LOG(INFO) << "wait for dm-verity device returned after " << t;
326 }
327 if (!found) {
328 LOG(ERROR) << "dm-verity device not found after polling timeout";
329 return false;
330 }
331
332 return true;
333}
334
335bool FirstStageMount::MountPartitions() {
336 for (auto fstab_rec : mount_fstab_recs_) {
337 if (fs_mgr_is_logical(fstab_rec)) {
338 if (!fs_mgr_update_logical_partition(fstab_rec)) {
339 return false;
340 }
341 if (!InitMappedDevice(fstab_rec->blk_device)) {
342 return false;
343 }
344 }
345 if (!SetUpDmVerity(fstab_rec)) {
346 PLOG(ERROR) << "Failed to setup verity for '" << fstab_rec->mount_point << "'";
347 return false;
348 }
349 if (fs_mgr_do_mount_one(fstab_rec)) {
350 PLOG(ERROR) << "Failed to mount '" << fstab_rec->mount_point << "'";
351 return false;
352 }
353 }
354 return true;
355}
356
357bool FirstStageMountVBootV1::GetDmVerityDevices() {
358 std::string verity_loc_device;
359 need_dm_verity_ = false;
360
361 for (auto fstab_rec : mount_fstab_recs_) {
362 // Don't allow verifyatboot in the first stage.
363 if (fs_mgr_is_verifyatboot(fstab_rec)) {
364 LOG(ERROR) << "Partitions can't be verified at boot";
365 return false;
366 }
367 // Checks for verified partitions.
368 if (fs_mgr_is_verified(fstab_rec)) {
369 need_dm_verity_ = true;
370 }
371 // Checks if verity metadata is on a separate partition. Note that it is
372 // not partition specific, so there must be only one additional partition
373 // that carries verity state.
374 if (fstab_rec->verity_loc) {
375 if (verity_loc_device.empty()) {
376 verity_loc_device = fstab_rec->verity_loc;
377 } else if (verity_loc_device != fstab_rec->verity_loc) {
378 LOG(ERROR) << "More than one verity_loc found: " << verity_loc_device << ", "
379 << fstab_rec->verity_loc;
380 return false;
381 }
382 }
383 }
384
385 // Includes the partition names of fstab records and verity_loc_device (if any).
386 // Notes that fstab_rec->blk_device has A/B suffix updated by fs_mgr when A/B is used.
387 for (auto fstab_rec : mount_fstab_recs_) {
388 required_devices_partition_names_.emplace(basename(fstab_rec->blk_device));
389 }
390
391 if (!verity_loc_device.empty()) {
392 required_devices_partition_names_.emplace(basename(verity_loc_device.c_str()));
393 }
394
395 return true;
396}
397
398bool FirstStageMountVBootV1::SetUpDmVerity(fstab_rec* fstab_rec) {
399 if (fs_mgr_is_verified(fstab_rec)) {
400 int ret = fs_mgr_setup_verity(fstab_rec, false /* wait_for_verity_dev */);
401 switch (ret) {
402 case FS_MGR_SETUP_VERITY_SKIPPED:
403 case FS_MGR_SETUP_VERITY_DISABLED:
404 LOG(INFO) << "Verity disabled/skipped for '" << fstab_rec->mount_point << "'";
405 return true;
406 case FS_MGR_SETUP_VERITY_SUCCESS:
407 // The exact block device name (fstab_rec->blk_device) is changed to
408 // "/dev/block/dm-XX". Needs to create it because ueventd isn't started in init
409 // first stage.
410 return InitMappedDevice(fstab_rec->blk_device);
411 default:
412 return false;
413 }
414 }
415 return true; // Returns true to mount the partition.
416}
417
418// FirstStageMountVBootV2 constructor.
419// Gets the vbmeta partitions from device tree.
420// /{
421// firmware {
422// android {
423// vbmeta {
424// compatible = "android,vbmeta";
425// parts = "vbmeta,boot,system,vendor"
426// };
427// };
428// };
429// }
430FirstStageMountVBootV2::FirstStageMountVBootV2() : avb_handle_(nullptr) {
431 if (!read_android_dt_file("vbmeta/parts", &device_tree_vbmeta_parts_)) {
432 PLOG(ERROR) << "Failed to read vbmeta/parts from device tree";
433 return;
434 }
435}
436
437bool FirstStageMountVBootV2::GetDmVerityDevices() {
438 need_dm_verity_ = false;
439
440 std::set<std::string> logical_partitions;
441
442 // fstab_rec->blk_device has A/B suffix.
443 for (auto fstab_rec : mount_fstab_recs_) {
444 if (fs_mgr_is_avb(fstab_rec)) {
445 need_dm_verity_ = true;
446 }
447 if (fs_mgr_is_logical(fstab_rec)) {
448 // Don't try to find logical partitions via uevent regeneration.
449 logical_partitions.emplace(basename(fstab_rec->blk_device));
450 } else {
451 required_devices_partition_names_.emplace(basename(fstab_rec->blk_device));
452 }
453 }
454
455 // libavb verifies AVB metadata on all verified partitions at once.
456 // e.g., The device_tree_vbmeta_parts_ will be "vbmeta,boot,system,vendor"
457 // for libavb to verify metadata, even if there is only /vendor in the
458 // above mount_fstab_recs_.
459 if (need_dm_verity_) {
460 if (device_tree_vbmeta_parts_.empty()) {
461 LOG(ERROR) << "Missing vbmeta parts in device tree";
462 return false;
463 }
464 std::vector<std::string> partitions = android::base::Split(device_tree_vbmeta_parts_, ",");
465 std::string ab_suffix = fs_mgr_get_slot_suffix();
466 for (const auto& partition : partitions) {
467 std::string partition_name = partition + ab_suffix;
468 if (logical_partitions.count(partition_name)) {
469 continue;
470 }
471 // required_devices_partition_names_ is of type std::set so it's not an issue
472 // to emplace a partition twice. e.g., /vendor might be in both places:
473 // - device_tree_vbmeta_parts_ = "vbmeta,boot,system,vendor"
474 // - mount_fstab_recs_: /vendor_a
475 required_devices_partition_names_.emplace(partition_name);
476 }
477 }
478 return true;
479}
480
481ListenerAction FirstStageMountVBootV2::UeventCallback(const Uevent& uevent) {
482 // Check if this uevent corresponds to one of the required partitions and store its symlinks if
483 // so, in order to create FsManagerAvbHandle later.
484 // Note that the parent callback removes partitions from the list of required partitions
485 // as it finds them, so this must happen first.
486 if (!uevent.partition_name.empty() &&
487 required_devices_partition_names_.find(uevent.partition_name) !=
488 required_devices_partition_names_.end()) {
489 // GetBlockDeviceSymlinks() will return three symlinks at most, depending on
490 // the content of uevent. by-name symlink will be at [0] if uevent->partition_name
491 // is not empty. e.g.,
492 // - /dev/block/platform/soc.0/f9824900.sdhci/by-name/modem
493 // - /dev/block/platform/soc.0/f9824900.sdhci/mmcblk0p1
494 std::vector<std::string> links = device_handler_->GetBlockDeviceSymlinks(uevent);
495 if (!links.empty()) {
496 auto [it, inserted] = by_name_symlink_map_.emplace(uevent.partition_name, links[0]);
497 if (!inserted) {
498 LOG(ERROR) << "Partition '" << uevent.partition_name
499 << "' already existed in the by-name symlink map with a value of '"
500 << it->second << "', new value '" << links[0] << "' will be ignored.";
501 }
502 }
503 }
504
505 return FirstStageMount::UeventCallback(uevent);
506}
507
508bool FirstStageMountVBootV2::SetUpDmVerity(fstab_rec* fstab_rec) {
509 if (fs_mgr_is_avb(fstab_rec)) {
510 if (!InitAvbHandle()) return false;
511 SetUpAvbHashtreeResult hashtree_result =
512 avb_handle_->SetUpAvbHashtree(fstab_rec, false /* wait_for_verity_dev */);
513 switch (hashtree_result) {
514 case SetUpAvbHashtreeResult::kDisabled:
515 return true; // Returns true to mount the partition.
516 case SetUpAvbHashtreeResult::kSuccess:
517 // The exact block device name (fstab_rec->blk_device) is changed to
518 // "/dev/block/dm-XX". Needs to create it because ueventd isn't started in init
519 // first stage.
520 return InitMappedDevice(fstab_rec->blk_device);
521 default:
522 return false;
523 }
524 }
525 return true; // Returns true to mount the partition.
526}
527
528bool FirstStageMountVBootV2::InitAvbHandle() {
529 if (avb_handle_) return true; // Returns true if the handle is already initialized.
530
531 if (by_name_symlink_map_.empty()) {
532 LOG(ERROR) << "by_name_symlink_map_ is empty";
533 return false;
534 }
535
536 avb_handle_ = FsManagerAvbHandle::Open(std::move(by_name_symlink_map_));
537 by_name_symlink_map_.clear(); // Removes all elements after the above std::move().
538
539 if (!avb_handle_) {
540 PLOG(ERROR) << "Failed to open FsManagerAvbHandle";
541 return false;
542 }
543 // Sets INIT_AVB_VERSION here for init to set ro.boot.avb_version in the second stage.
544 setenv("INIT_AVB_VERSION", avb_handle_->avb_version().c_str(), 1);
545 return true;
546}
547
548// Public functions
549// ----------------
550// Mounts partitions specified by fstab in device tree.
551bool DoFirstStageMount() {
552 // Skips first stage mount if we're in recovery mode.
553 if (IsRecoveryMode()) {
554 LOG(INFO) << "First stage mount skipped (recovery mode)";
555 return true;
556 }
557
558 std::unique_ptr<FirstStageMount> handle = FirstStageMount::Create();
559 if (!handle) {
560 LOG(ERROR) << "Failed to create FirstStageMount";
561 return false;
562 }
563 return handle->DoFirstStageMount();
564}
565
566void SetInitAvbVersionInRecovery() {
567 if (!IsRecoveryMode()) {
568 LOG(INFO) << "Skipped setting INIT_AVB_VERSION (not in recovery mode)";
569 return;
570 }
571
572 if (!IsDtVbmetaCompatible()) {
573 LOG(INFO) << "Skipped setting INIT_AVB_VERSION (not vbmeta compatible)";
574 return;
575 }
576
577 // Initializes required devices for the subsequent FsManagerAvbHandle::Open()
578 // to verify AVB metadata on all partitions in the verified chain.
579 // We only set INIT_AVB_VERSION when the AVB verification succeeds, i.e., the
580 // Open() function returns a valid handle.
581 // We don't need to mount partitions here in recovery mode.
582 FirstStageMountVBootV2 avb_first_mount;
583 if (!avb_first_mount.InitDevices()) {
584 LOG(ERROR) << "Failed to init devices for INIT_AVB_VERSION";
585 return;
586 }
587
588 FsManagerAvbUniquePtr avb_handle =
589 FsManagerAvbHandle::Open(std::move(avb_first_mount.by_name_symlink_map_));
590 if (!avb_handle) {
591 PLOG(ERROR) << "Failed to open FsManagerAvbHandle for INIT_AVB_VERSION";
592 return;
593 }
594 setenv("INIT_AVB_VERSION", avb_handle->avb_version().c_str(), 1);
595}
596
597} // namespace init
598} // namespace android