• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 "common.h"
26 #include "install.h"
27 #include "mincrypt/rsa.h"
28 #include "minui/minui.h"
29 #include "minzip/SysUtil.h"
30 #include "minzip/Zip.h"
31 #include "mtdutils/mounts.h"
32 #include "mtdutils/mtdutils.h"
33 #include "roots.h"
34 #include "verifier.h"
35 #include "firmware.h"
36 
37 #define ASSUMED_UPDATE_BINARY_NAME  "META-INF/com/google/android/update-binary"
38 #define PUBLIC_KEYS_FILE "/res/keys"
39 
40 // The update binary ask us to install a firmware file on reboot.  Set
41 // that up.  Takes ownership of type and filename.
42 static int
handle_firmware_update(char * type,char * filename,ZipArchive * zip)43 handle_firmware_update(char* type, char* filename, ZipArchive* zip) {
44     unsigned int data_size;
45     const ZipEntry* entry = NULL;
46 
47     if (strncmp(filename, "PACKAGE:", 8) == 0) {
48         entry = mzFindZipEntry(zip, filename+8);
49         if (entry == NULL) {
50             LOGE("Failed to find \"%s\" in package", filename+8);
51             return INSTALL_ERROR;
52         }
53         data_size = entry->uncompLen;
54     } else {
55         struct stat st_data;
56         if (stat(filename, &st_data) < 0) {
57             LOGE("Error stat'ing %s: %s\n", filename, strerror(errno));
58             return INSTALL_ERROR;
59         }
60         data_size = st_data.st_size;
61     }
62 
63     LOGI("type is %s; size is %d; file is %s\n",
64          type, data_size, filename);
65 
66     char* data = malloc(data_size);
67     if (data == NULL) {
68         LOGI("Can't allocate %d bytes for firmware data\n", data_size);
69         return INSTALL_ERROR;
70     }
71 
72     if (entry) {
73         if (mzReadZipEntry(zip, entry, data, data_size) == false) {
74             LOGE("Failed to read \"%s\" from package", filename+8);
75             return INSTALL_ERROR;
76         }
77     } else {
78         FILE* f = fopen(filename, "rb");
79         if (f == NULL) {
80             LOGE("Failed to open %s: %s\n", filename, strerror(errno));
81             return INSTALL_ERROR;
82         }
83         if (fread(data, 1, data_size, f) != data_size) {
84             LOGE("Failed to read firmware data: %s\n", strerror(errno));
85             return INSTALL_ERROR;
86         }
87         fclose(f);
88     }
89 
90     if (remember_firmware_update(type, data, data_size)) {
91         LOGE("Can't store %s image\n", type);
92         free(data);
93         return INSTALL_ERROR;
94     }
95     free(filename);
96 
97     return INSTALL_SUCCESS;
98 }
99 
100 // If the package contains an update binary, extract it and run it.
101 static int
try_update_binary(const char * path,ZipArchive * zip)102 try_update_binary(const char *path, ZipArchive *zip) {
103     const ZipEntry* binary_entry =
104             mzFindZipEntry(zip, ASSUMED_UPDATE_BINARY_NAME);
105     if (binary_entry == NULL) {
106         return INSTALL_CORRUPT;
107     }
108 
109     char* binary = "/tmp/update_binary";
110     unlink(binary);
111     int fd = creat(binary, 0755);
112     if (fd < 0) {
113         LOGE("Can't make %s\n", binary);
114         return 1;
115     }
116     bool ok = mzExtractZipEntryToFile(zip, binary_entry, fd);
117     close(fd);
118 
119     if (!ok) {
120         LOGE("Can't copy %s\n", ASSUMED_UPDATE_BINARY_NAME);
121         return 1;
122     }
123 
124     int pipefd[2];
125     pipe(pipefd);
126 
127     // When executing the update binary contained in the package, the
128     // arguments passed are:
129     //
130     //   - the version number for this interface
131     //
132     //   - an fd to which the program can write in order to update the
133     //     progress bar.  The program can write single-line commands:
134     //
135     //        progress <frac> <secs>
136     //            fill up the next <frac> part of of the progress bar
137     //            over <secs> seconds.  If <secs> is zero, use
138     //            set_progress commands to manually control the
139     //            progress of this segment of the bar
140     //
141     //        set_progress <frac>
142     //            <frac> should be between 0.0 and 1.0; sets the
143     //            progress bar within the segment defined by the most
144     //            recent progress command.
145     //
146     //        firmware <"hboot"|"radio"> <filename>
147     //            arrange to install the contents of <filename> in the
148     //            given partition on reboot.  (API v2: <filename> may
149     //            start with "PACKAGE:" to indicate taking a file from
150     //            the OTA package.)
151     //
152     //        ui_print <string>
153     //            display <string> on the screen.
154     //
155     //   - the name of the package zip file.
156     //
157 
158     char** args = malloc(sizeof(char*) * 5);
159     args[0] = binary;
160     args[1] = EXPAND(RECOVERY_API_VERSION);   // defined in Android.mk
161     args[2] = malloc(10);
162     sprintf(args[2], "%d", pipefd[1]);
163     args[3] = (char*)path;
164     args[4] = NULL;
165 
166     pid_t pid = fork();
167     if (pid == 0) {
168         close(pipefd[0]);
169         execv(binary, args);
170         fprintf(stderr, "E:Can't run %s (%s)\n", binary, strerror(errno));
171         _exit(-1);
172     }
173     close(pipefd[1]);
174 
175     char* firmware_type = NULL;
176     char* firmware_filename = NULL;
177 
178     char buffer[1024];
179     FILE* from_child = fdopen(pipefd[0], "r");
180     while (fgets(buffer, sizeof(buffer), from_child) != NULL) {
181         char* command = strtok(buffer, " \n");
182         if (command == NULL) {
183             continue;
184         } else if (strcmp(command, "progress") == 0) {
185             char* fraction_s = strtok(NULL, " \n");
186             char* seconds_s = strtok(NULL, " \n");
187 
188             float fraction = strtof(fraction_s, NULL);
189             int seconds = strtol(seconds_s, NULL, 10);
190 
191             ui_show_progress(fraction * (1-VERIFICATION_PROGRESS_FRACTION),
192                              seconds);
193         } else if (strcmp(command, "set_progress") == 0) {
194             char* fraction_s = strtok(NULL, " \n");
195             float fraction = strtof(fraction_s, NULL);
196             ui_set_progress(fraction);
197         } else if (strcmp(command, "firmware") == 0) {
198             char* type = strtok(NULL, " \n");
199             char* filename = strtok(NULL, " \n");
200 
201             if (type != NULL && filename != NULL) {
202                 if (firmware_type != NULL) {
203                     LOGE("ignoring attempt to do multiple firmware updates");
204                 } else {
205                     firmware_type = strdup(type);
206                     firmware_filename = strdup(filename);
207                 }
208             }
209         } else if (strcmp(command, "ui_print") == 0) {
210             char* str = strtok(NULL, "\n");
211             if (str) {
212                 ui_print(str);
213             } else {
214                 ui_print("\n");
215             }
216         } else {
217             LOGE("unknown command [%s]\n", command);
218         }
219     }
220     fclose(from_child);
221 
222     int status;
223     waitpid(pid, &status, 0);
224     if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
225         LOGE("Error in %s\n(Status %d)\n", path, WEXITSTATUS(status));
226         return INSTALL_ERROR;
227     }
228 
229     if (firmware_type != NULL) {
230         return handle_firmware_update(firmware_type, firmware_filename, zip);
231     } else {
232         return INSTALL_SUCCESS;
233     }
234 }
235 
236 static int
handle_update_package(const char * path,ZipArchive * zip,const RSAPublicKey * keys,int numKeys)237 handle_update_package(const char *path, ZipArchive *zip,
238                       const RSAPublicKey *keys, int numKeys)
239 {
240     // Give verification half the progress bar...
241     ui_print("Verifying update package...\n");
242     ui_show_progress(
243             VERIFICATION_PROGRESS_FRACTION,
244             VERIFICATION_PROGRESS_TIME);
245 
246     if (!verify_jar_signature(zip, keys, numKeys)) {
247         LOGE("Verification failed\n");
248         return INSTALL_CORRUPT;
249     }
250 
251     // Update should take the rest of the progress bar.
252     ui_print("Installing update...\n");
253 
254     int result = try_update_binary(path, zip);
255     register_package_root(NULL, NULL);  // Unregister package root
256     return result;
257 }
258 
259 // Reads a file containing one or more public keys as produced by
260 // DumpPublicKey:  this is an RSAPublicKey struct as it would appear
261 // as a C source literal, eg:
262 //
263 //  "{64,0xc926ad21,{1795090719,...,-695002876},{-857949815,...,1175080310}}"
264 //
265 // (Note that the braces and commas in this example are actual
266 // characters the parser expects to find in the file; the ellipses
267 // indicate more numbers omitted from this example.)
268 //
269 // The file may contain multiple keys in this format, separated by
270 // commas.  The last key must not be followed by a comma.
271 //
272 // Returns NULL if the file failed to parse, or if it contain zero keys.
273 static RSAPublicKey*
load_keys(const char * filename,int * numKeys)274 load_keys(const char* filename, int* numKeys) {
275     RSAPublicKey* out = NULL;
276     *numKeys = 0;
277 
278     FILE* f = fopen(filename, "r");
279     if (f == NULL) {
280         LOGE("opening %s: %s\n", filename, strerror(errno));
281         goto exit;
282     }
283 
284     int i;
285     bool done = false;
286     while (!done) {
287         ++*numKeys;
288         out = realloc(out, *numKeys * sizeof(RSAPublicKey));
289         RSAPublicKey* key = out + (*numKeys - 1);
290         if (fscanf(f, " { %i , %i , { %i",
291                    &(key->len), &(key->n0inv), &(key->n[0])) != 3) {
292             goto exit;
293         }
294         if (key->len != RSANUMWORDS) {
295             LOGE("key length (%d) does not match expected size\n", key->len);
296             goto exit;
297         }
298         for (i = 1; i < key->len; ++i) {
299             if (fscanf(f, " , %i", &(key->n[i])) != 1) goto exit;
300         }
301         if (fscanf(f, " } , { %i", &(key->rr[0])) != 1) goto exit;
302         for (i = 1; i < key->len; ++i) {
303             if (fscanf(f, " , %i", &(key->rr[i])) != 1) goto exit;
304         }
305         fscanf(f, " } } ");
306 
307         // if the line ends in a comma, this file has more keys.
308         switch (fgetc(f)) {
309             case ',':
310                 // more keys to come.
311                 break;
312 
313             case EOF:
314                 done = true;
315                 break;
316 
317             default:
318                 LOGE("unexpected character between keys\n");
319                 goto exit;
320         }
321     }
322 
323     fclose(f);
324     return out;
325 
326 exit:
327     if (f) fclose(f);
328     free(out);
329     *numKeys = 0;
330     return NULL;
331 }
332 
333 int
install_package(const char * root_path)334 install_package(const char *root_path)
335 {
336     ui_set_background(BACKGROUND_ICON_INSTALLING);
337     ui_print("Finding update package...\n");
338     ui_show_indeterminate_progress();
339     LOGI("Update location: %s\n", root_path);
340 
341     if (ensure_root_path_mounted(root_path) != 0) {
342         LOGE("Can't mount %s\n", root_path);
343         return INSTALL_CORRUPT;
344     }
345 
346     char path[PATH_MAX] = "";
347     if (translate_root_path(root_path, path, sizeof(path)) == NULL) {
348         LOGE("Bad path %s\n", root_path);
349         return INSTALL_CORRUPT;
350     }
351 
352     ui_print("Opening update package...\n");
353     LOGI("Update file path: %s\n", path);
354 
355     int numKeys;
356     RSAPublicKey* loadedKeys = load_keys(PUBLIC_KEYS_FILE, &numKeys);
357     if (loadedKeys == NULL) {
358         LOGE("Failed to load keys\n");
359         return INSTALL_CORRUPT;
360     }
361     LOGI("%d key(s) loaded from %s\n", numKeys, PUBLIC_KEYS_FILE);
362 
363     /* Try to open the package.
364      */
365     ZipArchive zip;
366     int err = mzOpenZipArchive(path, &zip);
367     if (err != 0) {
368         LOGE("Can't open %s\n(%s)\n", path, err != -1 ? strerror(err) : "bad");
369         return INSTALL_CORRUPT;
370     }
371 
372     /* Verify and install the contents of the package.
373      */
374     int status = handle_update_package(path, &zip, loadedKeys, numKeys);
375     mzCloseZipArchive(&zip);
376     free(loadedKeys);
377     return status;
378 }
379