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 "images.h"
18 
19 #include <limits.h>
20 #include <sys/stat.h>
21 
22 #include <android-base/file.h>
23 
24 #include "reader.h"
25 #include "utility.h"
26 #include "writer.h"
27 
28 namespace android {
29 namespace fs_mgr {
30 
31 using android::base::borrowed_fd;
32 using android::base::unique_fd;
33 
34 #if defined(_WIN32)
35 static const int O_NOFOLLOW = 0;
36 #endif
37 
IsEmptySuperImage(borrowed_fd fd)38 static bool IsEmptySuperImage(borrowed_fd fd) {
39     struct stat s;
40     if (fstat(fd.get(), &s) < 0) {
41         PERROR << __PRETTY_FUNCTION__ << " fstat failed";
42         return false;
43     }
44     if (s.st_size < LP_METADATA_GEOMETRY_SIZE) {
45         return false;
46     }
47 
48     // Rewind back to the start, read the geometry struct.
49     LpMetadataGeometry geometry = {};
50     if (SeekFile64(fd.get(), 0, SEEK_SET) < 0) {
51         PERROR << __PRETTY_FUNCTION__ << " lseek failed";
52         return false;
53     }
54     if (!android::base::ReadFully(fd, &geometry, sizeof(geometry))) {
55         PERROR << __PRETTY_FUNCTION__ << " read failed";
56         return false;
57     }
58     return geometry.magic == LP_METADATA_GEOMETRY_MAGIC;
59 }
60 
IsEmptySuperImage(const std::string & file)61 bool IsEmptySuperImage(const std::string& file) {
62     unique_fd fd = GetControlFileOrOpen(file, O_RDONLY | O_CLOEXEC);
63     if (fd < 0) {
64         PERROR << __PRETTY_FUNCTION__ << " open failed";
65         return false;
66     }
67     return IsEmptySuperImage(fd);
68 }
69 
ReadFromImageFile(int fd)70 std::unique_ptr<LpMetadata> ReadFromImageFile(int fd) {
71     std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(LP_METADATA_GEOMETRY_SIZE);
72     if (SeekFile64(fd, 0, SEEK_SET) < 0) {
73         PERROR << __PRETTY_FUNCTION__ << " lseek failed";
74         return nullptr;
75     }
76     if (!android::base::ReadFully(fd, buffer.get(), LP_METADATA_GEOMETRY_SIZE)) {
77         PERROR << __PRETTY_FUNCTION__ << " read failed";
78         return nullptr;
79     }
80     LpMetadataGeometry geometry;
81     if (!ParseGeometry(buffer.get(), &geometry)) {
82         return nullptr;
83     }
84     return ParseMetadata(geometry, fd);
85 }
86 
ReadFromImageBlob(const void * data,size_t bytes)87 std::unique_ptr<LpMetadata> ReadFromImageBlob(const void* data, size_t bytes) {
88     if (bytes < LP_METADATA_GEOMETRY_SIZE) {
89         LERROR << __PRETTY_FUNCTION__ << ": " << bytes << " is smaller than geometry header";
90         return nullptr;
91     }
92 
93     LpMetadataGeometry geometry;
94     if (!ParseGeometry(data, &geometry)) {
95         return nullptr;
96     }
97 
98     const uint8_t* metadata_buffer =
99             reinterpret_cast<const uint8_t*>(data) + LP_METADATA_GEOMETRY_SIZE;
100     size_t metadata_buffer_size = bytes - LP_METADATA_GEOMETRY_SIZE;
101     return ParseMetadata(geometry, metadata_buffer, metadata_buffer_size);
102 }
103 
ReadFromImageFile(const std::string & image_file)104 std::unique_ptr<LpMetadata> ReadFromImageFile(const std::string& image_file) {
105     unique_fd fd = GetControlFileOrOpen(image_file.c_str(), O_RDONLY | O_CLOEXEC);
106     if (fd < 0) {
107         PERROR << __PRETTY_FUNCTION__ << " open failed: " << image_file;
108         return nullptr;
109     }
110     return ReadFromImageFile(fd);
111 }
112 
WriteToImageFile(borrowed_fd fd,const LpMetadata & input)113 bool WriteToImageFile(borrowed_fd fd, const LpMetadata& input) {
114     std::string geometry = SerializeGeometry(input.geometry);
115     std::string metadata = SerializeMetadata(input);
116 
117     std::string everything = geometry + metadata;
118 
119     if (!android::base::WriteFully(fd, everything.data(), everything.size())) {
120         PERROR << __PRETTY_FUNCTION__ << " write " << everything.size() << " bytes failed";
121         return false;
122     }
123     return true;
124 }
125 
126 #if !defined(_WIN32)
FsyncDirectory(const char * dirname)127 bool FsyncDirectory(const char* dirname) {
128     android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(dirname, O_RDONLY | O_CLOEXEC)));
129     if (fd == -1) {
130         PLOG(ERROR) << "Failed to open " << dirname;
131         return false;
132     }
133     if (fsync(fd) == -1) {
134         if (errno == EROFS || errno == EINVAL) {
135             PLOG(WARNING) << "Skip fsync " << dirname
136                           << " on a file system does not support synchronization";
137         } else {
138             PLOG(ERROR) << "Failed to fsync " << dirname;
139             return false;
140         }
141     }
142     return true;
143 }
144 #endif
145 
WriteToImageFile(const std::string & file,const LpMetadata & input)146 bool WriteToImageFile(const std::string& file, const LpMetadata& input) {
147     const auto parent_dir = base::Dirname(file);
148     TemporaryFile tmpfile(parent_dir);
149     if (!WriteToImageFile(tmpfile.fd, input)) {
150         PLOG(ERROR) << "Failed to write geometry data to tmpfile " << tmpfile.path;
151         return false;
152     }
153 
154 #if !defined(_WIN32)
155     fsync(tmpfile.fd);
156 #endif
157     const auto err = rename(tmpfile.path, file.c_str());
158     if (err != 0) {
159         PLOG(ERROR) << "Failed to rename tmp geometry file " << tmpfile.path << " to " << file;
160         return false;
161     }
162 #if !defined(_WIN32)
163     FsyncDirectory(parent_dir.c_str());
164 #endif
165     return true;
166 }
167 
ImageBuilder(const LpMetadata & metadata,uint32_t block_size,const std::map<std::string,std::string> & images,bool sparsify)168 ImageBuilder::ImageBuilder(const LpMetadata& metadata, uint32_t block_size,
169                            const std::map<std::string, std::string>& images, bool sparsify)
170     : metadata_(metadata),
171       geometry_(metadata.geometry),
172       block_size_(block_size),
173       sparsify_(sparsify),
174       images_(images) {
175     uint64_t total_size = GetTotalSuperPartitionSize(metadata);
176     if (block_size % LP_SECTOR_SIZE != 0) {
177         LERROR << "Block size must be a multiple of the sector size, " << LP_SECTOR_SIZE;
178         return;
179     }
180     if (total_size % block_size != 0) {
181         LERROR << "Device size must be a multiple of the block size, " << block_size;
182         return;
183     }
184     if (metadata.geometry.metadata_max_size % block_size != 0) {
185         LERROR << "Metadata max size must be a multiple of the block size, " << block_size;
186         return;
187     }
188     if (LP_METADATA_GEOMETRY_SIZE % block_size != 0) {
189         LERROR << "Geometry size is not a multiple of the block size, " << block_size;
190         return;
191     }
192     if (LP_PARTITION_RESERVED_BYTES % block_size != 0) {
193         LERROR << "Reserved size is not a multiple of the block size, " << block_size;
194         return;
195     }
196 
197     uint64_t num_blocks = total_size / block_size;
198     if (num_blocks >= UINT_MAX) {
199         // libsparse counts blocks in unsigned 32-bit integers, so we check to
200         // make sure we're not going to overflow.
201         LERROR << "Block device is too large to encode with libsparse.";
202         return;
203     }
204 
205     for (const auto& block_device : metadata.block_devices) {
206         SparsePtr file(sparse_file_new(block_size_, block_device.size), sparse_file_destroy);
207         if (!file) {
208             LERROR << "Could not allocate sparse file of size " << block_device.size;
209             return;
210         }
211         device_images_.emplace_back(std::move(file));
212     }
213 }
214 
IsValid() const215 bool ImageBuilder::IsValid() const {
216     return device_images_.size() == metadata_.block_devices.size();
217 }
218 
Export(const std::string & file)219 bool ImageBuilder::Export(const std::string& file) {
220     unique_fd fd(open(file.c_str(), O_CREAT | O_RDWR | O_TRUNC | O_CLOEXEC | O_BINARY, 0644));
221     if (fd < 0) {
222         PERROR << "open failed: " << file;
223         return false;
224     }
225     if (device_images_.size() > 1) {
226         LERROR << "Cannot export to a single image on retrofit builds.";
227         return false;
228     }
229     // No gzip compression; no checksum.
230     int ret = sparse_file_write(device_images_[0].get(), fd, false, sparsify_, false);
231     if (ret != 0) {
232         LERROR << "sparse_file_write failed (error code " << ret << ")";
233         return false;
234     }
235     return true;
236 }
237 
ExportFiles(const std::string & output_dir)238 bool ImageBuilder::ExportFiles(const std::string& output_dir) {
239     for (size_t i = 0; i < device_images_.size(); i++) {
240         std::string name = GetBlockDevicePartitionName(metadata_.block_devices[i]);
241         std::string file_name = "super_" + name + ".img";
242         std::string file_path = output_dir + "/" + file_name;
243 
244         static const int kOpenFlags =
245                 O_CREAT | O_RDWR | O_TRUNC | O_CLOEXEC | O_NOFOLLOW | O_BINARY;
246         unique_fd fd(open(file_path.c_str(), kOpenFlags, 0644));
247         if (fd < 0) {
248             PERROR << "open failed: " << file_path;
249             return false;
250         }
251         // No gzip compression; no checksum.
252         int ret = sparse_file_write(device_images_[i].get(), fd, false, sparsify_, false);
253         if (ret != 0) {
254             LERROR << "sparse_file_write failed (error code " << ret << ")";
255             return false;
256         }
257     }
258     return true;
259 }
260 
AddData(sparse_file * file,const std::string & blob,uint64_t sector)261 bool ImageBuilder::AddData(sparse_file* file, const std::string& blob, uint64_t sector) {
262     uint32_t block;
263     if (!SectorToBlock(sector, &block)) {
264         return false;
265     }
266     void* data = const_cast<char*>(blob.data());
267     int ret = sparse_file_add_data(file, data, blob.size(), block);
268     if (ret != 0) {
269         LERROR << "sparse_file_add_data failed (error code " << ret << ")";
270         return false;
271     }
272     return true;
273 }
274 
SectorToBlock(uint64_t sector,uint32_t * block)275 bool ImageBuilder::SectorToBlock(uint64_t sector, uint32_t* block) {
276     // The caller must ensure that the metadata has an alignment that is a
277     // multiple of the block size. liblp will take care of the rest, ensuring
278     // that all partitions are on an aligned boundary. Therefore all writes
279     // should be block-aligned, and if they are not, the table was misconfigured.
280     // Note that the default alignment is 1MiB, which is a multiple of the
281     // default block size (4096).
282     if ((sector * LP_SECTOR_SIZE) % block_size_ != 0) {
283         LERROR << "sector " << sector << " is not aligned to block size " << block_size_;
284         return false;
285     }
286     *block = (sector * LP_SECTOR_SIZE) / block_size_;
287     return true;
288 }
289 
BlockToSector(uint64_t block) const290 uint64_t ImageBuilder::BlockToSector(uint64_t block) const {
291     return (block * block_size_) / LP_SECTOR_SIZE;
292 }
293 
Build()294 bool ImageBuilder::Build() {
295     if (sparse_file_add_fill(device_images_[0].get(), 0, LP_PARTITION_RESERVED_BYTES, 0) < 0) {
296         LERROR << "Could not add initial sparse block for reserved zeroes";
297         return false;
298     }
299 
300     std::string geometry_blob = SerializeGeometry(geometry_);
301     std::string metadata_blob = SerializeMetadata(metadata_);
302     metadata_blob.resize(geometry_.metadata_max_size);
303 
304     // Two copies of geometry, then two copies of each metadata slot.
305     all_metadata_ += geometry_blob + geometry_blob;
306     for (size_t i = 0; i < geometry_.metadata_slot_count * 2; i++) {
307         all_metadata_ += metadata_blob;
308     }
309 
310     uint64_t first_sector = LP_PARTITION_RESERVED_BYTES / LP_SECTOR_SIZE;
311     if (!AddData(device_images_[0].get(), all_metadata_, first_sector)) {
312         return false;
313     }
314 
315     if (!CheckExtentOrdering()) {
316         return false;
317     }
318 
319     for (const auto& partition : metadata_.partitions) {
320         auto iter = images_.find(GetPartitionName(partition));
321         if (iter == images_.end()) {
322             continue;
323         }
324         if (!AddPartitionImage(partition, iter->second)) {
325             return false;
326         }
327         images_.erase(iter);
328     }
329 
330     if (!images_.empty()) {
331         LERROR << "Partition image was specified but no partition was found.";
332         return false;
333     }
334     return true;
335 }
336 
HasFillValue(uint32_t * buffer,size_t count)337 static inline bool HasFillValue(uint32_t* buffer, size_t count) {
338     uint32_t fill_value = buffer[0];
339     for (size_t i = 1; i < count; i++) {
340         if (fill_value != buffer[i]) {
341             return false;
342         }
343     }
344     return true;
345 }
346 
AddPartitionImage(const LpMetadataPartition & partition,const std::string & file)347 bool ImageBuilder::AddPartitionImage(const LpMetadataPartition& partition,
348                                      const std::string& file) {
349     if (partition.num_extents == 0) {
350         LERROR << "Partition size is zero: " << GetPartitionName(partition);
351         return false;
352     }
353 
354     // Track which extent we're processing.
355     uint32_t extent_index = partition.first_extent_index;
356 
357     const LpMetadataExtent& extent = metadata_.extents[extent_index];
358     if (extent.target_type != LP_TARGET_TYPE_LINEAR) {
359         LERROR << "Partition should only have linear extents: " << GetPartitionName(partition);
360         return false;
361     }
362 
363     int fd = OpenImageFile(file);
364     if (fd < 0) {
365         LERROR << "Could not open image for partition: " << GetPartitionName(partition);
366         return false;
367     }
368 
369     // Make sure the image does not exceed the partition size.
370     uint64_t file_length;
371     if (!GetDescriptorSize(fd, &file_length)) {
372         LERROR << "Could not compute image size";
373         return false;
374     }
375     uint64_t partition_size = ComputePartitionSize(partition);
376     if (file_length > partition_size) {
377         LERROR << "Image for partition '" << GetPartitionName(partition)
378                << "' is greater than its size (" << file_length << ", expected " << partition_size
379                << ")";
380         return false;
381     }
382     if (SeekFile64(fd, 0, SEEK_SET)) {
383         PERROR << "lseek failed";
384         return false;
385     }
386 
387     // We track the current logical sector and the position the current extent
388     // ends at.
389     uint64_t output_sector = 0;
390     uint64_t extent_last_sector = extent.num_sectors;
391 
392     // We also track the output device and the current output block within that
393     // device.
394     uint32_t output_block;
395     if (!SectorToBlock(extent.target_data, &output_block)) {
396         return false;
397     }
398     sparse_file* output_device = device_images_[extent.target_source].get();
399 
400     // Proceed to read the file and build sparse images.
401     uint64_t pos = 0;
402     uint64_t remaining = file_length;
403     while (remaining) {
404         // Check if we need to advance to the next extent.
405         if (output_sector == extent_last_sector) {
406             extent_index++;
407             if (extent_index >= partition.first_extent_index + partition.num_extents) {
408                 LERROR << "image is larger than extent table";
409                 return false;
410             }
411 
412             const LpMetadataExtent& extent = metadata_.extents[extent_index];
413             extent_last_sector += extent.num_sectors;
414             output_device = device_images_[extent.target_source].get();
415             if (!SectorToBlock(extent.target_data, &output_block)) {
416                 return false;
417             }
418         }
419 
420         uint32_t buffer[block_size_ / sizeof(uint32_t)];
421         size_t read_size = remaining >= sizeof(buffer) ? sizeof(buffer) : size_t(remaining);
422         if (!android::base::ReadFully(fd, buffer, sizeof(buffer))) {
423             PERROR << "read failed";
424             return false;
425         }
426         if (read_size != sizeof(buffer) || !HasFillValue(buffer, read_size / sizeof(uint32_t))) {
427             int rv = sparse_file_add_fd(output_device, fd, pos, read_size, output_block);
428             if (rv) {
429                 LERROR << "sparse_file_add_fd failed with code: " << rv;
430                 return false;
431             }
432         } else {
433             int rv = sparse_file_add_fill(output_device, buffer[0], read_size, output_block);
434             if (rv) {
435                 LERROR << "sparse_file_add_fill failed with code: " << rv;
436                 return false;
437             }
438         }
439         pos += read_size;
440         remaining -= read_size;
441         output_sector += block_size_ / LP_SECTOR_SIZE;
442         output_block++;
443     }
444 
445     return true;
446 }
447 
ComputePartitionSize(const LpMetadataPartition & partition) const448 uint64_t ImageBuilder::ComputePartitionSize(const LpMetadataPartition& partition) const {
449     uint64_t sectors = 0;
450     for (size_t i = 0; i < partition.num_extents; i++) {
451         sectors += metadata_.extents[partition.first_extent_index + i].num_sectors;
452     }
453     return sectors * LP_SECTOR_SIZE;
454 }
455 
456 // For simplicity, we don't allow serializing any configuration: extents must
457 // be ordered, such that any extent at position I in the table occurs *before*
458 // any extent after position I, for the same block device. We validate that
459 // here.
460 //
461 // Without this, it would be more difficult to find the appropriate extent for
462 // an output block. With this guarantee it is a linear walk.
CheckExtentOrdering()463 bool ImageBuilder::CheckExtentOrdering() {
464     std::vector<uint64_t> last_sectors(metadata_.block_devices.size());
465 
466     for (const auto& extent : metadata_.extents) {
467         if (extent.target_type != LP_TARGET_TYPE_LINEAR) {
468             LERROR << "Extents must all be type linear.";
469             return false;
470         }
471         if (extent.target_data <= last_sectors[extent.target_source]) {
472             LERROR << "Extents must appear in increasing order.";
473             return false;
474         }
475         if ((extent.num_sectors * LP_SECTOR_SIZE) % block_size_ != 0) {
476             LERROR << "Extents must be aligned to the block size.";
477             return false;
478         }
479         last_sectors[extent.target_source] = extent.target_data;
480     }
481     return true;
482 }
483 
OpenImageFile(const std::string & file)484 int ImageBuilder::OpenImageFile(const std::string& file) {
485     unique_fd source_fd = GetControlFileOrOpen(file.c_str(), O_RDONLY | O_CLOEXEC | O_BINARY);
486     if (source_fd < 0) {
487         PERROR << "open image file failed: " << file;
488         return -1;
489     }
490 
491     SparsePtr source(sparse_file_import(source_fd, true, true), sparse_file_destroy);
492     if (!source) {
493         int fd = source_fd.get();
494         temp_fds_.push_back(std::move(source_fd));
495         return fd;
496     }
497 
498     TemporaryFile tf;
499     if (tf.fd < 0) {
500         PERROR << "make temporary file failed";
501         return -1;
502     }
503 
504     // We temporarily unsparse the file, rather than try to merge its chunks.
505     int rv = sparse_file_write(source.get(), tf.fd, false, false, false);
506     if (rv) {
507         LERROR << "sparse_file_write failed with code: " << rv;
508         return -1;
509     }
510     temp_fds_.push_back(android::base::unique_fd(tf.release()));
511     return temp_fds_.back().get();
512 }
513 
WriteToImageFile(const std::string & file,const LpMetadata & metadata,uint32_t block_size,const std::map<std::string,std::string> & images,bool sparsify)514 bool WriteToImageFile(const std::string& file, const LpMetadata& metadata, uint32_t block_size,
515                       const std::map<std::string, std::string>& images, bool sparsify) {
516     ImageBuilder builder(metadata, block_size, images, sparsify);
517     return builder.IsValid() && builder.Build() && builder.Export(file);
518 }
519 
WriteSplitImageFiles(const std::string & output_dir,const LpMetadata & metadata,uint32_t block_size,const std::map<std::string,std::string> & images,bool sparsify)520 bool WriteSplitImageFiles(const std::string& output_dir, const LpMetadata& metadata,
521                           uint32_t block_size, const std::map<std::string, std::string>& images,
522                           bool sparsify) {
523     ImageBuilder builder(metadata, block_size, images, sparsify);
524     return builder.IsValid() && builder.Build() && builder.ExportFiles(output_dir);
525 }
526 
527 }  // namespace fs_mgr
528 }  // namespace android
529