blob: e1133c01ec3b079f8ca2088fff2968c7e556048b [file] [log] [blame]
Dees_Troy32c8eb82012-09-11 15:28:06 -04001/*
2 * Copyright (C) 2007 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 <ctype.h>
18#include <errno.h>
19#include <fcntl.h>
20#include <limits.h>
21#include <sys/stat.h>
22#include <sys/wait.h>
23#include <unistd.h>
24
25#include <string.h>
26#include <stdio.h>
27
28#include "common.h"
Dees_Troyb9d88ac2012-09-14 14:34:19 -040029#include "mincrypt/rsa.h"
30#include "mincrypt/sha.h"
Dees_Troy32c8eb82012-09-11 15:28:06 -040031#include "minui/minui.h"
32#include "minzip/SysUtil.h"
33#include "minzip/Zip.h"
34#include "mtdutils/mounts.h"
35#include "mtdutils/mtdutils.h"
36#include "roots.h"
37#include "verifier.h"
38#include "ui.h"
39#include "variables.h"
40#include "data.hpp"
41#include "partitions.hpp"
bigbiff bigbiffcdcfee42013-02-27 21:11:26 -050042#include "twrpDigest.hpp"
Dees_Troy38bd7602012-09-14 13:33:53 -040043#include "twrp-functions.hpp"
Dees_Troy32c8eb82012-09-11 15:28:06 -040044
Dees_Troy32c8eb82012-09-11 15:28:06 -040045extern RecoveryUI* ui;
46
47#define ASSUMED_UPDATE_BINARY_NAME "META-INF/com/google/android/update-binary"
48#define PUBLIC_KEYS_FILE "/res/keys"
49
50// Default allocation of progress bar segments to operations
51static const int VERIFICATION_PROGRESS_TIME = 60;
52static const float VERIFICATION_PROGRESS_FRACTION = 0.25;
53static const float DEFAULT_FILES_PROGRESS_FRACTION = 0.4;
54static const float DEFAULT_IMAGE_PROGRESS_FRACTION = 0.1;
55
56enum { INSTALL_SUCCESS, INSTALL_ERROR, INSTALL_CORRUPT };
57
Dees_Troy32c8eb82012-09-11 15:28:06 -040058// If the package contains an update binary, extract it and run it.
59static int
60try_update_binary(const char *path, ZipArchive *zip, int* wipe_cache) {
61 const ZipEntry* binary_entry =
62 mzFindZipEntry(zip, ASSUMED_UPDATE_BINARY_NAME);
63 if (binary_entry == NULL) {
64 mzCloseZipArchive(zip);
65 return INSTALL_CORRUPT;
66 }
67
68 const char* binary = "/tmp/update_binary";
69 unlink(binary);
70 int fd = creat(binary, 0755);
71 if (fd < 0) {
72 mzCloseZipArchive(zip);
73 LOGE("Can't make %s\n", binary);
74 return INSTALL_ERROR;
75 }
76 bool ok = mzExtractZipEntryToFile(zip, binary_entry, fd);
77 close(fd);
78 mzCloseZipArchive(zip);
79
80 if (!ok) {
81 LOGE("Can't copy %s\n", ASSUMED_UPDATE_BINARY_NAME);
82 return INSTALL_ERROR;
83 }
84
85 int pipefd[2];
86 pipe(pipefd);
87
88 // When executing the update binary contained in the package, the
89 // arguments passed are:
90 //
91 // - the version number for this interface
92 //
93 // - an fd to which the program can write in order to update the
94 // progress bar. The program can write single-line commands:
95 //
96 // progress <frac> <secs>
97 // fill up the next <frac> part of of the progress bar
98 // over <secs> seconds. If <secs> is zero, use
99 // set_progress commands to manually control the
100 // progress of this segment of the bar
101 //
102 // set_progress <frac>
103 // <frac> should be between 0.0 and 1.0; sets the
104 // progress bar within the segment defined by the most
105 // recent progress command.
106 //
107 // firmware <"hboot"|"radio"> <filename>
108 // arrange to install the contents of <filename> in the
109 // given partition on reboot.
110 //
111 // (API v2: <filename> may start with "PACKAGE:" to
112 // indicate taking a file from the OTA package.)
113 //
114 // (API v3: this command no longer exists.)
115 //
116 // ui_print <string>
117 // display <string> on the screen.
118 //
119 // - the name of the package zip file.
120 //
121
122 const char** args = (const char**)malloc(sizeof(char*) * 5);
123 args[0] = binary;
124 args[1] = EXPAND(RECOVERY_API_VERSION); // defined in Android.mk
125 char* temp = (char*)malloc(10);
126 sprintf(temp, "%d", pipefd[1]);
127 args[2] = temp;
128 args[3] = (char*)path;
129 args[4] = NULL;
130
131 pid_t pid = fork();
132 if (pid == 0) {
133 close(pipefd[0]);
134 execv(binary, (char* const*)args);
135 fprintf(stdout, "E:Can't run %s (%s)\n", binary, strerror(errno));
136 _exit(-1);
137 }
138 close(pipefd[1]);
139
140 *wipe_cache = 0;
141
142 char buffer[1024];
143 FILE* from_child = fdopen(pipefd[0], "r");
144 while (fgets(buffer, sizeof(buffer), from_child) != NULL) {
145 char* command = strtok(buffer, " \n");
146 if (command == NULL) {
147 continue;
148 } else if (strcmp(command, "progress") == 0) {
149 char* fraction_s = strtok(NULL, " \n");
150 char* seconds_s = strtok(NULL, " \n");
151
152 float fraction = strtof(fraction_s, NULL);
153 int seconds = strtol(seconds_s, NULL, 10);
154
155 ui->ShowProgress(fraction * (1-VERIFICATION_PROGRESS_FRACTION), seconds);
156 } else if (strcmp(command, "set_progress") == 0) {
157 char* fraction_s = strtok(NULL, " \n");
158 float fraction = strtof(fraction_s, NULL);
159 ui->SetProgress(fraction);
160 } else if (strcmp(command, "ui_print") == 0) {
161 char* str = strtok(NULL, "\n");
162 if (str) {
163 ui->Print("%s", str);
164 } else {
165 ui->Print("\n");
166 }
167 } else if (strcmp(command, "wipe_cache") == 0) {
168 *wipe_cache = 1;
169 } else if (strcmp(command, "clear_display") == 0) {
170 //ui->SetBackground(RecoveryUI::NONE);
171 } else {
172 LOGE("unknown command [%s]\n", command);
173 }
174 }
175 fclose(from_child);
176
177 int status;
178 waitpid(pid, &status, 0);
179 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
180 LOGE("Error in %s\n(Status %d)\n", path, WEXITSTATUS(status));
181 return INSTALL_ERROR;
182 }
183
184 return INSTALL_SUCCESS;
185}
186
187// Reads a file containing one or more public keys as produced by
188// DumpPublicKey: this is an RSAPublicKey struct as it would appear
189// as a C source literal, eg:
190//
191// "{64,0xc926ad21,{1795090719,...,-695002876},{-857949815,...,1175080310}}"
192//
193// (Note that the braces and commas in this example are actual
194// characters the parser expects to find in the file; the ellipses
195// indicate more numbers omitted from this example.)
196//
197// The file may contain multiple keys in this format, separated by
198// commas. The last key must not be followed by a comma.
199//
200// Returns NULL if the file failed to parse, or if it contain zero keys.
201static RSAPublicKey*
202load_keys(const char* filename, int* numKeys) {
203 RSAPublicKey* out = NULL;
204 *numKeys = 0;
205
206 FILE* f = fopen(filename, "r");
207 if (f == NULL) {
208 LOGE("opening %s: %s\n", filename, strerror(errno));
209 goto exit;
210 }
211
212 {
213 int i;
214 bool done = false;
215 while (!done) {
216 ++*numKeys;
217 out = (RSAPublicKey*)realloc(out, *numKeys * sizeof(RSAPublicKey));
218 RSAPublicKey* key = out + (*numKeys - 1);
219 if (fscanf(f, " { %i , 0x%x , { %u",
220 &(key->len), &(key->n0inv), &(key->n[0])) != 3) {
221 goto exit;
222 }
223 if (key->len != RSANUMWORDS) {
224 LOGE("key length (%d) does not match expected size\n", key->len);
225 goto exit;
226 }
227 for (i = 1; i < key->len; ++i) {
228 if (fscanf(f, " , %u", &(key->n[i])) != 1) goto exit;
229 }
230 if (fscanf(f, " } , { %u", &(key->rr[0])) != 1) goto exit;
231 for (i = 1; i < key->len; ++i) {
232 if (fscanf(f, " , %u", &(key->rr[i])) != 1) goto exit;
233 }
234 fscanf(f, " } } ");
235
236 // if the line ends in a comma, this file has more keys.
237 switch (fgetc(f)) {
238 case ',':
239 // more keys to come.
240 break;
241
242 case EOF:
243 done = true;
244 break;
245
246 default:
247 LOGE("unexpected character between keys\n");
248 goto exit;
249 }
250 }
251 }
252
253 fclose(f);
254 return out;
255
256exit:
257 if (f) fclose(f);
258 free(out);
259 *numKeys = 0;
260 return NULL;
261}
262
Dees_Troy32c8eb82012-09-11 15:28:06 -0400263extern "C" int TWinstall_zip(const char* path, int* wipe_cache) {
Dees_Troye2c8ba72013-01-30 21:00:05 +0000264 int err, zip_verify, md5_return;
bigbiff bigbiffcdcfee42013-02-27 21:11:26 -0500265 twrpDigest md5sum;
266 string strpath = path;
Dees_Troy32c8eb82012-09-11 15:28:06 -0400267 ui_print("Installing '%s'...\n", path);
268
269 if (!PartitionManager.Mount_By_Path(path, 0)) {
270 LOGE("Failed to mount '%s'\n", path);
271 return -1;
272 }
273
274 ui_print("Checking for MD5 file...\n");
bigbiff bigbiffcdcfee42013-02-27 21:11:26 -0500275 md5sum.setfn(strpath);
276 md5_return = md5sum.verify_md5digest();
277 if (md5_return == -2) {
Dees_Troy32c8eb82012-09-11 15:28:06 -0400278 // MD5 did not match.
279 LOGE("Zip MD5 does not match.\nUnable to install zip.\n");
280 return INSTALL_CORRUPT;
281 } else if (md5_return == -1) {
Dees_Troye2c8ba72013-01-30 21:00:05 +0000282 ui_print("Skipping MD5 check: no MD5 file found.\n");
bigbiff bigbiffcdcfee42013-02-27 21:11:26 -0500283 } else if (md5_return == 0)
Dees_Troy32c8eb82012-09-11 15:28:06 -0400284 ui_print("Zip MD5 matched.\n"); // MD5 found and matched.
285
286 DataManager::GetValue(TW_SIGNED_ZIP_VERIFY_VAR, zip_verify);
287 if (zip_verify) {
288 ui_print("Verifying zip signature...\n");
289 int numKeys;
290 RSAPublicKey* loadedKeys = load_keys(PUBLIC_KEYS_FILE, &numKeys);
291 if (loadedKeys == NULL) {
292 LOGE("Failed to load keys\n");
293 return -1;
294 }
295 LOGI("%d key(s) loaded from %s\n", numKeys, PUBLIC_KEYS_FILE);
296
297 // Give verification half the progress bar...
298 ui->Print("Verifying update package...\n");
299 ui->SetProgressType(RecoveryUI::DETERMINATE);
300 ui->ShowProgress(VERIFICATION_PROGRESS_FRACTION, VERIFICATION_PROGRESS_TIME);
301
Dees_Troyb9d88ac2012-09-14 14:34:19 -0400302 err = verify_file(path, loadedKeys, numKeys);
Dees_Troy32c8eb82012-09-11 15:28:06 -0400303 free(loadedKeys);
304 LOGI("verify_file returned %d\n", err);
305 if (err != VERIFY_SUCCESS) {
306 LOGE("signature verification failed\n");
307 return -1;
308 }
309 }
310 /* Try to open the package.
311 */
312 ZipArchive zip;
313 err = mzOpenZipArchive(path, &zip);
314 if (err != 0) {
315 LOGE("Can't open %s\n(%s)\n", path, err != -1 ? strerror(err) : "bad");
316 return INSTALL_CORRUPT;
317 }
318
319 /* Verify and install the contents of the package.
320 */
321 return try_update_binary(path, &zip, wipe_cache);
322}