• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "init_first_stage.h"
18 
19 #include <stdlib.h>
20 #include <unistd.h>
21 
22 #include <memory>
23 #include <set>
24 #include <string>
25 #include <vector>
26 
27 #include <android-base/file.h>
28 #include <android-base/logging.h>
29 #include <android-base/strings.h>
30 
31 #include "devices.h"
32 #include "fs_mgr.h"
33 #include "fs_mgr_avb.h"
34 #include "util.h"
35 
36 // Class Declarations
37 // ------------------
38 class FirstStageMount {
39   public:
40     FirstStageMount();
41     virtual ~FirstStageMount() = default;
42 
43     // The factory method to create either FirstStageMountVBootV1 or FirstStageMountVBootV2
44     // based on device tree configurations.
45     static std::unique_ptr<FirstStageMount> Create();
46     bool DoFirstStageMount();  // Mounts fstab entries read from device tree.
47     bool InitDevices();
48 
49   protected:
50     void InitRequiredDevices();
51     void InitVerityDevice(const std::string& verity_device);
52     bool MountPartitions();
53 
54     virtual coldboot_action_t ColdbootCallback(uevent* uevent);
55 
56     // Pure virtual functions.
57     virtual bool GetRequiredDevices() = 0;
58     virtual bool SetUpDmVerity(fstab_rec* fstab_rec) = 0;
59 
60     bool need_dm_verity_;
61     // Device tree fstab entries.
62     std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> device_tree_fstab_;
63     // Eligible first stage mount candidates, only allow /system, /vendor and/or /odm.
64     std::vector<fstab_rec*> mount_fstab_recs_;
65     std::set<std::string> required_devices_partition_names_;
66 };
67 
68 class FirstStageMountVBootV1 : public FirstStageMount {
69   public:
70     FirstStageMountVBootV1() = default;
71     ~FirstStageMountVBootV1() override = default;
72 
73   protected:
74     bool GetRequiredDevices() override;
75     bool SetUpDmVerity(fstab_rec* fstab_rec) override;
76 };
77 
78 class FirstStageMountVBootV2 : public FirstStageMount {
79   public:
80     friend void SetInitAvbVersionInRecovery();
81 
82     FirstStageMountVBootV2();
83     ~FirstStageMountVBootV2() override = default;
84 
85   protected:
86     coldboot_action_t ColdbootCallback(uevent* uevent) override;
87     bool GetRequiredDevices() override;
88     bool SetUpDmVerity(fstab_rec* fstab_rec) override;
89     bool InitAvbHandle();
90 
91     std::string device_tree_vbmeta_parts_;
92     FsManagerAvbUniquePtr avb_handle_;
93     ByNameSymlinkMap by_name_symlink_map_;
94 };
95 
96 // Static Functions
97 // ----------------
IsDtVbmetaCompatible()98 static inline bool IsDtVbmetaCompatible() {
99     return is_android_dt_value_expected("vbmeta/compatible", "android,vbmeta");
100 }
101 
IsRecoveryMode()102 static bool inline IsRecoveryMode() {
103     return access("/sbin/recovery", F_OK) == 0;
104 }
105 
106 // Class Definitions
107 // -----------------
FirstStageMount()108 FirstStageMount::FirstStageMount()
109     : need_dm_verity_(false), device_tree_fstab_(fs_mgr_read_fstab_dt(), fs_mgr_free_fstab) {
110     if (!device_tree_fstab_) {
111         LOG(ERROR) << "Failed to read fstab from device tree";
112         return;
113     }
114     for (auto mount_point : {"/system", "/vendor", "/odm"}) {
115         fstab_rec* fstab_rec =
116             fs_mgr_get_entry_for_mount_point(device_tree_fstab_.get(), mount_point);
117         if (fstab_rec != nullptr) {
118             mount_fstab_recs_.push_back(fstab_rec);
119         }
120     }
121 }
122 
Create()123 std::unique_ptr<FirstStageMount> FirstStageMount::Create() {
124     if (IsDtVbmetaCompatible()) {
125         return std::make_unique<FirstStageMountVBootV2>();
126     } else {
127         return std::make_unique<FirstStageMountVBootV1>();
128     }
129 }
130 
DoFirstStageMount()131 bool FirstStageMount::DoFirstStageMount() {
132     // Nothing to mount.
133     if (mount_fstab_recs_.empty()) return true;
134 
135     if (!InitDevices()) return false;
136 
137     if (!MountPartitions()) return false;
138 
139     return true;
140 }
141 
InitDevices()142 bool FirstStageMount::InitDevices() {
143     if (!GetRequiredDevices()) return false;
144 
145     InitRequiredDevices();
146 
147     // InitRequiredDevices() will remove found partitions from required_devices_partition_names_.
148     // So if it isn't empty here, it means some partitions are not found.
149     if (!required_devices_partition_names_.empty()) {
150         LOG(ERROR) << __FUNCTION__ << "(): partition(s) not found: "
151                    << android::base::Join(required_devices_partition_names_, ", ");
152         return false;
153     } else {
154         return true;
155     }
156 }
157 
158 // Creates devices with uevent->partition_name matching one in the member variable
159 // required_devices_partition_names_. Found partitions will then be removed from it
160 // for the subsequent member function to check which devices are NOT created.
InitRequiredDevices()161 void FirstStageMount::InitRequiredDevices() {
162     if (required_devices_partition_names_.empty()) {
163         return;
164     }
165 
166     if (need_dm_verity_) {
167         const std::string dm_path = "/devices/virtual/misc/device-mapper";
168         device_init(("/sys" + dm_path).c_str(), [&dm_path](uevent* uevent) -> coldboot_action_t {
169             if (uevent->path && uevent->path == dm_path) return COLDBOOT_STOP;
170             return COLDBOOT_CONTINUE;  // dm_path not found, continue to find it.
171         });
172     }
173 
174     device_init(nullptr,
175                 [this](uevent* uevent) -> coldboot_action_t { return ColdbootCallback(uevent); });
176 
177     device_close();
178 }
179 
ColdbootCallback(uevent * uevent)180 coldboot_action_t FirstStageMount::ColdbootCallback(uevent* uevent) {
181     // We need platform devices to create symlinks.
182     if (!strncmp(uevent->subsystem, "platform", 8)) {
183         return COLDBOOT_CREATE;
184     }
185 
186     // Ignores everything that is not a block device.
187     if (strncmp(uevent->subsystem, "block", 5)) {
188         return COLDBOOT_CONTINUE;
189     }
190 
191     if (uevent->partition_name) {
192         // Matches partition name to create device nodes.
193         // Both required_devices_partition_names_ and uevent->partition_name have A/B
194         // suffix when A/B is used.
195         auto iter = required_devices_partition_names_.find(uevent->partition_name);
196         if (iter != required_devices_partition_names_.end()) {
197             LOG(VERBOSE) << __FUNCTION__ << "(): found partition: " << *iter;
198             required_devices_partition_names_.erase(iter);
199             if (required_devices_partition_names_.empty()) {
200                 return COLDBOOT_STOP;  // Found all partitions, stop coldboot.
201             } else {
202                 return COLDBOOT_CREATE;  // Creates this device and continue to find others.
203             }
204         }
205     }
206     // Not found a partition or find an unneeded partition, continue to find others.
207     return COLDBOOT_CONTINUE;
208 }
209 
210 // Creates "/dev/block/dm-XX" for dm-verity by running coldboot on /sys/block/dm-XX.
InitVerityDevice(const std::string & verity_device)211 void FirstStageMount::InitVerityDevice(const std::string& verity_device) {
212     const std::string device_name(basename(verity_device.c_str()));
213     const std::string syspath = "/sys/block/" + device_name;
214 
215     device_init(syspath.c_str(), [&](uevent* uevent) -> coldboot_action_t {
216         if (uevent->device_name && uevent->device_name == device_name) {
217             LOG(VERBOSE) << "Creating dm-verity device : " << verity_device;
218             return COLDBOOT_STOP;
219         }
220         return COLDBOOT_CONTINUE;
221     });
222     device_close();
223 }
224 
MountPartitions()225 bool FirstStageMount::MountPartitions() {
226     for (auto fstab_rec : mount_fstab_recs_) {
227         if (!SetUpDmVerity(fstab_rec)) {
228             PLOG(ERROR) << "Failed to setup verity for '" << fstab_rec->mount_point << "'";
229             return false;
230         }
231         if (fs_mgr_do_mount_one(fstab_rec)) {
232             PLOG(ERROR) << "Failed to mount '" << fstab_rec->mount_point << "'";
233             return false;
234         }
235     }
236     return true;
237 }
238 
GetRequiredDevices()239 bool FirstStageMountVBootV1::GetRequiredDevices() {
240     std::string verity_loc_device;
241     need_dm_verity_ = false;
242 
243     for (auto fstab_rec : mount_fstab_recs_) {
244         // Don't allow verifyatboot in the first stage.
245         if (fs_mgr_is_verifyatboot(fstab_rec)) {
246             LOG(ERROR) << "Partitions can't be verified at boot";
247             return false;
248         }
249         // Checks for verified partitions.
250         if (fs_mgr_is_verified(fstab_rec)) {
251             need_dm_verity_ = true;
252         }
253         // Checks if verity metadata is on a separate partition. Note that it is
254         // not partition specific, so there must be only one additional partition
255         // that carries verity state.
256         if (fstab_rec->verity_loc) {
257             if (verity_loc_device.empty()) {
258                 verity_loc_device = fstab_rec->verity_loc;
259             } else if (verity_loc_device != fstab_rec->verity_loc) {
260                 LOG(ERROR) << "More than one verity_loc found: " << verity_loc_device << ", "
261                            << fstab_rec->verity_loc;
262                 return false;
263             }
264         }
265     }
266 
267     // Includes the partition names of fstab records and verity_loc_device (if any).
268     // Notes that fstab_rec->blk_device has A/B suffix updated by fs_mgr when A/B is used.
269     for (auto fstab_rec : mount_fstab_recs_) {
270         required_devices_partition_names_.emplace(basename(fstab_rec->blk_device));
271     }
272 
273     if (!verity_loc_device.empty()) {
274         required_devices_partition_names_.emplace(basename(verity_loc_device.c_str()));
275     }
276 
277     return true;
278 }
279 
SetUpDmVerity(fstab_rec * fstab_rec)280 bool FirstStageMountVBootV1::SetUpDmVerity(fstab_rec* fstab_rec) {
281     if (fs_mgr_is_verified(fstab_rec)) {
282         int ret = fs_mgr_setup_verity(fstab_rec, false /* wait_for_verity_dev */);
283         if (ret == FS_MGR_SETUP_VERITY_DISABLED) {
284             LOG(INFO) << "Verity disabled for '" << fstab_rec->mount_point << "'";
285         } else if (ret == FS_MGR_SETUP_VERITY_SUCCESS) {
286             // The exact block device name (fstab_rec->blk_device) is changed to "/dev/block/dm-XX".
287             // Needs to create it because ueventd isn't started in init first stage.
288             InitVerityDevice(fstab_rec->blk_device);
289         } else {
290             return false;
291         }
292     }
293     return true;  // Returns true to mount the partition.
294 }
295 
296 // FirstStageMountVBootV2 constructor.
297 // Gets the vbmeta partitions from device tree.
298 // /{
299 //     firmware {
300 //         android {
301 //             vbmeta {
302 //                 compatible = "android,vbmeta";
303 //                 parts = "vbmeta,boot,system,vendor"
304 //             };
305 //         };
306 //     };
307 //  }
FirstStageMountVBootV2()308 FirstStageMountVBootV2::FirstStageMountVBootV2() : avb_handle_(nullptr) {
309     if (!read_android_dt_file("vbmeta/parts", &device_tree_vbmeta_parts_)) {
310         PLOG(ERROR) << "Failed to read vbmeta/parts from device tree";
311         return;
312     }
313 }
314 
GetRequiredDevices()315 bool FirstStageMountVBootV2::GetRequiredDevices() {
316     need_dm_verity_ = false;
317 
318     // fstab_rec->blk_device has A/B suffix.
319     for (auto fstab_rec : mount_fstab_recs_) {
320         if (fs_mgr_is_avb(fstab_rec)) {
321             need_dm_verity_ = true;
322         }
323         required_devices_partition_names_.emplace(basename(fstab_rec->blk_device));
324     }
325 
326     // libavb verifies AVB metadata on all verified partitions at once.
327     // e.g., The device_tree_vbmeta_parts_ will be "vbmeta,boot,system,vendor"
328     // for libavb to verify metadata, even if there is only /vendor in the
329     // above mount_fstab_recs_.
330     if (need_dm_verity_) {
331         if (device_tree_vbmeta_parts_.empty()) {
332             LOG(ERROR) << "Missing vbmeta parts in device tree";
333             return false;
334         }
335         std::vector<std::string> partitions = android::base::Split(device_tree_vbmeta_parts_, ",");
336         std::string ab_suffix = fs_mgr_get_slot_suffix();
337         for (const auto& partition : partitions) {
338             // required_devices_partition_names_ is of type std::set so it's not an issue
339             // to emplace a partition twice. e.g., /vendor might be in both places:
340             //   - device_tree_vbmeta_parts_ = "vbmeta,boot,system,vendor"
341             //   - mount_fstab_recs_: /vendor_a
342             required_devices_partition_names_.emplace(partition + ab_suffix);
343         }
344     }
345     return true;
346 }
347 
ColdbootCallback(uevent * uevent)348 coldboot_action_t FirstStageMountVBootV2::ColdbootCallback(uevent* uevent) {
349     // Invokes the parent function to see if any desired partition has been found.
350     // If yes, record the by-name symlink for creating FsManagerAvbHandle later.
351     coldboot_action_t parent_callback_ret = FirstStageMount::ColdbootCallback(uevent);
352 
353     // Skips the uevent if the parent function returns COLDBOOT_CONTINUE (meaning
354     // that the uevent was skipped) or there is no uevent->partition_name to
355     // create the by-name symlink.
356     if (parent_callback_ret != COLDBOOT_CONTINUE && uevent->partition_name) {
357         // get_block_device_symlinks() will return three symlinks at most, depending on
358         // the content of uevent. by-name symlink will be at [0] if uevent->partition_name
359         // is not empty. e.g.,
360         //   - /dev/block/platform/soc.0/f9824900.sdhci/by-name/modem
361         //   - /dev/block/platform/soc.0/f9824900.sdhci/by-num/p1
362         //   - /dev/block/platform/soc.0/f9824900.sdhci/mmcblk0p1
363         char** links = get_block_device_symlinks(uevent);
364         if (links && links[0]) {
365             auto[it, inserted] = by_name_symlink_map_.emplace(uevent->partition_name, links[0]);
366             if (!inserted) {
367                 LOG(ERROR) << "Partition '" << uevent->partition_name
368                            << "' already existed in the by-name symlink map with a value of '"
369                            << it->second << "', new value '" << links[0] << "' will be ignored.";
370             }
371         }
372     }
373 
374     return parent_callback_ret;
375 }
376 
SetUpDmVerity(fstab_rec * fstab_rec)377 bool FirstStageMountVBootV2::SetUpDmVerity(fstab_rec* fstab_rec) {
378     if (fs_mgr_is_avb(fstab_rec)) {
379         if (!InitAvbHandle()) return false;
380         if (avb_handle_->hashtree_disabled()) {
381             LOG(INFO) << "avb hashtree disabled for '" << fstab_rec->mount_point << "'";
382         } else if (avb_handle_->SetUpAvb(fstab_rec, false /* wait_for_verity_dev */)) {
383             // The exact block device name (fstab_rec->blk_device) is changed to "/dev/block/dm-XX".
384             // Needs to create it because ueventd isn't started in init first stage.
385             InitVerityDevice(fstab_rec->blk_device);
386         } else {
387             return false;
388         }
389     }
390     return true;  // Returns true to mount the partition.
391 }
392 
InitAvbHandle()393 bool FirstStageMountVBootV2::InitAvbHandle() {
394     if (avb_handle_) return true;  // Returns true if the handle is already initialized.
395 
396     if (by_name_symlink_map_.empty()) {
397         LOG(ERROR) << "by_name_symlink_map_ is empty";
398         return false;
399     }
400 
401     avb_handle_ = FsManagerAvbHandle::Open(std::move(by_name_symlink_map_));
402     by_name_symlink_map_.clear();  // Removes all elements after the above std::move().
403 
404     if (!avb_handle_) {
405         PLOG(ERROR) << "Failed to open FsManagerAvbHandle";
406         return false;
407     }
408     // Sets INIT_AVB_VERSION here for init to set ro.boot.avb_version in the second stage.
409     setenv("INIT_AVB_VERSION", avb_handle_->avb_version().c_str(), 1);
410     return true;
411 }
412 
413 // Public functions
414 // ----------------
415 // Mounts /system, /vendor, and/or /odm if they are present in the fstab provided by device tree.
DoFirstStageMount()416 bool DoFirstStageMount() {
417     // Skips first stage mount if we're in recovery mode.
418     if (IsRecoveryMode()) {
419         LOG(INFO) << "First stage mount skipped (recovery mode)";
420         return true;
421     }
422 
423     // Firstly checks if device tree fstab entries are compatible.
424     if (!is_android_dt_value_expected("fstab/compatible", "android,fstab")) {
425         LOG(INFO) << "First stage mount skipped (missing/incompatible fstab in device tree)";
426         return true;
427     }
428 
429     std::unique_ptr<FirstStageMount> handle = FirstStageMount::Create();
430     if (!handle) {
431         LOG(ERROR) << "Failed to create FirstStageMount";
432         return false;
433     }
434     return handle->DoFirstStageMount();
435 }
436 
SetInitAvbVersionInRecovery()437 void SetInitAvbVersionInRecovery() {
438     if (!IsRecoveryMode()) {
439         LOG(INFO) << "Skipped setting INIT_AVB_VERSION (not in recovery mode)";
440         return;
441     }
442 
443     if (!IsDtVbmetaCompatible()) {
444         LOG(INFO) << "Skipped setting INIT_AVB_VERSION (not vbmeta compatible)";
445         return;
446     }
447 
448     // Initializes required devices for the subsequent FsManagerAvbHandle::Open()
449     // to verify AVB metadata on all partitions in the verified chain.
450     // We only set INIT_AVB_VERSION when the AVB verification succeeds, i.e., the
451     // Open() function returns a valid handle.
452     // We don't need to mount partitions here in recovery mode.
453     FirstStageMountVBootV2 avb_first_mount;
454     if (!avb_first_mount.InitDevices()) {
455         LOG(ERROR) << "Failed to init devices for INIT_AVB_VERSION";
456         return;
457     }
458 
459     FsManagerAvbUniquePtr avb_handle =
460         FsManagerAvbHandle::Open(std::move(avb_first_mount.by_name_symlink_map_));
461     if (!avb_handle) {
462         PLOG(ERROR) << "Failed to open FsManagerAvbHandle for INIT_AVB_VERSION";
463         return;
464     }
465     setenv("INIT_AVB_VERSION", avb_handle->avb_version().c_str(), 1);
466 }
467