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 "utility.h"
18
19 #include <dirent.h>
20 #include <sys/stat.h>
21 #include <sys/types.h>
22 #include <unistd.h>
23
24 #include <android-base/file.h>
25 #include <android-base/logging.h>
26 #include <android-base/properties.h>
27 #include <android-base/strings.h>
28 #include <fs_mgr.h>
29 #include <fs_mgr/roots.h>
30 #include <fs_mgr_dm_linear.h>
31 #include <liblp/builder.h>
32 #include <liblp/liblp.h>
33
34 #include "fastboot_device.h"
35
36 using namespace android::fs_mgr;
37 using namespace std::chrono_literals;
38 using android::base::unique_fd;
39 using android::hardware::boot::V1_0::Slot;
40
41 namespace {
42
OpenPhysicalPartition(const std::string & name,PartitionHandle * handle)43 bool OpenPhysicalPartition(const std::string& name, PartitionHandle* handle) {
44 std::optional<std::string> path = FindPhysicalPartition(name);
45 if (!path) {
46 return false;
47 }
48 *handle = PartitionHandle(*path);
49 return true;
50 }
51
OpenLogicalPartition(FastbootDevice * device,const std::string & partition_name,PartitionHandle * handle)52 bool OpenLogicalPartition(FastbootDevice* device, const std::string& partition_name,
53 PartitionHandle* handle) {
54 std::string slot_suffix = GetSuperSlotSuffix(device, partition_name);
55 uint32_t slot_number = SlotNumberForSlotSuffix(slot_suffix);
56 auto path = FindPhysicalPartition(fs_mgr_get_super_partition_name(slot_number));
57 if (!path) {
58 return false;
59 }
60
61 CreateLogicalPartitionParams params = {
62 .block_device = *path,
63 .metadata_slot = slot_number,
64 .partition_name = partition_name,
65 .force_writable = true,
66 .timeout_ms = 5s,
67 };
68 std::string dm_path;
69 if (!CreateLogicalPartition(params, &dm_path)) {
70 LOG(ERROR) << "Could not map partition: " << partition_name;
71 return false;
72 }
73 auto closer = [partition_name]() -> void { DestroyLogicalPartition(partition_name); };
74 *handle = PartitionHandle(dm_path, std::move(closer));
75 return true;
76 }
77
78 } // namespace
79
OpenPartition(FastbootDevice * device,const std::string & name,PartitionHandle * handle)80 bool OpenPartition(FastbootDevice* device, const std::string& name, PartitionHandle* handle) {
81 // We prioritize logical partitions over physical ones, and do this
82 // consistently for other partition operations (like getvar:partition-size).
83 if (LogicalPartitionExists(device, name)) {
84 if (!OpenLogicalPartition(device, name, handle)) {
85 return false;
86 }
87 } else if (!OpenPhysicalPartition(name, handle)) {
88 LOG(ERROR) << "No such partition: " << name;
89 return false;
90 }
91
92 unique_fd fd(TEMP_FAILURE_RETRY(open(handle->path().c_str(), O_WRONLY | O_EXCL)));
93 if (fd < 0) {
94 PLOG(ERROR) << "Failed to open block device: " << handle->path();
95 return false;
96 }
97 handle->set_fd(std::move(fd));
98 return true;
99 }
100
FindPhysicalPartition(const std::string & name)101 std::optional<std::string> FindPhysicalPartition(const std::string& name) {
102 // Check for an invalid file name
103 if (android::base::StartsWith(name, "../") || name.find("/../") != std::string::npos) {
104 return {};
105 }
106 std::string path = "/dev/block/by-name/" + name;
107 if (access(path.c_str(), W_OK) < 0) {
108 return {};
109 }
110 return path;
111 }
112
FindLogicalPartition(const LpMetadata & metadata,const std::string & name)113 static const LpMetadataPartition* FindLogicalPartition(const LpMetadata& metadata,
114 const std::string& name) {
115 for (const auto& partition : metadata.partitions) {
116 if (GetPartitionName(partition) == name) {
117 return &partition;
118 }
119 }
120 return nullptr;
121 }
122
LogicalPartitionExists(FastbootDevice * device,const std::string & name,bool * is_zero_length)123 bool LogicalPartitionExists(FastbootDevice* device, const std::string& name, bool* is_zero_length) {
124 std::string slot_suffix = GetSuperSlotSuffix(device, name);
125 uint32_t slot_number = SlotNumberForSlotSuffix(slot_suffix);
126 auto path = FindPhysicalPartition(fs_mgr_get_super_partition_name(slot_number));
127 if (!path) {
128 return false;
129 }
130
131 std::unique_ptr<LpMetadata> metadata = ReadMetadata(path->c_str(), slot_number);
132 if (!metadata) {
133 return false;
134 }
135 const LpMetadataPartition* partition = FindLogicalPartition(*metadata.get(), name);
136 if (!partition) {
137 return false;
138 }
139 if (is_zero_length) {
140 *is_zero_length = (partition->num_extents == 0);
141 }
142 return true;
143 }
144
GetSlotNumber(const std::string & slot,Slot * number)145 bool GetSlotNumber(const std::string& slot, Slot* number) {
146 if (slot.size() != 1) {
147 return false;
148 }
149 if (slot[0] < 'a' || slot[0] > 'z') {
150 return false;
151 }
152 *number = slot[0] - 'a';
153 return true;
154 }
155
ListPartitions(FastbootDevice * device)156 std::vector<std::string> ListPartitions(FastbootDevice* device) {
157 std::vector<std::string> partitions;
158
159 // First get physical partitions.
160 struct dirent* de;
161 std::unique_ptr<DIR, decltype(&closedir)> by_name(opendir("/dev/block/by-name"), closedir);
162 while ((de = readdir(by_name.get())) != nullptr) {
163 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) {
164 continue;
165 }
166 struct stat s;
167 std::string path = "/dev/block/by-name/" + std::string(de->d_name);
168 if (!stat(path.c_str(), &s) && S_ISBLK(s.st_mode)) {
169 partitions.emplace_back(de->d_name);
170 }
171 }
172
173 // Find metadata in each super partition (on retrofit devices, there will
174 // be two).
175 std::vector<std::unique_ptr<LpMetadata>> metadata_list;
176
177 uint32_t current_slot = SlotNumberForSlotSuffix(device->GetCurrentSlot());
178 std::string super_name = fs_mgr_get_super_partition_name(current_slot);
179 if (auto metadata = ReadMetadata(super_name, current_slot)) {
180 metadata_list.emplace_back(std::move(metadata));
181 }
182
183 uint32_t other_slot = (current_slot == 0) ? 1 : 0;
184 std::string other_super = fs_mgr_get_super_partition_name(other_slot);
185 if (super_name != other_super) {
186 if (auto metadata = ReadMetadata(other_super, other_slot)) {
187 metadata_list.emplace_back(std::move(metadata));
188 }
189 }
190
191 for (const auto& metadata : metadata_list) {
192 for (const auto& partition : metadata->partitions) {
193 std::string partition_name = GetPartitionName(partition);
194 if (std::find(partitions.begin(), partitions.end(), partition_name) ==
195 partitions.end()) {
196 partitions.emplace_back(partition_name);
197 }
198 }
199 }
200 return partitions;
201 }
202
GetDeviceLockStatus()203 bool GetDeviceLockStatus() {
204 std::string cmdline;
205 // Return lock status true if unable to read kernel command line.
206 if (!android::base::ReadFileToString("/proc/cmdline", &cmdline)) {
207 return true;
208 }
209 return cmdline.find("androidboot.verifiedbootstate=orange") == std::string::npos;
210 }
211
UpdateAllPartitionMetadata(FastbootDevice * device,const std::string & super_name,const android::fs_mgr::LpMetadata & metadata)212 bool UpdateAllPartitionMetadata(FastbootDevice* device, const std::string& super_name,
213 const android::fs_mgr::LpMetadata& metadata) {
214 size_t num_slots = 1;
215 auto boot_control_hal = device->boot_control_hal();
216 if (boot_control_hal) {
217 num_slots = boot_control_hal->getNumberSlots();
218 }
219
220 bool ok = true;
221 for (size_t i = 0; i < num_slots; i++) {
222 ok &= UpdatePartitionTable(super_name, metadata, i);
223 }
224 return ok;
225 }
226
GetSuperSlotSuffix(FastbootDevice * device,const std::string & partition_name)227 std::string GetSuperSlotSuffix(FastbootDevice* device, const std::string& partition_name) {
228 // If the super partition does not have a slot suffix, this is not a
229 // retrofit device, and we should take the current slot.
230 std::string current_slot_suffix = device->GetCurrentSlot();
231 uint32_t current_slot_number = SlotNumberForSlotSuffix(current_slot_suffix);
232 std::string super_partition = fs_mgr_get_super_partition_name(current_slot_number);
233 if (GetPartitionSlotSuffix(super_partition).empty()) {
234 return current_slot_suffix;
235 }
236
237 // Otherwise, infer the slot from the partition name.
238 std::string slot_suffix = GetPartitionSlotSuffix(partition_name);
239 if (!slot_suffix.empty()) {
240 return slot_suffix;
241 }
242 return current_slot_suffix;
243 }
244
AutoMountMetadata()245 AutoMountMetadata::AutoMountMetadata() {
246 android::fs_mgr::Fstab proc_mounts;
247 if (!ReadFstabFromFile("/proc/mounts", &proc_mounts)) {
248 LOG(ERROR) << "Could not read /proc/mounts";
249 return;
250 }
251
252 if (GetEntryForMountPoint(&proc_mounts, "/metadata")) {
253 mounted_ = true;
254 return;
255 }
256
257 if (!ReadDefaultFstab(&fstab_)) {
258 LOG(ERROR) << "Could not read default fstab";
259 return;
260 }
261 mounted_ = EnsurePathMounted(&fstab_, "/metadata");
262 should_unmount_ = true;
263 }
264
~AutoMountMetadata()265 AutoMountMetadata::~AutoMountMetadata() {
266 if (mounted_ && should_unmount_) {
267 EnsurePathUnmounted(&fstab_, "/metadata");
268 }
269 }
270