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