• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "bootloader.h"
18 #include "common.h"
19 #include "firmware.h"
20 #include "mtdutils/mtdutils.h"
21 #include "mincrypt/sha.h"
22 
23 #include <errno.h>
24 #include <string.h>
25 #include <sys/reboot.h>
26 
27 /* Bootloader / Recovery Flow
28  *
29  * On every boot, the bootloader will read the bootloader_message
30  * from flash and check the command field.  The bootloader should
31  * deal with the command field not having a 0 terminator correctly
32  * (so as to not crash if the block is invalid or corrupt).
33  *
34  * The bootloader will have to publish the partition that contains
35  * the bootloader_message to the linux kernel so it can update it.
36  *
37  * if command == "boot-recovery" -> boot recovery.img
38  * else if command == "update-radio" -> update radio image (below)
39  * else if command == "update-hboot" -> update hboot image (below)
40  * else -> boot boot.img (normal boot)
41  *
42  * Radio/Hboot Update Flow
43  * 1. the bootloader will attempt to load and validate the header
44  * 2. if the header is invalid, status="invalid-update", goto #8
45  * 3. display the busy image on-screen
46  * 4. if the update image is invalid, status="invalid-radio-image", goto #8
47  * 5. attempt to update the firmware (depending on the command)
48  * 6. if successful, status="okay", goto #8
49  * 7. if failed, and the old image can still boot, status="failed-update"
50  * 8. write the bootloader_message, leaving the recovery field
51  *    unchanged, updating status, and setting command to
52  *    "boot-recovery"
53  * 9. reboot
54  *
55  * The bootloader will not modify or erase the cache partition.
56  * It is recovery's responsibility to clean up the mess afterwards.
57  */
58 
59 #undef LOGE
60 #define LOGE(...) fprintf(stderr, "E:" __VA_ARGS__)
61 
62 
verify_image(const uint8_t * expected_sha1)63 int verify_image(const uint8_t* expected_sha1) {
64     MtdPartition* part = mtd_find_partition_by_name(CACHE_NAME);
65     if (part == NULL) {
66         printf("verify image: failed to find cache partition\n");
67         return -1;
68     }
69 
70     size_t block_size;
71     if (mtd_partition_info(part, NULL, &block_size, NULL) != 0) {
72         printf("verify image: failed to get cache partition block size\n");
73         return -1;
74     }
75     printf("block size is 0x%x\n", block_size);
76 
77     char* buffer = malloc(block_size);
78     if (buffer == NULL) {
79         printf("verify image: failed to allocate memory\n");
80         return -1;
81     }
82 
83     MtdReadContext* ctx = mtd_read_partition(part);
84     if (ctx == NULL) {
85         printf("verify image: failed to init read context\n");
86         return -1;
87     }
88 
89     size_t pos = 0;
90     if (mtd_read_data(ctx, buffer, block_size) != block_size) {
91         printf("verify image: failed to read header\n");
92         return -1;
93     }
94     pos += block_size;
95 
96     if (strncmp(buffer, "MSM-RADIO-UPDATE", 16) != 0) {
97         printf("verify image: header missing magic\n");
98         return -1;
99     }
100 
101     unsigned image_offset = *(unsigned*)(buffer+24);
102     unsigned image_length = *(unsigned*)(buffer+28);
103     printf("image offset 0x%x length 0x%x\n", image_offset, image_length);
104     mtd_read_skip_to(ctx, image_offset);
105 
106     FILE* f = fopen("/tmp/read-radio.dat", "wb");
107     if (f == NULL) {
108         printf("verify image: failed to open temp file\n");
109     }
110 
111     SHA_CTX sha_ctx;
112     SHA_init(&sha_ctx);
113 
114     size_t total = 0;
115     while (total < image_length) {
116         size_t to_read = image_length - total;
117         if (to_read > block_size) to_read = block_size;
118         ssize_t read = mtd_read_data(ctx, buffer, to_read);
119         if (read < 0) {
120             printf("verify image: failed reading image (read 0x%x so far)\n",
121                    total);
122             return -1;
123         }
124         if (f) {
125             fwrite(buffer, 1, read, f);
126         }
127         SHA_update(&sha_ctx, buffer, read);
128         total += read;
129     }
130 
131     if (f) fclose(f);
132 
133     free(buffer);
134     mtd_read_close(ctx);
135 
136     const uint8_t* sha1 = SHA_final(&sha_ctx);
137     if (memcmp(sha1, expected_sha1, SHA_DIGEST_SIZE) != 0) {
138         printf("verify image: sha1 doesn't match\n");
139         return -1;
140     }
141 
142     printf("verify image: verification succeeded\n");
143 
144     return 0;
145 }
146 
install_firmware_update(const char * update_type,const char * update_data,size_t update_length,int width,int height,int bpp,const char * busy_image,const char * fail_image,const char * log_filename,const uint8_t * expected_sha1)147 int install_firmware_update(const char *update_type,
148                             const char *update_data,
149                             size_t update_length,
150                             int width, int height, int bpp,
151                             const char* busy_image,
152                             const char* fail_image,
153                             const char *log_filename,
154                             const uint8_t* expected_sha1) {
155     if (update_data == NULL || update_length == 0) return 0;
156 
157     mtd_scan_partitions();
158 
159     /* We destroy the cache partition to pass the update image to the
160      * bootloader, so all we can really do afterwards is wipe cache and reboot.
161      * Set up this instruction now, in case we're interrupted while writing.
162      */
163 
164     struct bootloader_message boot;
165     memset(&boot, 0, sizeof(boot));
166     strlcpy(boot.command, "boot-recovery", sizeof(boot.command));
167     strlcpy(boot.recovery, "recovery\n--wipe_cache\n", sizeof(boot.command));
168     if (set_bootloader_message(&boot)) return -1;
169 
170     if (write_update_for_bootloader(
171             update_data, update_length,
172             width, height, bpp, busy_image, fail_image, log_filename)) {
173         LOGE("Can't write %s image\n(%s)\n", update_type, strerror(errno));
174         return -1;
175     }
176 
177     if (verify_image(expected_sha1) == 0) {
178         /* The update image is fully written, so now we can instruct
179          * the bootloader to install it.  (After doing so, it will
180          * come back here, and we will wipe the cache and reboot into
181          * the system.)
182          */
183         snprintf(boot.command, sizeof(boot.command), "update-%s", update_type);
184         if (set_bootloader_message(&boot)) {
185             return -1;
186         }
187 
188         reboot(RB_AUTOBOOT);
189 
190         // Can't reboot?  WTF?
191         LOGE("Can't reboot\n");
192     }
193     return -1;
194 }
195