diff options
Diffstat (limited to '')
-rw-r--r-- | Android.mk | 1 | ||||
-rw-r--r-- | install.cpp | 30 | ||||
-rw-r--r-- | minzip/SysUtil.c | 152 | ||||
-rw-r--r-- | minzip/SysUtil.h | 38 | ||||
-rw-r--r-- | minzip/Zip.c | 121 | ||||
-rw-r--r-- | minzip/Zip.h | 12 | ||||
-rw-r--r-- | roots.cpp | 10 | ||||
-rw-r--r-- | updater/updater.c | 15 | ||||
-rw-r--r-- | verifier.cpp | 70 | ||||
-rw-r--r-- | verifier.h | 9 | ||||
-rw-r--r-- | verifier_test.cpp | 12 |
11 files changed, 261 insertions, 209 deletions
diff --git a/Android.mk b/Android.mk index c544db964..bd8d09b80 100644 --- a/Android.mk +++ b/Android.mk @@ -98,6 +98,7 @@ LOCAL_SRC_FILES := \ LOCAL_STATIC_LIBRARIES := \ libmincrypt \ libminui \ + libminzip \ libcutils \ libstdc++ \ libc diff --git a/install.cpp b/install.cpp index 980830cc0..0bd7945c4 100644 --- a/install.cpp +++ b/install.cpp @@ -186,12 +186,22 @@ really_install_package(const char *path, int* wipe_cache) ui->ShowProgress(VERIFICATION_PROGRESS_FRACTION, VERIFICATION_PROGRESS_TIME); LOGI("Update location: %s\n", path); - if (ensure_path_mounted(path) != 0) { - LOGE("Can't mount %s\n", path); - return INSTALL_CORRUPT; + // Map the update package into memory. + ui->Print("Opening update package...\n"); + + if (path) { + if (path[0] == '@') { + ensure_path_mounted(path+1); + } else { + ensure_path_mounted(path); + } } - ui->Print("Opening update package...\n"); + MemMapping map; + if (sysMapFile(path, &map) != 0) { + LOGE("failed to map file\n"); + return INSTALL_CORRUPT; + } int numKeys; Certificate* loadedKeys = load_keys(PUBLIC_KEYS_FILE, &numKeys); @@ -204,27 +214,33 @@ really_install_package(const char *path, int* wipe_cache) ui->Print("Verifying update package...\n"); int err; - err = verify_file(path, loadedKeys, numKeys); + err = verify_file(map.addr, map.length, loadedKeys, numKeys); free(loadedKeys); LOGI("verify_file returned %d\n", err); if (err != VERIFY_SUCCESS) { LOGE("signature verification failed\n"); + sysReleaseMap(&map); return INSTALL_CORRUPT; } /* Try to open the package. */ ZipArchive zip; - err = mzOpenZipArchive(path, &zip); + err = mzOpenZipArchive(map.addr, map.length, &zip); if (err != 0) { LOGE("Can't open %s\n(%s)\n", path, err != -1 ? strerror(err) : "bad"); + sysReleaseMap(&map); return INSTALL_CORRUPT; } /* Verify and install the contents of the package. */ ui->Print("Installing update...\n"); - return try_update_binary(path, &zip, wipe_cache); + int result = try_update_binary(path, &zip, wipe_cache); + + sysReleaseMap(&map); + + return result; } int diff --git a/minzip/SysUtil.c b/minzip/SysUtil.c index e6f650644..2cfa39ae3 100644 --- a/minzip/SysUtil.c +++ b/minzip/SysUtil.c @@ -8,11 +8,14 @@ #include <unistd.h> #include <string.h> #include <sys/mman.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> #include <limits.h> #include <errno.h> #include <assert.h> -#define LOG_TAG "minzip" +#define LOG_TAG "sysutil" #include "Log.h" #include "SysUtil.h" @@ -46,13 +49,13 @@ static int getFileStartAndLength(int fd, off_t *start_, size_t *length_) } /* - * Map a file (from fd's current offset) into a shared, read-only memory + * Map a file (from fd's current offset) into a private, read-only memory * segment. The file offset must be a multiple of the page size. * * On success, returns 0 and fills out "pMap". On failure, returns a nonzero * value and does not disturb "pMap". */ -int sysMapFileInShmem(int fd, MemMapping* pMap) +static int sysMapFD(int fd, MemMapping* pMap) { off_t start; size_t length; @@ -63,33 +66,146 @@ int sysMapFileInShmem(int fd, MemMapping* pMap) if (getFileStartAndLength(fd, &start, &length) < 0) return -1; - memPtr = mmap(NULL, length, PROT_READ, MAP_FILE | MAP_SHARED, fd, start); + memPtr = mmap(NULL, length, PROT_READ, MAP_PRIVATE, fd, start); if (memPtr == MAP_FAILED) { - LOGW("mmap(%d, R, FILE|SHARED, %d, %d) failed: %s\n", (int) length, + LOGW("mmap(%d, R, PRIVATE, %d, %d) failed: %s\n", (int) length, fd, (int) start, strerror(errno)); return -1; } - pMap->baseAddr = pMap->addr = memPtr; - pMap->baseLength = pMap->length = length; + pMap->addr = memPtr; + pMap->length = length; + pMap->range_count = 1; + pMap->ranges = malloc(sizeof(MappedRange)); + pMap->ranges[0].addr = memPtr; + pMap->ranges[0].length = length; return 0; } +static int sysMapBlockFile(FILE* mapf, MemMapping* pMap) +{ + char block_dev[PATH_MAX+1]; + size_t size; + unsigned int blksize; + unsigned int blocks; + unsigned int range_count; + unsigned int i; + + if (fgets(block_dev, sizeof(block_dev), mapf) == NULL) { + LOGW("failed to read block device from header\n"); + return -1; + } + for (i = 0; i < sizeof(block_dev); ++i) { + if (block_dev[i] == '\n') { + block_dev[i] = 0; + break; + } + } + + if (fscanf(mapf, "%d %d\n%d\n", &size, &blksize, &range_count) != 3) { + LOGW("failed to parse block map header\n"); + return -1; + } + + blocks = ((size-1) / blksize) + 1; + + pMap->range_count = range_count; + pMap->ranges = malloc(range_count * sizeof(MappedRange)); + memset(pMap->ranges, 0, range_count * sizeof(MappedRange)); + + // Reserve enough contiguous address space for the whole file. + unsigned char* reserve; + reserve = mmap64(NULL, blocks * blksize, PROT_NONE, MAP_PRIVATE | MAP_ANON, -1, 0); + if (reserve == MAP_FAILED) { + LOGW("failed to reserve address space: %s\n", strerror(errno)); + return -1; + } + + pMap->ranges[range_count-1].addr = reserve; + pMap->ranges[range_count-1].length = blocks * blksize; + + int fd = open(block_dev, O_RDONLY); + if (fd < 0) { + LOGW("failed to open block device %s: %s\n", block_dev, strerror(errno)); + return -1; + } + + unsigned char* next = reserve; + for (i = 0; i < range_count; ++i) { + int start, end; + if (fscanf(mapf, "%d %d\n", &start, &end) != 2) { + LOGW("failed to parse range %d in block map\n", i); + return -1; + } + + void* addr = mmap64(next, (end-start)*blksize, PROT_READ, MAP_PRIVATE | MAP_FIXED, fd, ((off64_t)start)*blksize); + if (addr == MAP_FAILED) { + LOGW("failed to map block %d: %s\n", i, strerror(errno)); + return -1; + } + pMap->ranges[i].addr = addr; + pMap->ranges[i].length = (end-start)*blksize; + + next += pMap->ranges[i].length; + } + + pMap->addr = reserve; + pMap->length = size; + + return 0; +} + +int sysMapFile(const char* fn, MemMapping* pMap) +{ + memset(pMap, 0, sizeof(*pMap)); + + if (fn && fn[0] == '@') { + // A map of blocks + FILE* mapf = fopen(fn+1, "r"); + if (mapf == NULL) { + LOGV("Unable to open '%s': %s\n", fn+1, strerror(errno)); + return -1; + } + + if (sysMapBlockFile(mapf, pMap) != 0) { + LOGW("Map of '%s' failed\n", fn); + return -1; + } + + fclose(mapf); + } else { + // This is a regular file. + int fd = open(fn, O_RDONLY, 0); + if (fd < 0) { + LOGE("Unable to open '%s': %s\n", fn, strerror(errno)); + return -1; + } + + if (sysMapFD(fd, pMap) != 0) { + LOGE("Map of '%s' failed\n", fn); + close(fd); + return -1; + } + + close(fd); + } + return 0; +} + /* * Release a memory mapping. */ -void sysReleaseShmem(MemMapping* pMap) +void sysReleaseMap(MemMapping* pMap) { - if (pMap->baseAddr == NULL && pMap->baseLength == 0) - return; - - if (munmap(pMap->baseAddr, pMap->baseLength) < 0) { - LOGW("munmap(%p, %d) failed: %s\n", - pMap->baseAddr, (int)pMap->baseLength, strerror(errno)); - } else { - LOGV("munmap(%p, %d) succeeded\n", pMap->baseAddr, pMap->baseLength); - pMap->baseAddr = NULL; - pMap->baseLength = 0; + int i; + for (i = 0; i < pMap->range_count; ++i) { + if (munmap(pMap->ranges[i].addr, pMap->ranges[i].length) < 0) { + LOGW("munmap(%p, %d) failed: %s\n", + pMap->ranges[i].addr, (int)pMap->ranges[i].length, strerror(errno)); + } } + free(pMap->ranges); + pMap->ranges = NULL; + pMap->range_count = 0; } diff --git a/minzip/SysUtil.h b/minzip/SysUtil.h index 55cd0e769..7adff1e54 100644 --- a/minzip/SysUtil.h +++ b/minzip/SysUtil.h @@ -6,39 +6,47 @@ #ifndef _MINZIP_SYSUTIL #define _MINZIP_SYSUTIL -#include "inline_magic.h" - +#include <stdio.h> #include <sys/types.h> +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct MappedRange { + void* addr; + size_t length; +} MappedRange; + /* * Use this to keep track of mapped segments. */ typedef struct MemMapping { - void* addr; /* start of data */ - size_t length; /* length of data */ + unsigned char* addr; /* start of data */ + size_t length; /* length of data */ - void* baseAddr; /* page-aligned base address */ - size_t baseLength; /* length of mapping */ + int range_count; + MappedRange* ranges; } MemMapping; -/* copy a map */ -INLINE void sysCopyMap(MemMapping* dst, const MemMapping* src) { - *dst = *src; -} - /* - * Map a file (from fd's current offset) into a shared, - * read-only memory segment. + * Map a file into a private, read-only memory segment. If 'fn' + * begins with an '@' character, it is a map of blocks to be mapped, + * otherwise it is treated as an ordinary file. * * On success, "pMap" is filled in, and zero is returned. */ -int sysMapFileInShmem(int fd, MemMapping* pMap); +int sysMapFile(const char* fn, MemMapping* pMap); /* * Release the pages associated with a shared memory segment. * * This does not free "pMap"; it just releases the memory. */ -void sysReleaseShmem(MemMapping* pMap); +void sysReleaseMap(MemMapping* pMap); + +#ifdef __cplusplus +} +#endif #endif /*_MINZIP_SYSUTIL*/ diff --git a/minzip/Zip.c b/minzip/Zip.c index 439e5d9cd..6752bced5 100644 --- a/minzip/Zip.c +++ b/minzip/Zip.c @@ -184,7 +184,7 @@ static int validFilename(const char *fileName, unsigned int fileNameLen) * * Returns "true" on success. */ -static bool parseZipArchive(ZipArchive* pArchive, const MemMapping* pMap) +static bool parseZipArchive(ZipArchive* pArchive) { bool result = false; const unsigned char* ptr; @@ -196,7 +196,7 @@ static bool parseZipArchive(ZipArchive* pArchive, const MemMapping* pMap) * signature for the first file (LOCSIG) or, if the archive doesn't * have any files in it, the end-of-central-directory signature (ENDSIG). */ - val = get4LE(pMap->addr); + val = get4LE(pArchive->addr); if (val == ENDSIG) { LOGI("Found Zip archive, but it looks empty\n"); goto bail; @@ -209,14 +209,14 @@ static bool parseZipArchive(ZipArchive* pArchive, const MemMapping* pMap) * Find the EOCD. We'll find it immediately unless they have a file * comment. */ - ptr = pMap->addr + pMap->length - ENDHDR; + ptr = pArchive->addr + pArchive->length - ENDHDR; - while (ptr >= (const unsigned char*) pMap->addr) { + while (ptr >= (const unsigned char*) pArchive->addr) { if (*ptr == (ENDSIG & 0xff) && get4LE(ptr) == ENDSIG) break; ptr--; } - if (ptr < (const unsigned char*) pMap->addr) { + if (ptr < (const unsigned char*) pArchive->addr) { LOGI("Could not find end-of-central-directory in Zip\n"); goto bail; } @@ -230,9 +230,9 @@ static bool parseZipArchive(ZipArchive* pArchive, const MemMapping* pMap) cdOffset = get4LE(ptr + ENDOFF); LOGVV("numEntries=%d cdOffset=%d\n", numEntries, cdOffset); - if (numEntries == 0 || cdOffset >= pMap->length) { + if (numEntries == 0 || cdOffset >= pArchive->length) { LOGW("Invalid entries=%d offset=%d (len=%zd)\n", - numEntries, cdOffset, pMap->length); + numEntries, cdOffset, pArchive->length); goto bail; } @@ -245,14 +245,14 @@ static bool parseZipArchive(ZipArchive* pArchive, const MemMapping* pMap) if (pArchive->pEntries == NULL || pArchive->pHash == NULL) goto bail; - ptr = pMap->addr + cdOffset; + ptr = pArchive->addr + cdOffset; for (i = 0; i < numEntries; i++) { ZipEntry* pEntry; unsigned int fileNameLen, extraLen, commentLen, localHdrOffset; const unsigned char* localHdr; const char *fileName; - if (ptr + CENHDR > (const unsigned char*)pMap->addr + pMap->length) { + if (ptr + CENHDR > (const unsigned char*)pArchive->addr + pArchive->length) { LOGW("Ran off the end (at %d)\n", i); goto bail; } @@ -266,7 +266,7 @@ static bool parseZipArchive(ZipArchive* pArchive, const MemMapping* pMap) extraLen = get2LE(ptr + CENEXT); commentLen = get2LE(ptr + CENCOM); fileName = (const char*)ptr + CENHDR; - if (fileName + fileNameLen > (const char*)pMap->addr + pMap->length) { + if (fileName + fileNameLen > (const char*)pArchive->addr + pArchive->length) { LOGW("Filename ran off the end (at %d)\n", i); goto bail; } @@ -352,15 +352,15 @@ static bool parseZipArchive(ZipArchive* pArchive, const MemMapping* pMap) } pEntry->externalFileAttributes = get4LE(ptr + CENATX); - // Perform pMap->addr + localHdrOffset, ensuring that it won't + // Perform pArchive->addr + localHdrOffset, ensuring that it won't // overflow. This is needed because localHdrOffset is untrusted. - if (!safe_add((uintptr_t *)&localHdr, (uintptr_t)pMap->addr, + if (!safe_add((uintptr_t *)&localHdr, (uintptr_t)pArchive->addr, (uintptr_t)localHdrOffset)) { LOGW("Integer overflow adding in parseZipArchive\n"); goto bail; } if ((uintptr_t)localHdr + LOCHDR > - (uintptr_t)pMap->addr + pMap->length) { + (uintptr_t)pArchive->addr + pArchive->length) { LOGW("Bad offset to local header: %d (at %d)\n", localHdrOffset, i); goto bail; } @@ -374,7 +374,7 @@ static bool parseZipArchive(ZipArchive* pArchive, const MemMapping* pMap) LOGW("Integer overflow adding in parseZipArchive\n"); goto bail; } - if ((size_t)pEntry->offset + pEntry->compLen > pMap->length) { + if ((size_t)pEntry->offset + pEntry->compLen > pArchive->length) { LOGW("Data ran off the end (at %d)\n", i); goto bail; } @@ -427,50 +427,30 @@ bail: * * On success, we fill out the contents of "pArchive". */ -int mzOpenZipArchive(const char* fileName, ZipArchive* pArchive) +int mzOpenZipArchive(unsigned char* addr, size_t length, ZipArchive* pArchive) { - MemMapping map; int err; - LOGV("Opening archive '%s' %p\n", fileName, pArchive); - - map.addr = NULL; - memset(pArchive, 0, sizeof(*pArchive)); - - pArchive->fd = open(fileName, O_RDONLY, 0); - if (pArchive->fd < 0) { - err = errno ? errno : -1; - LOGV("Unable to open '%s': %s\n", fileName, strerror(err)); - goto bail; - } - - if (sysMapFileInShmem(pArchive->fd, &map) != 0) { - err = -1; - LOGW("Map of '%s' failed\n", fileName); - goto bail; - } - - if (map.length < ENDHDR) { + if (length < ENDHDR) { err = -1; LOGV("File '%s' too small to be zip (%zd)\n", fileName, map.length); goto bail; } - if (!parseZipArchive(pArchive, &map)) { + pArchive->addr = addr; + pArchive->length = length; + + if (!parseZipArchive(pArchive)) { err = -1; LOGV("Parsing '%s' failed\n", fileName); goto bail; } err = 0; - sysCopyMap(&pArchive->map, &map); - map.addr = NULL; bail: if (err != 0) mzCloseZipArchive(pArchive); - if (map.addr != NULL) - sysReleaseShmem(&map); return err; } @@ -483,16 +463,10 @@ void mzCloseZipArchive(ZipArchive* pArchive) { LOGV("Closing archive %p\n", pArchive); - if (pArchive->fd >= 0) - close(pArchive->fd); - if (pArchive->map.addr != NULL) - sysReleaseShmem(&pArchive->map); - free(pArchive->pEntries); mzHashTableFree(pArchive->pHash); - pArchive->fd = -1; pArchive->pHash = NULL; pArchive->pEntries = NULL; } @@ -528,29 +502,7 @@ static bool processStoredEntry(const ZipArchive *pArchive, const ZipEntry *pEntry, ProcessZipEntryContentsFunction processFunction, void *cookie) { - size_t bytesLeft = pEntry->compLen; - while (bytesLeft > 0) { - unsigned char buf[32 * 1024]; - ssize_t n; - size_t count; - bool ret; - - count = bytesLeft; - if (count > sizeof(buf)) { - count = sizeof(buf); - } - n = read(pArchive->fd, buf, count); - if (n < 0 || (size_t)n != count) { - LOGE("Can't read %zu bytes from zip file: %ld\n", count, n); - return false; - } - ret = processFunction(buf, n, cookie); - if (!ret) { - return false; - } - bytesLeft -= count; - } - return true; + return processFunction(pArchive->addr + pEntry->offset, pEntry->uncompLen, cookie); } static bool processDeflatedEntry(const ZipArchive *pArchive, @@ -573,8 +525,8 @@ static bool processDeflatedEntry(const ZipArchive *pArchive, zstream.zalloc = Z_NULL; zstream.zfree = Z_NULL; zstream.opaque = Z_NULL; - zstream.next_in = NULL; - zstream.avail_in = 0; + zstream.next_in = pArchive->addr + pEntry->offset; + zstream.avail_in = pEntry->compLen; zstream.next_out = (Bytef*) procBuf; zstream.avail_out = sizeof(procBuf); zstream.data_type = Z_UNKNOWN; @@ -598,25 +550,6 @@ static bool processDeflatedEntry(const ZipArchive *pArchive, * Loop while we have data. */ do { - /* read as much as we can */ - if (zstream.avail_in == 0) { - long getSize = (compRemaining > (long)sizeof(readBuf)) ? - (long)sizeof(readBuf) : compRemaining; - LOGVV("+++ reading %ld bytes (%ld left)\n", - getSize, compRemaining); - - int cc = read(pArchive->fd, readBuf, getSize); - if (cc != (int) getSize) { - LOGW("inflate read failed (%d vs %ld)\n", cc, getSize); - goto z_bail; - } - - compRemaining -= getSize; - - zstream.next_in = readBuf; - zstream.avail_in = getSize; - } - /* uncompress the data */ zerr = inflate(&zstream, Z_NO_FLUSH); if (zerr != Z_OK && zerr != Z_STREAM_END) { @@ -676,12 +609,6 @@ bool mzProcessZipEntryContents(const ZipArchive *pArchive, bool ret = false; off_t oldOff; - /* save current offset */ - oldOff = lseek(pArchive->fd, 0, SEEK_CUR); - - /* Seek to the beginning of the entry's compressed data. */ - lseek(pArchive->fd, pEntry->offset, SEEK_SET); - switch (pEntry->compression) { case STORED: ret = processStoredEntry(pArchive, pEntry, processFunction, cookie); @@ -695,8 +622,6 @@ bool mzProcessZipEntryContents(const ZipArchive *pArchive, break; } - /* restore file offset */ - lseek(pArchive->fd, oldOff, SEEK_SET); return ret; } diff --git a/minzip/Zip.h b/minzip/Zip.h index c94282827..05a2e60e0 100644 --- a/minzip/Zip.h +++ b/minzip/Zip.h @@ -46,11 +46,11 @@ typedef struct ZipEntry { * One Zip archive. Treat as opaque. */ typedef struct ZipArchive { - int fd; - unsigned int numEntries; - ZipEntry* pEntries; - HashTable* pHash; // maps file name to ZipEntry - MemMapping map; + unsigned int numEntries; + ZipEntry* pEntries; + HashTable* pHash; // maps file name to ZipEntry + unsigned char* addr; + size_t length; } ZipArchive; /* @@ -68,7 +68,7 @@ typedef struct { * On success, returns 0 and populates "pArchive". Returns nonzero errno * value on failure. */ -int mzOpenZipArchive(const char* fileName, ZipArchive* pArchive); +int mzOpenZipArchive(unsigned char* addr, size_t length, ZipArchive* pArchive); /* * Close archive, releasing resources associated with it. @@ -238,10 +238,16 @@ int setup_install_mounts() { if (strcmp(v->mount_point, "/tmp") == 0 || strcmp(v->mount_point, "/cache") == 0) { - if (ensure_path_mounted(v->mount_point) != 0) return -1; + if (ensure_path_mounted(v->mount_point) != 0) { + LOGE("failed to mount %s\n", v->mount_point); + return -1; + } } else { - if (ensure_path_unmounted(v->mount_point) != 0) return -1; + if (ensure_path_unmounted(v->mount_point) != 0) { + LOGE("failed to unmount %s\n", v->mount_point); + return -1; + } } } return 0; diff --git a/updater/updater.c b/updater/updater.c index c7009feac..4e1cc9c38 100644 --- a/updater/updater.c +++ b/updater/updater.c @@ -22,6 +22,7 @@ #include "updater.h" #include "install.h" #include "minzip/Zip.h" +#include "minzip/SysUtil.h" // Generated by the makefile, this function defines the // RegisterDeviceExtensions() function, which calls all the @@ -65,19 +66,24 @@ int main(int argc, char** argv) { // Extract the script from the package. - char* package_data = argv[3]; + const char* package_filename = argv[3]; + MemMapping map; + if (sysMapFile(package_filename, &map) != 0) { + printf("failed to map package %s\n", argv[3]); + return 3; + } ZipArchive za; int err; - err = mzOpenZipArchive(package_data, &za); + err = mzOpenZipArchive(map.addr, map.length, &za); if (err != 0) { printf("failed to open package %s: %s\n", - package_data, strerror(err)); + argv[3], strerror(err)); return 3; } const ZipEntry* script_entry = mzFindZipEntry(&za, SCRIPT_NAME); if (script_entry == NULL) { - printf("failed to find %s in %s\n", SCRIPT_NAME, package_data); + printf("failed to find %s in %s\n", SCRIPT_NAME, package_filename); return 4; } @@ -152,6 +158,7 @@ int main(int argc, char** argv) { if (updater_info.package_zip) { mzCloseZipArchive(updater_info.package_zip); } + sysReleaseMap(&map); free(script); return 0; diff --git a/verifier.cpp b/verifier.cpp index 0930fbd15..55d58ee22 100644 --- a/verifier.cpp +++ b/verifier.cpp @@ -111,15 +111,10 @@ static bool read_pkcs7(uint8_t* pkcs7_der, size_t pkcs7_der_len, uint8_t** sig_d // Return VERIFY_SUCCESS, VERIFY_FAILURE (if any error is encountered // or no key matches the signature). -int verify_file(const char* path, const Certificate* pKeys, unsigned int numKeys) { +int verify_file(unsigned char* addr, size_t length, + const Certificate* pKeys, unsigned int numKeys) { ui->SetProgress(0.0); - FILE* f = fopen(path, "rb"); - if (f == NULL) { - LOGE("failed to open %s (%s)\n", path, strerror(errno)); - return VERIFY_FAILURE; - } - // An archive with a whole-file signature will end in six bytes: // // (2-byte signature start) $ff $ff (2-byte comment size) @@ -131,22 +126,15 @@ int verify_file(const char* path, const Certificate* pKeys, unsigned int numKeys #define FOOTER_SIZE 6 - if (fseek(f, -FOOTER_SIZE, SEEK_END) != 0) { - LOGE("failed to seek in %s (%s)\n", path, strerror(errno)); - fclose(f); + if (length < FOOTER_SIZE) { + LOGE("not big enough to contain footer\n"); return VERIFY_FAILURE; } - unsigned char footer[FOOTER_SIZE]; - if (fread(footer, 1, FOOTER_SIZE, f) != FOOTER_SIZE) { - LOGE("failed to read footer from %s (%s)\n", path, strerror(errno)); - fclose(f); - return VERIFY_FAILURE; - } + unsigned char* footer = addr + length - FOOTER_SIZE; if (footer[2] != 0xff || footer[3] != 0xff) { LOGE("footer is wrong\n"); - fclose(f); return VERIFY_FAILURE; } @@ -157,7 +145,6 @@ int verify_file(const char* path, const Certificate* pKeys, unsigned int numKeys if (signature_start <= FOOTER_SIZE) { LOGE("Signature start is in the footer"); - fclose(f); return VERIFY_FAILURE; } @@ -167,9 +154,8 @@ int verify_file(const char* path, const Certificate* pKeys, unsigned int numKeys // comment length. size_t eocd_size = comment_size + EOCD_HEADER_SIZE; - if (fseek(f, -eocd_size, SEEK_END) != 0) { - LOGE("failed to seek in %s (%s)\n", path, strerror(errno)); - fclose(f); + if (length < eocd_size) { + LOGE("not big enough to contain EOCD\n"); return VERIFY_FAILURE; } @@ -177,26 +163,15 @@ int verify_file(const char* path, const Certificate* pKeys, unsigned int numKeys // This is everything except the signature data and length, which // includes all of the EOCD except for the comment length field (2 // bytes) and the comment data. - size_t signed_len = ftell(f) + EOCD_HEADER_SIZE - 2; + size_t signed_len = length - eocd_size + EOCD_HEADER_SIZE - 2; - unsigned char* eocd = (unsigned char*)malloc(eocd_size); - if (eocd == NULL) { - LOGE("malloc for EOCD record failed\n"); - fclose(f); - return VERIFY_FAILURE; - } - if (fread(eocd, 1, eocd_size, f) != eocd_size) { - LOGE("failed to read eocd from %s (%s)\n", path, strerror(errno)); - fclose(f); - return VERIFY_FAILURE; - } + unsigned char* eocd = addr + length - eocd_size; // If this is really is the EOCD record, it will begin with the // magic number $50 $4b $05 $06. if (eocd[0] != 0x50 || eocd[1] != 0x4b || eocd[2] != 0x05 || eocd[3] != 0x06) { LOGE("signature length doesn't match EOCD marker\n"); - fclose(f); return VERIFY_FAILURE; } @@ -209,7 +184,6 @@ int verify_file(const char* path, const Certificate* pKeys, unsigned int numKeys // which could be exploitable. Fail verification if // this sequence occurs anywhere after the real one. LOGE("EOCD marker occurs after start of EOCD\n"); - fclose(f); return VERIFY_FAILURE; } } @@ -229,35 +203,23 @@ int verify_file(const char* path, const Certificate* pKeys, unsigned int numKeys SHA256_CTX sha256_ctx; SHA_init(&sha1_ctx); SHA256_init(&sha256_ctx); - unsigned char* buffer = (unsigned char*)malloc(BUFFER_SIZE); - if (buffer == NULL) { - LOGE("failed to alloc memory for sha1 buffer\n"); - fclose(f); - return VERIFY_FAILURE; - } double frac = -1.0; size_t so_far = 0; - fseek(f, 0, SEEK_SET); while (so_far < signed_len) { - size_t size = BUFFER_SIZE; - if (signed_len - so_far < size) size = signed_len - so_far; - if (fread(buffer, 1, size, f) != size) { - LOGE("failed to read data from %s (%s)\n", path, strerror(errno)); - fclose(f); - return VERIFY_FAILURE; - } - if (need_sha1) SHA_update(&sha1_ctx, buffer, size); - if (need_sha256) SHA256_update(&sha256_ctx, buffer, size); + size_t size = signed_len - so_far; + if (size > BUFFER_SIZE) size = BUFFER_SIZE; + + if (need_sha1) SHA_update(&sha1_ctx, addr + so_far, size); + if (need_sha256) SHA256_update(&sha256_ctx, addr + so_far, size); so_far += size; + double f = so_far / (double)signed_len; if (f > frac + 0.02 || size == so_far) { ui->SetProgress(f); frac = f; } } - fclose(f); - free(buffer); const uint8_t* sha1 = SHA_final(&sha1_ctx); const uint8_t* sha256 = SHA256_final(&sha256_ctx); @@ -269,10 +231,8 @@ int verify_file(const char* path, const Certificate* pKeys, unsigned int numKeys if (!read_pkcs7(eocd + eocd_size - signature_start, signature_size, &sig_der, &sig_der_length)) { LOGE("Could not find signature DER block\n"); - free(eocd); return VERIFY_FAILURE; } - free(eocd); /* * Check to make sure at least one of the keys matches the signature. Since diff --git a/verifier.h b/verifier.h index 023d3bf89..15f8d98e4 100644 --- a/verifier.h +++ b/verifier.h @@ -37,10 +37,13 @@ typedef struct { ECPublicKey* ec; } Certificate; -/* Look in the file for a signature footer, and verify that it - * matches one of the given keys. Return one of the constants below. +/* addr and length define a an update package file that has been + * loaded (or mmap'ed, or whatever) into memory. Verify that the file + * is signed and the signature matches one of the given keys. Return + * one of the constants below. */ -int verify_file(const char* path, const Certificate *pKeys, unsigned int numKeys); +int verify_file(unsigned char* addr, size_t length, + const Certificate *pKeys, unsigned int numKeys); Certificate* load_keys(const char* filename, int* numKeys); diff --git a/verifier_test.cpp b/verifier_test.cpp index 88fcad4ea..10a5ddaad 100644 --- a/verifier_test.cpp +++ b/verifier_test.cpp @@ -17,12 +17,16 @@ #include <stdio.h> #include <stdlib.h> #include <stdarg.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> #include "common.h" #include "verifier.h" #include "ui.h" #include "mincrypt/sha.h" #include "mincrypt/sha256.h" +#include "minzip/SysUtil.h" // This is build/target/product/security/testkey.x509.pem after being // dumped out by dumpkey.jar. @@ -227,7 +231,13 @@ int main(int argc, char **argv) { ui = new FakeUI(); - int result = verify_file(argv[argn], certs, num_keys); + MemMapping map; + if (sysMapFile(argv[argn], &map) != 0) { + fprintf(stderr, "failed to mmap %s: %s\n", argv[argn], strerror(errno)); + return 4; + } + + int result = verify_file(map.addr, map.length, certs, num_keys); if (result == VERIFY_SUCCESS) { printf("VERIFIED\n"); return 0; |