1 /*
2  * Copyright (C) 2008 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 "applypatch/applypatch.h"
18 
19 #include <errno.h>
20 #include <fcntl.h>
21 #include <libgen.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <sys/stat.h>
26 #include <sys/types.h>
27 #include <unistd.h>
28 
29 #include <algorithm>
30 #include <functional>
31 #include <memory>
32 #include <string>
33 #include <utility>
34 #include <vector>
35 
36 #include <android-base/file.h>
37 #include <android-base/logging.h>
38 #include <android-base/parseint.h>
39 #include <android-base/strings.h>
40 #include <android-base/unique_fd.h>
41 #include <openssl/sha.h>
42 
43 #include "edify/expr.h"
44 #include "otautil/paths.h"
45 #include "otautil/print_sha1.h"
46 
47 using namespace std::string_literals;
48 
49 static bool GenerateTarget(const Partition& target, const FileContents& source_file,
50                            const Value& patch, const Value* bonus_data, bool backup_source);
51 
LoadFileContents(const std::string & filename,FileContents * file)52 bool LoadFileContents(const std::string& filename, FileContents* file) {
53   // No longer allow loading contents from eMMC partitions.
54   if (android::base::StartsWith(filename, "EMMC:")) {
55     return false;
56   }
57 
58   std::string data;
59   if (!android::base::ReadFileToString(filename, &data)) {
60     PLOG(ERROR) << "Failed to read \"" << filename << "\"";
61     return false;
62   }
63 
64   file->data = std::vector<unsigned char>(data.begin(), data.end());
65   SHA1(file->data.data(), file->data.size(), file->sha1);
66   return true;
67 }
68 
69 // Reads the contents of a Partition to the given FileContents buffer.
ReadPartitionToBuffer(const Partition & partition,FileContents * out,bool check_backup)70 static bool ReadPartitionToBuffer(const Partition& partition, FileContents* out,
71                                   bool check_backup) {
72   uint8_t expected_sha1[SHA_DIGEST_LENGTH];
73   if (ParseSha1(partition.hash, expected_sha1) != 0) {
74     LOG(ERROR) << "Failed to parse target hash \"" << partition.hash << "\"";
75     return false;
76   }
77 
78   android::base::unique_fd dev(open(partition.name.c_str(), O_RDONLY));
79   if (dev == -1) {
80     PLOG(ERROR) << "Failed to open eMMC partition \"" << partition << "\"";
81   } else {
82     std::vector<unsigned char> buffer(partition.size);
83     if (!android::base::ReadFully(dev, buffer.data(), buffer.size())) {
84       PLOG(ERROR) << "Failed to read " << buffer.size() << " bytes of data for partition "
85                   << partition;
86     } else {
87       SHA1(buffer.data(), buffer.size(), out->sha1);
88       if (memcmp(out->sha1, expected_sha1, SHA_DIGEST_LENGTH) == 0) {
89         out->data = std::move(buffer);
90         return true;
91       }
92     }
93   }
94 
95   if (!check_backup) {
96     LOG(ERROR) << "Partition contents don't have the expected checksum";
97     return false;
98   }
99 
100   if (LoadFileContents(Paths::Get().cache_temp_source(), out) &&
101       memcmp(out->sha1, expected_sha1, SHA_DIGEST_LENGTH) == 0) {
102     return true;
103   }
104 
105   LOG(ERROR) << "Both of partition contents and backup don't have the expected checksum";
106   return false;
107 }
108 
SaveFileContents(const std::string & filename,const FileContents * file)109 bool SaveFileContents(const std::string& filename, const FileContents* file) {
110   android::base::unique_fd fd(
111       open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_SYNC, S_IRUSR | S_IWUSR));
112   if (fd == -1) {
113     PLOG(ERROR) << "Failed to open \"" << filename << "\" for write";
114     return false;
115   }
116 
117   if (!android::base::WriteFully(fd, file->data.data(), file->data.size())) {
118     PLOG(ERROR) << "Failed to write " << file->data.size() << " bytes of data to " << filename;
119     return false;
120   }
121 
122   if (fsync(fd) != 0) {
123     PLOG(ERROR) << "Failed to fsync \"" << filename << "\"";
124     return false;
125   }
126 
127   if (close(fd.release()) != 0) {
128     PLOG(ERROR) << "Failed to close \"" << filename << "\"";
129     return false;
130   }
131 
132   return true;
133 }
134 
135 // Writes a memory buffer to 'target' Partition.
WriteBufferToPartition(const FileContents & file_contents,const Partition & partition)136 static bool WriteBufferToPartition(const FileContents& file_contents, const Partition& partition) {
137   const unsigned char* data = file_contents.data.data();
138   size_t len = file_contents.data.size();
139   size_t start = 0;
140   bool success = false;
141   for (size_t attempt = 0; attempt < 2; ++attempt) {
142     android::base::unique_fd fd(open(partition.name.c_str(), O_RDWR));
143     if (fd == -1) {
144       PLOG(ERROR) << "Failed to open \"" << partition << "\"";
145       return false;
146     }
147 
148     if (TEMP_FAILURE_RETRY(lseek(fd, start, SEEK_SET)) == -1) {
149       PLOG(ERROR) << "Failed to seek to " << start << " on \"" << partition << "\"";
150       return false;
151     }
152 
153     if (!android::base::WriteFully(fd, data + start, len - start)) {
154       PLOG(ERROR) << "Failed to write " << len - start << " bytes to \"" << partition << "\"";
155       return false;
156     }
157 
158     if (fsync(fd) != 0) {
159       PLOG(ERROR) << "Failed to sync \"" << partition << "\"";
160       return false;
161     }
162     if (close(fd.release()) != 0) {
163       PLOG(ERROR) << "Failed to close \"" << partition << "\"";
164       return false;
165     }
166 
167     fd.reset(open(partition.name.c_str(), O_RDONLY));
168     if (fd == -1) {
169       PLOG(ERROR) << "Failed to reopen \"" << partition << "\" for verification";
170       return false;
171     }
172 
173     // Drop caches so our subsequent verification read won't just be reading the cache.
174     sync();
175     std::string drop_cache = "/proc/sys/vm/drop_caches";
176     if (!android::base::WriteStringToFile("3\n", drop_cache)) {
177       PLOG(ERROR) << "Failed to write to " << drop_cache;
178     } else {
179       LOG(INFO) << "  caches dropped";
180     }
181     sleep(1);
182 
183     // Verify.
184     if (TEMP_FAILURE_RETRY(lseek(fd, 0, SEEK_SET)) == -1) {
185       PLOG(ERROR) << "Failed to seek to 0 on " << partition;
186       return false;
187     }
188 
189     unsigned char buffer[4096];
190     start = len;
191     for (size_t p = 0; p < len; p += sizeof(buffer)) {
192       size_t to_read = len - p;
193       if (to_read > sizeof(buffer)) {
194         to_read = sizeof(buffer);
195       }
196 
197       if (!android::base::ReadFully(fd, buffer, to_read)) {
198         PLOG(ERROR) << "Failed to verify-read " << partition << " at " << p;
199         return false;
200       }
201 
202       if (memcmp(buffer, data + p, to_read) != 0) {
203         LOG(ERROR) << "Verification failed starting at " << p;
204         start = p;
205         break;
206       }
207     }
208 
209     if (start == len) {
210       LOG(INFO) << "Verification read succeeded (attempt " << attempt + 1 << ")";
211       success = true;
212       break;
213     }
214 
215     if (close(fd.release()) != 0) {
216       PLOG(ERROR) << "Failed to close " << partition;
217       return false;
218     }
219   }
220 
221   if (!success) {
222     LOG(ERROR) << "Failed to verify after all attempts";
223     return false;
224   }
225 
226   sync();
227 
228   return true;
229 }
230 
ParseSha1(const std::string & str,uint8_t * digest)231 int ParseSha1(const std::string& str, uint8_t* digest) {
232   const char* ps = str.c_str();
233   uint8_t* pd = digest;
234   for (int i = 0; i < SHA_DIGEST_LENGTH * 2; ++i, ++ps) {
235     int digit;
236     if (*ps >= '0' && *ps <= '9') {
237       digit = *ps - '0';
238     } else if (*ps >= 'a' && *ps <= 'f') {
239       digit = *ps - 'a' + 10;
240     } else if (*ps >= 'A' && *ps <= 'F') {
241       digit = *ps - 'A' + 10;
242     } else {
243       return -1;
244     }
245     if (i % 2 == 0) {
246       *pd = digit << 4;
247     } else {
248       *pd |= digit;
249       ++pd;
250     }
251   }
252   if (*ps != '\0') return -1;
253   return 0;
254 }
255 
PatchPartitionCheck(const Partition & target,const Partition & source)256 bool PatchPartitionCheck(const Partition& target, const Partition& source) {
257   FileContents target_file;
258   FileContents source_file;
259   return (ReadPartitionToBuffer(target, &target_file, false) ||
260           ReadPartitionToBuffer(source, &source_file, true));
261 }
262 
ShowLicenses()263 int ShowLicenses() {
264   ShowBSDiffLicense();
265   return 0;
266 }
267 
PatchPartition(const Partition & target,const Partition & source,const Value & patch,const Value * bonus,bool backup_source)268 bool PatchPartition(const Partition& target, const Partition& source, const Value& patch,
269                     const Value* bonus, bool backup_source) {
270   LOG(INFO) << "Patching " << target.name;
271 
272   // We try to load and check against the target hash first.
273   FileContents target_file;
274   if (ReadPartitionToBuffer(target, &target_file, false)) {
275     // The early-exit case: the patch was already applied, this file has the desired hash, nothing
276     // for us to do.
277     LOG(INFO) << "  already " << target.hash.substr(0, 8);
278     return true;
279   }
280 
281   FileContents source_file;
282   if (ReadPartitionToBuffer(source, &source_file, backup_source)) {
283     return GenerateTarget(target, source_file, patch, bonus, backup_source);
284   }
285 
286   LOG(ERROR) << "Failed to find any match";
287   return false;
288 }
289 
FlashPartition(const Partition & partition,const std::string & source_filename)290 bool FlashPartition(const Partition& partition, const std::string& source_filename) {
291   LOG(INFO) << "Flashing " << partition;
292 
293   // We try to load and check against the target hash first.
294   FileContents target_file;
295   if (ReadPartitionToBuffer(partition, &target_file, false)) {
296     // The early-exit case: the patch was already applied, this file has the desired hash, nothing
297     // for us to do.
298     LOG(INFO) << "  already " << partition.hash.substr(0, 8);
299     return true;
300   }
301 
302   FileContents source_file;
303   if (!LoadFileContents(source_filename, &source_file)) {
304     LOG(ERROR) << "Failed to load source file";
305     return false;
306   }
307 
308   uint8_t expected_sha1[SHA_DIGEST_LENGTH];
309   if (ParseSha1(partition.hash, expected_sha1) != 0) {
310     LOG(ERROR) << "Failed to parse source hash \"" << partition.hash << "\"";
311     return false;
312   }
313 
314   if (memcmp(source_file.sha1, expected_sha1, SHA_DIGEST_LENGTH) != 0) {
315     // The source doesn't have desired checksum.
316     LOG(ERROR) << "source \"" << source_filename << "\" doesn't have expected SHA-1 sum";
317     LOG(ERROR) << "expected: " << partition.hash.substr(0, 8)
318                << ", found: " << short_sha1(source_file.sha1);
319     return false;
320   }
321   if (!WriteBufferToPartition(source_file, partition)) {
322     LOG(ERROR) << "Failed to write to " << partition;
323     return false;
324   }
325   return true;
326 }
327 
GenerateTarget(const Partition & target,const FileContents & source_file,const Value & patch,const Value * bonus_data,bool backup_source)328 static bool GenerateTarget(const Partition& target, const FileContents& source_file,
329                            const Value& patch, const Value* bonus_data, bool backup_source) {
330   uint8_t expected_sha1[SHA_DIGEST_LENGTH];
331   if (ParseSha1(target.hash, expected_sha1) != 0) {
332     LOG(ERROR) << "Failed to parse target hash \"" << target.hash << "\"";
333     return false;
334   }
335 
336   if (patch.type != Value::Type::BLOB) {
337     LOG(ERROR) << "patch is not a blob";
338     return false;
339   }
340 
341   const char* header = patch.data.data();
342   size_t header_bytes_read = patch.data.size();
343   bool use_bsdiff = false;
344   if (header_bytes_read >= 8 && memcmp(header, "BSDIFF40", 8) == 0) {
345     use_bsdiff = true;
346   } else if (header_bytes_read >= 8 && memcmp(header, "IMGDIFF2", 8) == 0) {
347     use_bsdiff = false;
348   } else {
349     LOG(ERROR) << "Unknown patch file format";
350     return false;
351   }
352 
353   // We write the original source to cache, in case the partition write is interrupted.
354   if (backup_source && !CheckAndFreeSpaceOnCache(source_file.data.size())) {
355     LOG(ERROR) << "Not enough free space on /cache";
356     return false;
357   }
358   if (backup_source && !SaveFileContents(Paths::Get().cache_temp_source(), &source_file)) {
359     LOG(ERROR) << "Failed to back up source file";
360     return false;
361   }
362 
363   // We store the decoded output in memory.
364   FileContents patched;
365   SHA_CTX ctx;
366   SHA1_Init(&ctx);
367   SinkFn sink = [&patched, &ctx](const unsigned char* data, size_t len) {
368     SHA1_Update(&ctx, data, len);
369     patched.data.insert(patched.data.end(), data, data + len);
370     return len;
371   };
372 
373   int result;
374   if (use_bsdiff) {
375     result = ApplyBSDiffPatch(source_file.data.data(), source_file.data.size(), patch, 0, sink);
376   } else {
377     result =
378         ApplyImagePatch(source_file.data.data(), source_file.data.size(), patch, sink, bonus_data);
379   }
380 
381   if (result != 0) {
382     LOG(ERROR) << "Failed to apply the patch: " << result;
383     return false;
384   }
385 
386   SHA1_Final(patched.sha1, &ctx);
387   if (memcmp(patched.sha1, expected_sha1, SHA_DIGEST_LENGTH) != 0) {
388     LOG(ERROR) << "Patching did not produce the expected SHA-1 of " << short_sha1(expected_sha1);
389 
390     LOG(ERROR) << "target size " << patched.data.size() << " SHA-1 " << short_sha1(patched.sha1);
391     LOG(ERROR) << "source size " << source_file.data.size() << " SHA-1 "
392                << short_sha1(source_file.sha1);
393 
394     uint8_t patch_digest[SHA_DIGEST_LENGTH];
395     SHA1(reinterpret_cast<const uint8_t*>(patch.data.data()), patch.data.size(), patch_digest);
396     LOG(ERROR) << "patch size " << patch.data.size() << " SHA-1 " << short_sha1(patch_digest);
397 
398     if (bonus_data != nullptr) {
399       uint8_t bonus_digest[SHA_DIGEST_LENGTH];
400       SHA1(reinterpret_cast<const uint8_t*>(bonus_data->data.data()), bonus_data->data.size(),
401            bonus_digest);
402       LOG(ERROR) << "bonus size " << bonus_data->data.size() << " SHA-1 "
403                  << short_sha1(bonus_digest);
404     }
405 
406     return false;
407   }
408 
409   LOG(INFO) << "  now " << short_sha1(expected_sha1);
410 
411   // Write back the temp file to the partition.
412   if (!WriteBufferToPartition(patched, target)) {
413     LOG(ERROR) << "Failed to write patched data to " << target.name;
414     return false;
415   }
416 
417   // Delete the backup copy of the source.
418   if (backup_source) {
419     unlink(Paths::Get().cache_temp_source().c_str());
420   }
421 
422   // Success!
423   return true;
424 }
425 
CheckPartition(const Partition & partition)426 bool CheckPartition(const Partition& partition) {
427   FileContents target_file;
428   return ReadPartitionToBuffer(partition, &target_file, false);
429 }
430 
Parse(const std::string & input_str,std::string * err)431 Partition Partition::Parse(const std::string& input_str, std::string* err) {
432   std::vector<std::string> pieces = android::base::Split(input_str, ":");
433   if (pieces.size() != 4 || pieces[0] != "EMMC") {
434     *err = "Invalid number of tokens or non-eMMC target";
435     return {};
436   }
437 
438   size_t size;
439   if (!android::base::ParseUint(pieces[2], &size) || size == 0) {
440     *err = "Failed to parse \"" + pieces[2] + "\" as byte count";
441     return {};
442   }
443 
444   return Partition(pieces[1], size, pieces[3]);
445 }
446 
ToString() const447 std::string Partition::ToString() const {
448   if (*this) {
449     return "EMMC:"s + name + ":" + std::to_string(size) + ":" + hash;
450   }
451   return "<invalid-partition>";
452 }
453 
operator <<(std::ostream & os,const Partition & partition)454 std::ostream& operator<<(std::ostream& os, const Partition& partition) {
455   os << partition.ToString();
456   return os;
457 }
458