1 /*
2  * Copyright (C) 2021 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 "vendor_boot_img_utils.h"
18 
19 #include <string.h>
20 
21 #include <android-base/file.h>
22 #include <android-base/result.h>
23 #include <bootimg.h>
24 #include <libavb/libavb.h>
25 
26 namespace {
27 
28 using android::base::Result;
29 
30 // Updates a given buffer by creating a new one.
31 class DataUpdater {
32   public:
DataUpdater(const std::string & old_data)33     DataUpdater(const std::string& old_data) : old_data_(&old_data) {
34         old_data_ptr_ = old_data_->data();
35         new_data_.resize(old_data_->size(), '\0');
36         new_data_ptr_ = new_data_.data();
37     }
38     // Copy |num_bytes| from src to dst.
Copy(uint32_t num_bytes)39     [[nodiscard]] Result<void> Copy(uint32_t num_bytes) {
40         if (num_bytes == 0) return {};
41         if (auto res = CheckAdvance(old_data_ptr_, old_end(), num_bytes, __FUNCTION__); !res.ok())
42             return res;
43         if (auto res = CheckAdvance(new_data_ptr_, new_end(), num_bytes, __FUNCTION__); !res.ok())
44             return res;
45         memcpy(new_data_ptr_, old_data_ptr_, num_bytes);
46         old_data_ptr_ += num_bytes;
47         new_data_ptr_ += num_bytes;
48         return {};
49     }
50     // Replace |old_num_bytes| from src with new data.
Replace(uint32_t old_num_bytes,const std::string & new_data)51     [[nodiscard]] Result<void> Replace(uint32_t old_num_bytes, const std::string& new_data) {
52         return Replace(old_num_bytes, new_data.data(), new_data.size());
53     }
Replace(uint32_t old_num_bytes,const void * new_data,uint32_t new_data_size)54     [[nodiscard]] Result<void> Replace(uint32_t old_num_bytes, const void* new_data,
55                                        uint32_t new_data_size) {
56         if (auto res = CheckAdvance(old_data_ptr_, old_end(), old_num_bytes, __FUNCTION__);
57             !res.ok())
58             return res;
59         old_data_ptr_ += old_num_bytes;
60 
61         if (new_data_size == 0) return {};
62         if (auto res = CheckAdvance(new_data_ptr_, new_end(), new_data_size, __FUNCTION__);
63             !res.ok())
64             return res;
65         memcpy(new_data_ptr_, new_data, new_data_size);
66         new_data_ptr_ += new_data_size;
67         return {};
68     }
69     // Skip |old_skip| from src and |new_skip| from dst, respectively.
Skip(uint32_t old_skip,uint32_t new_skip)70     [[nodiscard]] Result<void> Skip(uint32_t old_skip, uint32_t new_skip) {
71         if (auto res = CheckAdvance(old_data_ptr_, old_end(), old_skip, __FUNCTION__); !res.ok())
72             return res;
73         old_data_ptr_ += old_skip;
74         if (auto res = CheckAdvance(new_data_ptr_, new_end(), new_skip, __FUNCTION__); !res.ok())
75             return res;
76         new_data_ptr_ += new_skip;
77         return {};
78     }
79 
Seek(uint32_t offset)80     [[nodiscard]] Result<void> Seek(uint32_t offset) {
81         if (offset > size()) return Errorf("Cannot seek 0x{:x}, size is 0x{:x}", offset, size());
82         old_data_ptr_ = old_begin() + offset;
83         new_data_ptr_ = new_begin() + offset;
84         return {};
85     }
86 
Finish()87     std::string Finish() {
88         new_data_ptr_ = nullptr;
89         return std::move(new_data_);
90     }
91 
CheckOffset(uint32_t old_offset,uint32_t new_offset)92     [[nodiscard]] Result<void> CheckOffset(uint32_t old_offset, uint32_t new_offset) {
93         if (old_begin() + old_offset != old_cur())
94             return Errorf("Old offset mismatch: expected: 0x{:x}, actual: 0x{:x}", old_offset,
95                           old_cur() - old_begin());
96         if (new_begin() + new_offset != new_cur())
97             return Errorf("New offset mismatch: expected: 0x{:x}, actual: 0x{:x}", new_offset,
98                           new_cur() - new_begin());
99         return {};
100     }
101 
size() const102     uint64_t size() const { return old_data_->size(); }
old_begin() const103     const char* old_begin() const { return old_data_->data(); }
old_cur()104     const char* old_cur() { return old_data_ptr_; }
old_end() const105     const char* old_end() const { return old_data_->data() + old_data_->size(); }
new_begin()106     char* new_begin() { return new_data_.data(); }
new_cur()107     char* new_cur() { return new_data_ptr_; }
new_end()108     char* new_end() { return new_data_.data() + new_data_.size(); }
109 
110   private:
111     // Check if it is okay to advance |num_bytes| from |current|.
CheckAdvance(const char * current,const char * end,uint32_t num_bytes,const char * op)112     [[nodiscard]] Result<void> CheckAdvance(const char* current, const char* end,
113                                             uint32_t num_bytes, const char* op) {
114         auto new_end = current + num_bytes;
115         if (new_end < current /* add overflow */)
116             return Errorf("{}: Addition overflow: 0x{} + 0x{:x} < 0x{}", op, fmt::ptr(current),
117                           num_bytes, fmt::ptr(current));
118         if (new_end > end)
119             return Errorf("{}: Boundary overflow: 0x{} + 0x{:x} > 0x{}", op, fmt::ptr(current),
120                           num_bytes, fmt::ptr(end));
121         return {};
122     }
123     const std::string* old_data_;
124     std::string new_data_;
125     const char* old_data_ptr_;
126     char* new_data_ptr_;
127 };
128 
129 // Get the size of vendor boot header.
get_vendor_boot_header_size(const vendor_boot_img_hdr_v3 * hdr)130 [[nodiscard]] Result<uint32_t> get_vendor_boot_header_size(const vendor_boot_img_hdr_v3* hdr) {
131     if (hdr->header_version == 3) return sizeof(vendor_boot_img_hdr_v3);
132     if (hdr->header_version == 4) return sizeof(vendor_boot_img_hdr_v4);
133     return Errorf("Unrecognized vendor boot header version {}", hdr->header_version);
134 }
135 
136 // Check that content contains a valid vendor boot image header with a version at least |version|.
check_vendor_boot_hdr(const std::string & content,uint32_t version)137 [[nodiscard]] Result<void> check_vendor_boot_hdr(const std::string& content, uint32_t version) {
138     // get_vendor_boot_header_size reads header_version, so make sure reading it does not
139     // go out of bounds by ensuring that the content has at least the size of V3 header.
140     if (content.size() < sizeof(vendor_boot_img_hdr_v3)) {
141         return Errorf("Size of vendor boot is 0x{:x}, less than size of V3 header: 0x{:x}",
142                       content.size(), sizeof(vendor_boot_img_hdr_v3));
143     }
144     // Now read hdr->header_version and assert the size.
145     auto hdr = reinterpret_cast<const vendor_boot_img_hdr_v3*>(content.data());
146     auto expect_header_size = get_vendor_boot_header_size(hdr);
147     if (!expect_header_size.ok()) return expect_header_size.error();
148     if (content.size() < *expect_header_size) {
149         return Errorf("Size of vendor boot is 0x{:x}, less than size of V{} header: 0x{:x}",
150                       content.size(), version, *expect_header_size);
151     }
152     if (memcmp(hdr->magic, VENDOR_BOOT_MAGIC, VENDOR_BOOT_MAGIC_SIZE) != 0) {
153         return Errorf("Vendor boot image magic mismatch");
154     }
155     if (hdr->header_version < version) {
156         return Errorf("Require vendor boot header V{} but is V{}", version, hdr->header_version);
157     }
158     return {};
159 }
160 
161 // Wrapper of ReadFdToString. Seek to the beginning and read the whole file to string.
load_file(android::base::borrowed_fd fd,uint64_t expected_size,const char * what)162 [[nodiscard]] Result<std::string> load_file(android::base::borrowed_fd fd, uint64_t expected_size,
163                                             const char* what) {
164     if (lseek(fd.get(), 0, SEEK_SET) != 0) {
165         return ErrnoErrorf("Can't seek to the beginning of {} image", what);
166     }
167     std::string content;
168     if (!android::base::ReadFdToString(fd, &content)) {
169         return ErrnoErrorf("Cannot read {} to string", what);
170     }
171     if (content.size() != expected_size) {
172         return Errorf("Size of {} does not match, expected 0x{:x}, read 0x{:x}", what,
173                       expected_size, content.size());
174     }
175     return content;
176 }
177 
178 // Wrapper of WriteStringToFd. Seek to the beginning and write the whole file to string.
store_file(android::base::borrowed_fd fd,const std::string & data,const char * what)179 [[nodiscard]] Result<void> store_file(android::base::borrowed_fd fd, const std::string& data,
180                                       const char* what) {
181     if (lseek(fd.get(), 0, SEEK_SET) != 0) {
182         return ErrnoErrorf("Cannot seek to beginning of {} before writing", what);
183     }
184     if (!android::base::WriteStringToFd(data, fd)) {
185         return ErrnoErrorf("Cannot write new content to {}", what);
186     }
187     if (TEMP_FAILURE_RETRY(ftruncate(fd.get(), data.size())) == -1) {
188         return ErrnoErrorf("Truncating new vendor boot image to 0x{:x} fails", data.size());
189     }
190     return {};
191 }
192 
193 // Copy AVB footer if it exists in the old buffer.
copy_avb_footer(DataUpdater * updater)194 [[nodiscard]] Result<void> copy_avb_footer(DataUpdater* updater) {
195     if (updater->size() < AVB_FOOTER_SIZE) return {};
196     if (auto res = updater->Seek(updater->size() - AVB_FOOTER_SIZE); !res.ok()) return res;
197     if (memcmp(updater->old_cur(), AVB_FOOTER_MAGIC, AVB_FOOTER_MAGIC_LEN) != 0) return {};
198     return updater->Copy(AVB_FOOTER_SIZE);
199 }
200 
201 // round |value| up to a multiple of |page_size|.
round_up(uint32_t value,uint32_t page_size)202 inline uint32_t round_up(uint32_t value, uint32_t page_size) {
203     return (value + page_size - 1) / page_size * page_size;
204 }
205 
206 // Replace the vendor ramdisk as a whole.
replace_default_vendor_ramdisk(const std::string & vendor_boot,const std::string & new_ramdisk)207 [[nodiscard]] Result<std::string> replace_default_vendor_ramdisk(const std::string& vendor_boot,
208                                                                  const std::string& new_ramdisk) {
209     if (auto res = check_vendor_boot_hdr(vendor_boot, 3); !res.ok()) return res.error();
210     auto hdr = reinterpret_cast<const vendor_boot_img_hdr_v3*>(vendor_boot.data());
211     auto hdr_size = get_vendor_boot_header_size(hdr);
212     if (!hdr_size.ok()) return hdr_size.error();
213     // Refer to bootimg.h for details. Numbers are in bytes.
214     const uint32_t o = round_up(*hdr_size, hdr->page_size);
215     const uint32_t p = round_up(hdr->vendor_ramdisk_size, hdr->page_size);
216     const uint32_t q = round_up(hdr->dtb_size, hdr->page_size);
217 
218     DataUpdater updater(vendor_boot);
219 
220     // Copy header (O bytes), then update fields in header.
221     if (auto res = updater.Copy(o); !res.ok()) return res.error();
222     auto new_hdr = reinterpret_cast<vendor_boot_img_hdr_v3*>(updater.new_begin());
223     new_hdr->vendor_ramdisk_size = new_ramdisk.size();
224     // Because it is unknown how the new ramdisk is fragmented, the whole table is replaced
225     // with a single entry representing the full ramdisk.
226     if (new_hdr->header_version >= 4) {
227         auto new_hdr_v4 = static_cast<vendor_boot_img_hdr_v4*>(new_hdr);
228         new_hdr_v4->vendor_ramdisk_table_entry_size = sizeof(vendor_ramdisk_table_entry_v4);
229         new_hdr_v4->vendor_ramdisk_table_entry_num = 1;
230         new_hdr_v4->vendor_ramdisk_table_size = new_hdr_v4->vendor_ramdisk_table_entry_num *
231                                                 new_hdr_v4->vendor_ramdisk_table_entry_size;
232     }
233 
234     // Copy the new ramdisk.
235     if (auto res = updater.Replace(hdr->vendor_ramdisk_size, new_ramdisk); !res.ok())
236         return res.error();
237     const uint32_t new_p = round_up(new_hdr->vendor_ramdisk_size, new_hdr->page_size);
238     if (auto res = updater.Skip(p - hdr->vendor_ramdisk_size, new_p - new_hdr->vendor_ramdisk_size);
239         !res.ok())
240         return res.error();
241     if (auto res = updater.CheckOffset(o + p, o + new_p); !res.ok()) return res.error();
242 
243     // Copy DTB (Q bytes).
244     if (auto res = updater.Copy(q); !res.ok()) return res.error();
245 
246     if (new_hdr->header_version >= 4) {
247         auto hdr_v4 = static_cast<const vendor_boot_img_hdr_v4*>(hdr);
248         const uint32_t r = round_up(hdr_v4->vendor_ramdisk_table_size, hdr_v4->page_size);
249         const uint32_t s = round_up(hdr_v4->bootconfig_size, hdr_v4->page_size);
250 
251         auto new_entry = reinterpret_cast<vendor_ramdisk_table_entry_v4*>(updater.new_cur());
252         auto new_hdr_v4 = static_cast<const vendor_boot_img_hdr_v4*>(new_hdr);
253         auto new_r = round_up(new_hdr_v4->vendor_ramdisk_table_size, new_hdr->page_size);
254         if (auto res = updater.Skip(r, new_r); !res.ok()) return res.error();
255         if (auto res = updater.CheckOffset(o + p + q + r, o + new_p + q + new_r); !res.ok())
256             return res.error();
257 
258         // Replace table with single entry representing the full ramdisk.
259         new_entry->ramdisk_size = new_hdr->vendor_ramdisk_size;
260         new_entry->ramdisk_offset = 0;
261         new_entry->ramdisk_type = VENDOR_RAMDISK_TYPE_NONE;
262         memset(new_entry->ramdisk_name, '\0', VENDOR_RAMDISK_NAME_SIZE);
263         memset(new_entry->board_id, '\0', VENDOR_RAMDISK_TABLE_ENTRY_BOARD_ID_SIZE);
264 
265         // Copy bootconfig (S bytes).
266         if (auto res = updater.Copy(s); !res.ok()) return res.error();
267     }
268 
269     if (auto res = copy_avb_footer(&updater); !res.ok()) return res.error();
270     return updater.Finish();
271 }
272 
273 // Find a ramdisk fragment with a unique name. Abort if none or multiple fragments are found.
find_unique_ramdisk(const std::string & ramdisk_name,const vendor_ramdisk_table_entry_v4 * table,uint32_t size)274 [[nodiscard]] Result<const vendor_ramdisk_table_entry_v4*> find_unique_ramdisk(
275         const std::string& ramdisk_name, const vendor_ramdisk_table_entry_v4* table,
276         uint32_t size) {
277     const vendor_ramdisk_table_entry_v4* ret = nullptr;
278     uint32_t idx = 0;
279     const vendor_ramdisk_table_entry_v4* entry = table;
280     for (; idx < size; idx++, entry++) {
281         auto entry_name_c_str = reinterpret_cast<const char*>(entry->ramdisk_name);
282         auto entry_name_len = strnlen(entry_name_c_str, VENDOR_RAMDISK_NAME_SIZE);
283         std::string_view entry_name(entry_name_c_str, entry_name_len);
284         if (entry_name == ramdisk_name) {
285             if (ret != nullptr) {
286                 return Errorf("Multiple vendor ramdisk '{}' found, name should be unique",
287                               ramdisk_name.c_str());
288             }
289             ret = entry;
290         }
291     }
292     if (ret == nullptr) {
293         return Errorf("Vendor ramdisk '{}' not found", ramdisk_name.c_str());
294     }
295     return ret;
296 }
297 
298 // Find the vendor ramdisk fragment with |ramdisk_name| within the content of |vendor_boot|, and
299 // replace it with the content of |new_ramdisk|.
replace_vendor_ramdisk_fragment(const std::string & ramdisk_name,const std::string & vendor_boot,const std::string & new_ramdisk)300 [[nodiscard]] Result<std::string> replace_vendor_ramdisk_fragment(const std::string& ramdisk_name,
301                                                                   const std::string& vendor_boot,
302                                                                   const std::string& new_ramdisk) {
303     if (auto res = check_vendor_boot_hdr(vendor_boot, 4); !res.ok()) return res.error();
304     auto hdr = reinterpret_cast<const vendor_boot_img_hdr_v4*>(vendor_boot.data());
305     auto hdr_size = get_vendor_boot_header_size(hdr);
306     if (!hdr_size.ok()) return hdr_size.error();
307     // Refer to bootimg.h for details. Numbers are in bytes.
308     const uint32_t o = round_up(*hdr_size, hdr->page_size);
309     const uint32_t p = round_up(hdr->vendor_ramdisk_size, hdr->page_size);
310     const uint32_t q = round_up(hdr->dtb_size, hdr->page_size);
311     const uint32_t r = round_up(hdr->vendor_ramdisk_table_size, hdr->page_size);
312     const uint32_t s = round_up(hdr->bootconfig_size, hdr->page_size);
313 
314     if (hdr->vendor_ramdisk_table_entry_num == std::numeric_limits<uint32_t>::max()) {
315         return Errorf("Too many vendor ramdisk entries in table, overflow");
316     }
317 
318     // Find entry with name |ramdisk_name|.
319     auto old_table_start =
320             reinterpret_cast<const vendor_ramdisk_table_entry_v4*>(vendor_boot.data() + o + p + q);
321     auto find_res =
322             find_unique_ramdisk(ramdisk_name, old_table_start, hdr->vendor_ramdisk_table_entry_num);
323     if (!find_res.ok()) return find_res.error();
324     const vendor_ramdisk_table_entry_v4* replace_entry = *find_res;
325     uint32_t replace_idx = replace_entry - old_table_start;
326 
327     // Now reconstruct.
328     DataUpdater updater(vendor_boot);
329 
330     // Copy header (O bytes), then update fields in header.
331     if (auto res = updater.Copy(o); !res.ok()) return res.error();
332     auto new_hdr = reinterpret_cast<vendor_boot_img_hdr_v4*>(updater.new_begin());
333 
334     // Copy ramdisk fragments, replace for the matching index.
335     {
336         auto old_ramdisk_entry = reinterpret_cast<const vendor_ramdisk_table_entry_v4*>(
337                 vendor_boot.data() + o + p + q);
338         uint32_t new_total_ramdisk_size = 0;
339         for (uint32_t new_ramdisk_idx = 0; new_ramdisk_idx < hdr->vendor_ramdisk_table_entry_num;
340              new_ramdisk_idx++, old_ramdisk_entry++) {
341             if (new_ramdisk_idx == replace_idx) {
342                 if (auto res = updater.Replace(replace_entry->ramdisk_size, new_ramdisk); !res.ok())
343                     return res.error();
344                 new_total_ramdisk_size += new_ramdisk.size();
345             } else {
346                 if (auto res = updater.Copy(old_ramdisk_entry->ramdisk_size); !res.ok())
347                     return res.error();
348                 new_total_ramdisk_size += old_ramdisk_entry->ramdisk_size;
349             }
350         }
351         new_hdr->vendor_ramdisk_size = new_total_ramdisk_size;
352     }
353 
354     // Pad ramdisk to page boundary.
355     const uint32_t new_p = round_up(new_hdr->vendor_ramdisk_size, new_hdr->page_size);
356     if (auto res = updater.Skip(p - hdr->vendor_ramdisk_size, new_p - new_hdr->vendor_ramdisk_size);
357         !res.ok())
358         return res.error();
359     if (auto res = updater.CheckOffset(o + p, o + new_p); !res.ok()) return res.error();
360 
361     // Copy DTB (Q bytes).
362     if (auto res = updater.Copy(q); !res.ok()) return res.error();
363 
364     // Copy table, but with corresponding entries modified, including:
365     // - ramdisk_size of the entry replaced
366     // - ramdisk_offset of subsequent entries.
367     for (uint32_t new_total_ramdisk_size = 0, new_entry_idx = 0;
368          new_entry_idx < hdr->vendor_ramdisk_table_entry_num; new_entry_idx++) {
369         auto new_entry = reinterpret_cast<vendor_ramdisk_table_entry_v4*>(updater.new_cur());
370         if (auto res = updater.Copy(hdr->vendor_ramdisk_table_entry_size); !res.ok())
371             return res.error();
372         new_entry->ramdisk_offset = new_total_ramdisk_size;
373 
374         if (new_entry_idx == replace_idx) {
375             new_entry->ramdisk_size = new_ramdisk.size();
376         }
377         new_total_ramdisk_size += new_entry->ramdisk_size;
378     }
379 
380     // Copy padding of R pages; this is okay because table size is not changed.
381     if (auto res = updater.Copy(r - hdr->vendor_ramdisk_table_entry_num *
382                                             hdr->vendor_ramdisk_table_entry_size);
383         !res.ok())
384         return res.error();
385     if (auto res = updater.CheckOffset(o + p + q + r, o + new_p + q + r); !res.ok())
386         return res.error();
387 
388     // Copy bootconfig (S bytes).
389     if (auto res = updater.Copy(s); !res.ok()) return res.error();
390 
391     if (auto res = copy_avb_footer(&updater); !res.ok()) return res.error();
392     return updater.Finish();
393 }
394 
395 }  // namespace
396 
replace_vendor_ramdisk(android::base::borrowed_fd vendor_boot_fd,uint64_t vendor_boot_size,const std::string & ramdisk_name,android::base::borrowed_fd new_ramdisk_fd,uint64_t new_ramdisk_size)397 [[nodiscard]] Result<void> replace_vendor_ramdisk(android::base::borrowed_fd vendor_boot_fd,
398                                                   uint64_t vendor_boot_size,
399                                                   const std::string& ramdisk_name,
400                                                   android::base::borrowed_fd new_ramdisk_fd,
401                                                   uint64_t new_ramdisk_size) {
402     if (new_ramdisk_size > std::numeric_limits<uint32_t>::max()) {
403         return Errorf("New vendor ramdisk is too big");
404     }
405 
406     auto vendor_boot = load_file(vendor_boot_fd, vendor_boot_size, "vendor boot");
407     if (!vendor_boot.ok()) return vendor_boot.error();
408     auto new_ramdisk = load_file(new_ramdisk_fd, new_ramdisk_size, "new vendor ramdisk");
409     if (!new_ramdisk.ok()) return new_ramdisk.error();
410 
411     Result<std::string> new_vendor_boot;
412     if (ramdisk_name == "default") {
413         new_vendor_boot = replace_default_vendor_ramdisk(*vendor_boot, *new_ramdisk);
414     } else {
415         new_vendor_boot = replace_vendor_ramdisk_fragment(ramdisk_name, *vendor_boot, *new_ramdisk);
416     }
417     if (!new_vendor_boot.ok()) return new_vendor_boot.error();
418     if (auto res = store_file(vendor_boot_fd, *new_vendor_boot, "new vendor boot image"); !res.ok())
419         return res.error();
420 
421     return {};
422 }
423