• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 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 "writer.h"
18 
19 #include <inttypes.h>
20 #include <unistd.h>
21 
22 #include <string>
23 
24 #include <android-base/file.h>
25 #include <android-base/unique_fd.h>
26 
27 #include "reader.h"
28 #include "utility.h"
29 
30 namespace android {
31 namespace fs_mgr {
32 
SerializeGeometry(const LpMetadataGeometry & input)33 std::string SerializeGeometry(const LpMetadataGeometry& input) {
34     LpMetadataGeometry geometry = input;
35     memset(geometry.checksum, 0, sizeof(geometry.checksum));
36     SHA256(&geometry, sizeof(geometry), geometry.checksum);
37 
38     std::string blob(reinterpret_cast<const char*>(&geometry), sizeof(geometry));
39     blob.resize(LP_METADATA_GEOMETRY_SIZE);
40     return blob;
41 }
42 
CompareGeometry(const LpMetadataGeometry & g1,const LpMetadataGeometry & g2)43 static bool CompareGeometry(const LpMetadataGeometry& g1, const LpMetadataGeometry& g2) {
44     return g1.metadata_max_size == g2.metadata_max_size &&
45            g1.metadata_slot_count == g2.metadata_slot_count &&
46            g1.logical_block_size == g2.logical_block_size;
47 }
48 
SerializeMetadata(const LpMetadata & input)49 std::string SerializeMetadata(const LpMetadata& input) {
50     LpMetadata metadata = input;
51     LpMetadataHeader& header = metadata.header;
52 
53     // Serialize individual tables.
54     std::string partitions(reinterpret_cast<const char*>(metadata.partitions.data()),
55                            metadata.partitions.size() * sizeof(LpMetadataPartition));
56     std::string extents(reinterpret_cast<const char*>(metadata.extents.data()),
57                         metadata.extents.size() * sizeof(LpMetadataExtent));
58     std::string groups(reinterpret_cast<const char*>(metadata.groups.data()),
59                        metadata.groups.size() * sizeof(LpMetadataPartitionGroup));
60     std::string block_devices(reinterpret_cast<const char*>(metadata.block_devices.data()),
61                               metadata.block_devices.size() * sizeof(LpMetadataBlockDevice));
62 
63     // Compute positions of tables.
64     header.partitions.offset = 0;
65     header.extents.offset = header.partitions.offset + partitions.size();
66     header.groups.offset = header.extents.offset + extents.size();
67     header.block_devices.offset = header.groups.offset + groups.size();
68     header.tables_size = header.block_devices.offset + block_devices.size();
69 
70     // Compute payload checksum.
71     std::string tables = partitions + extents + groups + block_devices;
72     SHA256(tables.data(), tables.size(), header.tables_checksum);
73 
74     // Compute header checksum.
75     memset(header.header_checksum, 0, sizeof(header.header_checksum));
76     SHA256(&header, sizeof(header), header.header_checksum);
77 
78     std::string header_blob =
79             std::string(reinterpret_cast<const char*>(&metadata.header), sizeof(metadata.header));
80     return header_blob + tables;
81 }
82 
83 // Perform sanity checks so we don't accidentally overwrite valid metadata
84 // with potentially invalid metadata, or random partition data with metadata.
ValidateAndSerializeMetadata(const IPartitionOpener & opener,const LpMetadata & metadata,const std::string & slot_suffix,std::string * blob)85 static bool ValidateAndSerializeMetadata(const IPartitionOpener& opener, const LpMetadata& metadata,
86                                          const std::string& slot_suffix, std::string* blob) {
87     const LpMetadataGeometry& geometry = metadata.geometry;
88 
89     *blob = SerializeMetadata(metadata);
90 
91     // Make sure we're writing within the space reserved.
92     if (blob->size() > geometry.metadata_max_size) {
93         LERROR << "Logical partition metadata is too large. " << blob->size() << " > "
94                << geometry.metadata_max_size;
95         return false;
96     }
97 
98     // Make sure the device has enough space to store two backup copies of the
99     // metadata.
100     uint64_t reserved_size = LP_METADATA_GEOMETRY_SIZE +
101                              uint64_t(geometry.metadata_max_size) * geometry.metadata_slot_count;
102     uint64_t total_reserved = LP_PARTITION_RESERVED_BYTES + reserved_size * 2;
103 
104     const LpMetadataBlockDevice* super_device = GetMetadataSuperBlockDevice(metadata);
105     if (!super_device) {
106         LERROR << "Logical partition metadata does not have a super block device.";
107         return false;
108     }
109 
110     if (total_reserved > super_device->first_logical_sector * LP_SECTOR_SIZE) {
111         LERROR << "Not enough space to store all logical partition metadata slots.";
112         return false;
113     }
114     for (const auto& block_device : metadata.block_devices) {
115         std::string partition_name = GetBlockDevicePartitionName(block_device);
116         if (block_device.flags & LP_BLOCK_DEVICE_SLOT_SUFFIXED) {
117             if (slot_suffix.empty()) {
118                 LERROR << "Block device " << partition_name << " requires a slot suffix,"
119                        << " which could not be derived from the super partition name.";
120                 return false;
121             }
122             partition_name += slot_suffix;
123         }
124 
125         if ((block_device.first_logical_sector + 1) * LP_SECTOR_SIZE > block_device.size) {
126             LERROR << "Block device " << partition_name << " has invalid first sector "
127                    << block_device.first_logical_sector << " for size " << block_device.size;
128             return false;
129         }
130         BlockDeviceInfo info;
131         if (!opener.GetInfo(partition_name, &info)) {
132             PERROR << partition_name << ": ioctl";
133             return false;
134         }
135         if (info.size != block_device.size) {
136             LERROR << "Block device " << partition_name << " size mismatch (expected"
137                    << block_device.size << ", got " << info.size << ")";
138             return false;
139         }
140     }
141 
142     // Make sure all partition entries reference valid extents.
143     for (const auto& partition : metadata.partitions) {
144         if (partition.first_extent_index + partition.num_extents > metadata.extents.size()) {
145             LERROR << "Partition references invalid extent.";
146             return false;
147         }
148     }
149 
150     // Make sure all linear extents have a valid range.
151     uint64_t last_sector = super_device->size / LP_SECTOR_SIZE;
152     for (const auto& extent : metadata.extents) {
153         if (extent.target_type == LP_TARGET_TYPE_LINEAR) {
154             uint64_t physical_sector = extent.target_data;
155             if (physical_sector < super_device->first_logical_sector ||
156                 physical_sector + extent.num_sectors > last_sector) {
157                 LERROR << "Extent table entry is out of bounds.";
158                 return false;
159             }
160         }
161     }
162     return true;
163 }
164 
165 // Check that the given region is within metadata bounds.
ValidateMetadataRegion(const LpMetadata & metadata,uint64_t start,size_t size)166 static bool ValidateMetadataRegion(const LpMetadata& metadata, uint64_t start, size_t size) {
167     const LpMetadataBlockDevice* super_device = GetMetadataSuperBlockDevice(metadata);
168     if (!super_device) {
169         LERROR << __PRETTY_FUNCTION__ << " could not locate super block device in metadata";
170         return false;
171     }
172     if (start + size >= super_device->first_logical_sector * LP_SECTOR_SIZE) {
173         LERROR << __PRETTY_FUNCTION__ << " write of " << size << " bytes at " << start
174                << " overlaps with logical partition contents";
175         return false;
176     }
177     return true;
178 }
179 
WritePrimaryMetadata(int fd,const LpMetadata & metadata,uint32_t slot_number,const std::string & blob,const std::function<bool (int,const std::string &)> & writer)180 static bool WritePrimaryMetadata(int fd, const LpMetadata& metadata, uint32_t slot_number,
181                                  const std::string& blob,
182                                  const std::function<bool(int, const std::string&)>& writer) {
183     int64_t primary_offset = GetPrimaryMetadataOffset(metadata.geometry, slot_number);
184     if (!ValidateMetadataRegion(metadata, primary_offset, blob.size())) {
185         return false;
186     }
187     if (SeekFile64(fd, primary_offset, SEEK_SET) < 0) {
188         PERROR << __PRETTY_FUNCTION__ << " lseek failed: offset " << primary_offset;
189         return false;
190     }
191     if (!writer(fd, blob)) {
192         PERROR << __PRETTY_FUNCTION__ << " write " << blob.size() << " bytes failed";
193         return false;
194     }
195     return true;
196 }
197 
WriteBackupMetadata(int fd,const LpMetadata & metadata,uint32_t slot_number,const std::string & blob,const std::function<bool (int,const std::string &)> & writer)198 static bool WriteBackupMetadata(int fd, const LpMetadata& metadata, uint32_t slot_number,
199                                 const std::string& blob,
200                                 const std::function<bool(int, const std::string&)>& writer) {
201     int64_t backup_offset = GetBackupMetadataOffset(metadata.geometry, slot_number);
202     if (!ValidateMetadataRegion(metadata, backup_offset, blob.size())) {
203         return false;
204     }
205     if (SeekFile64(fd, backup_offset, SEEK_SET) < 0) {
206         PERROR << __PRETTY_FUNCTION__ << " lseek failed: offset " << backup_offset;
207         return false;
208     }
209     if (!writer(fd, blob)) {
210         PERROR << __PRETTY_FUNCTION__ << " backup write " << blob.size() << " bytes failed";
211         return false;
212     }
213     return true;
214 }
215 
WriteMetadata(int fd,const LpMetadata & metadata,uint32_t slot_number,const std::string & blob,const std::function<bool (int,const std::string &)> & writer)216 static bool WriteMetadata(int fd, const LpMetadata& metadata, uint32_t slot_number,
217                           const std::string& blob,
218                           const std::function<bool(int, const std::string&)>& writer) {
219     // Make sure we're writing to a valid metadata slot.
220     if (slot_number >= metadata.geometry.metadata_slot_count) {
221         LERROR << "Invalid logical partition metadata slot number.";
222         return false;
223     }
224     if (!WritePrimaryMetadata(fd, metadata, slot_number, blob, writer)) {
225         return false;
226     }
227     if (!WriteBackupMetadata(fd, metadata, slot_number, blob, writer)) {
228         return false;
229     }
230     return true;
231 }
232 
DefaultWriter(int fd,const std::string & blob)233 static bool DefaultWriter(int fd, const std::string& blob) {
234     return android::base::WriteFully(fd, blob.data(), blob.size());
235 }
236 
237 #if defined(_WIN32)
238 static const int O_SYNC = 0;
239 #endif
240 
FlashPartitionTable(const IPartitionOpener & opener,const std::string & super_partition,const LpMetadata & metadata)241 bool FlashPartitionTable(const IPartitionOpener& opener, const std::string& super_partition,
242                          const LpMetadata& metadata) {
243     android::base::unique_fd fd = opener.Open(super_partition, O_RDWR | O_SYNC);
244     if (fd < 0) {
245         PERROR << __PRETTY_FUNCTION__ << " open failed: " << super_partition;
246         return false;
247     }
248 
249     // This is only used in update_engine and fastbootd, where the super
250     // partition should be specified as a name (or by-name link), and
251     // therefore, we should be able to extract a slot suffix.
252     std::string slot_suffix = GetPartitionSlotSuffix(super_partition);
253 
254     // Before writing geometry and/or logical partition tables, perform some
255     // basic checks that the geometry and tables are coherent, and will fit
256     // on the given block device.
257     std::string metadata_blob;
258     if (!ValidateAndSerializeMetadata(opener, metadata, slot_suffix, &metadata_blob)) {
259         return false;
260     }
261 
262     // On retrofit devices, super_partition is system_other and might be set to readonly by
263     // fs_mgr_set_blk_ro(). Unset readonly so that fd can be written to.
264     if (!SetBlockReadonly(fd.get(), false)) {
265         PWARNING << __PRETTY_FUNCTION__ << " BLKROSET 0 failed: " << super_partition;
266     }
267 
268     // Write zeroes to the first block.
269     std::string zeroes(LP_PARTITION_RESERVED_BYTES, 0);
270     if (SeekFile64(fd, 0, SEEK_SET) < 0) {
271         PERROR << __PRETTY_FUNCTION__ << " lseek failed: offset 0";
272         return false;
273     }
274     if (!android::base::WriteFully(fd, zeroes.data(), zeroes.size())) {
275         PERROR << __PRETTY_FUNCTION__ << " write " << zeroes.size() << " bytes failed";
276         return false;
277     }
278 
279     LWARN << "Flashing new logical partition geometry to " << super_partition;
280 
281     // Write geometry to the primary and backup locations.
282     std::string blob = SerializeGeometry(metadata.geometry);
283     if (SeekFile64(fd, GetPrimaryGeometryOffset(), SEEK_SET) < 0) {
284         PERROR << __PRETTY_FUNCTION__ << " lseek failed: primary geometry";
285         return false;
286     }
287     if (!android::base::WriteFully(fd, blob.data(), blob.size())) {
288         PERROR << __PRETTY_FUNCTION__ << " write " << blob.size() << " bytes failed";
289         return false;
290     }
291     if (SeekFile64(fd, GetBackupGeometryOffset(), SEEK_SET) < 0) {
292         PERROR << __PRETTY_FUNCTION__ << " lseek failed: backup geometry";
293         return false;
294     }
295     if (!android::base::WriteFully(fd, blob.data(), blob.size())) {
296         PERROR << __PRETTY_FUNCTION__ << " backup write " << blob.size() << " bytes failed";
297         return false;
298     }
299 
300     bool ok = true;
301     for (size_t i = 0; i < metadata.geometry.metadata_slot_count; i++) {
302         ok &= WriteMetadata(fd, metadata, i, metadata_blob, DefaultWriter);
303     }
304     return ok;
305 }
306 
FlashPartitionTable(const std::string & super_partition,const LpMetadata & metadata)307 bool FlashPartitionTable(const std::string& super_partition, const LpMetadata& metadata) {
308     return FlashPartitionTable(PartitionOpener(), super_partition, metadata);
309 }
310 
CompareMetadata(const LpMetadata & a,const LpMetadata & b)311 static bool CompareMetadata(const LpMetadata& a, const LpMetadata& b) {
312     return !memcmp(a.header.header_checksum, b.header.header_checksum,
313                    sizeof(a.header.header_checksum));
314 }
315 
UpdatePartitionTable(const IPartitionOpener & opener,const std::string & super_partition,const LpMetadata & metadata,uint32_t slot_number,const std::function<bool (int,const std::string &)> & writer)316 bool UpdatePartitionTable(const IPartitionOpener& opener, const std::string& super_partition,
317                           const LpMetadata& metadata, uint32_t slot_number,
318                           const std::function<bool(int, const std::string&)>& writer) {
319     android::base::unique_fd fd = opener.Open(super_partition, O_RDWR | O_SYNC);
320     if (fd < 0) {
321         PERROR << __PRETTY_FUNCTION__ << " open failed: " << super_partition;
322         return false;
323     }
324 
325     std::string slot_suffix = SlotSuffixForSlotNumber(slot_number);
326 
327     // Before writing geometry and/or logical partition tables, perform some
328     // basic checks that the geometry and tables are coherent, and will fit
329     // on the given block device.
330     std::string blob;
331     if (!ValidateAndSerializeMetadata(opener, metadata, slot_suffix, &blob)) {
332         return false;
333     }
334 
335     // Verify that the old geometry is identical. If it's not, then we might be
336     // writing a table that was built for a different device, so we must reject
337     // it.
338     const LpMetadataGeometry& geometry = metadata.geometry;
339     LpMetadataGeometry old_geometry;
340     if (!ReadLogicalPartitionGeometry(fd, &old_geometry)) {
341         return false;
342     }
343     if (!CompareGeometry(geometry, old_geometry)) {
344         LERROR << "Incompatible geometry in new logical partition metadata";
345         return false;
346     }
347 
348     // Validate the slot number now, before we call Read*Metadata.
349     if (slot_number >= geometry.metadata_slot_count) {
350         LERROR << "Invalid logical partition metadata slot number.";
351         return false;
352     }
353 
354     // Try to read both existing copies of the metadata, if any.
355     std::unique_ptr<LpMetadata> primary = ReadPrimaryMetadata(fd, geometry, slot_number);
356     std::unique_ptr<LpMetadata> backup = ReadBackupMetadata(fd, geometry, slot_number);
357 
358     if (primary && (!backup || !CompareMetadata(*primary.get(), *backup.get()))) {
359         // If the backup copy does not match the primary copy, we first
360         // synchronize the backup copy. This guarantees that a partial write
361         // still leaves one copy intact.
362         std::string old_blob;
363         if (!ValidateAndSerializeMetadata(opener, *primary.get(), slot_suffix, &old_blob)) {
364             LERROR << "Error serializing primary metadata to repair corrupted backup";
365             return false;
366         }
367         if (!WriteBackupMetadata(fd, metadata, slot_number, old_blob, writer)) {
368             LERROR << "Error writing primary metadata to repair corrupted backup";
369             return false;
370         }
371     } else if (backup && !primary) {
372         // The backup copy is coherent, and the primary is not. Sync it for
373         // safety.
374         std::string old_blob;
375         if (!ValidateAndSerializeMetadata(opener, *backup.get(), slot_suffix, &old_blob)) {
376             LERROR << "Error serializing backup metadata to repair corrupted primary";
377             return false;
378         }
379         if (!WritePrimaryMetadata(fd, metadata, slot_number, old_blob, writer)) {
380             LERROR << "Error writing backup metadata to repair corrupted primary";
381             return false;
382         }
383     }
384 
385     // Both copies should now be in sync, so we can continue the update.
386     if (!WriteMetadata(fd, metadata, slot_number, blob, writer)) {
387         return false;
388     }
389 
390     LINFO << "Updated logical partition table at slot " << slot_number << " on device "
391           << super_partition;
392     return true;
393 }
394 
UpdatePartitionTable(const IPartitionOpener & opener,const std::string & super_partition,const LpMetadata & metadata,uint32_t slot_number)395 bool UpdatePartitionTable(const IPartitionOpener& opener, const std::string& super_partition,
396                           const LpMetadata& metadata, uint32_t slot_number) {
397     return UpdatePartitionTable(opener, super_partition, metadata, slot_number, DefaultWriter);
398 }
399 
UpdatePartitionTable(const std::string & super_partition,const LpMetadata & metadata,uint32_t slot_number)400 bool UpdatePartitionTable(const std::string& super_partition, const LpMetadata& metadata,
401                           uint32_t slot_number) {
402     PartitionOpener opener;
403     return UpdatePartitionTable(opener, super_partition, metadata, slot_number, DefaultWriter);
404 }
405 
406 }  // namespace fs_mgr
407 }  // namespace android
408