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