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 "update_engine/payload_generator/boot_img_filesystem.h"
18
19 #include <base/logging.h>
20 #include <bootimg.h>
21 #include <brillo/secure_blob.h>
22 #include <puffin/utils.h>
23
24 #include "update_engine/common/utils.h"
25 #include "update_engine/payload_generator/delta_diff_generator.h"
26 #include "update_engine/payload_generator/extent_ranges.h"
27
28 using std::string;
29 using std::unique_ptr;
30 using std::vector;
31
32 namespace chromeos_update_engine {
33
CreateFromFile(const string & filename)34 unique_ptr<BootImgFilesystem> BootImgFilesystem::CreateFromFile(
35 const string& filename) {
36 if (filename.empty())
37 return nullptr;
38
39 if (brillo::Blob header_magic;
40 !utils::ReadFileChunk(filename, 0, BOOT_MAGIC_SIZE, &header_magic) ||
41 memcmp(header_magic.data(), BOOT_MAGIC, BOOT_MAGIC_SIZE) != 0) {
42 return nullptr;
43 }
44
45 // The order of image header fields are different in version 3 from the
46 // previous versions. But the position of "header_version" is fixed at #9
47 // across all image headers.
48 // See details in system/tools/mkbootimg/include/bootimg/bootimg.h
49 constexpr size_t header_version_offset =
50 BOOT_MAGIC_SIZE + 8 * sizeof(uint32_t);
51 brillo::Blob header_version_blob;
52 if (!utils::ReadFileChunk(filename,
53 header_version_offset,
54 sizeof(uint32_t),
55 &header_version_blob)) {
56 return nullptr;
57 }
58 uint32_t header_version =
59 *reinterpret_cast<uint32_t*>(header_version_blob.data());
60 if (header_version > 3) {
61 LOG(WARNING) << "Boot image header version " << header_version
62 << " isn't supported for parsing";
63 return nullptr;
64 }
65
66 // Read the bytes of boot image header based on the header version.
67 size_t header_size =
68 header_version == 3 ? sizeof(boot_img_hdr_v3) : sizeof(boot_img_hdr_v0);
69 brillo::Blob header_blob;
70 if (!utils::ReadFileChunk(filename, 0, header_size, &header_blob)) {
71 return nullptr;
72 }
73
74 unique_ptr<BootImgFilesystem> result(new BootImgFilesystem());
75 result->filename_ = filename;
76 if (header_version < 3) {
77 auto hdr_v0 = reinterpret_cast<boot_img_hdr_v0*>(header_blob.data());
78 CHECK_EQ(0, memcmp(hdr_v0->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE));
79 CHECK_LT(hdr_v0->header_version, 3u);
80 result->kernel_size_ = hdr_v0->kernel_size;
81 result->ramdisk_size_ = hdr_v0->ramdisk_size;
82 result->page_size_ = hdr_v0->page_size;
83 } else {
84 auto hdr_v3 = reinterpret_cast<boot_img_hdr_v3*>(header_blob.data());
85 CHECK_EQ(0, memcmp(hdr_v3->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE));
86 CHECK_EQ(3u, hdr_v3->header_version);
87 result->kernel_size_ = hdr_v3->kernel_size;
88 result->ramdisk_size_ = hdr_v3->ramdisk_size;
89 result->page_size_ = 4096;
90 }
91
92 CHECK_GT(result->page_size_, 0u);
93
94 return result;
95 }
96
GetBlockSize() const97 size_t BootImgFilesystem::GetBlockSize() const {
98 // Page size may not be 4K, but we currently only support 4K block size.
99 return kBlockSize;
100 }
101
GetBlockCount() const102 size_t BootImgFilesystem::GetBlockCount() const {
103 return utils::DivRoundUp(utils::FileSize(filename_), kBlockSize);
104 }
105
GetFile(const string & name,uint64_t offset,uint64_t size) const106 FilesystemInterface::File BootImgFilesystem::GetFile(const string& name,
107 uint64_t offset,
108 uint64_t size) const {
109 File file;
110 file.name = name;
111 file.extents = {ExtentForBytes(kBlockSize, offset, size)};
112
113 brillo::Blob data;
114 if (utils::ReadFileChunk(filename_, offset, size, &data)) {
115 constexpr size_t kGZipHeaderSize = 10;
116 // Check GZip header magic.
117 if (data.size() > kGZipHeaderSize && data[0] == 0x1F && data[1] == 0x8B) {
118 if (!puffin::LocateDeflatesInGzip(data, &file.deflates)) {
119 LOG(ERROR) << "Error occurred parsing gzip " << name << " at offset "
120 << offset << " of " << filename_ << ", found "
121 << file.deflates.size() << " deflates.";
122 return file;
123 }
124 for (auto& deflate : file.deflates) {
125 deflate.offset += offset * 8;
126 }
127 }
128 }
129 return file;
130 }
131
GetFiles(vector<File> * files) const132 bool BootImgFilesystem::GetFiles(vector<File>* files) const {
133 files->clear();
134 const uint64_t file_size = utils::FileSize(filename_);
135 // The first page is header.
136 uint64_t offset = page_size_;
137 if (kernel_size_ > 0 && offset + kernel_size_ <= file_size) {
138 files->emplace_back(GetFile("<kernel>", offset, kernel_size_));
139 }
140 offset += utils::RoundUp(kernel_size_, page_size_);
141 if (ramdisk_size_ > 0 && offset + ramdisk_size_ <= file_size) {
142 files->emplace_back(GetFile("<ramdisk>", offset, ramdisk_size_));
143 }
144 return true;
145 }
146
LoadSettings(brillo::KeyValueStore * store) const147 bool BootImgFilesystem::LoadSettings(brillo::KeyValueStore* store) const {
148 return false;
149 }
150
151 } // namespace chromeos_update_engine
152