blob: 033ce419acc85fe86f520d4fe4bd18d56fc1bdd6 [file] [log] [blame]
Bowgo Tsaid2620172017-04-17 22:17:09 +08001/*
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 "init_first_stage.h"
18
19#include <stdlib.h>
20#include <unistd.h>
21
Sandeep Patil4cbedee2017-06-21 13:02:57 -070022#include <chrono>
Bowgo Tsaid2620172017-04-17 22:17:09 +080023#include <memory>
24#include <set>
25#include <string>
26#include <vector>
27
Tom Cherryede0d532017-07-06 14:20:11 -070028#include <android-base/chrono_utils.h>
Bowgo Tsaid2620172017-04-17 22:17:09 +080029#include <android-base/file.h>
30#include <android-base/logging.h>
31#include <android-base/strings.h>
32
33#include "devices.h"
34#include "fs_mgr.h"
35#include "fs_mgr_avb.h"
Tom Cherryed506f72017-05-25 15:58:59 -070036#include "uevent.h"
37#include "uevent_listener.h"
Bowgo Tsaid2620172017-04-17 22:17:09 +080038#include "util.h"
39
Tom Cherryede0d532017-07-06 14:20:11 -070040using android::base::Timer;
Sandeep Patil4cbedee2017-06-21 13:02:57 -070041
Tom Cherry81f5d3e2017-06-22 12:53:17 -070042namespace android {
43namespace init {
44
Bowgo Tsaifd18a452017-04-24 18:36:25 +080045// Class Declarations
46// ------------------
Bowgo Tsaid2620172017-04-17 22:17:09 +080047class FirstStageMount {
48 public:
49 FirstStageMount();
50 virtual ~FirstStageMount() = default;
51
52 // The factory method to create either FirstStageMountVBootV1 or FirstStageMountVBootV2
53 // based on device tree configurations.
54 static std::unique_ptr<FirstStageMount> Create();
55 bool DoFirstStageMount(); // Mounts fstab entries read from device tree.
Bowgo Tsaifd18a452017-04-24 18:36:25 +080056 bool InitDevices();
Bowgo Tsaid2620172017-04-17 22:17:09 +080057
58 protected:
Greg Hartman88647492018-02-05 13:48:11 -080059 ListenerAction HandleBlockDevice(const std::string& name, const Uevent&);
Sandeep Patil4cbedee2017-06-21 13:02:57 -070060 bool InitRequiredDevices();
61 bool InitVerityDevice(const std::string& verity_device);
Bowgo Tsaid2620172017-04-17 22:17:09 +080062 bool MountPartitions();
63
Sandeep Patil4cbedee2017-06-21 13:02:57 -070064 virtual ListenerAction UeventCallback(const Uevent& uevent);
Bowgo Tsai20651f62017-05-08 20:45:50 +080065
66 // Pure virtual functions.
67 virtual bool GetRequiredDevices() = 0;
Bowgo Tsaid2620172017-04-17 22:17:09 +080068 virtual bool SetUpDmVerity(fstab_rec* fstab_rec) = 0;
69
Bowgo Tsai20651f62017-05-08 20:45:50 +080070 bool need_dm_verity_;
Bowgo Tsai06ed6132017-06-08 10:43:41 +080071
Bowgo Tsaid2620172017-04-17 22:17:09 +080072 std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> device_tree_fstab_;
Bowgo Tsaid2620172017-04-17 22:17:09 +080073 std::vector<fstab_rec*> mount_fstab_recs_;
Bowgo Tsai20651f62017-05-08 20:45:50 +080074 std::set<std::string> required_devices_partition_names_;
Bowgo Tsai5ee7dae2018-05-16 18:33:44 +080075 std::unique_ptr<DeviceHandler> device_handler_;
Tom Cherryed506f72017-05-25 15:58:59 -070076 UeventListener uevent_listener_;
Bowgo Tsaid2620172017-04-17 22:17:09 +080077};
78
79class FirstStageMountVBootV1 : public FirstStageMount {
80 public:
81 FirstStageMountVBootV1() = default;
82 ~FirstStageMountVBootV1() override = default;
83
84 protected:
Bowgo Tsai20651f62017-05-08 20:45:50 +080085 bool GetRequiredDevices() override;
Bowgo Tsaid2620172017-04-17 22:17:09 +080086 bool SetUpDmVerity(fstab_rec* fstab_rec) override;
87};
88
89class FirstStageMountVBootV2 : public FirstStageMount {
90 public:
Bowgo Tsai20651f62017-05-08 20:45:50 +080091 friend void SetInitAvbVersionInRecovery();
92
Bowgo Tsaid2620172017-04-17 22:17:09 +080093 FirstStageMountVBootV2();
94 ~FirstStageMountVBootV2() override = default;
95
96 protected:
Sandeep Patil4cbedee2017-06-21 13:02:57 -070097 ListenerAction UeventCallback(const Uevent& uevent) override;
Bowgo Tsai20651f62017-05-08 20:45:50 +080098 bool GetRequiredDevices() override;
Bowgo Tsaid2620172017-04-17 22:17:09 +080099 bool SetUpDmVerity(fstab_rec* fstab_rec) override;
100 bool InitAvbHandle();
101
102 std::string device_tree_vbmeta_parts_;
Bowgo Tsaid2620172017-04-17 22:17:09 +0800103 FsManagerAvbUniquePtr avb_handle_;
Bowgo Tsai20651f62017-05-08 20:45:50 +0800104 ByNameSymlinkMap by_name_symlink_map_;
Bowgo Tsaid2620172017-04-17 22:17:09 +0800105};
106
Bowgo Tsaifd18a452017-04-24 18:36:25 +0800107// Static Functions
108// ----------------
109static inline bool IsDtVbmetaCompatible() {
110 return is_android_dt_value_expected("vbmeta/compatible", "android,vbmeta");
111}
112
113static bool inline IsRecoveryMode() {
114 return access("/sbin/recovery", F_OK) == 0;
115}
116
117// Class Definitions
118// -----------------
Bowgo Tsai20651f62017-05-08 20:45:50 +0800119FirstStageMount::FirstStageMount()
120 : need_dm_verity_(false), device_tree_fstab_(fs_mgr_read_fstab_dt(), fs_mgr_free_fstab) {
Bowgo Tsaid2620172017-04-17 22:17:09 +0800121 if (!device_tree_fstab_) {
Bowgo Tsaife92dd02018-04-30 16:13:42 +0800122 LOG(INFO) << "Failed to read fstab from device tree";
Bowgo Tsaid2620172017-04-17 22:17:09 +0800123 return;
124 }
Bowgo Tsai06ed6132017-06-08 10:43:41 +0800125 // Stores device_tree_fstab_->recs[] into mount_fstab_recs_ (vector<fstab_rec*>)
126 // for easier manipulation later, e.g., range-base for loop.
127 for (int i = 0; i < device_tree_fstab_->num_entries; i++) {
128 mount_fstab_recs_.push_back(&device_tree_fstab_->recs[i]);
Bowgo Tsaid2620172017-04-17 22:17:09 +0800129 }
Bowgo Tsai5ee7dae2018-05-16 18:33:44 +0800130
131 auto boot_devices = fs_mgr_get_boot_devices();
132 device_handler_ =
133 std::make_unique<DeviceHandler>(std::vector<Permissions>{}, std::vector<SysfsPermissions>{},
134 std::vector<Subsystem>{}, std::move(boot_devices), false);
Bowgo Tsaid2620172017-04-17 22:17:09 +0800135}
136
137std::unique_ptr<FirstStageMount> FirstStageMount::Create() {
Bowgo Tsaifd18a452017-04-24 18:36:25 +0800138 if (IsDtVbmetaCompatible()) {
Bowgo Tsaid2620172017-04-17 22:17:09 +0800139 return std::make_unique<FirstStageMountVBootV2>();
140 } else {
141 return std::make_unique<FirstStageMountVBootV1>();
142 }
143}
144
145bool FirstStageMount::DoFirstStageMount() {
146 // Nothing to mount.
147 if (mount_fstab_recs_.empty()) return true;
148
Bowgo Tsaifd18a452017-04-24 18:36:25 +0800149 if (!InitDevices()) return false;
150
151 if (!MountPartitions()) return false;
152
153 return true;
154}
155
156bool FirstStageMount::InitDevices() {
Sandeep Patil4cbedee2017-06-21 13:02:57 -0700157 return GetRequiredDevices() && InitRequiredDevices();
Bowgo Tsai20651f62017-05-08 20:45:50 +0800158}
159
160// Creates devices with uevent->partition_name matching one in the member variable
161// required_devices_partition_names_. Found partitions will then be removed from it
162// for the subsequent member function to check which devices are NOT created.
Sandeep Patil4cbedee2017-06-21 13:02:57 -0700163bool FirstStageMount::InitRequiredDevices() {
Bowgo Tsai20651f62017-05-08 20:45:50 +0800164 if (required_devices_partition_names_.empty()) {
Sandeep Patil4cbedee2017-06-21 13:02:57 -0700165 return true;
Bowgo Tsai20651f62017-05-08 20:45:50 +0800166 }
167
168 if (need_dm_verity_) {
Bowgo Tsaiea5fca42017-05-02 18:30:33 +0800169 const std::string dm_path = "/devices/virtual/misc/device-mapper";
Sandeep Patil4cbedee2017-06-21 13:02:57 -0700170 bool found = false;
171 auto dm_callback = [this, &dm_path, &found](const Uevent& uevent) {
172 if (uevent.path == dm_path) {
Bowgo Tsai5ee7dae2018-05-16 18:33:44 +0800173 device_handler_->HandleDeviceEvent(uevent);
Sandeep Patil4cbedee2017-06-21 13:02:57 -0700174 found = true;
175 return ListenerAction::kStop;
176 }
177 return ListenerAction::kContinue;
178 };
179 uevent_listener_.RegenerateUeventsForPath("/sys" + dm_path, dm_callback);
180 if (!found) {
Tom Cherry322e1762017-07-05 13:57:42 -0700181 LOG(INFO) << "device-mapper device not found in /sys, waiting for its uevent";
182 Timer t;
Sandeep Patil4cbedee2017-06-21 13:02:57 -0700183 uevent_listener_.Poll(dm_callback, 10s);
Tom Cherry322e1762017-07-05 13:57:42 -0700184 LOG(INFO) << "Wait for device-mapper returned after " << t;
Sandeep Patil4cbedee2017-06-21 13:02:57 -0700185 }
186 if (!found) {
Tom Cherry322e1762017-07-05 13:57:42 -0700187 LOG(ERROR) << "device-mapper device not found after polling timeout";
Sandeep Patil4cbedee2017-06-21 13:02:57 -0700188 return false;
189 }
Bowgo Tsaid2620172017-04-17 22:17:09 +0800190 }
191
Sandeep Patil4cbedee2017-06-21 13:02:57 -0700192 auto uevent_callback = [this](const Uevent& uevent) { return UeventCallback(uevent); };
193 uevent_listener_.RegenerateUevents(uevent_callback);
194
195 // UeventCallback() will remove found partitions from required_devices_partition_names_.
196 // So if it isn't empty here, it means some partitions are not found.
197 if (!required_devices_partition_names_.empty()) {
Tom Cherry322e1762017-07-05 13:57:42 -0700198 LOG(INFO) << __PRETTY_FUNCTION__
199 << ": partition(s) not found in /sys, waiting for their uevent(s): "
200 << android::base::Join(required_devices_partition_names_, ", ");
201 Timer t;
Sandeep Patil4cbedee2017-06-21 13:02:57 -0700202 uevent_listener_.Poll(uevent_callback, 10s);
Tom Cherry322e1762017-07-05 13:57:42 -0700203 LOG(INFO) << "Wait for partitions returned after " << t;
Sandeep Patil4cbedee2017-06-21 13:02:57 -0700204 }
205
206 if (!required_devices_partition_names_.empty()) {
Tom Cherry322e1762017-07-05 13:57:42 -0700207 LOG(ERROR) << __PRETTY_FUNCTION__ << ": partition(s) not found after polling timeout: "
Sandeep Patil4cbedee2017-06-21 13:02:57 -0700208 << android::base::Join(required_devices_partition_names_, ", ");
209 return false;
210 }
211
212 return true;
Bowgo Tsaid2620172017-04-17 22:17:09 +0800213}
214
Greg Hartman88647492018-02-05 13:48:11 -0800215ListenerAction FirstStageMount::HandleBlockDevice(const std::string& name, const Uevent& uevent) {
216 // Matches partition name to create device nodes.
217 // Both required_devices_partition_names_ and uevent->partition_name have A/B
218 // suffix when A/B is used.
219 auto iter = required_devices_partition_names_.find(name);
220 if (iter != required_devices_partition_names_.end()) {
221 LOG(VERBOSE) << __PRETTY_FUNCTION__ << ": found partition: " << *iter;
222 required_devices_partition_names_.erase(iter);
Bowgo Tsai5ee7dae2018-05-16 18:33:44 +0800223 device_handler_->HandleDeviceEvent(uevent);
Greg Hartman88647492018-02-05 13:48:11 -0800224 if (required_devices_partition_names_.empty()) {
225 return ListenerAction::kStop;
226 } else {
227 return ListenerAction::kContinue;
228 }
229 }
230 return ListenerAction::kContinue;
231}
232
Sandeep Patil4cbedee2017-06-21 13:02:57 -0700233ListenerAction FirstStageMount::UeventCallback(const Uevent& uevent) {
Bowgo Tsai20651f62017-05-08 20:45:50 +0800234 // Ignores everything that is not a block device.
Tom Cherryed506f72017-05-25 15:58:59 -0700235 if (uevent.subsystem != "block") {
Sandeep Patil4cbedee2017-06-21 13:02:57 -0700236 return ListenerAction::kContinue;
Bowgo Tsai20651f62017-05-08 20:45:50 +0800237 }
Bowgo Tsaid2620172017-04-17 22:17:09 +0800238
Tom Cherryed506f72017-05-25 15:58:59 -0700239 if (!uevent.partition_name.empty()) {
Greg Hartman88647492018-02-05 13:48:11 -0800240 return HandleBlockDevice(uevent.partition_name, uevent);
241 } else {
242 size_t base_idx = uevent.path.rfind('/');
243 if (base_idx != std::string::npos) {
244 return HandleBlockDevice(uevent.path.substr(base_idx + 1), uevent);
Bowgo Tsaid2620172017-04-17 22:17:09 +0800245 }
Bowgo Tsai20651f62017-05-08 20:45:50 +0800246 }
247 // Not found a partition or find an unneeded partition, continue to find others.
Sandeep Patil4cbedee2017-06-21 13:02:57 -0700248 return ListenerAction::kContinue;
Bowgo Tsaid2620172017-04-17 22:17:09 +0800249}
250
251// Creates "/dev/block/dm-XX" for dm-verity by running coldboot on /sys/block/dm-XX.
Sandeep Patil4cbedee2017-06-21 13:02:57 -0700252bool FirstStageMount::InitVerityDevice(const std::string& verity_device) {
Bowgo Tsaid2620172017-04-17 22:17:09 +0800253 const std::string device_name(basename(verity_device.c_str()));
254 const std::string syspath = "/sys/block/" + device_name;
Sandeep Patil4cbedee2017-06-21 13:02:57 -0700255 bool found = false;
Bowgo Tsaid2620172017-04-17 22:17:09 +0800256
Sandeep Patil4cbedee2017-06-21 13:02:57 -0700257 auto verity_callback = [&device_name, &verity_device, this, &found](const Uevent& uevent) {
258 if (uevent.device_name == device_name) {
259 LOG(VERBOSE) << "Creating dm-verity device : " << verity_device;
Bowgo Tsai5ee7dae2018-05-16 18:33:44 +0800260 device_handler_->HandleDeviceEvent(uevent);
Sandeep Patil4cbedee2017-06-21 13:02:57 -0700261 found = true;
262 return ListenerAction::kStop;
263 }
264 return ListenerAction::kContinue;
265 };
266
267 uevent_listener_.RegenerateUeventsForPath(syspath, verity_callback);
268 if (!found) {
Tom Cherry322e1762017-07-05 13:57:42 -0700269 LOG(INFO) << "dm-verity device not found in /sys, waiting for its uevent";
270 Timer t;
Sandeep Patil4cbedee2017-06-21 13:02:57 -0700271 uevent_listener_.Poll(verity_callback, 10s);
Tom Cherry322e1762017-07-05 13:57:42 -0700272 LOG(INFO) << "wait for dm-verity device returned after " << t;
Sandeep Patil4cbedee2017-06-21 13:02:57 -0700273 }
274 if (!found) {
Tom Cherry322e1762017-07-05 13:57:42 -0700275 LOG(ERROR) << "dm-verity device not found after polling timeout";
Sandeep Patil4cbedee2017-06-21 13:02:57 -0700276 return false;
277 }
278
279 return true;
Bowgo Tsaid2620172017-04-17 22:17:09 +0800280}
281
282bool FirstStageMount::MountPartitions() {
283 for (auto fstab_rec : mount_fstab_recs_) {
284 if (!SetUpDmVerity(fstab_rec)) {
285 PLOG(ERROR) << "Failed to setup verity for '" << fstab_rec->mount_point << "'";
286 return false;
287 }
288 if (fs_mgr_do_mount_one(fstab_rec)) {
289 PLOG(ERROR) << "Failed to mount '" << fstab_rec->mount_point << "'";
290 return false;
291 }
292 }
293 return true;
294}
295
Bowgo Tsai20651f62017-05-08 20:45:50 +0800296bool FirstStageMountVBootV1::GetRequiredDevices() {
Bowgo Tsai71881ff2017-04-25 13:09:47 +0800297 std::string verity_loc_device;
Bowgo Tsai20651f62017-05-08 20:45:50 +0800298 need_dm_verity_ = false;
Bowgo Tsaid2620172017-04-17 22:17:09 +0800299
300 for (auto fstab_rec : mount_fstab_recs_) {
301 // Don't allow verifyatboot in the first stage.
302 if (fs_mgr_is_verifyatboot(fstab_rec)) {
303 LOG(ERROR) << "Partitions can't be verified at boot";
304 return false;
305 }
306 // Checks for verified partitions.
307 if (fs_mgr_is_verified(fstab_rec)) {
Bowgo Tsai20651f62017-05-08 20:45:50 +0800308 need_dm_verity_ = true;
Bowgo Tsaid2620172017-04-17 22:17:09 +0800309 }
Bowgo Tsai71881ff2017-04-25 13:09:47 +0800310 // Checks if verity metadata is on a separate partition. Note that it is
311 // not partition specific, so there must be only one additional partition
312 // that carries verity state.
Bowgo Tsaid2620172017-04-17 22:17:09 +0800313 if (fstab_rec->verity_loc) {
Bowgo Tsai71881ff2017-04-25 13:09:47 +0800314 if (verity_loc_device.empty()) {
315 verity_loc_device = fstab_rec->verity_loc;
316 } else if (verity_loc_device != fstab_rec->verity_loc) {
317 LOG(ERROR) << "More than one verity_loc found: " << verity_loc_device << ", "
318 << fstab_rec->verity_loc;
Bowgo Tsaid2620172017-04-17 22:17:09 +0800319 return false;
320 }
321 }
322 }
323
Bowgo Tsai71881ff2017-04-25 13:09:47 +0800324 // Includes the partition names of fstab records and verity_loc_device (if any).
Bowgo Tsaid2620172017-04-17 22:17:09 +0800325 // Notes that fstab_rec->blk_device has A/B suffix updated by fs_mgr when A/B is used.
326 for (auto fstab_rec : mount_fstab_recs_) {
Bowgo Tsai20651f62017-05-08 20:45:50 +0800327 required_devices_partition_names_.emplace(basename(fstab_rec->blk_device));
Bowgo Tsaid2620172017-04-17 22:17:09 +0800328 }
329
Bowgo Tsai71881ff2017-04-25 13:09:47 +0800330 if (!verity_loc_device.empty()) {
Bowgo Tsai20651f62017-05-08 20:45:50 +0800331 required_devices_partition_names_.emplace(basename(verity_loc_device.c_str()));
Bowgo Tsaid2620172017-04-17 22:17:09 +0800332 }
333
334 return true;
335}
336
337bool FirstStageMountVBootV1::SetUpDmVerity(fstab_rec* fstab_rec) {
338 if (fs_mgr_is_verified(fstab_rec)) {
339 int ret = fs_mgr_setup_verity(fstab_rec, false /* wait_for_verity_dev */);
Sandeep Patil95366e92017-06-21 12:58:31 -0700340 switch (ret) {
Bowgo Tsai60f19a02017-06-22 22:23:08 +0800341 case FS_MGR_SETUP_VERITY_SKIPPED:
342 case FS_MGR_SETUP_VERITY_DISABLED:
343 LOG(INFO) << "Verity disabled/skipped for '" << fstab_rec->mount_point << "'";
344 return true;
345 case FS_MGR_SETUP_VERITY_SUCCESS:
346 // The exact block device name (fstab_rec->blk_device) is changed to
347 // "/dev/block/dm-XX". Needs to create it because ueventd isn't started in init
348 // first stage.
349 return InitVerityDevice(fstab_rec->blk_device);
350 default:
351 return false;
Bowgo Tsaid2620172017-04-17 22:17:09 +0800352 }
353 }
354 return true; // Returns true to mount the partition.
355}
356
357// FirstStageMountVBootV2 constructor.
Bowgo Tsai20651f62017-05-08 20:45:50 +0800358// Gets the vbmeta partitions from device tree.
Bowgo Tsaid2620172017-04-17 22:17:09 +0800359// /{
360// firmware {
361// android {
362// vbmeta {
363// compatible = "android,vbmeta";
364// parts = "vbmeta,boot,system,vendor"
Bowgo Tsaid2620172017-04-17 22:17:09 +0800365// };
366// };
367// };
368// }
369FirstStageMountVBootV2::FirstStageMountVBootV2() : avb_handle_(nullptr) {
370 if (!read_android_dt_file("vbmeta/parts", &device_tree_vbmeta_parts_)) {
371 PLOG(ERROR) << "Failed to read vbmeta/parts from device tree";
372 return;
373 }
Bowgo Tsaid2620172017-04-17 22:17:09 +0800374}
375
Bowgo Tsai20651f62017-05-08 20:45:50 +0800376bool FirstStageMountVBootV2::GetRequiredDevices() {
377 need_dm_verity_ = false;
Bowgo Tsaid2620172017-04-17 22:17:09 +0800378
379 // fstab_rec->blk_device has A/B suffix.
380 for (auto fstab_rec : mount_fstab_recs_) {
381 if (fs_mgr_is_avb(fstab_rec)) {
Bowgo Tsai20651f62017-05-08 20:45:50 +0800382 need_dm_verity_ = true;
Bowgo Tsaid2620172017-04-17 22:17:09 +0800383 }
Bowgo Tsai20651f62017-05-08 20:45:50 +0800384 required_devices_partition_names_.emplace(basename(fstab_rec->blk_device));
Bowgo Tsaid2620172017-04-17 22:17:09 +0800385 }
386
387 // libavb verifies AVB metadata on all verified partitions at once.
388 // e.g., The device_tree_vbmeta_parts_ will be "vbmeta,boot,system,vendor"
389 // for libavb to verify metadata, even if there is only /vendor in the
390 // above mount_fstab_recs_.
Bowgo Tsai20651f62017-05-08 20:45:50 +0800391 if (need_dm_verity_) {
Bowgo Tsaid2620172017-04-17 22:17:09 +0800392 if (device_tree_vbmeta_parts_.empty()) {
393 LOG(ERROR) << "Missing vbmeta parts in device tree";
394 return false;
395 }
396 std::vector<std::string> partitions = android::base::Split(device_tree_vbmeta_parts_, ",");
397 std::string ab_suffix = fs_mgr_get_slot_suffix();
398 for (const auto& partition : partitions) {
Bowgo Tsai20651f62017-05-08 20:45:50 +0800399 // required_devices_partition_names_ is of type std::set so it's not an issue
400 // to emplace a partition twice. e.g., /vendor might be in both places:
Bowgo Tsaid2620172017-04-17 22:17:09 +0800401 // - device_tree_vbmeta_parts_ = "vbmeta,boot,system,vendor"
402 // - mount_fstab_recs_: /vendor_a
Bowgo Tsai20651f62017-05-08 20:45:50 +0800403 required_devices_partition_names_.emplace(partition + ab_suffix);
Bowgo Tsaid2620172017-04-17 22:17:09 +0800404 }
405 }
406 return true;
407}
408
Sandeep Patil4cbedee2017-06-21 13:02:57 -0700409ListenerAction FirstStageMountVBootV2::UeventCallback(const Uevent& uevent) {
Tom Cherryed506f72017-05-25 15:58:59 -0700410 // Check if this uevent corresponds to one of the required partitions and store its symlinks if
411 // so, in order to create FsManagerAvbHandle later.
412 // Note that the parent callback removes partitions from the list of required partitions
413 // as it finds them, so this must happen first.
414 if (!uevent.partition_name.empty() &&
415 required_devices_partition_names_.find(uevent.partition_name) !=
416 required_devices_partition_names_.end()) {
417 // GetBlockDeviceSymlinks() will return three symlinks at most, depending on
Bowgo Tsai20651f62017-05-08 20:45:50 +0800418 // the content of uevent. by-name symlink will be at [0] if uevent->partition_name
419 // is not empty. e.g.,
420 // - /dev/block/platform/soc.0/f9824900.sdhci/by-name/modem
Bowgo Tsai20651f62017-05-08 20:45:50 +0800421 // - /dev/block/platform/soc.0/f9824900.sdhci/mmcblk0p1
Bowgo Tsai5ee7dae2018-05-16 18:33:44 +0800422 std::vector<std::string> links = device_handler_->GetBlockDeviceSymlinks(uevent);
Bowgo Tsai20651f62017-05-08 20:45:50 +0800423 if (!links.empty()) {
Tom Cherryed506f72017-05-25 15:58:59 -0700424 auto[it, inserted] = by_name_symlink_map_.emplace(uevent.partition_name, links[0]);
Bowgo Tsai20651f62017-05-08 20:45:50 +0800425 if (!inserted) {
Tom Cherryed506f72017-05-25 15:58:59 -0700426 LOG(ERROR) << "Partition '" << uevent.partition_name
Bowgo Tsai20651f62017-05-08 20:45:50 +0800427 << "' already existed in the by-name symlink map with a value of '"
428 << it->second << "', new value '" << links[0] << "' will be ignored.";
429 }
430 }
431 }
432
Tom Cherryed506f72017-05-25 15:58:59 -0700433 return FirstStageMount::UeventCallback(uevent);
Bowgo Tsai20651f62017-05-08 20:45:50 +0800434}
435
Bowgo Tsaid2620172017-04-17 22:17:09 +0800436bool FirstStageMountVBootV2::SetUpDmVerity(fstab_rec* fstab_rec) {
437 if (fs_mgr_is_avb(fstab_rec)) {
438 if (!InitAvbHandle()) return false;
Bowgo Tsai60f19a02017-06-22 22:23:08 +0800439 SetUpAvbHashtreeResult hashtree_result =
440 avb_handle_->SetUpAvbHashtree(fstab_rec, false /* wait_for_verity_dev */);
441 switch (hashtree_result) {
442 case SetUpAvbHashtreeResult::kDisabled:
443 return true; // Returns true to mount the partition.
444 case SetUpAvbHashtreeResult::kSuccess:
445 // The exact block device name (fstab_rec->blk_device) is changed to
446 // "/dev/block/dm-XX". Needs to create it because ueventd isn't started in init
447 // first stage.
448 return InitVerityDevice(fstab_rec->blk_device);
449 default:
450 return false;
Bowgo Tsaid2620172017-04-17 22:17:09 +0800451 }
452 }
453 return true; // Returns true to mount the partition.
454}
455
456bool FirstStageMountVBootV2::InitAvbHandle() {
457 if (avb_handle_) return true; // Returns true if the handle is already initialized.
458
Bowgo Tsai20651f62017-05-08 20:45:50 +0800459 if (by_name_symlink_map_.empty()) {
460 LOG(ERROR) << "by_name_symlink_map_ is empty";
461 return false;
462 }
463
464 avb_handle_ = FsManagerAvbHandle::Open(std::move(by_name_symlink_map_));
465 by_name_symlink_map_.clear(); // Removes all elements after the above std::move().
466
Bowgo Tsaid2620172017-04-17 22:17:09 +0800467 if (!avb_handle_) {
468 PLOG(ERROR) << "Failed to open FsManagerAvbHandle";
469 return false;
470 }
471 // Sets INIT_AVB_VERSION here for init to set ro.boot.avb_version in the second stage.
472 setenv("INIT_AVB_VERSION", avb_handle_->avb_version().c_str(), 1);
473 return true;
474}
475
476// Public functions
477// ----------------
Bowgo Tsai06ed6132017-06-08 10:43:41 +0800478// Mounts partitions specified by fstab in device tree.
Bowgo Tsaid2620172017-04-17 22:17:09 +0800479bool DoFirstStageMount() {
480 // Skips first stage mount if we're in recovery mode.
Bowgo Tsaifd18a452017-04-24 18:36:25 +0800481 if (IsRecoveryMode()) {
Bowgo Tsaid2620172017-04-17 22:17:09 +0800482 LOG(INFO) << "First stage mount skipped (recovery mode)";
483 return true;
484 }
485
486 // Firstly checks if device tree fstab entries are compatible.
487 if (!is_android_dt_value_expected("fstab/compatible", "android,fstab")) {
488 LOG(INFO) << "First stage mount skipped (missing/incompatible fstab in device tree)";
489 return true;
490 }
491
492 std::unique_ptr<FirstStageMount> handle = FirstStageMount::Create();
493 if (!handle) {
494 LOG(ERROR) << "Failed to create FirstStageMount";
495 return false;
496 }
497 return handle->DoFirstStageMount();
498}
Bowgo Tsaifd18a452017-04-24 18:36:25 +0800499
500void SetInitAvbVersionInRecovery() {
501 if (!IsRecoveryMode()) {
502 LOG(INFO) << "Skipped setting INIT_AVB_VERSION (not in recovery mode)";
503 return;
504 }
505
506 if (!IsDtVbmetaCompatible()) {
507 LOG(INFO) << "Skipped setting INIT_AVB_VERSION (not vbmeta compatible)";
508 return;
509 }
510
511 // Initializes required devices for the subsequent FsManagerAvbHandle::Open()
512 // to verify AVB metadata on all partitions in the verified chain.
513 // We only set INIT_AVB_VERSION when the AVB verification succeeds, i.e., the
514 // Open() function returns a valid handle.
515 // We don't need to mount partitions here in recovery mode.
516 FirstStageMountVBootV2 avb_first_mount;
517 if (!avb_first_mount.InitDevices()) {
518 LOG(ERROR) << "Failed to init devices for INIT_AVB_VERSION";
519 return;
520 }
521
Bowgo Tsai20651f62017-05-08 20:45:50 +0800522 FsManagerAvbUniquePtr avb_handle =
523 FsManagerAvbHandle::Open(std::move(avb_first_mount.by_name_symlink_map_));
Bowgo Tsaifd18a452017-04-24 18:36:25 +0800524 if (!avb_handle) {
525 PLOG(ERROR) << "Failed to open FsManagerAvbHandle for INIT_AVB_VERSION";
526 return;
527 }
528 setenv("INIT_AVB_VERSION", avb_handle->avb_version().c_str(), 1);
529}
Tom Cherry81f5d3e2017-06-22 12:53:17 -0700530
531} // namespace init
532} // namespace android