1 /*
2 * Copyright (C) 2019 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 "install/package.h"
18
19 #include <string.h>
20 #include <unistd.h>
21
22 #include <android-base/file.h>
23 #include <android-base/logging.h>
24 #include <android-base/stringprintf.h>
25 #include <android-base/unique_fd.h>
26
27 #include "otautil/error_code.h"
28 #include "otautil/sysutil.h"
29
30 // This class wraps the package in memory, i.e. a memory mapped package, or a package loaded
31 // to a string/vector.
32 class MemoryPackage : public Package {
33 public:
34 // Constructs the class from a file. We will memory maps the file later.
35 MemoryPackage(const std::string& path, std::unique_ptr<MemMapping> map,
36 const std::function<void(float)>& set_progress);
37
38 // Constructs the class from the package bytes in |content|.
39 MemoryPackage(std::vector<uint8_t> content, const std::function<void(float)>& set_progress);
40
41 ~MemoryPackage() override;
42
GetType() const43 PackageType GetType() const override {
44 return PackageType::kMemory;
45 }
46
47 // Memory maps the package file if necessary. Initializes the start address and size of the
48 // package.
GetPackageSize() const49 uint64_t GetPackageSize() const override {
50 return package_size_;
51 }
52
GetPath() const53 std::string GetPath() const override {
54 return path_;
55 }
56
57 bool ReadFullyAtOffset(uint8_t* buffer, uint64_t byte_count, uint64_t offset) override;
58
59 ZipArchiveHandle GetZipArchiveHandle() override;
60
61 bool UpdateHashAtOffset(const std::vector<HasherUpdateCallback>& hashers, uint64_t start,
62 uint64_t length) override;
63
64 private:
65 const uint8_t* addr_; // Start address of the package in memory.
66 uint64_t package_size_; // Package size in bytes.
67
68 // The memory mapped package.
69 std::unique_ptr<MemMapping> map_;
70 // A copy of the package content, valid only if we create the class with the exact bytes of
71 // the package.
72 std::vector<uint8_t> package_content_;
73 // The physical path to the package, empty if we create the class with the package content.
74 std::string path_;
75
76 // The ZipArchiveHandle of the package.
77 ZipArchiveHandle zip_handle_;
78 };
79
SetProgress(float progress)80 void Package::SetProgress(float progress) {
81 if (set_progress_) {
82 set_progress_(progress);
83 }
84 }
85
86 class FilePackage : public Package {
87 public:
88 FilePackage(android::base::unique_fd&& fd, uint64_t file_size, const std::string& path,
89 const std::function<void(float)>& set_progress);
90
91 ~FilePackage() override;
92
GetType() const93 PackageType GetType() const override {
94 return PackageType::kFile;
95 }
96
GetPackageSize() const97 uint64_t GetPackageSize() const override {
98 return package_size_;
99 }
100
GetPath() const101 std::string GetPath() const override {
102 return path_;
103 }
104
105 bool ReadFullyAtOffset(uint8_t* buffer, uint64_t byte_count, uint64_t offset) override;
106
107 ZipArchiveHandle GetZipArchiveHandle() override;
108
109 bool UpdateHashAtOffset(const std::vector<HasherUpdateCallback>& hashers, uint64_t start,
110 uint64_t length) override;
111
112 private:
113 android::base::unique_fd fd_; // The underlying fd to the open package.
114 uint64_t package_size_;
115 std::string path_; // The physical path to the package.
116
117 ZipArchiveHandle zip_handle_;
118 };
119
CreateMemoryPackage(const std::string & path,const std::function<void (float)> & set_progress)120 std::unique_ptr<Package> Package::CreateMemoryPackage(
121 const std::string& path, const std::function<void(float)>& set_progress) {
122 std::unique_ptr<MemMapping> mmap = std::make_unique<MemMapping>();
123 if (!mmap->MapFile(path)) {
124 LOG(ERROR) << "failed to map file";
125 return nullptr;
126 }
127
128 return std::make_unique<MemoryPackage>(path, std::move(mmap), set_progress);
129 }
130
CreateFilePackage(const std::string & path,const std::function<void (float)> & set_progress)131 std::unique_ptr<Package> Package::CreateFilePackage(
132 const std::string& path, const std::function<void(float)>& set_progress) {
133 android::base::unique_fd fd(open(path.c_str(), O_RDONLY));
134 if (fd == -1) {
135 PLOG(ERROR) << "Failed to open " << path;
136 return nullptr;
137 }
138
139 off64_t file_size = lseek64(fd.get(), 0, SEEK_END);
140 if (file_size == -1) {
141 PLOG(ERROR) << "Failed to get the package size";
142 return nullptr;
143 }
144
145 return std::make_unique<FilePackage>(std::move(fd), file_size, path, set_progress);
146 }
147
CreateMemoryPackage(std::vector<uint8_t> content,const std::function<void (float)> & set_progress)148 std::unique_ptr<Package> Package::CreateMemoryPackage(
149 std::vector<uint8_t> content, const std::function<void(float)>& set_progress) {
150 return std::make_unique<MemoryPackage>(std::move(content), set_progress);
151 }
152
MemoryPackage(const std::string & path,std::unique_ptr<MemMapping> map,const std::function<void (float)> & set_progress)153 MemoryPackage::MemoryPackage(const std::string& path, std::unique_ptr<MemMapping> map,
154 const std::function<void(float)>& set_progress)
155 : map_(std::move(map)), path_(path), zip_handle_(nullptr) {
156 addr_ = map_->addr;
157 package_size_ = map_->length;
158 set_progress_ = set_progress;
159 }
160
MemoryPackage(std::vector<uint8_t> content,const std::function<void (float)> & set_progress)161 MemoryPackage::MemoryPackage(std::vector<uint8_t> content,
162 const std::function<void(float)>& set_progress)
163 : package_content_(std::move(content)), zip_handle_(nullptr) {
164 CHECK(!package_content_.empty());
165 addr_ = package_content_.data();
166 package_size_ = package_content_.size();
167 set_progress_ = set_progress;
168 }
169
~MemoryPackage()170 MemoryPackage::~MemoryPackage() {
171 if (zip_handle_) {
172 CloseArchive(zip_handle_);
173 }
174 }
175
ReadFullyAtOffset(uint8_t * buffer,uint64_t byte_count,uint64_t offset)176 bool MemoryPackage::ReadFullyAtOffset(uint8_t* buffer, uint64_t byte_count, uint64_t offset) {
177 if (byte_count > package_size_ || offset > package_size_ - byte_count) {
178 LOG(ERROR) << "Out of bound read, offset: " << offset << ", size: " << byte_count
179 << ", total package_size: " << package_size_;
180 return false;
181 }
182 memcpy(buffer, addr_ + offset, byte_count);
183 return true;
184 }
185
UpdateHashAtOffset(const std::vector<HasherUpdateCallback> & hashers,uint64_t start,uint64_t length)186 bool MemoryPackage::UpdateHashAtOffset(const std::vector<HasherUpdateCallback>& hashers,
187 uint64_t start, uint64_t length) {
188 if (length > package_size_ || start > package_size_ - length) {
189 LOG(ERROR) << "Out of bound read, offset: " << start << ", size: " << length
190 << ", total package_size: " << package_size_;
191 return false;
192 }
193
194 for (const auto& hasher : hashers) {
195 hasher(addr_ + start, length);
196 }
197 return true;
198 }
199
GetZipArchiveHandle()200 ZipArchiveHandle MemoryPackage::GetZipArchiveHandle() {
201 if (zip_handle_) {
202 return zip_handle_;
203 }
204
205 if (auto err = OpenArchiveFromMemory(const_cast<uint8_t*>(addr_), package_size_, path_.c_str(),
206 &zip_handle_);
207 err != 0) {
208 LOG(ERROR) << "Can't open package" << path_ << " : " << ErrorCodeString(err);
209 return nullptr;
210 }
211
212 return zip_handle_;
213 }
214
FilePackage(android::base::unique_fd && fd,uint64_t file_size,const std::string & path,const std::function<void (float)> & set_progress)215 FilePackage::FilePackage(android::base::unique_fd&& fd, uint64_t file_size, const std::string& path,
216 const std::function<void(float)>& set_progress)
217 : fd_(std::move(fd)), package_size_(file_size), path_(path), zip_handle_(nullptr) {
218 set_progress_ = set_progress;
219 }
220
~FilePackage()221 FilePackage::~FilePackage() {
222 if (zip_handle_) {
223 CloseArchive(zip_handle_);
224 }
225 }
226
ReadFullyAtOffset(uint8_t * buffer,uint64_t byte_count,uint64_t offset)227 bool FilePackage::ReadFullyAtOffset(uint8_t* buffer, uint64_t byte_count, uint64_t offset) {
228 if (byte_count > package_size_ || offset > package_size_ - byte_count) {
229 LOG(ERROR) << "Out of bound read, offset: " << offset << ", size: " << byte_count
230 << ", total package_size: " << package_size_;
231 return false;
232 }
233
234 if (!android::base::ReadFullyAtOffset(fd_.get(), buffer, byte_count, offset)) {
235 PLOG(ERROR) << "Failed to read " << byte_count << " bytes data at offset " << offset;
236 return false;
237 }
238
239 return true;
240 }
241
UpdateHashAtOffset(const std::vector<HasherUpdateCallback> & hashers,uint64_t start,uint64_t length)242 bool FilePackage::UpdateHashAtOffset(const std::vector<HasherUpdateCallback>& hashers,
243 uint64_t start, uint64_t length) {
244 if (length > package_size_ || start > package_size_ - length) {
245 LOG(ERROR) << "Out of bound read, offset: " << start << ", size: " << length
246 << ", total package_size: " << package_size_;
247 return false;
248 }
249
250 uint64_t so_far = 0;
251 while (so_far < length) {
252 uint64_t read_size = std::min<uint64_t>(length - so_far, 16 * MiB);
253 std::vector<uint8_t> buffer(read_size);
254 if (!ReadFullyAtOffset(buffer.data(), read_size, start + so_far)) {
255 return false;
256 }
257
258 for (const auto& hasher : hashers) {
259 hasher(buffer.data(), read_size);
260 }
261 so_far += read_size;
262 }
263
264 return true;
265 }
266
GetZipArchiveHandle()267 ZipArchiveHandle FilePackage::GetZipArchiveHandle() {
268 if (zip_handle_) {
269 return zip_handle_;
270 }
271
272 if (auto err = OpenArchiveFd(fd_.get(), path_.c_str(), &zip_handle_, false); err != 0) {
273 LOG(ERROR) << "Can't open package" << path_ << " : " << ErrorCodeString(err);
274 return nullptr;
275 }
276
277 return zip_handle_;
278 }
279