blob: 8c48cdf17b844964a0b97d97ce2bef176aa78f29
1 | #include <ctype.h> |
2 | #include <errno.h> |
3 | #include <fcntl.h> |
4 | #include <limits.h> |
5 | #include <sys/stat.h> |
6 | #include <sys/wait.h> |
7 | #include <unistd.h> |
8 | #include <sys/types.h> |
9 | #include <sys/mount.h> |
10 | #include <string.h> |
11 | |
12 | #include <ziparchive/zip_archive.h> |
13 | #include <android-base/logging.h> |
14 | |
15 | #include "common.h" |
16 | #include "cutils/properties.h" |
17 | #include "security.h" |
18 | |
19 | T_KernelVersion kernel_ver = KernelV_3_10; |
20 | /** |
21 | * --- judge platform whether match with zip image or not |
22 | * |
23 | * @platformEncryptStatus: 0: platform unencrypted, 1: platform encrypted |
24 | * @imageEncryptStatus: 0: image unencrypted, 1: image encrypted |
25 | * @imageName: image name |
26 | * @imageBuffer: image data address |
27 | * @imageSize: image data size |
28 | * |
29 | * return value: |
30 | * <0: failed |
31 | * =0: not match |
32 | * >0: match |
33 | */ |
34 | static int IsPlatformMachWithZipArchiveImage( |
35 | const int platformEncryptStatus, |
36 | const int imageEncryptStatus, |
37 | const char *imageName, |
38 | const unsigned char *imageBuffer, |
39 | const int imageSize) |
40 | { |
41 | int fd = -1, ret = -1; |
42 | ssize_t result = -1; |
43 | |
44 | if (strcmp(imageName, BOOT_IMG) && |
45 | strcmp(imageName, RECOVERY_IMG) && |
46 | strcmp(imageName, BOOTLOADER_IMG)) { |
47 | printf("can't support %s at present\n", |
48 | imageName); |
49 | return -1; |
50 | } |
51 | |
52 | if (imageBuffer == NULL) { |
53 | printf("havn't malloc space for %s\n", |
54 | imageName); |
55 | return -1; |
56 | } |
57 | |
58 | if (imageSize <= 0) { |
59 | printf("%s size is %d\n", |
60 | imageName, imageSize); |
61 | return -1; |
62 | } |
63 | |
64 | switch (platformEncryptStatus) { |
65 | case 0: { |
66 | if (!imageEncryptStatus) { |
67 | ret = 1; |
68 | } else { |
69 | ret = 0; |
70 | } |
71 | break; |
72 | } |
73 | |
74 | case 1: { |
75 | if (!imageEncryptStatus) { |
76 | ret = 0; |
77 | } else { |
78 | fd = open(DEFEND_KEY, O_RDWR); |
79 | if (fd <= 0) { |
80 | printf("open %s failed (%s)\n", |
81 | DEFEND_KEY, strerror(errno)); |
82 | return -1; |
83 | } |
84 | result = write(fd, imageBuffer, imageSize);// check rsa |
85 | printf("write %s datas to %s. [imgsize:%d, result:%d, %s]\n", |
86 | imageName, DEFEND_KEY, imageSize, result, |
87 | (result == 1) ? "match" : |
88 | (result == -2) ? "not match" : "failed or not support"); |
89 | if (result == 1) { |
90 | ret = 1; |
91 | } else if(result == -2) { |
92 | ret = 0; |
93 | } else { // failed or not support |
94 | ret = -1; |
95 | } |
96 | close(fd); |
97 | fd = -1; |
98 | } |
99 | break; |
100 | } |
101 | } |
102 | |
103 | return ret; |
104 | } |
105 | |
106 | /** |
107 | * --- check bootloader.img whether encrypt or not |
108 | * |
109 | * @imageName: bootloader.img |
110 | * @imageBuffer: bootloader.img data address |
111 | * |
112 | * return value: |
113 | * <0: failed |
114 | * =0: unencrypted |
115 | * >0: encrypted |
116 | */ |
117 | static int IsBootloaderImageEncrypted( |
118 | const char *imageName, |
119 | const unsigned char *imageBuffer) |
120 | { |
121 | int step0=1; |
122 | int step1=1; |
123 | int index=0; |
124 | unsigned char result= 0; |
125 | const unsigned char *pstart = NULL; |
126 | const unsigned char *pImageAddr = imageBuffer; |
127 | const unsigned char *pEncryptedBootloaderInfoBufAddr = NULL; |
128 | |
129 | // Don't modify. unencrypt bootloader info, for kernel version 3.10 |
130 | const int bootloaderEncryptInfoOffset = 0x1b0; |
131 | const unsigned char unencryptedBootloaderInfoBuf[] = |
132 | { 0x4D, 0x33, 0x48, 0x48, 0x52, 0x45, 0x56, 0x30 }; |
133 | |
134 | // Don't modify. unencrypt bootloader info, for kernel version 3.14 |
135 | const int newbootloaderEncryptInfoOffset = 0x10; |
136 | const int newbootloaderEncryptInfoOffset1 = 0x70; |
137 | const unsigned char newunencryptedBootloaderInfoBuf[] = { 0x40, 0x41, 0x4D, 0x4C}; |
138 | |
139 | if (strcmp(imageName, BOOTLOADER_IMG)) { |
140 | printf("this image must be %s,but it is %s\n", |
141 | BOOTLOADER_IMG, imageName); |
142 | return -1; |
143 | } |
144 | |
145 | if (imageBuffer == NULL) { |
146 | printf("havn't malloc space for %s\n", |
147 | imageName); |
148 | return -1; |
149 | } |
150 | |
151 | if (kernel_ver == KernelV_3_10) { |
152 | //check image whether encrypted for kernel 3.10 |
153 | pEncryptedBootloaderInfoBufAddr = pImageAddr + bootloaderEncryptInfoOffset; |
154 | if (!memcmp(unencryptedBootloaderInfoBuf, pEncryptedBootloaderInfoBufAddr, |
155 | ARRAY_SIZE(unencryptedBootloaderInfoBuf))) { |
156 | return 0; // unencrypted |
157 | } else { |
158 | return 1; |
159 | } |
160 | } |
161 | |
162 | //check image whether encrypted for kernel 3.14 |
163 | pEncryptedBootloaderInfoBufAddr = pImageAddr + newbootloaderEncryptInfoOffset; |
164 | if (!memcmp(newunencryptedBootloaderInfoBuf, pEncryptedBootloaderInfoBufAddr, |
165 | ARRAY_SIZE(newunencryptedBootloaderInfoBuf))) { |
166 | step0 = 0; |
167 | } |
168 | |
169 | pstart = pImageAddr + newbootloaderEncryptInfoOffset1; |
170 | for (index=0;index<16;index++) { |
171 | result ^= pstart[index]; |
172 | } |
173 | |
174 | if (result == 0) { |
175 | step1 = 0; |
176 | } |
177 | |
178 | if ((step0 == 1) && (step0 == 1)) { |
179 | return 1; // encrypted |
180 | } |
181 | |
182 | return 0;//unencrypted |
183 | } |
184 | |
185 | /* return value: |
186 | * <0: failed |
187 | * =0: not match |
188 | * >0: match |
189 | */ |
190 | int DtbImgEncrypted( |
191 | const char *imageName, |
192 | const unsigned char *imageBuffer, |
193 | const int imageSize, |
194 | const char *flag, |
195 | unsigned char *encryptedbuf) |
196 | { |
197 | int len = 0; |
198 | ssize_t result = -1; |
199 | ssize_t readlen = -1; |
200 | int fd = -1, ret = -1; |
201 | |
202 | if ((imageBuffer == NULL) || (imageName == NULL)) { |
203 | printf("imageBuffer is null!\n"); |
204 | return -1; |
205 | } |
206 | |
207 | if (access(DECRYPT_DTB, F_OK) ||access(DEFEND_KEY, F_OK)) { |
208 | printf("doesn't support dtb secure check\n"); |
209 | return 2; // kernel doesn't support |
210 | } |
211 | |
212 | fd = open(DECRYPT_DTB, O_RDWR); |
213 | if (fd <= 0) { |
214 | printf("open %s failed!\n", DECRYPT_DTB); |
215 | return -1; |
216 | } |
217 | |
218 | len = write(fd, flag, 1); |
219 | if (len != 1) { |
220 | printf("write %s failed!\n", DECRYPT_DTB); |
221 | close(fd); |
222 | fd = -1; |
223 | return -1; |
224 | } |
225 | |
226 | close(fd); |
227 | fd = -1; |
228 | |
229 | fd = open(DEFEND_KEY, O_RDWR); |
230 | if (fd <= 0) { |
231 | printf("open %s failed (%s)\n",DEFEND_KEY, strerror(errno)); |
232 | return -1; |
233 | } |
234 | |
235 | result = write(fd, imageBuffer, imageSize);// check rsa |
236 | printf("write %s datas to %s. [imgsize:%d, result:%d, %s]\n", |
237 | imageName, DEFEND_KEY, imageSize, result, |
238 | (result == 1) ? "match" : |
239 | (result == -2) ? "not match" : "failed or not support"); |
240 | |
241 | if (!strcmp(flag, "1")) { |
242 | printf("dtb.img need to encrypted!\n"); |
243 | readlen = read(fd, encryptedbuf, imageSize); |
244 | if (readlen < 0) { |
245 | printf("read %s error!\n", DEFEND_KEY); |
246 | close(fd); |
247 | return -1; |
248 | } |
249 | |
250 | } |
251 | |
252 | if (result == 1) { |
253 | ret = 1; |
254 | } else if(result == -2) { |
255 | ret = 0; |
256 | } else { // failed or not support |
257 | ret = -1; |
258 | } |
259 | |
260 | close(fd); |
261 | fd = -1; |
262 | |
263 | return ret; |
264 | } |
265 | |
266 | /** |
267 | * --- check zip archive image whether encrypt or not |
268 | * image is bootloader.img/boot.img/recovery.img |
269 | * |
270 | * @imageName: image name |
271 | * @imageBuffer: image data address |
272 | * @imageSize: image data size |
273 | * |
274 | * return value: |
275 | * <0: failed |
276 | * =0: unencrypted |
277 | * >0: encrypted |
278 | */ |
279 | static int IsZipArchiveImageEncrypted( |
280 | const char *imageName, |
281 | const unsigned char *imageBuffer, |
282 | const int imageSize) |
283 | { |
284 | int ret = -1; |
285 | const unsigned char *pImageAddr = imageBuffer; |
286 | |
287 | if (strcmp(imageName, BOOT_IMG) && |
288 | strcmp(imageName, RECOVERY_IMG) && |
289 | strcmp(imageName, BOOTLOADER_IMG)) { |
290 | printf("can't support %s at present\n", |
291 | imageName); |
292 | return -1; |
293 | } |
294 | |
295 | if (imageBuffer == NULL) { |
296 | printf("havn't malloc space for %s\n", |
297 | imageName); |
298 | return -1; |
299 | } |
300 | |
301 | if (imageSize <= 0) { |
302 | printf("%s size is %d\n", |
303 | imageName, imageSize); |
304 | return -1; |
305 | } |
306 | |
307 | if (!strcmp(imageName, BOOTLOADER_IMG)) { |
308 | return IsBootloaderImageEncrypted(imageName, imageBuffer); |
309 | } |
310 | |
311 | if (kernel_ver == KernelV_3_10) { |
312 | //check image whether encrypted for kernel 3.10 |
313 | const pT_SecureBootImgHdr encryptSecureBootImgHdr = |
314 | (const pT_SecureBootImgHdr)pImageAddr; |
315 | const pT_EncryptBootImgInfo encryptBootImgInfo = |
316 | &encryptSecureBootImgHdr->encryptBootImgInfo; |
317 | |
318 | secureDbg("magic:%s, version:0x%04x, totalLenAfterEncrypted:0x%0x\n", |
319 | encryptBootImgInfo->magic, encryptBootImgInfo->version, |
320 | encryptBootImgInfo->totalLenAfterEncrypted); |
321 | |
322 | ret = memcmp(encryptBootImgInfo->magic, SECUREBOOT_MAGIC, |
323 | strlen(SECUREBOOT_MAGIC)); |
324 | if (!ret && encryptBootImgInfo->version != 0x0) { |
325 | return 1; // encrypted |
326 | } |
327 | |
328 | return 0; |
329 | } |
330 | |
331 | //check image whether encrypted for kernel 3.14 |
332 | const AmlSecureBootImgHeader encryptSecureBootImgHeader = |
333 | (const AmlSecureBootImgHeader)pImageAddr; |
334 | const p_AmlEncryptBootImgInfo encryptBootImgHeader = |
335 | &encryptSecureBootImgHeader->encrypteImgInfo; |
336 | |
337 | secureDbg("magic:%s, version:0x%04x\n", |
338 | encryptBootImgHeader->magic, encryptBootImgHeader->version); |
339 | |
340 | ret = memcmp(encryptBootImgHeader->magic, SECUREBOOT_MAGIC, |
341 | strlen(SECUREBOOT_MAGIC)); |
342 | if (!ret && encryptBootImgHeader->version != 0x0) { |
343 | return 1; // encrypted |
344 | } |
345 | |
346 | return 0; // unencrypted |
347 | } |
348 | |
349 | /** |
350 | * --- check platform whether encrypt or not |
351 | * |
352 | * return value: |
353 | * <0: failed |
354 | * =0: unencrypted |
355 | * >0: encrypted |
356 | */ |
357 | int IsPlatformEncrypted(void) |
358 | { |
359 | int fd = -1, ret = -1; |
360 | ssize_t count = 0; |
361 | char rBuf[128] = {0}; |
362 | char platform[PROPERTY_VALUE_MAX+1] = {0}; |
363 | |
364 | if (!(access(SECURE_CHECK, F_OK) || (access(SECURE_CHECK_BAK, F_OK))) \ |
365 | || access(DEFEND_KEY, F_OK)) { |
366 | printf("kernel doesn't support secure check\n"); |
367 | return 2; // kernel doesn't support |
368 | } |
369 | |
370 | fd = open(SECURE_CHECK, O_RDONLY); |
371 | if (fd <= 0) { |
372 | fd = open(SECURE_CHECK_BAK, O_RDONLY); |
373 | if (fd <= 0) { |
374 | printf("open %s failed (%s)\n", |
375 | SECURE_CHECK, strerror(errno)); |
376 | return -1; |
377 | } |
378 | kernel_ver = KernelV_3_14; |
379 | } |
380 | |
381 | property_get("ro.build.product", platform, "unknow"); |
382 | count = read(fd, rBuf, sizeof(rBuf) - 1); |
383 | if (count <= 0) { |
384 | printf("read %s failed (count:%d)\n", |
385 | SECURE_CHECK, count); |
386 | close(fd); |
387 | return -1; |
388 | } |
389 | rBuf[count] = '\0'; |
390 | |
391 | if (!strcmp(rBuf, s_pStatus[UNENCRYPT])) { |
392 | printf("check platform(%s): unencrypted\n", platform); |
393 | ret = 0; |
394 | } else if (!strcmp(rBuf, s_pStatus[ENCRYPT])) { |
395 | printf("check platform(%s): encrypted\n", platform); |
396 | ret = 1; |
397 | } else if (!strcmp(rBuf, s_pStatus[FAIL])) { |
398 | printf("check platform(%s): failed\n", platform); |
399 | } else { |
400 | printf("check platform(%s): %s\n", platform, rBuf); |
401 | } |
402 | |
403 | if (fd > 0) { |
404 | close(fd); |
405 | fd = -1; |
406 | } |
407 | |
408 | return ret; |
409 | } |
410 | |
411 | /** |
412 | * --- get upgrade package image data |
413 | * |
414 | * @zipArchive: zip archive object |
415 | * @imageName: upgrade package image's name |
416 | * @imageSize: upgrade package image's size |
417 | * |
418 | * return value: |
419 | * <0: failed |
420 | * =0: can't find image |
421 | * >0: get image data successful |
422 | */ |
423 | static unsigned char *s_pImageBuffer = NULL; |
424 | static int GetZipArchiveImage( |
425 | const ZipArchiveHandle za, |
426 | const char *imageName, |
427 | int *imageSize) |
428 | { |
429 | ZipString zip_path(imageName); |
430 | ZipEntry entry; |
431 | if (FindEntry(za, zip_path, &entry) != 0) { |
432 | printf("no %s in package!\n", imageName); |
433 | return 0; |
434 | } |
435 | |
436 | *imageSize = entry.uncompressed_length; |
437 | if (*imageSize <= 0) { |
438 | printf("can't get package entry uncomp len(%d) (%s)\n", |
439 | *imageSize, strerror(errno)); |
440 | return -1; |
441 | } |
442 | |
443 | if (s_pImageBuffer != NULL) { |
444 | free(s_pImageBuffer); |
445 | s_pImageBuffer = NULL; |
446 | } |
447 | |
448 | s_pImageBuffer = (unsigned char *)calloc(*imageSize, sizeof(unsigned char)); |
449 | if (!s_pImageBuffer) { |
450 | printf("can't malloc %d size space (%s)\n", |
451 | *imageSize, strerror(errno)); |
452 | return -1; |
453 | } |
454 | |
455 | int32_t ret = ExtractToMemory(za, &entry, s_pImageBuffer, entry.uncompressed_length); |
456 | if (ret != 0) { |
457 | printf("can't extract package entry to image buffer\n"); |
458 | goto FREE_IMAGE_MEM; |
459 | } |
460 | |
461 | return 1; |
462 | |
463 | |
464 | FREE_IMAGE_MEM: |
465 | if (s_pImageBuffer != NULL) { |
466 | free(s_pImageBuffer); |
467 | s_pImageBuffer = NULL; |
468 | } |
469 | |
470 | return -1; |
471 | } |
472 | |
473 | /** |
474 | * --- check platform and upgrade package whether |
475 | * encrypted,if all encrypted,rsa whether all the same |
476 | * |
477 | * @ziparchive: Archive of Zip Package |
478 | * |
479 | * return value: |
480 | * =-1: failed; not allow upgrade |
481 | * = 0: check not match; not allow upgrade |
482 | * = 1: check match; allow upgrade |
483 | * = 2: kernel not support secure check; allow upgrade |
484 | */ |
485 | int RecoverySecureCheck(const ZipArchiveHandle zipArchive) |
486 | { |
487 | int i = 0, ret = -1, err = -1; |
488 | int ret_dtb = 0; |
489 | int imageSize = 0; |
490 | int platformEncryptStatus = 0, imageEncryptStatus = 0; |
491 | const char *pImageName[] = { |
492 | BOOTLOADER_IMG, |
493 | BOOT_IMG, |
494 | RECOVERY_IMG }; |
495 | |
496 | platformEncryptStatus = IsPlatformEncrypted(); |
497 | if (platformEncryptStatus == 2) { |
498 | return 2;// kernel doesn't support |
499 | } |
500 | |
501 | if (platformEncryptStatus < 0) { |
502 | return -1; |
503 | } |
504 | |
505 | if (platformEncryptStatus >0 ) { |
506 | ret = GetZipArchiveImage(zipArchive, DTB_IMG, &imageSize); |
507 | if (ret > 0) { |
508 | ret_dtb = DtbImgEncrypted(DTB_IMG, s_pImageBuffer, imageSize, "0", NULL); |
509 | if (ret_dtb == 2) { |
510 | printf("dtb secure check not support!\n"); |
511 | } else if (ret_dtb > 0){ |
512 | printf("dtb secure check success!\n"); |
513 | |
514 | } else { |
515 | printf("dtb secure check error!\n"); |
516 | ret = -1; |
517 | goto ERR1; |
518 | } |
519 | } else if (ret == 0) { |
520 | printf("check %s: not find,skiping...\n", DTB_IMG); |
521 | } else { |
522 | printf("get %s datas failed\n", DTB_IMG); |
523 | goto ERR1; |
524 | } |
525 | } |
526 | |
527 | for (i = 0; i < ARRAY_SIZE(pImageName); i++) { |
528 | ret = GetZipArchiveImage(zipArchive, pImageName[i], &imageSize); |
529 | if (ret < 0) { |
530 | printf("get %s datas failed\n", pImageName[i]); |
531 | goto ERR1; |
532 | } else if (ret == 0) { |
533 | printf("check %s: not find,skiping...\n", pImageName[i]); |
534 | continue; |
535 | } else if (ret > 0) { |
536 | secureDbg("get %s datas(size:0x%0x, addr:0x%x) successful\n", |
537 | pImageName[i], imageSize, (int)s_pImageBuffer); |
538 | imageEncryptStatus = IsZipArchiveImageEncrypted(pImageName[i], s_pImageBuffer, imageSize); |
539 | |
540 | printf("check %s: %s\n", |
541 | pImageName[i], (imageEncryptStatus < 0) ? "failed" : |
542 | !imageEncryptStatus ? "unencrypted" : "encrypted"); |
543 | if (imageEncryptStatus < 0) { |
544 | ret = -1; |
545 | goto ERR1; |
546 | } |
547 | |
548 | ret = IsPlatformMachWithZipArchiveImage( |
549 | platformEncryptStatus, imageEncryptStatus, pImageName[i], |
550 | s_pImageBuffer, imageSize); |
551 | if (ret < 0) { |
552 | printf("%s match platform failed\n", pImageName[i]); |
553 | goto ERR1; |
554 | } else if (ret == 0) { // if one of image doesn't match with platform,exit |
555 | printf("%s doesn't match platform\n", pImageName[i]); |
556 | goto ERR1; |
557 | } else { |
558 | secureDbg("%s match platform\n", pImageName[i]); |
559 | } |
560 | |
561 | if (s_pImageBuffer != NULL) { |
562 | free(s_pImageBuffer); |
563 | s_pImageBuffer = NULL; |
564 | } |
565 | } |
566 | } |
567 | |
568 | return 1; |
569 | |
570 | |
571 | ERR1: |
572 | if (s_pImageBuffer != NULL) { |
573 | free(s_pImageBuffer); |
574 | s_pImageBuffer = NULL; |
575 | } |
576 | |
577 | return ret; |
578 | } |
579 |