• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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->page_size == 0) {
156         return Errorf("Page size cannot be zero");
157     }
158     if (hdr->header_version < version) {
159         return Errorf("Require vendor boot header V{} but is V{}", version, hdr->header_version);
160     }
161     return {};
162 }
163 
164 // 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)165 [[nodiscard]] Result<std::string> load_file(android::base::borrowed_fd fd, uint64_t expected_size,
166                                             const char* what) {
167     if (lseek(fd.get(), 0, SEEK_SET) != 0) {
168         return ErrnoErrorf("Can't seek to the beginning of {} image", what);
169     }
170     std::string content;
171     if (!android::base::ReadFdToString(fd, &content)) {
172         return ErrnoErrorf("Cannot read {} to string", what);
173     }
174     if (content.size() != expected_size) {
175         return Errorf("Size of {} does not match, expected 0x{:x}, read 0x{:x}", what,
176                       expected_size, content.size());
177     }
178     return content;
179 }
180 
181 // 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)182 [[nodiscard]] Result<void> store_file(android::base::borrowed_fd fd, const std::string& data,
183                                       const char* what) {
184     if (lseek(fd.get(), 0, SEEK_SET) != 0) {
185         return ErrnoErrorf("Cannot seek to beginning of {} before writing", what);
186     }
187     if (!android::base::WriteStringToFd(data, fd)) {
188         return ErrnoErrorf("Cannot write new content to {}", what);
189     }
190     if (TEMP_FAILURE_RETRY(ftruncate(fd.get(), data.size())) == -1) {
191         return ErrnoErrorf("Truncating new vendor boot image to 0x{:x} fails", data.size());
192     }
193     return {};
194 }
195 
196 // Copy AVB footer if it exists in the old buffer.
copy_avb_footer(DataUpdater * updater)197 [[nodiscard]] Result<void> copy_avb_footer(DataUpdater* updater) {
198     if (updater->size() < AVB_FOOTER_SIZE) return {};
199     if (auto res = updater->Seek(updater->size() - AVB_FOOTER_SIZE); !res.ok()) return res;
200     if (memcmp(updater->old_cur(), AVB_FOOTER_MAGIC, AVB_FOOTER_MAGIC_LEN) != 0) return {};
201     return updater->Copy(AVB_FOOTER_SIZE);
202 }
203 
204 // round |value| up to a multiple of |page_size|.
205 // aware that this can be integer overflow if value is too large
round_up(uint32_t value,uint32_t page_size)206 inline uint32_t round_up(uint32_t value, uint32_t page_size) {
207     return (value + page_size - 1) / page_size * page_size;
208 }
209 
210 // Replace the vendor ramdisk as a whole.
replace_default_vendor_ramdisk(const std::string & vendor_boot,const std::string & new_ramdisk)211 [[nodiscard]] Result<std::string> replace_default_vendor_ramdisk(const std::string& vendor_boot,
212                                                                  const std::string& new_ramdisk) {
213     if (auto res = check_vendor_boot_hdr(vendor_boot, 3); !res.ok()) return res.error();
214     auto hdr = reinterpret_cast<const vendor_boot_img_hdr_v3*>(vendor_boot.data());
215     auto hdr_size = get_vendor_boot_header_size(hdr);
216     if (!hdr_size.ok()) return hdr_size.error();
217     // Refer to bootimg.h for details. Numbers are in bytes.
218     const uint32_t o = round_up(*hdr_size, hdr->page_size);
219     const uint32_t p = round_up(hdr->vendor_ramdisk_size, hdr->page_size);
220     const uint32_t q = round_up(hdr->dtb_size, hdr->page_size);
221 
222     DataUpdater updater(vendor_boot);
223 
224     // Copy header (O bytes), then update fields in header.
225     if (auto res = updater.Copy(o); !res.ok()) return res.error();
226     auto new_hdr = reinterpret_cast<vendor_boot_img_hdr_v3*>(updater.new_begin());
227     new_hdr->vendor_ramdisk_size = new_ramdisk.size();
228     // Because it is unknown how the new ramdisk is fragmented, the whole table is replaced
229     // with a single entry representing the full ramdisk.
230     if (new_hdr->header_version >= 4) {
231         auto new_hdr_v4 = static_cast<vendor_boot_img_hdr_v4*>(new_hdr);
232         new_hdr_v4->vendor_ramdisk_table_entry_size = sizeof(vendor_ramdisk_table_entry_v4);
233         new_hdr_v4->vendor_ramdisk_table_entry_num = 1;
234         new_hdr_v4->vendor_ramdisk_table_size = new_hdr_v4->vendor_ramdisk_table_entry_num *
235                                                 new_hdr_v4->vendor_ramdisk_table_entry_size;
236     }
237 
238     // Copy the new ramdisk.
239     if (auto res = updater.Replace(hdr->vendor_ramdisk_size, new_ramdisk); !res.ok())
240         return res.error();
241     const uint32_t new_p = round_up(new_hdr->vendor_ramdisk_size, new_hdr->page_size);
242     if (auto res = updater.Skip(p - hdr->vendor_ramdisk_size, new_p - new_hdr->vendor_ramdisk_size);
243         !res.ok())
244         return res.error();
245     if (auto res = updater.CheckOffset(o + p, o + new_p); !res.ok()) return res.error();
246 
247     // Copy DTB (Q bytes).
248     if (auto res = updater.Copy(q); !res.ok()) return res.error();
249 
250     if (new_hdr->header_version >= 4) {
251         auto hdr_v4 = static_cast<const vendor_boot_img_hdr_v4*>(hdr);
252         const uint32_t r = round_up(hdr_v4->vendor_ramdisk_table_size, hdr_v4->page_size);
253         const uint32_t s = round_up(hdr_v4->bootconfig_size, hdr_v4->page_size);
254 
255         auto new_entry = reinterpret_cast<vendor_ramdisk_table_entry_v4*>(updater.new_cur());
256         auto new_hdr_v4 = static_cast<const vendor_boot_img_hdr_v4*>(new_hdr);
257         auto new_r = round_up(new_hdr_v4->vendor_ramdisk_table_size, new_hdr->page_size);
258         if (auto res = updater.Skip(r, new_r); !res.ok()) return res.error();
259         if (auto res = updater.CheckOffset(o + p + q + r, o + new_p + q + new_r); !res.ok())
260             return res.error();
261 
262         // Replace table with single entry representing the full ramdisk.
263         new_entry->ramdisk_size = new_hdr->vendor_ramdisk_size;
264         new_entry->ramdisk_offset = 0;
265         new_entry->ramdisk_type = VENDOR_RAMDISK_TYPE_NONE;
266         memset(new_entry->ramdisk_name, '\0', VENDOR_RAMDISK_NAME_SIZE);
267         memset(new_entry->board_id, '\0', VENDOR_RAMDISK_TABLE_ENTRY_BOARD_ID_SIZE);
268 
269         // Copy bootconfig (S bytes).
270         if (auto res = updater.Copy(s); !res.ok()) return res.error();
271     }
272 
273     if (auto res = copy_avb_footer(&updater); !res.ok()) return res.error();
274     return updater.Finish();
275 }
276 
277 // 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)278 [[nodiscard]] Result<const vendor_ramdisk_table_entry_v4*> find_unique_ramdisk(
279         const std::string& ramdisk_name, const vendor_ramdisk_table_entry_v4* table,
280         uint32_t size) {
281     const vendor_ramdisk_table_entry_v4* ret = nullptr;
282     uint32_t idx = 0;
283     const vendor_ramdisk_table_entry_v4* entry = table;
284     for (; idx < size; idx++, entry++) {
285         auto entry_name_c_str = reinterpret_cast<const char*>(entry->ramdisk_name);
286         auto entry_name_len = strnlen(entry_name_c_str, VENDOR_RAMDISK_NAME_SIZE);
287         std::string_view entry_name(entry_name_c_str, entry_name_len);
288         if (entry_name == ramdisk_name) {
289             if (ret != nullptr) {
290                 return Errorf("Multiple vendor ramdisk '{}' found, name should be unique",
291                               ramdisk_name.c_str());
292             }
293             ret = entry;
294         }
295     }
296     if (ret == nullptr) {
297         return Errorf("Vendor ramdisk '{}' not found", ramdisk_name.c_str());
298     }
299     return ret;
300 }
301 
302 // Find the vendor ramdisk fragment with |ramdisk_name| within the content of |vendor_boot|, and
303 // 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)304 [[nodiscard]] Result<std::string> replace_vendor_ramdisk_fragment(const std::string& ramdisk_name,
305                                                                   const std::string& vendor_boot,
306                                                                   const std::string& new_ramdisk) {
307     if (auto res = check_vendor_boot_hdr(vendor_boot, 4); !res.ok()) return res.error();
308     auto hdr = reinterpret_cast<const vendor_boot_img_hdr_v4*>(vendor_boot.data());
309     auto hdr_size = get_vendor_boot_header_size(hdr);
310     if (!hdr_size.ok()) return hdr_size.error();
311     // Refer to bootimg.h for details. Numbers are in bytes.
312     const uint32_t o = round_up(*hdr_size, hdr->page_size);
313     const uint32_t p = round_up(hdr->vendor_ramdisk_size, hdr->page_size);
314     const uint32_t q = round_up(hdr->dtb_size, hdr->page_size);
315     const uint32_t r = round_up(hdr->vendor_ramdisk_table_size, hdr->page_size);
316     const uint32_t s = round_up(hdr->bootconfig_size, hdr->page_size);
317 
318     uint64_t total_size = (uint64_t)o + p + q + r + s;
319     if (total_size > vendor_boot.size()) {
320         return Errorf("Vendor boot image size is too small, overflow");
321     }
322 
323     if ((uint64_t)hdr->vendor_ramdisk_table_entry_num * sizeof(vendor_ramdisk_table_entry_v4) >
324         (uint64_t)o + p + q + r) {
325         return Errorf("Too many vendor ramdisk entries in table, overflow");
326     }
327 
328     // Find entry with name |ramdisk_name|.
329     auto old_table_start =
330             reinterpret_cast<const vendor_ramdisk_table_entry_v4*>(vendor_boot.data() + o + p + q);
331     auto find_res =
332             find_unique_ramdisk(ramdisk_name, old_table_start, hdr->vendor_ramdisk_table_entry_num);
333     if (!find_res.ok()) return find_res.error();
334     const vendor_ramdisk_table_entry_v4* replace_entry = *find_res;
335     uint32_t replace_idx = replace_entry - old_table_start;
336 
337     // Now reconstruct.
338     DataUpdater updater(vendor_boot);
339 
340     // Copy header (O bytes), then update fields in header.
341     if (auto res = updater.Copy(o); !res.ok()) return res.error();
342     auto new_hdr = reinterpret_cast<vendor_boot_img_hdr_v4*>(updater.new_begin());
343 
344     // Copy ramdisk fragments, replace for the matching index.
345     {
346         auto old_ramdisk_entry = reinterpret_cast<const vendor_ramdisk_table_entry_v4*>(
347                 vendor_boot.data() + o + p + q);
348         uint32_t new_total_ramdisk_size = 0;
349         for (uint32_t new_ramdisk_idx = 0; new_ramdisk_idx < hdr->vendor_ramdisk_table_entry_num;
350              new_ramdisk_idx++, old_ramdisk_entry++) {
351             if (new_ramdisk_idx == replace_idx) {
352                 if (auto res = updater.Replace(replace_entry->ramdisk_size, new_ramdisk); !res.ok())
353                     return res.error();
354                 new_total_ramdisk_size += new_ramdisk.size();
355             } else {
356                 if (auto res = updater.Copy(old_ramdisk_entry->ramdisk_size); !res.ok())
357                     return res.error();
358                 new_total_ramdisk_size += old_ramdisk_entry->ramdisk_size;
359             }
360         }
361         new_hdr->vendor_ramdisk_size = new_total_ramdisk_size;
362     }
363 
364     // Pad ramdisk to page boundary.
365     const uint32_t new_p = round_up(new_hdr->vendor_ramdisk_size, new_hdr->page_size);
366     if (auto res = updater.Skip(p - hdr->vendor_ramdisk_size, new_p - new_hdr->vendor_ramdisk_size);
367         !res.ok())
368         return res.error();
369     if (auto res = updater.CheckOffset(o + p, o + new_p); !res.ok()) return res.error();
370 
371     // Copy DTB (Q bytes).
372     if (auto res = updater.Copy(q); !res.ok()) return res.error();
373 
374     // Copy table, but with corresponding entries modified, including:
375     // - ramdisk_size of the entry replaced
376     // - ramdisk_offset of subsequent entries.
377     for (uint32_t new_total_ramdisk_size = 0, new_entry_idx = 0;
378          new_entry_idx < hdr->vendor_ramdisk_table_entry_num; new_entry_idx++) {
379         auto new_entry = reinterpret_cast<vendor_ramdisk_table_entry_v4*>(updater.new_cur());
380         if (auto res = updater.Copy(hdr->vendor_ramdisk_table_entry_size); !res.ok())
381             return res.error();
382         new_entry->ramdisk_offset = new_total_ramdisk_size;
383 
384         if (new_entry_idx == replace_idx) {
385             new_entry->ramdisk_size = new_ramdisk.size();
386         }
387         new_total_ramdisk_size += new_entry->ramdisk_size;
388     }
389 
390     // Copy padding of R pages; this is okay because table size is not changed.
391     if (auto res = updater.Copy(r - hdr->vendor_ramdisk_table_entry_num *
392                                             hdr->vendor_ramdisk_table_entry_size);
393         !res.ok())
394         return res.error();
395     if (auto res = updater.CheckOffset(o + p + q + r, o + new_p + q + r); !res.ok())
396         return res.error();
397 
398     // Copy bootconfig (S bytes).
399     if (auto res = updater.Copy(s); !res.ok()) return res.error();
400 
401     if (auto res = copy_avb_footer(&updater); !res.ok()) return res.error();
402     return updater.Finish();
403 }
404 
405 }  // namespace
406 
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)407 [[nodiscard]] Result<void> replace_vendor_ramdisk(android::base::borrowed_fd vendor_boot_fd,
408                                                   uint64_t vendor_boot_size,
409                                                   const std::string& ramdisk_name,
410                                                   android::base::borrowed_fd new_ramdisk_fd,
411                                                   uint64_t new_ramdisk_size) {
412     if (new_ramdisk_size > std::numeric_limits<uint32_t>::max()) {
413         return Errorf("New vendor ramdisk is too big");
414     }
415 
416     auto vendor_boot = load_file(vendor_boot_fd, vendor_boot_size, "vendor boot");
417     if (!vendor_boot.ok()) return vendor_boot.error();
418     auto new_ramdisk = load_file(new_ramdisk_fd, new_ramdisk_size, "new vendor ramdisk");
419     if (!new_ramdisk.ok()) return new_ramdisk.error();
420 
421     Result<std::string> new_vendor_boot;
422     if (ramdisk_name == "default") {
423         new_vendor_boot = replace_default_vendor_ramdisk(*vendor_boot, *new_ramdisk);
424     } else {
425         new_vendor_boot = replace_vendor_ramdisk_fragment(ramdisk_name, *vendor_boot, *new_ramdisk);
426     }
427     if (!new_vendor_boot.ok()) return new_vendor_boot.error();
428     if (auto res = store_file(vendor_boot_fd, *new_vendor_boot, "new vendor boot image"); !res.ok())
429         return res.error();
430 
431     return {};
432 }
433