summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Android.mk21
-rw-r--r--README.md17
-rw-r--r--applypatch/Android.mk30
-rw-r--r--applypatch/Makefile32
-rw-r--r--applypatch/applypatch.cpp346
-rw-r--r--applypatch/applypatch.h28
-rw-r--r--applypatch/bsdiff.cpp1
-rw-r--r--applypatch/bspatch.cpp41
-rw-r--r--applypatch/freecache.cpp141
-rw-r--r--applypatch/imgdiff.cpp24
-rw-r--r--applypatch/imgpatch.cpp84
-rw-r--r--applypatch/include/applypatch/imgpatch.h26
-rw-r--r--applypatch/libimgpatch.pc6
-rw-r--r--applypatch/main.cpp116
-rw-r--r--bootloader.cpp133
-rw-r--r--edify/lexer.ll24
-rw-r--r--edify/main.cpp5
-rw-r--r--install.cpp23
-rw-r--r--minadbd/services.cpp3
-rw-r--r--minui/resources.cpp22
-rw-r--r--minzip/Android.mk2
-rw-r--r--minzip/DirUtil.cpp (renamed from minzip/DirUtil.c)61
-rw-r--r--otafault/Android.mk58
-rw-r--r--otafault/ota_io.cpp160
-rw-r--r--otafault/ota_io.h49
-rw-r--r--otafault/test.cpp32
-rw-r--r--print_sha1.h10
-rw-r--r--tests/Android.mk35
-rw-r--r--tests/component/verifier_test.cpp (renamed from verifier_test.cpp)212
-rw-r--r--tests/testdata/alter-footer.zip (renamed from testdata/alter-footer.zip)bin4009 -> 4009 bytes
-rw-r--r--tests/testdata/alter-metadata.zip (renamed from testdata/alter-metadata.zip)bin4009 -> 4009 bytes
-rw-r--r--tests/testdata/fake-eocd.zip (renamed from testdata/fake-eocd.zip)bin4313 -> 4313 bytes
-rw-r--r--tests/testdata/jarsigned.zip (renamed from testdata/jarsigned.zip)bin2271 -> 2271 bytes
-rw-r--r--tests/testdata/otasigned.zip (renamed from testdata/otasigned.zip)bin4009 -> 4009 bytes
-rw-r--r--tests/testdata/otasigned_ecdsa_sha256.zip (renamed from testdata/otasigned_ecdsa_sha256.zip)bin3085 -> 3085 bytes
-rw-r--r--tests/testdata/otasigned_f4.zip (renamed from testdata/otasigned_f4.zip)bin5195 -> 5195 bytes
-rw-r--r--tests/testdata/otasigned_f4_sha256.zip (renamed from testdata/otasigned_f4_sha256.zip)bin5319 -> 5319 bytes
-rw-r--r--tests/testdata/otasigned_sha256.zip (renamed from testdata/otasigned_sha256.zip)bin5326 -> 5326 bytes
-rw-r--r--tests/testdata/random.zip (renamed from testdata/random.zip)bin1024 -> 1024 bytes
-rw-r--r--tests/testdata/test_f4.pk8 (renamed from testdata/test_f4.pk8)bin1217 -> 1217 bytes
-rw-r--r--tests/testdata/test_f4.x509.pem (renamed from testdata/test_f4.x509.pem)0
-rw-r--r--tests/testdata/test_f4_sha256.x509.pem (renamed from testdata/test_f4_sha256.x509.pem)0
-rw-r--r--tests/testdata/testkey.pk8 (renamed from testdata/testkey.pk8)bin1217 -> 1217 bytes
-rw-r--r--tests/testdata/testkey.x509.pem (renamed from testdata/testkey.x509.pem)0
-rw-r--r--tests/testdata/testkey_ecdsa.pk8 (renamed from testdata/testkey_ecdsa.pk8)bin138 -> 138 bytes
-rw-r--r--tests/testdata/testkey_ecdsa.x509.pem (renamed from testdata/testkey_ecdsa.x509.pem)0
-rw-r--r--tests/testdata/testkey_sha256.x509.pem (renamed from testdata/testkey_sha256.x509.pem)0
-rw-r--r--tests/testdata/unsigned.zip (renamed from testdata/unsigned.zip)bin376 -> 376 bytes
-rw-r--r--tests/unit/asn1_decoder_test.cpp (renamed from tests/asn1_decoder_test.cpp)0
-rw-r--r--uncrypt/uncrypt.cpp432
-rw-r--r--uncrypt/uncrypt.rc10
-rw-r--r--updater/Android.mk4
-rw-r--r--updater/blockimg.cpp44
-rw-r--r--updater/install.cpp159
-rw-r--r--verifier.cpp265
-rw-r--r--verifier.h23
-rwxr-xr-xverifier_test.sh121
57 files changed, 1532 insertions, 1268 deletions
diff --git a/Android.mk b/Android.mk
index 602a85673..4da34eef5 100644
--- a/Android.mk
+++ b/Android.mk
@@ -104,28 +104,10 @@ LOCAL_CLANG := true
LOCAL_MODULE := libverifier
LOCAL_MODULE_TAGS := tests
LOCAL_SRC_FILES := \
- asn1_decoder.cpp
-include $(BUILD_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_CLANG := true
-LOCAL_MODULE := verifier_test
-LOCAL_FORCE_STATIC_EXECUTABLE := true
-LOCAL_MODULE_TAGS := tests
-LOCAL_CFLAGS += -Wno-unused-parameter
-LOCAL_SRC_FILES := \
- verifier_test.cpp \
asn1_decoder.cpp \
verifier.cpp \
ui.cpp
-LOCAL_STATIC_LIBRARIES := \
- libmincrypt \
- libminui \
- libminzip \
- libcutils \
- libc
-include $(BUILD_EXECUTABLE)
-
+include $(BUILD_STATIC_LIBRARY)
include $(LOCAL_PATH)/minui/Android.mk \
$(LOCAL_PATH)/minzip/Android.mk \
@@ -135,6 +117,7 @@ include $(LOCAL_PATH)/minui/Android.mk \
$(LOCAL_PATH)/tools/Android.mk \
$(LOCAL_PATH)/edify/Android.mk \
$(LOCAL_PATH)/uncrypt/Android.mk \
+ $(LOCAL_PATH)/otafault/Android.mk \
$(LOCAL_PATH)/updater/Android.mk \
$(LOCAL_PATH)/update_verifier/Android.mk \
$(LOCAL_PATH)/applypatch/Android.mk
diff --git a/README.md b/README.md
index bab7e87cd..01fab9465 100644
--- a/README.md
+++ b/README.md
@@ -10,3 +10,20 @@ Quick turn-around testing
# without flashing the recovery partition:
adb reboot bootloader
fastboot boot $ANDROID_PRODUCT_OUT/recovery.img
+
+Running the tests
+-----------------
+ # After setting up environment and lunch.
+ mmma -j bootable/recovery
+
+ # Running the tests on device.
+ adb root
+ adb sync data
+
+ # 32-bit device
+ adb shell /data/nativetest/recovery_unit_test/recovery_unit_test
+ adb shell /data/nativetest/recovery_component_test/recovery_component_test
+
+ # Or 64-bit device
+ adb shell /data/nativetest64/recovery_unit_test/recovery_unit_test
+ adb shell /data/nativetest64/recovery_component_test/recovery_component_test
diff --git a/applypatch/Android.mk b/applypatch/Android.mk
index 93a272997..90a86dcb0 100644
--- a/applypatch/Android.mk
+++ b/applypatch/Android.mk
@@ -20,18 +20,42 @@ LOCAL_CLANG := true
LOCAL_SRC_FILES := applypatch.cpp bspatch.cpp freecache.cpp imgpatch.cpp utils.cpp
LOCAL_MODULE := libapplypatch
LOCAL_MODULE_TAGS := eng
-LOCAL_C_INCLUDES += external/bzip2 external/zlib bootable/recovery
-LOCAL_STATIC_LIBRARIES += libbase libmtdutils libmincrypt libbz libz
+LOCAL_C_INCLUDES += bootable/recovery
+LOCAL_STATIC_LIBRARIES += libbase libotafault libmtdutils libcrypto_static libbz libz
+
+include $(BUILD_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+
+LOCAL_CLANG := true
+LOCAL_SRC_FILES := bspatch.cpp imgpatch.cpp utils.cpp
+LOCAL_MODULE := libimgpatch
+LOCAL_C_INCLUDES += bootable/recovery
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_STATIC_LIBRARIES += libcrypto_static libbz libz
include $(BUILD_STATIC_LIBRARY)
+ifeq ($(HOST_OS),linux)
+include $(CLEAR_VARS)
+
+LOCAL_CLANG := true
+LOCAL_SRC_FILES := bspatch.cpp imgpatch.cpp utils.cpp
+LOCAL_MODULE := libimgpatch
+LOCAL_C_INCLUDES += bootable/recovery
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_STATIC_LIBRARIES += libcrypto_static libbz libz
+
+include $(BUILD_HOST_STATIC_LIBRARY)
+endif # HOST_OS == linux
+
include $(CLEAR_VARS)
LOCAL_CLANG := true
LOCAL_SRC_FILES := main.cpp
LOCAL_MODULE := applypatch
LOCAL_C_INCLUDES += bootable/recovery
-LOCAL_STATIC_LIBRARIES += libapplypatch libbase libmtdutils libmincrypt libbz
+LOCAL_STATIC_LIBRARIES += libapplypatch libbase libotafault libmtdutils libcrypto_static libbz libedify
LOCAL_SHARED_LIBRARIES += libz libcutils libc
include $(BUILD_EXECUTABLE)
diff --git a/applypatch/Makefile b/applypatch/Makefile
new file mode 100644
index 000000000..fa6298d46
--- /dev/null
+++ b/applypatch/Makefile
@@ -0,0 +1,32 @@
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# This file is for building imgdiff in Chrome OS.
+
+CPPFLAGS += -iquote..
+CXXFLAGS += -std=c++11 -O3 -Wall -Werror
+LDLIBS += -lbz2 -lz
+
+.PHONY: all clean
+
+all: imgdiff libimgpatch.a
+
+clean:
+ rm -f *.o imgdiff libimgpatch.a
+
+imgdiff: imgdiff.o bsdiff.o utils.o
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDLIBS) -o $@ $^
+
+libimgpatch.a: imgpatch.o bspatch.o utils.o
+ ${AR} rcs $@ $^
diff --git a/applypatch/applypatch.cpp b/applypatch/applypatch.cpp
index f9425af93..f66dbe3bf 100644
--- a/applypatch/applypatch.cpp
+++ b/applypatch/applypatch.cpp
@@ -25,13 +25,17 @@
#include <sys/types.h>
#include <unistd.h>
+#include <memory>
+#include <string>
+
#include <android-base/strings.h>
-#include "mincrypt/sha.h"
+#include "openssl/sha.h"
#include "applypatch.h"
#include "mtdutils/mtdutils.h"
#include "edify/expr.h"
#include "print_sha1.h"
+#include "otafault/ota_io.h"
static int LoadPartitionContents(const char* filename, FileContents* file);
static ssize_t FileSink(const unsigned char* data, ssize_t len, void* token);
@@ -41,7 +45,7 @@ static int GenerateTarget(FileContents* source_file,
const Value* copy_patch_value,
const char* source_filename,
const char* target_filename,
- const uint8_t target_sha1[SHA_DIGEST_SIZE],
+ const uint8_t target_sha1[SHA_DIGEST_LENGTH],
size_t target_size,
const Value* bonus_data);
@@ -52,8 +56,6 @@ static bool mtd_partitions_scanned = false;
//
// Return 0 on success.
int LoadFileContents(const char* filename, FileContents* file) {
- file->data = NULL;
-
// A special 'filename' beginning with "MTD:" or "EMMC:" means to
// load the contents of a partition.
if (strncmp(filename, "MTD:", 4) == 0 ||
@@ -66,27 +68,22 @@ int LoadFileContents(const char* filename, FileContents* file) {
return -1;
}
- file->size = file->st.st_size;
- file->data = reinterpret_cast<unsigned char*>(malloc(file->size));
-
- FILE* f = fopen(filename, "rb");
+ std::vector<unsigned char> data(file->st.st_size);
+ FILE* f = ota_fopen(filename, "rb");
if (f == NULL) {
printf("failed to open \"%s\": %s\n", filename, strerror(errno));
- free(file->data);
- file->data = NULL;
return -1;
}
- size_t bytes_read = fread(file->data, 1, file->size, f);
- if (bytes_read != static_cast<size_t>(file->size)) {
- printf("short read of \"%s\" (%zu bytes of %zd)\n", filename, bytes_read, file->size);
- free(file->data);
- file->data = NULL;
+ size_t bytes_read = ota_fread(data.data(), 1, data.size(), f);
+ if (bytes_read != data.size()) {
+ printf("short read of \"%s\" (%zu bytes of %zu)\n", filename, bytes_read, data.size());
+ ota_fclose(f);
return -1;
}
- fclose(f);
-
- SHA_hash(file->data, file->size, file->sha1);
+ ota_fclose(f);
+ file->data = std::move(data);
+ SHA1(file->data.data(), file->data.size(), file->sha1);
return 0;
}
@@ -173,7 +170,7 @@ static int LoadPartitionContents(const char* filename, FileContents* file) {
}
case EMMC:
- dev = fopen(partition, "rb");
+ dev = ota_fopen(partition, "rb");
if (dev == NULL) {
printf("failed to open emmc partition \"%s\": %s\n", partition, strerror(errno));
return -1;
@@ -181,55 +178,53 @@ static int LoadPartitionContents(const char* filename, FileContents* file) {
}
SHA_CTX sha_ctx;
- SHA_init(&sha_ctx);
- uint8_t parsed_sha[SHA_DIGEST_SIZE];
+ SHA1_Init(&sha_ctx);
+ uint8_t parsed_sha[SHA_DIGEST_LENGTH];
// Allocate enough memory to hold the largest size.
- file->data = reinterpret_cast<unsigned char*>(malloc(size[index[pairs-1]]));
- char* p = (char*)file->data;
- file->size = 0; // # bytes read so far
+ std::vector<unsigned char> data(size[index[pairs-1]]);
+ char* p = reinterpret_cast<char*>(data.data());
+ size_t data_size = 0; // # bytes read so far
bool found = false;
for (size_t i = 0; i < pairs; ++i) {
// Read enough additional bytes to get us up to the next size. (Again,
// we're trying the possibilities in order of increasing size).
- size_t next = size[index[i]] - file->size;
- size_t read = 0;
+ size_t next = size[index[i]] - data_size;
if (next > 0) {
+ size_t read = 0;
switch (type) {
case MTD:
read = mtd_read_data(ctx, p, next);
break;
case EMMC:
- read = fread(p, 1, next, dev);
+ read = ota_fread(p, 1, next, dev);
break;
}
if (next != read) {
printf("short read (%zu bytes of %zu) for partition \"%s\"\n",
read, next, partition);
- free(file->data);
- file->data = NULL;
return -1;
}
- SHA_update(&sha_ctx, p, read);
- file->size += read;
+ SHA1_Update(&sha_ctx, p, read);
+ data_size += read;
+ p += read;
}
// Duplicate the SHA context and finalize the duplicate so we can
// check it against this pair's expected hash.
SHA_CTX temp_ctx;
memcpy(&temp_ctx, &sha_ctx, sizeof(SHA_CTX));
- const uint8_t* sha_so_far = SHA_final(&temp_ctx);
+ uint8_t sha_so_far[SHA_DIGEST_LENGTH];
+ SHA1_Final(sha_so_far, &temp_ctx);
if (ParseSha1(sha1sum[index[i]].c_str(), parsed_sha) != 0) {
printf("failed to parse sha1 %s in %s\n", sha1sum[index[i]].c_str(), filename);
- free(file->data);
- file->data = NULL;
return -1;
}
- if (memcmp(sha_so_far, parsed_sha, SHA_DIGEST_SIZE) == 0) {
+ if (memcmp(sha_so_far, parsed_sha, SHA_DIGEST_LENGTH) == 0) {
// we have a match. stop reading the partition; we'll return
// the data we've read so far.
printf("partition read matched size %zu sha %s\n",
@@ -237,8 +232,6 @@ static int LoadPartitionContents(const char* filename, FileContents* file) {
found = true;
break;
}
-
- p += read;
}
switch (type) {
@@ -247,7 +240,7 @@ static int LoadPartitionContents(const char* filename, FileContents* file) {
break;
case EMMC:
- fclose(dev);
+ ota_fclose(dev);
break;
}
@@ -255,16 +248,13 @@ static int LoadPartitionContents(const char* filename, FileContents* file) {
if (!found) {
// Ran off the end of the list of (size,sha1) pairs without finding a match.
printf("contents of partition \"%s\" didn't match %s\n", partition, filename);
- free(file->data);
- file->data = NULL;
return -1;
}
- const uint8_t* sha_final = SHA_final(&sha_ctx);
- for (size_t i = 0; i < SHA_DIGEST_SIZE; ++i) {
- file->sha1[i] = sha_final[i];
- }
+ SHA1_Final(file->sha1, &sha_ctx);
+ data.resize(data_size);
+ file->data = std::move(data);
// Fake some stat() info.
file->st.st_mode = 0644;
file->st.st_uid = 0;
@@ -277,24 +267,24 @@ static int LoadPartitionContents(const char* filename, FileContents* file) {
// Save the contents of the given FileContents object under the given
// filename. Return 0 on success.
int SaveFileContents(const char* filename, const FileContents* file) {
- int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_SYNC, S_IRUSR | S_IWUSR);
+ int fd = ota_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_SYNC, S_IRUSR | S_IWUSR);
if (fd < 0) {
printf("failed to open \"%s\" for write: %s\n", filename, strerror(errno));
return -1;
}
- ssize_t bytes_written = FileSink(file->data, file->size, &fd);
- if (bytes_written != file->size) {
- printf("short write of \"%s\" (%zd bytes of %zd) (%s)\n",
- filename, bytes_written, file->size, strerror(errno));
- close(fd);
+ ssize_t bytes_written = FileSink(file->data.data(), file->data.size(), &fd);
+ if (bytes_written != static_cast<ssize_t>(file->data.size())) {
+ printf("short write of \"%s\" (%zd bytes of %zu) (%s)\n",
+ filename, bytes_written, file->data.size(), strerror(errno));
+ ota_close(fd);
return -1;
}
- if (fsync(fd) != 0) {
+ if (ota_fsync(fd) != 0) {
printf("fsync of \"%s\" failed: %s\n", filename, strerror(errno));
return -1;
}
- if (close(fd) != 0) {
+ if (ota_close(fd) != 0) {
printf("close of \"%s\" failed: %s\n", filename, strerror(errno));
return -1;
}
@@ -315,7 +305,7 @@ int SaveFileContents(const char* filename, const FileContents* file) {
// "MTD:<partition>[:...]" or "EMMC:<partition_device>[:...]". The target name
// might contain multiple colons, but WriteToPartition() only uses the first
// two and ignores the rest. Return 0 on success.
-int WriteToPartition(unsigned char* data, size_t len, const char* target) {
+int WriteToPartition(const unsigned char* data, size_t len, const char* target) {
std::string copy(target);
std::vector<std::string> pieces = android::base::Split(copy, ":");
@@ -354,7 +344,7 @@ int WriteToPartition(unsigned char* data, size_t len, const char* target) {
return -1;
}
- size_t written = mtd_write_data(ctx, reinterpret_cast<char*>(data), len);
+ size_t written = mtd_write_data(ctx, reinterpret_cast<const char*>(data), len);
if (written != len) {
printf("only wrote %zu of %zu bytes to MTD %s\n", written, len, partition);
mtd_write_close(ctx);
@@ -377,7 +367,7 @@ int WriteToPartition(unsigned char* data, size_t len, const char* target) {
case EMMC: {
size_t start = 0;
bool success = false;
- int fd = open(partition, O_RDWR | O_SYNC);
+ int fd = ota_open(partition, O_RDWR | O_SYNC);
if (fd < 0) {
printf("failed to open %s: %s\n", partition, strerror(errno));
return -1;
@@ -392,22 +382,22 @@ int WriteToPartition(unsigned char* data, size_t len, const char* target) {
size_t to_write = len - start;
if (to_write > 1<<20) to_write = 1<<20;
- ssize_t written = TEMP_FAILURE_RETRY(write(fd, data+start, to_write));
+ ssize_t written = TEMP_FAILURE_RETRY(ota_write(fd, data+start, to_write));
if (written == -1) {
printf("failed write writing to %s: %s\n", partition, strerror(errno));
return -1;
}
start += written;
}
- if (fsync(fd) != 0) {
+ if (ota_fsync(fd) != 0) {
printf("failed to sync to %s (%s)\n", partition, strerror(errno));
return -1;
}
- if (close(fd) != 0) {
+ if (ota_close(fd) != 0) {
printf("failed to close %s (%s)\n", partition, strerror(errno));
return -1;
}
- fd = open(partition, O_RDONLY);
+ fd = ota_open(partition, O_RDONLY);
if (fd < 0) {
printf("failed to reopen %s for verify (%s)\n", partition, strerror(errno));
return -1;
@@ -416,13 +406,13 @@ int WriteToPartition(unsigned char* data, size_t len, const char* target) {
// Drop caches so our subsequent verification read
// won't just be reading the cache.
sync();
- int dc = open("/proc/sys/vm/drop_caches", O_WRONLY);
- if (TEMP_FAILURE_RETRY(write(dc, "3\n", 2)) == -1) {
+ int dc = ota_open("/proc/sys/vm/drop_caches", O_WRONLY);
+ if (TEMP_FAILURE_RETRY(ota_write(dc, "3\n", 2)) == -1) {
printf("write to /proc/sys/vm/drop_caches failed: %s\n", strerror(errno));
} else {
printf(" caches dropped\n");
}
- close(dc);
+ ota_close(dc);
sleep(1);
// verify
@@ -442,7 +432,7 @@ int WriteToPartition(unsigned char* data, size_t len, const char* target) {
size_t so_far = 0;
while (so_far < to_read) {
ssize_t read_count =
- TEMP_FAILURE_RETRY(read(fd, buffer+so_far, to_read-so_far));
+ TEMP_FAILURE_RETRY(ota_read(fd, buffer+so_far, to_read-so_far));
if (read_count == -1) {
printf("verify read error %s at %zu: %s\n",
partition, p, strerror(errno));
@@ -474,7 +464,7 @@ int WriteToPartition(unsigned char* data, size_t len, const char* target) {
return -1;
}
- if (close(fd) != 0) {
+ if (ota_close(fd) != 0) {
printf("error closing %s (%s)\n", partition, strerror(errno));
return -1;
}
@@ -494,7 +484,7 @@ int WriteToPartition(unsigned char* data, size_t len, const char* target) {
int ParseSha1(const char* str, uint8_t* digest) {
const char* ps = str;
uint8_t* pd = digest;
- for (int i = 0; i < SHA_DIGEST_SIZE * 2; ++i, ++ps) {
+ for (int i = 0; i < SHA_DIGEST_LENGTH * 2; ++i, ++ps) {
int digit;
if (*ps >= '0' && *ps <= '9') {
digit = *ps - '0';
@@ -521,10 +511,10 @@ int ParseSha1(const char* str, uint8_t* digest) {
// found.
int FindMatchingPatch(uint8_t* sha1, char* const * const patch_sha1_str,
int num_patches) {
- uint8_t patch_sha1[SHA_DIGEST_SIZE];
+ uint8_t patch_sha1[SHA_DIGEST_LENGTH];
for (int i = 0; i < num_patches; ++i) {
if (ParseSha1(patch_sha1_str[i], patch_sha1) == 0 &&
- memcmp(patch_sha1, sha1, SHA_DIGEST_SIZE) == 0) {
+ memcmp(patch_sha1, sha1, SHA_DIGEST_LENGTH) == 0) {
return i;
}
}
@@ -537,7 +527,6 @@ int FindMatchingPatch(uint8_t* sha1, char* const * const patch_sha1_str,
int applypatch_check(const char* filename, int num_patches,
char** const patch_sha1_str) {
FileContents file;
- file.data = NULL;
// It's okay to specify no sha1s; the check will pass if the
// LoadFileContents is successful. (Useful for reading
@@ -549,9 +538,6 @@ int applypatch_check(const char* filename, int num_patches,
printf("file \"%s\" doesn't have any of expected "
"sha1 sums; checking cache\n", filename);
- free(file.data);
- file.data = NULL;
-
// If the source file is missing or corrupted, it might be because
// we were killed in the middle of patching it. A copy of it
// should have been made in CACHE_TEMP_SOURCE. If that file
@@ -565,12 +551,9 @@ int applypatch_check(const char* filename, int num_patches,
if (FindMatchingPatch(file.sha1, patch_sha1_str, num_patches) < 0) {
printf("cache bits don't match any sha1 for \"%s\"\n", filename);
- free(file.data);
return 1;
}
}
-
- free(file.data);
return 0;
}
@@ -580,11 +563,11 @@ int ShowLicenses() {
}
ssize_t FileSink(const unsigned char* data, ssize_t len, void* token) {
- int fd = *reinterpret_cast<int *>(token);
+ int fd = *static_cast<int*>(token);
ssize_t done = 0;
ssize_t wrote;
while (done < len) {
- wrote = TEMP_FAILURE_RETRY(write(fd, data+done, len-done));
+ wrote = TEMP_FAILURE_RETRY(ota_write(fd, data+done, len-done));
if (wrote == -1) {
printf("error writing %zd bytes: %s\n", (len-done), strerror(errno));
return done;
@@ -594,19 +577,9 @@ ssize_t FileSink(const unsigned char* data, ssize_t len, void* token) {
return done;
}
-typedef struct {
- unsigned char* buffer;
- ssize_t size;
- ssize_t pos;
-} MemorySinkInfo;
-
ssize_t MemorySink(const unsigned char* data, ssize_t len, void* token) {
- MemorySinkInfo* msi = reinterpret_cast<MemorySinkInfo*>(token);
- if (msi->size - msi->pos < len) {
- return -1;
- }
- memcpy(msi->buffer + msi->pos, data, len);
- msi->pos += len;
+ std::string* s = static_cast<std::string*>(token);
+ s->append(reinterpret_cast<const char*>(data), len);
return len;
}
@@ -670,7 +643,7 @@ int applypatch(const char* source_filename,
target_filename = source_filename;
}
- uint8_t target_sha1[SHA_DIGEST_SIZE];
+ uint8_t target_sha1[SHA_DIGEST_LENGTH];
if (ParseSha1(target_sha1_str, target_sha1) != 0) {
printf("failed to parse tgt-sha1 \"%s\"\n", target_sha1_str);
return 1;
@@ -678,33 +651,29 @@ int applypatch(const char* source_filename,
FileContents copy_file;
FileContents source_file;
- copy_file.data = NULL;
- source_file.data = NULL;
const Value* source_patch_value = NULL;
const Value* copy_patch_value = NULL;
// We try to load the target file into the source_file object.
if (LoadFileContents(target_filename, &source_file) == 0) {
- if (memcmp(source_file.sha1, target_sha1, SHA_DIGEST_SIZE) == 0) {
+ if (memcmp(source_file.sha1, target_sha1, SHA_DIGEST_LENGTH) == 0) {
// The early-exit case: the patch was already applied, this file
// has the desired hash, nothing for us to do.
printf("already %s\n", short_sha1(target_sha1).c_str());
- free(source_file.data);
return 0;
}
}
- if (source_file.data == NULL ||
+ if (source_file.data.empty() ||
(target_filename != source_filename &&
strcmp(target_filename, source_filename) != 0)) {
// Need to load the source file: either we failed to load the
// target file, or we did but it's different from the source file.
- free(source_file.data);
- source_file.data = NULL;
+ source_file.data.clear();
LoadFileContents(source_filename, &source_file);
}
- if (source_file.data != NULL) {
+ if (!source_file.data.empty()) {
int to_use = FindMatchingPatch(source_file.sha1, patch_sha1_str, num_patches);
if (to_use >= 0) {
source_patch_value = patch_data[to_use];
@@ -712,8 +681,7 @@ int applypatch(const char* source_filename,
}
if (source_patch_value == NULL) {
- free(source_file.data);
- source_file.data = NULL;
+ source_file.data.clear();
printf("source file is bad; trying copy\n");
if (LoadFileContents(CACHE_TEMP_SOURCE, &copy_file) < 0) {
@@ -730,19 +698,14 @@ int applypatch(const char* source_filename,
if (copy_patch_value == NULL) {
// fail.
printf("copy file doesn't match source SHA-1s either\n");
- free(copy_file.data);
return 1;
}
}
- int result = GenerateTarget(&source_file, source_patch_value,
- &copy_file, copy_patch_value,
- source_filename, target_filename,
- target_sha1, target_size, bonus_data);
- free(source_file.data);
- free(copy_file.data);
-
- return result;
+ return GenerateTarget(&source_file, source_patch_value,
+ &copy_file, copy_patch_value,
+ source_filename, target_filename,
+ target_sha1, target_size, bonus_data);
}
/*
@@ -756,14 +719,13 @@ int applypatch_flash(const char* source_filename, const char* target_filename,
const char* target_sha1_str, size_t target_size) {
printf("flash %s: ", target_filename);
- uint8_t target_sha1[SHA_DIGEST_SIZE];
+ uint8_t target_sha1[SHA_DIGEST_LENGTH];
if (ParseSha1(target_sha1_str, target_sha1) != 0) {
printf("failed to parse tgt-sha1 \"%s\"\n", target_sha1_str);
return 1;
}
FileContents source_file;
- source_file.data = NULL;
std::string target_str(target_filename);
std::vector<std::string> pieces = android::base::Split(target_str, ":");
@@ -777,32 +739,27 @@ int applypatch_flash(const char* source_filename, const char* target_filename,
pieces.push_back(target_sha1_str);
std::string fullname = android::base::Join(pieces, ':');
if (LoadPartitionContents(fullname.c_str(), &source_file) == 0 &&
- memcmp(source_file.sha1, target_sha1, SHA_DIGEST_SIZE) == 0) {
+ memcmp(source_file.sha1, target_sha1, SHA_DIGEST_LENGTH) == 0) {
// The early-exit case: the image was already applied, this partition
// has the desired hash, nothing for us to do.
printf("already %s\n", short_sha1(target_sha1).c_str());
- free(source_file.data);
return 0;
}
if (LoadFileContents(source_filename, &source_file) == 0) {
- if (memcmp(source_file.sha1, target_sha1, SHA_DIGEST_SIZE) != 0) {
+ if (memcmp(source_file.sha1, target_sha1, SHA_DIGEST_LENGTH) != 0) {
// The source doesn't have desired checksum.
printf("source \"%s\" doesn't have expected sha1 sum\n", source_filename);
printf("expected: %s, found: %s\n", short_sha1(target_sha1).c_str(),
short_sha1(source_file.sha1).c_str());
- free(source_file.data);
return 1;
}
}
- if (WriteToPartition(source_file.data, target_size, target_filename) != 0) {
+ if (WriteToPartition(source_file.data.data(), target_size, target_filename) != 0) {
printf("write of copied data to %s failed\n", target_filename);
- free(source_file.data);
return 1;
}
-
- free(source_file.data);
return 0;
}
@@ -812,36 +769,57 @@ static int GenerateTarget(FileContents* source_file,
const Value* copy_patch_value,
const char* source_filename,
const char* target_filename,
- const uint8_t target_sha1[SHA_DIGEST_SIZE],
+ const uint8_t target_sha1[SHA_DIGEST_LENGTH],
size_t target_size,
const Value* bonus_data) {
int retry = 1;
SHA_CTX ctx;
- int output;
- MemorySinkInfo msi;
+ std::string memory_sink_str;
FileContents* source_to_use;
- char* outname;
int made_copy = 0;
+ bool target_is_partition = (strncmp(target_filename, "MTD:", 4) == 0 ||
+ strncmp(target_filename, "EMMC:", 5) == 0);
+ const std::string tmp_target_filename = std::string(target_filename) + ".patch";
+
// assume that target_filename (eg "/system/app/Foo.apk") is located
// on the same filesystem as its top-level directory ("/system").
// We need something that exists for calling statfs().
- char target_fs[strlen(target_filename)+1];
- char* slash = strchr(target_filename+1, '/');
- if (slash != NULL) {
- int count = slash - target_filename;
- strncpy(target_fs, target_filename, count);
- target_fs[count] = '\0';
+ std::string target_fs = target_filename;
+ auto slash_pos = target_fs.find('/', 1);
+ if (slash_pos != std::string::npos) {
+ target_fs.resize(slash_pos);
+ }
+
+ const Value* patch;
+ if (source_patch_value != NULL) {
+ source_to_use = source_file;
+ patch = source_patch_value;
} else {
- strcpy(target_fs, target_filename);
+ source_to_use = copy_file;
+ patch = copy_patch_value;
+ }
+ if (patch->type != VAL_BLOB) {
+ printf("patch is not a blob\n");
+ return 1;
+ }
+ char* header = patch->data;
+ ssize_t header_bytes_read = patch->size;
+ bool use_bsdiff = false;
+ if (header_bytes_read >= 8 && memcmp(header, "BSDIFF40", 8) == 0) {
+ use_bsdiff = true;
+ } else if (header_bytes_read >= 8 && memcmp(header, "IMGDIFF2", 8) == 0) {
+ use_bsdiff = false;
+ } else {
+ printf("Unknown patch file format\n");
+ return 1;
}
do {
// Is there enough room in the target filesystem to hold the patched
// file?
- if (strncmp(target_filename, "MTD:", 4) == 0 ||
- strncmp(target_filename, "EMMC:", 5) == 0) {
+ if (target_is_partition) {
// If the target is a partition, we're actually going to
// write the output to /tmp and then copy it to the
// partition. statfs() always returns 0 blocks free for
@@ -850,7 +828,7 @@ static int GenerateTarget(FileContents* source_file,
// We still write the original source to cache, in case
// the partition write is interrupted.
- if (MakeFreeSpaceOnCache(source_file->size) < 0) {
+ if (MakeFreeSpaceOnCache(source_file->data.size()) < 0) {
printf("not enough free space on /cache\n");
return 1;
}
@@ -863,7 +841,7 @@ static int GenerateTarget(FileContents* source_file,
} else {
int enough_space = 0;
if (retry > 0) {
- size_t free_space = FreeSpaceForFile(target_fs);
+ size_t free_space = FreeSpaceForFile(target_fs.c_str());
enough_space =
(free_space > (256 << 10)) && // 256k (two-block) minimum
(free_space > (target_size * 3 / 2)); // 50% margin of error
@@ -891,7 +869,7 @@ static int GenerateTarget(FileContents* source_file,
return 1;
}
- if (MakeFreeSpaceOnCache(source_file->size) < 0) {
+ if (MakeFreeSpaceOnCache(source_file->data.size()) < 0) {
printf("not enough free space on /cache\n");
return 1;
}
@@ -903,84 +881,53 @@ static int GenerateTarget(FileContents* source_file,
made_copy = 1;
unlink(source_filename);
- size_t free_space = FreeSpaceForFile(target_fs);
+ size_t free_space = FreeSpaceForFile(target_fs.c_str());
printf("(now %zu bytes free for target) ", free_space);
}
}
- const Value* patch;
- if (source_patch_value != NULL) {
- source_to_use = source_file;
- patch = source_patch_value;
- } else {
- source_to_use = copy_file;
- patch = copy_patch_value;
- }
-
- if (patch->type != VAL_BLOB) {
- printf("patch is not a blob\n");
- return 1;
- }
SinkFn sink = NULL;
void* token = NULL;
- output = -1;
- outname = NULL;
- if (strncmp(target_filename, "MTD:", 4) == 0 ||
- strncmp(target_filename, "EMMC:", 5) == 0) {
+ int output_fd = -1;
+ if (target_is_partition) {
// We store the decoded output in memory.
- msi.buffer = reinterpret_cast<unsigned char*>(malloc(target_size));
- if (msi.buffer == NULL) {
- printf("failed to alloc %zu bytes for output\n", target_size);
- return 1;
- }
- msi.pos = 0;
- msi.size = target_size;
sink = MemorySink;
- token = &msi;
+ token = &memory_sink_str;
} else {
// We write the decoded output to "<tgt-file>.patch".
- outname = reinterpret_cast<char*>(malloc(strlen(target_filename) + 10));
- strcpy(outname, target_filename);
- strcat(outname, ".patch");
-
- output = open(outname, O_WRONLY | O_CREAT | O_TRUNC | O_SYNC, S_IRUSR | S_IWUSR);
- if (output < 0) {
- printf("failed to open output file %s: %s\n",
- outname, strerror(errno));
+ output_fd = ota_open(tmp_target_filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_SYNC,
+ S_IRUSR | S_IWUSR);
+ if (output_fd < 0) {
+ printf("failed to open output file %s: %s\n", tmp_target_filename.c_str(),
+ strerror(errno));
return 1;
}
sink = FileSink;
- token = &output;
+ token = &output_fd;
}
- char* header = patch->data;
- ssize_t header_bytes_read = patch->size;
- SHA_init(&ctx);
+ SHA1_Init(&ctx);
int result;
-
- if (header_bytes_read >= 8 &&
- memcmp(header, "BSDIFF40", 8) == 0) {
- result = ApplyBSDiffPatch(source_to_use->data, source_to_use->size,
+ if (use_bsdiff) {
+ result = ApplyBSDiffPatch(source_to_use->data.data(), source_to_use->data.size(),
patch, 0, sink, token, &ctx);
- } else if (header_bytes_read >= 8 &&
- memcmp(header, "IMGDIFF2", 8) == 0) {
- result = ApplyImagePatch(source_to_use->data, source_to_use->size,
- patch, sink, token, &ctx, bonus_data);
} else {
- printf("Unknown patch file format\n");
- return 1;
+ result = ApplyImagePatch(source_to_use->data.data(), source_to_use->data.size(),
+ patch, sink, token, &ctx, bonus_data);
}
- if (output >= 0) {
- if (fsync(output) != 0) {
- printf("failed to fsync file \"%s\" (%s)\n", outname, strerror(errno));
+ if (!target_is_partition) {
+ if (ota_fsync(output_fd) != 0) {
+ printf("failed to fsync file \"%s\" (%s)\n", tmp_target_filename.c_str(),
+ strerror(errno));
result = 1;
}
- if (close(output) != 0) {
- printf("failed to close file \"%s\" (%s)\n", outname, strerror(errno));
+ if (ota_close(output_fd) != 0) {
+ printf("failed to close file \"%s\" (%s)\n", tmp_target_filename.c_str(),
+ strerror(errno));
result = 1;
}
}
@@ -992,8 +939,8 @@ static int GenerateTarget(FileContents* source_file,
} else {
printf("applying patch failed; retrying\n");
}
- if (outname != NULL) {
- unlink(outname);
+ if (!target_is_partition) {
+ unlink(tmp_target_filename.c_str());
}
} else {
// succeeded; no need to retry
@@ -1001,35 +948,36 @@ static int GenerateTarget(FileContents* source_file,
}
} while (retry-- > 0);
- const uint8_t* current_target_sha1 = SHA_final(&ctx);
- if (memcmp(current_target_sha1, target_sha1, SHA_DIGEST_SIZE) != 0) {
+ uint8_t current_target_sha1[SHA_DIGEST_LENGTH];
+ SHA1_Final(current_target_sha1, &ctx);
+ if (memcmp(current_target_sha1, target_sha1, SHA_DIGEST_LENGTH) != 0) {
printf("patch did not produce expected sha1\n");
return 1;
} else {
printf("now %s\n", short_sha1(target_sha1).c_str());
}
- if (output < 0) {
+ if (target_is_partition) {
// Copy the temp file to the partition.
- if (WriteToPartition(msi.buffer, msi.pos, target_filename) != 0) {
+ if (WriteToPartition(reinterpret_cast<const unsigned char*>(memory_sink_str.c_str()),
+ memory_sink_str.size(), target_filename) != 0) {
printf("write of patched data to %s failed\n", target_filename);
return 1;
}
- free(msi.buffer);
} else {
// Give the .patch file the same owner, group, and mode of the
// original source file.
- if (chmod(outname, source_to_use->st.st_mode) != 0) {
- printf("chmod of \"%s\" failed: %s\n", outname, strerror(errno));
+ if (chmod(tmp_target_filename.c_str(), source_to_use->st.st_mode) != 0) {
+ printf("chmod of \"%s\" failed: %s\n", tmp_target_filename.c_str(), strerror(errno));
return 1;
}
- if (chown(outname, source_to_use->st.st_uid, source_to_use->st.st_gid) != 0) {
- printf("chown of \"%s\" failed: %s\n", outname, strerror(errno));
+ if (chown(tmp_target_filename.c_str(), source_to_use->st.st_uid, source_to_use->st.st_gid) != 0) {
+ printf("chown of \"%s\" failed: %s\n", tmp_target_filename.c_str(), strerror(errno));
return 1;
}
// Finally, rename the .patch file to replace the target file.
- if (rename(outname, target_filename) != 0) {
+ if (rename(tmp_target_filename.c_str(), target_filename) != 0) {
printf("rename of .patch to \"%s\" failed: %s\n", target_filename, strerror(errno));
return 1;
}
diff --git a/applypatch/applypatch.h b/applypatch/applypatch.h
index 415bc1b3c..9ee39d293 100644
--- a/applypatch/applypatch.h
+++ b/applypatch/applypatch.h
@@ -17,21 +17,19 @@
#ifndef _APPLYPATCH_H
#define _APPLYPATCH_H
+#include <stdint.h>
#include <sys/stat.h>
-#include "mincrypt/sha.h"
-#include "edify/expr.h"
-typedef struct _Patch {
- uint8_t sha1[SHA_DIGEST_SIZE];
- const char* patch_filename;
-} Patch;
+#include <vector>
+
+#include "openssl/sha.h"
+#include "edify/expr.h"
-typedef struct _FileContents {
- uint8_t sha1[SHA_DIGEST_SIZE];
- unsigned char* data;
- ssize_t size;
+struct FileContents {
+ uint8_t sha1[SHA_DIGEST_LENGTH];
+ std::vector<unsigned char> data;
struct stat st;
-} FileContents;
+};
// When there isn't enough room on the target filesystem to hold the
// patched version of the file, we copy the original here and delete
@@ -68,22 +66,22 @@ void FreeFileContents(FileContents* file);
int FindMatchingPatch(uint8_t* sha1, char* const * const patch_sha1_str,
int num_patches);
-// bsdiff.c
+// bsdiff.cpp
void ShowBSDiffLicense();
int ApplyBSDiffPatch(const unsigned char* old_data, ssize_t old_size,
const Value* patch, ssize_t patch_offset,
SinkFn sink, void* token, SHA_CTX* ctx);
int ApplyBSDiffPatchMem(const unsigned char* old_data, ssize_t old_size,
const Value* patch, ssize_t patch_offset,
- unsigned char** new_data, ssize_t* new_size);
+ std::vector<unsigned char>* new_data);
-// imgpatch.c
+// imgpatch.cpp
int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size,
const Value* patch,
SinkFn sink, void* token, SHA_CTX* ctx,
const Value* bonus_data);
-// freecache.c
+// freecache.cpp
int MakeFreeSpaceOnCache(size_t bytes_needed);
#endif
diff --git a/applypatch/bsdiff.cpp b/applypatch/bsdiff.cpp
index 55dbe5cf1..cca1b32fb 100644
--- a/applypatch/bsdiff.cpp
+++ b/applypatch/bsdiff.cpp
@@ -224,7 +224,6 @@ static void offtout(off_t x,u_char *buf)
int bsdiff(u_char* old, off_t oldsize, off_t** IP, u_char* newdata, off_t newsize,
const char* patch_filename)
{
- int fd;
off_t *I;
off_t scan,pos,len;
off_t lastscan,lastpos,lastoffset;
diff --git a/applypatch/bspatch.cpp b/applypatch/bspatch.cpp
index 9d201b477..1fc1455a6 100644
--- a/applypatch/bspatch.cpp
+++ b/applypatch/bspatch.cpp
@@ -22,14 +22,14 @@
#include <stdio.h>
#include <sys/stat.h>
+#include <sys/types.h>
#include <errno.h>
-#include <malloc.h>
#include <unistd.h>
#include <string.h>
#include <bzlib.h>
-#include "mincrypt/sha.h"
+#include "openssl/sha.h"
#include "applypatch.h"
void ShowBSDiffLicense() {
@@ -102,26 +102,22 @@ int ApplyBSDiffPatch(const unsigned char* old_data, ssize_t old_size,
const Value* patch, ssize_t patch_offset,
SinkFn sink, void* token, SHA_CTX* ctx) {
- unsigned char* new_data;
- ssize_t new_size;
- if (ApplyBSDiffPatchMem(old_data, old_size, patch, patch_offset,
- &new_data, &new_size) != 0) {
+ std::vector<unsigned char> new_data;
+ if (ApplyBSDiffPatchMem(old_data, old_size, patch, patch_offset, &new_data) != 0) {
return -1;
}
- if (sink(new_data, new_size, token) < new_size) {
+ if (sink(new_data.data(), new_data.size(), token) < static_cast<ssize_t>(new_data.size())) {
printf("short write of output: %d (%s)\n", errno, strerror(errno));
return 1;
}
- if (ctx) SHA_update(ctx, new_data, new_size);
- free(new_data);
-
+ if (ctx) SHA1_Update(ctx, new_data.data(), new_data.size());
return 0;
}
int ApplyBSDiffPatchMem(const unsigned char* old_data, ssize_t old_size,
const Value* patch, ssize_t patch_offset,
- unsigned char** new_data, ssize_t* new_size) {
+ std::vector<unsigned char>* new_data) {
// Patch data format:
// 0 8 "BSDIFF40"
// 8 8 X
@@ -140,12 +136,12 @@ int ApplyBSDiffPatchMem(const unsigned char* old_data, ssize_t old_size,
return 1;
}
- ssize_t ctrl_len, data_len;
+ ssize_t ctrl_len, data_len, new_size;
ctrl_len = offtin(header+8);
data_len = offtin(header+16);
- *new_size = offtin(header+24);
+ new_size = offtin(header+24);
- if (ctrl_len < 0 || data_len < 0 || *new_size < 0) {
+ if (ctrl_len < 0 || data_len < 0 || new_size < 0) {
printf("corrupt patch file header (data lengths)\n");
return 1;
}
@@ -182,18 +178,13 @@ int ApplyBSDiffPatchMem(const unsigned char* old_data, ssize_t old_size,
printf("failed to bzinit extra stream (%d)\n", bzerr);
}
- *new_data = reinterpret_cast<unsigned char*>(malloc(*new_size));
- if (*new_data == NULL) {
- printf("failed to allocate %zd bytes of memory for output file\n", *new_size);
- return 1;
- }
+ new_data->resize(new_size);
off_t oldpos = 0, newpos = 0;
off_t ctrl[3];
- off_t len_read;
int i;
unsigned char buf[24];
- while (newpos < *new_size) {
+ while (newpos < new_size) {
// Read control data
if (FillBuffer(buf, 24, &cstream) != 0) {
printf("error while reading control stream\n");
@@ -209,13 +200,13 @@ int ApplyBSDiffPatchMem(const unsigned char* old_data, ssize_t old_size,
}
// Sanity check
- if (newpos + ctrl[0] > *new_size) {
+ if (newpos + ctrl[0] > new_size) {
printf("corrupt patch (new file overrun)\n");
return 1;
}
// Read diff string
- if (FillBuffer(*new_data + newpos, ctrl[0], &dstream) != 0) {
+ if (FillBuffer(new_data->data() + newpos, ctrl[0], &dstream) != 0) {
printf("error while reading diff stream\n");
return 1;
}
@@ -232,13 +223,13 @@ int ApplyBSDiffPatchMem(const unsigned char* old_data, ssize_t old_size,
oldpos += ctrl[0];
// Sanity check
- if (newpos + ctrl[1] > *new_size) {
+ if (newpos + ctrl[1] > new_size) {
printf("corrupt patch (new file overrun)\n");
return 1;
}
// Read extra string
- if (FillBuffer(*new_data + newpos, ctrl[1], &estream) != 0) {
+ if (FillBuffer(new_data->data() + newpos, ctrl[1], &estream) != 0) {
printf("error while reading extra stream\n");
return 1;
}
diff --git a/applypatch/freecache.cpp b/applypatch/freecache.cpp
index 2eb2f55ef..c84f42797 100644
--- a/applypatch/freecache.cpp
+++ b/applypatch/freecache.cpp
@@ -25,119 +25,90 @@
#include <dirent.h>
#include <ctype.h>
+#include <memory>
+#include <set>
+#include <string>
+
+#include <android-base/parseint.h>
+#include <android-base/stringprintf.h>
+
#include "applypatch.h"
-static int EliminateOpenFiles(char** files, int file_count) {
- DIR* d;
- struct dirent* de;
- d = opendir("/proc");
- if (d == NULL) {
+static int EliminateOpenFiles(std::set<std::string>* files) {
+ std::unique_ptr<DIR, decltype(&closedir)> d(opendir("/proc"), closedir);
+ if (!d) {
printf("error opening /proc: %s\n", strerror(errno));
return -1;
}
- while ((de = readdir(d)) != 0) {
- int i;
- for (i = 0; de->d_name[i] != '\0' && isdigit(de->d_name[i]); ++i);
- if (de->d_name[i]) continue;
-
- // de->d_name[i] is numeric
-
- char path[FILENAME_MAX];
- strcpy(path, "/proc/");
- strcat(path, de->d_name);
- strcat(path, "/fd/");
+ struct dirent* de;
+ while ((de = readdir(d.get())) != 0) {
+ unsigned int pid;
+ if (!android::base::ParseUint(de->d_name, &pid)) {
+ continue;
+ }
+ std::string path = android::base::StringPrintf("/proc/%s/fd/", de->d_name);
- DIR* fdd;
struct dirent* fdde;
- fdd = opendir(path);
- if (fdd == NULL) {
- printf("error opening %s: %s\n", path, strerror(errno));
+ std::unique_ptr<DIR, decltype(&closedir)> fdd(opendir(path.c_str()), closedir);
+ if (!fdd) {
+ printf("error opening %s: %s\n", path.c_str(), strerror(errno));
continue;
}
- while ((fdde = readdir(fdd)) != 0) {
- char fd_path[FILENAME_MAX];
+ while ((fdde = readdir(fdd.get())) != 0) {
+ std::string fd_path = path + fdde->d_name;
char link[FILENAME_MAX];
- strcpy(fd_path, path);
- strcat(fd_path, fdde->d_name);
- int count;
- count = readlink(fd_path, link, sizeof(link)-1);
+ int count = readlink(fd_path.c_str(), link, sizeof(link)-1);
if (count >= 0) {
link[count] = '\0';
-
- // This is inefficient, but it should only matter if there are
- // lots of files in /cache, and lots of them are open (neither
- // of which should be true, especially in recovery).
if (strncmp(link, "/cache/", 7) == 0) {
- int j;
- for (j = 0; j < file_count; ++j) {
- if (files[j] && strcmp(files[j], link) == 0) {
- printf("%s is open by %s\n", link, de->d_name);
- free(files[j]);
- files[j] = NULL;
- }
+ if (files->erase(link) > 0) {
+ printf("%s is open by %s\n", link, de->d_name);
}
}
}
}
- closedir(fdd);
}
- closedir(d);
-
return 0;
}
-int FindExpendableFiles(char*** names, int* entries) {
- DIR* d;
- struct dirent* de;
- int size = 32;
- *entries = 0;
- *names = reinterpret_cast<char**>(malloc(size * sizeof(char*)));
-
- char path[FILENAME_MAX];
-
+static std::set<std::string> FindExpendableFiles() {
+ std::set<std::string> files;
// We're allowed to delete unopened regular files in any of these
// directories.
const char* dirs[2] = {"/cache", "/cache/recovery/otatest"};
for (size_t i = 0; i < sizeof(dirs)/sizeof(dirs[0]); ++i) {
- d = opendir(dirs[i]);
- if (d == NULL) {
+ std::unique_ptr<DIR, decltype(&closedir)> d(opendir(dirs[i]), closedir);
+ if (!d) {
printf("error opening %s: %s\n", dirs[i], strerror(errno));
continue;
}
// Look for regular files in the directory (not in any subdirectories).
- while ((de = readdir(d)) != 0) {
- strcpy(path, dirs[i]);
- strcat(path, "/");
- strcat(path, de->d_name);
+ struct dirent* de;
+ while ((de = readdir(d.get())) != 0) {
+ std::string path = std::string(dirs[i]) + "/" + de->d_name;
// We can't delete CACHE_TEMP_SOURCE; if it's there we might have
// restarted during installation and could be depending on it to
// be there.
- if (strcmp(path, CACHE_TEMP_SOURCE) == 0) continue;
+ if (path == CACHE_TEMP_SOURCE) {
+ continue;
+ }
struct stat st;
- if (stat(path, &st) == 0 && S_ISREG(st.st_mode)) {
- if (*entries >= size) {
- size *= 2;
- *names = reinterpret_cast<char**>(realloc(*names, size * sizeof(char*)));
- }
- (*names)[(*entries)++] = strdup(path);
+ if (stat(path.c_str(), &st) == 0 && S_ISREG(st.st_mode)) {
+ files.insert(path);
}
}
-
- closedir(d);
}
- printf("%d regular files in deletable directories\n", *entries);
-
- if (EliminateOpenFiles(*names, *entries) < 0) {
- return -1;
+ printf("%zu regular files in deletable directories\n", files.size());
+ if (EliminateOpenFiles(&files) < 0) {
+ return std::set<std::string>();
}
-
- return 0;
+ return files;
}
int MakeFreeSpaceOnCache(size_t bytes_needed) {
@@ -147,15 +118,8 @@ int MakeFreeSpaceOnCache(size_t bytes_needed) {
if (free_now >= bytes_needed) {
return 0;
}
-
- char** names;
- int entries;
-
- if (FindExpendableFiles(&names, &entries) < 0) {
- return -1;
- }
-
- if (entries == 0) {
+ std::set<std::string> files = FindExpendableFiles();
+ if (files.empty()) {
// nothing we can delete to free up space!
printf("no files can be deleted to free space on /cache\n");
return -1;
@@ -167,20 +131,13 @@ int MakeFreeSpaceOnCache(size_t bytes_needed) {
//
// Instead, we'll be dumb.
- int i;
- for (i = 0; i < entries && free_now < bytes_needed; ++i) {
- if (names[i]) {
- unlink(names[i]);
- free_now = FreeSpaceForFile("/cache");
- printf("deleted %s; now %zu bytes free\n", names[i], free_now);
- free(names[i]);
+ for (const auto& file : files) {
+ unlink(file.c_str());
+ free_now = FreeSpaceForFile("/cache");
+ printf("deleted %s; now %zu bytes free\n", file.c_str(), free_now);
+ if (free_now < bytes_needed) {
+ break;
}
}
-
- for (; i < entries; ++i) {
- free(names[i]);
- }
- free(names);
-
return (free_now >= bytes_needed) ? 0 : -1;
}
diff --git a/applypatch/imgdiff.cpp b/applypatch/imgdiff.cpp
index f22502e38..2aa4a6862 100644
--- a/applypatch/imgdiff.cpp
+++ b/applypatch/imgdiff.cpp
@@ -407,7 +407,6 @@ unsigned char* ReadImage(const char* filename,
while (pos < sz) {
unsigned char* p = img+pos;
- bool processed_deflate = false;
if (sz - pos >= 4 &&
p[0] == 0x1f && p[1] == 0x8b &&
p[2] == 0x08 && // deflate compression
@@ -461,28 +460,27 @@ unsigned char* ReadImage(const char* filename,
strm.next_out = curr->data + curr->len;
ret = inflate(&strm, Z_NO_FLUSH);
if (ret < 0) {
- if (!processed_deflate) {
- // This is the first chunk, assume that it's just a spurious
- // gzip header instead of a real one.
- break;
- }
- printf("Error: inflate failed [%s] at file offset [%zu]\n"
- "imgdiff only supports gzip kernel compression,"
- " did you try CONFIG_KERNEL_LZO?\n",
+ printf("Warning: inflate failed [%s] at offset [%zu],"
+ " treating as a normal chunk\n",
strm.msg, chunk_offset);
- free(img);
- return NULL;
+ break;
}
curr->len = allocated - strm.avail_out;
if (strm.avail_out == 0) {
allocated *= 2;
curr->data = reinterpret_cast<unsigned char*>(realloc(curr->data, allocated));
}
- processed_deflate = true;
} while (ret != Z_STREAM_END);
curr->deflate_len = sz - strm.avail_in - pos;
inflateEnd(&strm);
+
+ if (ret < 0) {
+ free(curr->data);
+ *num_chunks -= 2;
+ continue;
+ }
+
pos += curr->deflate_len;
p += curr->deflate_len;
++curr;
@@ -598,7 +596,6 @@ int ReconstructDeflateChunk(ImageChunk* chunk) {
return -1;
}
- size_t p = 0;
unsigned char* out = reinterpret_cast<unsigned char*>(malloc(BUFFER_SIZE));
// We only check two combinations of encoder parameters: level 6
@@ -844,7 +841,6 @@ int main(int argc, char** argv) {
}
if (argc != 4) {
- usage:
printf("usage: %s [-z] [-b <bonus-file>] <src-img> <tgt-img> <patch-file>\n",
argv[0]);
return 2;
diff --git a/applypatch/imgpatch.cpp b/applypatch/imgpatch.cpp
index 26888f8ee..0ab995b30 100644
--- a/applypatch/imgpatch.cpp
+++ b/applypatch/imgpatch.cpp
@@ -21,23 +21,33 @@
#include <sys/cdefs.h>
#include <sys/stat.h>
#include <errno.h>
-#include <malloc.h>
#include <unistd.h>
#include <string.h>
+#include <vector>
+
#include "zlib.h"
-#include "mincrypt/sha.h"
+#include "openssl/sha.h"
#include "applypatch.h"
#include "imgdiff.h"
#include "utils.h"
+int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size,
+ const unsigned char* patch_data, ssize_t patch_size,
+ SinkFn sink, void* token) {
+ Value patch = {VAL_BLOB, patch_size,
+ reinterpret_cast<char*>(const_cast<unsigned char*>(patch_data))};
+ return ApplyImagePatch(
+ old_data, old_size, &patch, sink, token, nullptr, nullptr);
+}
+
/*
* Apply the patch given in 'patch_filename' to the source data given
* by (old_data, old_size). Write the patched output to the 'output'
* file, and update the SHA context with the output data as well.
* Return 0 on success.
*/
-int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size __unused,
+int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size,
const Value* patch,
SinkFn sink, void* token, SHA_CTX* ctx,
const Value* bonus_data) {
@@ -80,6 +90,10 @@ int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size __unused,
size_t src_len = Read8(normal_header+8);
size_t patch_offset = Read8(normal_header+16);
+ if (src_start + src_len > static_cast<size_t>(old_size)) {
+ printf("source data too short\n");
+ return -1;
+ }
ApplyBSDiffPatch(old_data + src_start, src_len,
patch, patch_offset, sink, token, ctx);
} else if (type == CHUNK_RAW) {
@@ -96,7 +110,7 @@ int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size __unused,
printf("failed to read chunk %d raw data\n", i);
return -1;
}
- if (ctx) SHA_update(ctx, patch->data + pos, data_len);
+ if (ctx) SHA1_Update(ctx, patch->data + pos, data_len);
if (sink((unsigned char*)patch->data + pos,
data_len, token) != data_len) {
printf("failed to write chunk %d raw data\n", i);
@@ -123,6 +137,11 @@ int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size __unused,
int memLevel = Read4(deflate_header+52);
int strategy = Read4(deflate_header+56);
+ if (src_start + src_len > static_cast<size_t>(old_size)) {
+ printf("source data too short\n");
+ return -1;
+ }
+
// Decompress the source data; the chunk header tells us exactly
// how big we expect it to be when decompressed.
@@ -132,13 +151,7 @@ int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size __unused,
// must be appended from the bonus_data value.
size_t bonus_size = (i == 1 && bonus_data != NULL) ? bonus_data->size : 0;
- unsigned char* expanded_source = reinterpret_cast<unsigned char*>(malloc(expanded_len));
- if (expanded_source == NULL) {
- printf("failed to allocate %zu bytes for expanded_source\n",
- expanded_len);
- return -1;
- }
-
+ std::vector<unsigned char> expanded_source(expanded_len);
z_stream strm;
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
@@ -146,7 +159,7 @@ int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size __unused,
strm.avail_in = src_len;
strm.next_in = (unsigned char*)(old_data + src_start);
strm.avail_out = expanded_len;
- strm.next_out = expanded_source;
+ strm.next_out = expanded_source.data();
int ret;
ret = inflateInit2(&strm, -15);
@@ -171,18 +184,21 @@ int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size __unused,
inflateEnd(&strm);
if (bonus_size) {
- memcpy(expanded_source + (expanded_len - bonus_size),
+ memcpy(expanded_source.data() + (expanded_len - bonus_size),
bonus_data->data, bonus_size);
}
// Next, apply the bsdiff patch (in memory) to the uncompressed
// data.
- unsigned char* uncompressed_target_data;
- ssize_t uncompressed_target_size;
- if (ApplyBSDiffPatchMem(expanded_source, expanded_len,
+ std::vector<unsigned char> uncompressed_target_data;
+ if (ApplyBSDiffPatchMem(expanded_source.data(), expanded_len,
patch, patch_offset,
- &uncompressed_target_data,
- &uncompressed_target_size) != 0) {
+ &uncompressed_target_data) != 0) {
+ return -1;
+ }
+ if (uncompressed_target_data.size() != target_len) {
+ printf("expected target len to be %zu, but it's %zu\n",
+ target_len, uncompressed_target_data.size());
return -1;
}
@@ -190,40 +206,36 @@ int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size __unused,
// we're done with the expanded_source data buffer, so we'll
// reuse that memory to receive the output of deflate.
- unsigned char* temp_data = expanded_source;
- ssize_t temp_size = expanded_len;
- if (temp_size < 32768) {
- // ... unless the buffer is too small, in which case we'll
- // allocate a fresh one.
- free(temp_data);
- temp_data = reinterpret_cast<unsigned char*>(malloc(32768));
- temp_size = 32768;
+ if (expanded_source.size() < 32768U) {
+ expanded_source.resize(32768U);
}
+ std::vector<unsigned char>& temp_data = expanded_source;
// now the deflate stream
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
- strm.avail_in = uncompressed_target_size;
- strm.next_in = uncompressed_target_data;
+ strm.avail_in = uncompressed_target_data.size();
+ strm.next_in = uncompressed_target_data.data();
ret = deflateInit2(&strm, level, method, windowBits, memLevel, strategy);
+ if (ret != Z_OK) {
+ printf("failed to init uncompressed data deflation: %d\n", ret);
+ return -1;
+ }
do {
- strm.avail_out = temp_size;
- strm.next_out = temp_data;
+ strm.avail_out = temp_data.size();
+ strm.next_out = temp_data.data();
ret = deflate(&strm, Z_FINISH);
- ssize_t have = temp_size - strm.avail_out;
+ ssize_t have = temp_data.size() - strm.avail_out;
- if (sink(temp_data, have, token) != have) {
+ if (sink(temp_data.data(), have, token) != have) {
printf("failed to write %ld compressed bytes to output\n",
(long)have);
return -1;
}
- if (ctx) SHA_update(ctx, temp_data, have);
+ if (ctx) SHA1_Update(ctx, temp_data.data(), have);
} while (ret != Z_STREAM_END);
deflateEnd(&strm);
-
- free(temp_data);
- free(uncompressed_target_data);
} else {
printf("patch chunk %d is unknown type %d\n", i, type);
return -1;
diff --git a/applypatch/include/applypatch/imgpatch.h b/applypatch/include/applypatch/imgpatch.h
new file mode 100644
index 000000000..64d9aa9eb
--- /dev/null
+++ b/applypatch/include/applypatch/imgpatch.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _IMGPATCH_H
+#define _IMGPATCH_H
+
+typedef ssize_t (*SinkFn)(const unsigned char*, ssize_t, void*);
+
+int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size,
+ const unsigned char* patch_data, ssize_t patch_size,
+ SinkFn sink, void* token);
+
+#endif //_IMGPATCH_H
diff --git a/applypatch/libimgpatch.pc b/applypatch/libimgpatch.pc
new file mode 100644
index 000000000..e5002934f
--- /dev/null
+++ b/applypatch/libimgpatch.pc
@@ -0,0 +1,6 @@
+# This file is for libimgpatch in Chrome OS.
+
+Name: libimgpatch
+Description: Apply imgdiff patch
+Version: 0.0.1
+Libs: -limgpatch -lbz2 -lz
diff --git a/applypatch/main.cpp b/applypatch/main.cpp
index 966d8b91f..9013760c4 100644
--- a/applypatch/main.cpp
+++ b/applypatch/main.cpp
@@ -19,9 +19,12 @@
#include <string.h>
#include <unistd.h>
+#include <memory>
+#include <vector>
+
#include "applypatch.h"
#include "edify/expr.h"
-#include "mincrypt/sha.h"
+#include "openssl/sha.h"
static int CheckMode(int argc, char** argv) {
if (argc < 3) {
@@ -43,59 +46,34 @@ static int SpaceMode(int argc, char** argv) {
return CacheSizeCheck(bytes);
}
-// Parse arguments (which should be of the form "<sha1>" or
-// "<sha1>:<filename>" into the new parallel arrays *sha1s and
-// *patches (loading file contents into the patches). Returns true on
+// Parse arguments (which should be of the form "<sha1>:<filename>"
+// into the new parallel arrays *sha1s and *files.Returns true on
// success.
-static bool ParsePatchArgs(int argc, char** argv, char*** sha1s,
- Value*** patches, int* num_patches) {
- *num_patches = argc;
- *sha1s = reinterpret_cast<char**>(malloc(*num_patches * sizeof(char*)));
- *patches = reinterpret_cast<Value**>(malloc(*num_patches * sizeof(Value*)));
- memset(*patches, 0, *num_patches * sizeof(Value*));
-
- uint8_t digest[SHA_DIGEST_SIZE];
+static bool ParsePatchArgs(int argc, char** argv, std::vector<char*>* sha1s,
+ std::vector<FileContents>* files) {
+ uint8_t digest[SHA_DIGEST_LENGTH];
- for (int i = 0; i < *num_patches; ++i) {
+ for (int i = 0; i < argc; ++i) {
char* colon = strchr(argv[i], ':');
- if (colon != NULL) {
- *colon = '\0';
- ++colon;
+ if (colon == nullptr) {
+ printf("no ':' in patch argument \"%s\"\n", argv[i]);
+ return false;
}
-
+ *colon = '\0';
+ ++colon;
if (ParseSha1(argv[i], digest) != 0) {
printf("failed to parse sha1 \"%s\"\n", argv[i]);
return false;
}
- (*sha1s)[i] = argv[i];
- if (colon == NULL) {
- (*patches)[i] = NULL;
- } else {
- FileContents fc;
- if (LoadFileContents(colon, &fc) != 0) {
- goto abort;
- }
- (*patches)[i] = reinterpret_cast<Value*>(malloc(sizeof(Value)));
- (*patches)[i]->type = VAL_BLOB;
- (*patches)[i]->size = fc.size;
- (*patches)[i]->data = reinterpret_cast<char*>(fc.data);
+ sha1s->push_back(argv[i]);
+ FileContents fc;
+ if (LoadFileContents(colon, &fc) != 0) {
+ return false;
}
+ files->push_back(std::move(fc));
}
-
return true;
-
- abort:
- for (int i = 0; i < *num_patches; ++i) {
- Value* p = (*patches)[i];
- if (p != NULL) {
- free(p->data);
- free(p);
- }
- }
- free(*sha1s);
- free(*patches);
- return false;
}
static int FlashMode(const char* src_filename, const char* tgt_filename,
@@ -104,17 +82,19 @@ static int FlashMode(const char* src_filename, const char* tgt_filename,
}
static int PatchMode(int argc, char** argv) {
- Value* bonus = NULL;
+ FileContents bonusFc;
+ Value bonusValue;
+ Value* bonus = nullptr;
+
if (argc >= 3 && strcmp(argv[1], "-b") == 0) {
- FileContents fc;
- if (LoadFileContents(argv[2], &fc) != 0) {
+ if (LoadFileContents(argv[2], &bonusFc) != 0) {
printf("failed to load bonus file %s\n", argv[2]);
return 1;
}
- bonus = reinterpret_cast<Value*>(malloc(sizeof(Value)));
+ bonus = &bonusValue;
bonus->type = VAL_BLOB;
- bonus->size = fc.size;
- bonus->data = (char*)fc.data;
+ bonus->size = bonusFc.data.size();
+ bonus->data = reinterpret_cast<char*>(bonusFc.data.data());
argc -= 2;
argv += 2;
}
@@ -132,41 +112,29 @@ static int PatchMode(int argc, char** argv) {
// If no <src-sha1>:<patch> is provided, it is in flash mode.
if (argc == 5) {
- if (bonus != NULL) {
+ if (bonus != nullptr) {
printf("bonus file not supported in flash mode\n");
return 1;
}
return FlashMode(argv[1], argv[2], argv[3], target_size);
}
-
-
- char** sha1s;
- Value** patches;
- int num_patches;
- if (!ParsePatchArgs(argc-5, argv+5, &sha1s, &patches, &num_patches)) {
+ std::vector<char*> sha1s;
+ std::vector<FileContents> files;
+ if (!ParsePatchArgs(argc-5, argv+5, &sha1s, &files)) {
printf("failed to parse patch args\n");
return 1;
}
-
- int result = applypatch(argv[1], argv[2], argv[3], target_size,
- num_patches, sha1s, patches, bonus);
-
- int i;
- for (i = 0; i < num_patches; ++i) {
- Value* p = patches[i];
- if (p != NULL) {
- free(p->data);
- free(p);
- }
- }
- if (bonus) {
- free(bonus->data);
- free(bonus);
+ std::vector<Value> patches(files.size());
+ std::vector<Value*> patch_ptrs(files.size());
+ for (size_t i = 0; i < files.size(); ++i) {
+ patches[i].type = VAL_BLOB;
+ patches[i].size = files[i].data.size();
+ patches[i].data = reinterpret_cast<char*>(files[i].data.data());
+ patch_ptrs[i] = &patches[i];
}
- free(sha1s);
- free(patches);
-
- return result;
+ return applypatch(argv[1], argv[2], argv[3], target_size,
+ patch_ptrs.size(), sha1s.data(),
+ patch_ptrs.data(), bonus);
}
// This program applies binary patches to files in a way that is safe
diff --git a/bootloader.cpp b/bootloader.cpp
index 600d238f5..d80c5e793 100644
--- a/bootloader.cpp
+++ b/bootloader.cpp
@@ -14,28 +14,33 @@
* limitations under the License.
*/
-#include <fs_mgr.h>
-#include "bootloader.h"
-#include "common.h"
-#include "mtdutils/mtdutils.h"
-#include "roots.h"
-
#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
+#include <sys/types.h>
#include <unistd.h>
-static int get_bootloader_message_mtd(struct bootloader_message *out, const Volume* v);
-static int set_bootloader_message_mtd(const struct bootloader_message *in, const Volume* v);
-static int get_bootloader_message_block(struct bootloader_message *out, const Volume* v);
-static int set_bootloader_message_block(const struct bootloader_message *in, const Volume* v);
+#include <fs_mgr.h>
+
+#include "bootloader.h"
+#include "common.h"
+#include "mtdutils/mtdutils.h"
+#include "roots.h"
+#include "unique_fd.h"
+
+static int get_bootloader_message_mtd(bootloader_message* out, const Volume* v);
+static int set_bootloader_message_mtd(const bootloader_message* in, const Volume* v);
+static int get_bootloader_message_block(bootloader_message* out, const Volume* v);
+static int set_bootloader_message_block(const bootloader_message* in, const Volume* v);
-int get_bootloader_message(struct bootloader_message *out) {
+int get_bootloader_message(bootloader_message* out) {
Volume* v = volume_for_path("/misc");
- if (v == NULL) {
- LOGE("Cannot load volume /misc!\n");
- return -1;
+ if (v == nullptr) {
+ LOGE("Cannot load volume /misc!\n");
+ return -1;
}
if (strcmp(v->fs_type, "mtd") == 0) {
return get_bootloader_message_mtd(out, v);
@@ -46,11 +51,11 @@ int get_bootloader_message(struct bootloader_message *out) {
return -1;
}
-int set_bootloader_message(const struct bootloader_message *in) {
+int set_bootloader_message(const bootloader_message* in) {
Volume* v = volume_for_path("/misc");
- if (v == NULL) {
- LOGE("Cannot load volume /misc!\n");
- return -1;
+ if (v == nullptr) {
+ LOGE("Cannot load volume /misc!\n");
+ return -1;
}
if (strcmp(v->fs_type, "mtd") == 0) {
return set_bootloader_message_mtd(in, v);
@@ -68,69 +73,69 @@ int set_bootloader_message(const struct bootloader_message *in) {
static const int MISC_PAGES = 3; // number of pages to save
static const int MISC_COMMAND_PAGE = 1; // bootloader command is this page
-static int get_bootloader_message_mtd(struct bootloader_message *out,
+static int get_bootloader_message_mtd(bootloader_message* out,
const Volume* v) {
size_t write_size;
mtd_scan_partitions();
- const MtdPartition *part = mtd_find_partition_by_name(v->blk_device);
- if (part == NULL || mtd_partition_info(part, NULL, NULL, &write_size)) {
- LOGE("Can't find %s\n", v->blk_device);
+ const MtdPartition* part = mtd_find_partition_by_name(v->blk_device);
+ if (part == nullptr || mtd_partition_info(part, nullptr, nullptr, &write_size)) {
+ LOGE("failed to find \"%s\"\n", v->blk_device);
return -1;
}
- MtdReadContext *read = mtd_read_partition(part);
- if (read == NULL) {
- LOGE("Can't open %s\n(%s)\n", v->blk_device, strerror(errno));
+ MtdReadContext* read = mtd_read_partition(part);
+ if (read == nullptr) {
+ LOGE("failed to open \"%s\": %s\n", v->blk_device, strerror(errno));
return -1;
}
const ssize_t size = write_size * MISC_PAGES;
char data[size];
ssize_t r = mtd_read_data(read, data, size);
- if (r != size) LOGE("Can't read %s\n(%s)\n", v->blk_device, strerror(errno));
+ if (r != size) LOGE("failed to read \"%s\": %s\n", v->blk_device, strerror(errno));
mtd_read_close(read);
if (r != size) return -1;
memcpy(out, &data[write_size * MISC_COMMAND_PAGE], sizeof(*out));
return 0;
}
-static int set_bootloader_message_mtd(const struct bootloader_message *in,
+static int set_bootloader_message_mtd(const bootloader_message* in,
const Volume* v) {
size_t write_size;
mtd_scan_partitions();
- const MtdPartition *part = mtd_find_partition_by_name(v->blk_device);
- if (part == NULL || mtd_partition_info(part, NULL, NULL, &write_size)) {
- LOGE("Can't find %s\n", v->blk_device);
+ const MtdPartition* part = mtd_find_partition_by_name(v->blk_device);
+ if (part == nullptr || mtd_partition_info(part, nullptr, nullptr, &write_size)) {
+ LOGE("failed to find \"%s\"\n", v->blk_device);
return -1;
}
- MtdReadContext *read = mtd_read_partition(part);
- if (read == NULL) {
- LOGE("Can't open %s\n(%s)\n", v->blk_device, strerror(errno));
+ MtdReadContext* read = mtd_read_partition(part);
+ if (read == nullptr) {
+ LOGE("failed to open \"%s\": %s\n", v->blk_device, strerror(errno));
return -1;
}
ssize_t size = write_size * MISC_PAGES;
char data[size];
ssize_t r = mtd_read_data(read, data, size);
- if (r != size) LOGE("Can't read %s\n(%s)\n", v->blk_device, strerror(errno));
+ if (r != size) LOGE("failed to read \"%s\": %s\n", v->blk_device, strerror(errno));
mtd_read_close(read);
if (r != size) return -1;
memcpy(&data[write_size * MISC_COMMAND_PAGE], in, sizeof(*in));
- MtdWriteContext *write = mtd_write_partition(part);
- if (write == NULL) {
- LOGE("Can't open %s\n(%s)\n", v->blk_device, strerror(errno));
+ MtdWriteContext* write = mtd_write_partition(part);
+ if (write == nullptr) {
+ LOGE("failed to open \"%s\": %s\n", v->blk_device, strerror(errno));
return -1;
}
if (mtd_write_data(write, data, size) != size) {
- LOGE("Can't write %s\n(%s)\n", v->blk_device, strerror(errno));
+ LOGE("failed to write \"%s\": %s\n", v->blk_device, strerror(errno));
mtd_write_close(write);
return -1;
}
if (mtd_write_close(write)) {
- LOGE("Can't finish %s\n(%s)\n", v->blk_device, strerror(errno));
+ LOGE("failed to finish \"%s\": %s\n", v->blk_device, strerror(errno));
return -1;
}
@@ -146,57 +151,67 @@ static int set_bootloader_message_mtd(const struct bootloader_message *in,
static void wait_for_device(const char* fn) {
int tries = 0;
int ret;
- struct stat buf;
do {
++tries;
+ struct stat buf;
ret = stat(fn, &buf);
- if (ret) {
- printf("stat %s try %d: %s\n", fn, tries, strerror(errno));
+ if (ret == -1) {
+ printf("failed to stat \"%s\" try %d: %s\n", fn, tries, strerror(errno));
sleep(1);
}
} while (ret && tries < 10);
+
if (ret) {
- printf("failed to stat %s\n", fn);
+ printf("failed to stat \"%s\"\n", fn);
}
}
-static int get_bootloader_message_block(struct bootloader_message *out,
+static int get_bootloader_message_block(bootloader_message* out,
const Volume* v) {
wait_for_device(v->blk_device);
FILE* f = fopen(v->blk_device, "rb");
- if (f == NULL) {
- LOGE("Can't open %s\n(%s)\n", v->blk_device, strerror(errno));
+ if (f == nullptr) {
+ LOGE("failed to open \"%s\": %s\n", v->blk_device, strerror(errno));
return -1;
}
- struct bootloader_message temp;
+ bootloader_message temp;
int count = fread(&temp, sizeof(temp), 1, f);
if (count != 1) {
- LOGE("Failed reading %s\n(%s)\n", v->blk_device, strerror(errno));
+ LOGE("failed to read \"%s\": %s\n", v->blk_device, strerror(errno));
return -1;
}
if (fclose(f) != 0) {
- LOGE("Failed closing %s\n(%s)\n", v->blk_device, strerror(errno));
+ LOGE("failed to close \"%s\": %s\n", v->blk_device, strerror(errno));
return -1;
}
memcpy(out, &temp, sizeof(temp));
return 0;
}
-static int set_bootloader_message_block(const struct bootloader_message *in,
+static int set_bootloader_message_block(const bootloader_message* in,
const Volume* v) {
wait_for_device(v->blk_device);
- FILE* f = fopen(v->blk_device, "wb");
- if (f == NULL) {
- LOGE("Can't open %s\n(%s)\n", v->blk_device, strerror(errno));
+ unique_fd fd(open(v->blk_device, O_WRONLY | O_SYNC));
+ if (fd.get() == -1) {
+ LOGE("failed to open \"%s\": %s\n", v->blk_device, strerror(errno));
return -1;
}
- int count = fwrite(in, sizeof(*in), 1, f);
- if (count != 1) {
- LOGE("Failed writing %s\n(%s)\n", v->blk_device, strerror(errno));
- return -1;
+
+ size_t written = 0;
+ const uint8_t* start = reinterpret_cast<const uint8_t*>(in);
+ size_t total = sizeof(*in);
+ while (written < total) {
+ ssize_t wrote = TEMP_FAILURE_RETRY(write(fd.get(), start + written, total - written));
+ if (wrote == -1) {
+ LOGE("failed to write %" PRId64 " bytes: %s\n",
+ static_cast<off64_t>(written), strerror(errno));
+ return -1;
+ }
+ written += wrote;
}
- if (fclose(f) != 0) {
- LOGE("Failed closing %s\n(%s)\n", v->blk_device, strerror(errno));
+
+ if (fsync(fd.get()) == -1) {
+ LOGE("failed to fsync \"%s\": %s\n", v->blk_device, strerror(errno));
return -1;
}
return 0;
diff --git a/edify/lexer.ll b/edify/lexer.ll
index fb2933bee..b764d1699 100644
--- a/edify/lexer.ll
+++ b/edify/lexer.ll
@@ -16,6 +16,7 @@
*/
#include <string.h>
+#include <string>
#include "expr.h"
#include "yydefs.h"
@@ -25,9 +26,7 @@ int gLine = 1;
int gColumn = 1;
int gPos = 0;
-// TODO: enforce MAX_STRING_LEN during lexing
-char string_buffer[MAX_STRING_LEN];
-char* string_pos;
+std::string string_buffer;
#define ADVANCE do {yylloc.start=gPos; yylloc.end=gPos+yyleng; \
gColumn+=yyleng; gPos+=yyleng;} while(0)
@@ -43,7 +42,7 @@ char* string_pos;
\" {
BEGIN(STR);
- string_pos = string_buffer;
+ string_buffer.clear();
yylloc.start = gPos;
++gColumn;
++gPos;
@@ -54,36 +53,35 @@ char* string_pos;
++gColumn;
++gPos;
BEGIN(INITIAL);
- *string_pos = '\0';
- yylval.str = strdup(string_buffer);
+ yylval.str = strdup(string_buffer.c_str());
yylloc.end = gPos;
return STRING;
}
- \\n { gColumn += yyleng; gPos += yyleng; *string_pos++ = '\n'; }
- \\t { gColumn += yyleng; gPos += yyleng; *string_pos++ = '\t'; }
- \\\" { gColumn += yyleng; gPos += yyleng; *string_pos++ = '\"'; }
- \\\\ { gColumn += yyleng; gPos += yyleng; *string_pos++ = '\\'; }
+ \\n { gColumn += yyleng; gPos += yyleng; string_buffer.push_back('\n'); }
+ \\t { gColumn += yyleng; gPos += yyleng; string_buffer.push_back('\t'); }
+ \\\" { gColumn += yyleng; gPos += yyleng; string_buffer.push_back('\"'); }
+ \\\\ { gColumn += yyleng; gPos += yyleng; string_buffer.push_back('\\'); }
\\x[0-9a-fA-F]{2} {
gColumn += yyleng;
gPos += yyleng;
int val;
sscanf(yytext+2, "%x", &val);
- *string_pos++ = val;
+ string_buffer.push_back(static_cast<char>(val));
}
\n {
++gLine;
++gPos;
gColumn = 1;
- *string_pos++ = yytext[0];
+ string_buffer.push_back(yytext[0]);
}
. {
++gColumn;
++gPos;
- *string_pos++ = yytext[0];
+ string_buffer.push_back(yytext[0]);
}
}
diff --git a/edify/main.cpp b/edify/main.cpp
index b1baa0b13..6007a3d58 100644
--- a/edify/main.cpp
+++ b/edify/main.cpp
@@ -18,6 +18,8 @@
#include <stdlib.h>
#include <string.h>
+#include <string>
+
#include "expr.h"
#include "parser.h"
@@ -151,6 +153,9 @@ int test() {
expect("greater_than_int(x, 3)", "", &errors);
expect("greater_than_int(3, x)", "", &errors);
+ // big string
+ expect(std::string(8192, 's').c_str(), std::string(8192, 's').c_str(), &errors);
+
printf("\n");
return errors;
diff --git a/install.cpp b/install.cpp
index 7d88ed72a..33c1f5498 100644
--- a/install.cpp
+++ b/install.cpp
@@ -23,6 +23,8 @@
#include <sys/wait.h>
#include <unistd.h>
+#include <vector>
+
#include "common.h"
#include "install.h"
#include "mincrypt/rsa.h"
@@ -122,20 +124,20 @@ try_update_binary(const char* path, ZipArchive* zip, bool* wipe_cache) {
// - the name of the package zip file.
//
- const char** args = (const char**)malloc(sizeof(char*) * 5);
+ const char* args[5];
args[0] = binary;
args[1] = EXPAND(RECOVERY_API_VERSION); // defined in Android.mk
- char* temp = (char*)malloc(10);
- sprintf(temp, "%d", pipefd[1]);
+ char temp[16];
+ snprintf(temp, sizeof(temp), "%d", pipefd[1]);
args[2] = temp;
- args[3] = (char*)path;
+ args[3] = path;
args[4] = NULL;
pid_t pid = fork();
if (pid == 0) {
umask(022);
close(pipefd[0]);
- execv(binary, (char* const*)args);
+ execv(binary, const_cast<char**>(args));
fprintf(stdout, "E:Can't run %s (%s)\n", binary, strerror(errno));
_exit(-1);
}
@@ -221,19 +223,16 @@ really_install_package(const char *path, bool* wipe_cache, bool needs_mount)
return INSTALL_CORRUPT;
}
- int numKeys;
- Certificate* loadedKeys = load_keys(PUBLIC_KEYS_FILE, &numKeys);
- if (loadedKeys == NULL) {
+ std::vector<Certificate> loadedKeys;
+ if (!load_keys(PUBLIC_KEYS_FILE, loadedKeys)) {
LOGE("Failed to load keys\n");
return INSTALL_CORRUPT;
}
- LOGI("%d key(s) loaded from %s\n", numKeys, PUBLIC_KEYS_FILE);
+ LOGI("%zu key(s) loaded from %s\n", loadedKeys.size(), PUBLIC_KEYS_FILE);
ui->Print("Verifying update package...\n");
- int err;
- err = verify_file(map.addr, map.length, loadedKeys, numKeys);
- free(loadedKeys);
+ int err = verify_file(map.addr, map.length, loadedKeys);
LOGI("verify_file returned %d\n", err);
if (err != VERIFY_SUCCESS) {
LOGE("signature verification failed\n");
diff --git a/minadbd/services.cpp b/minadbd/services.cpp
index d25648fb4..658a43f36 100644
--- a/minadbd/services.cpp
+++ b/minadbd/services.cpp
@@ -35,11 +35,10 @@ struct stinfo {
void *cookie;
};
-void* service_bootstrap_func(void* x) {
+void service_bootstrap_func(void* x) {
stinfo* sti = reinterpret_cast<stinfo*>(x);
sti->func(sti->fd, sti->cookie);
free(sti);
- return 0;
}
static void sideload_host_service(int sfd, void* data) {
diff --git a/minui/resources.cpp b/minui/resources.cpp
index 63a0dff28..fdbe554fe 100644
--- a/minui/resources.cpp
+++ b/minui/resources.cpp
@@ -28,6 +28,7 @@
#include <linux/fb.h>
#include <linux/kd.h>
+#include <vector>
#include <png.h>
#include "minui.h"
@@ -398,18 +399,13 @@ int res_create_localized_alpha_surface(const char* name,
png_infop info_ptr = NULL;
png_uint_32 width, height;
png_byte channels;
- unsigned char* row;
png_uint_32 y;
+ std::vector<unsigned char> row;
*pSurface = NULL;
if (locale == NULL) {
- surface = malloc_surface(0);
- surface->width = 0;
- surface->height = 0;
- surface->row_bytes = 0;
- surface->pixel_bytes = 1;
- goto exit;
+ return result;
}
result = open_png(name, &png_ptr, &info_ptr, &width, &height, &channels);
@@ -420,13 +416,13 @@ int res_create_localized_alpha_surface(const char* name,
goto exit;
}
- row = reinterpret_cast<unsigned char*>(malloc(width));
+ row.resize(width);
for (y = 0; y < height; ++y) {
- png_read_row(png_ptr, row, NULL);
+ png_read_row(png_ptr, row.data(), NULL);
int w = (row[1] << 8) | row[0];
int h = (row[3] << 8) | row[2];
int len = row[4];
- char* loc = (char*)row+5;
+ char* loc = reinterpret_cast<char*>(&row[5]);
if (y+1+h >= height || matches_locale(loc, locale)) {
printf(" %20s: %s (%d x %d @ %d)\n", name, loc, w, h, y);
@@ -443,8 +439,8 @@ int res_create_localized_alpha_surface(const char* name,
int i;
for (i = 0; i < h; ++i, ++y) {
- png_read_row(png_ptr, row, NULL);
- memcpy(surface->data + i*w, row, w);
+ png_read_row(png_ptr, row.data(), NULL);
+ memcpy(surface->data + i*w, row.data(), w);
}
*pSurface = reinterpret_cast<GRSurface*>(surface);
@@ -452,7 +448,7 @@ int res_create_localized_alpha_surface(const char* name,
} else {
int i;
for (i = 0; i < h; ++i, ++y) {
- png_read_row(png_ptr, row, NULL);
+ png_read_row(png_ptr, row.data(), NULL);
}
}
}
diff --git a/minzip/Android.mk b/minzip/Android.mk
index 22eabfbb1..3d36fd64e 100644
--- a/minzip/Android.mk
+++ b/minzip/Android.mk
@@ -4,7 +4,7 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
Hash.c \
SysUtil.c \
- DirUtil.c \
+ DirUtil.cpp \
Inlines.c \
Zip.c
diff --git a/minzip/DirUtil.c b/minzip/DirUtil.cpp
index 97cb2e0ee..823b6ed2f 100644
--- a/minzip/DirUtil.c
+++ b/minzip/DirUtil.cpp
@@ -24,6 +24,8 @@
#include <dirent.h>
#include <limits.h>
+#include <string>
+
#include "DirUtil.h"
typedef enum { DMISSING, DDIR, DILLEGAL } DirStatus;
@@ -66,43 +68,25 @@ dirCreateHierarchy(const char *path, int mode,
errno = ENOENT;
return -1;
}
-
- /* Allocate a path that we can modify; stick a slash on
- * the end to make things easier.
- */
- size_t pathLen = strlen(path);
- char *cpath = (char *)malloc(pathLen + 2);
- if (cpath == NULL) {
- errno = ENOMEM;
- return -1;
- }
- memcpy(cpath, path, pathLen);
+ // Allocate a path that we can modify; stick a slash on
+ // the end to make things easier.
+ std::string cpath = path;
if (stripFileName) {
- /* Strip everything after the last slash.
- */
- char *c = cpath + pathLen - 1;
- while (c != cpath && *c != '/') {
- c--;
- }
- if (c == cpath) {
- //xxx test this path
- /* No directory component. Act like the path was empty.
- */
+ // Strip everything after the last slash.
+ size_t pos = cpath.rfind('/');
+ if (pos == std::string::npos) {
errno = ENOENT;
- free(cpath);
return -1;
}
- c[1] = '\0'; // Terminate after the slash we found.
+ cpath.resize(pos + 1);
} else {
- /* Make sure that the path ends in a slash.
- */
- cpath[pathLen] = '/';
- cpath[pathLen + 1] = '\0';
+ // Make sure that the path ends in a slash.
+ cpath.push_back('/');
}
/* See if it already exists.
*/
- ds = getPathDirStatus(cpath);
+ ds = getPathDirStatus(cpath.c_str());
if (ds == DDIR) {
return 0;
} else if (ds == DILLEGAL) {
@@ -112,7 +96,8 @@ dirCreateHierarchy(const char *path, int mode,
/* Walk up the path from the root and make each level.
* If a directory already exists, no big deal.
*/
- char *p = cpath;
+ const char *path_start = &cpath[0];
+ char *p = &cpath[0];
while (*p != '\0') {
/* Skip any slashes, watching out for the end of the string.
*/
@@ -135,12 +120,11 @@ dirCreateHierarchy(const char *path, int mode,
/* Check this part of the path and make a new directory
* if necessary.
*/
- ds = getPathDirStatus(cpath);
+ ds = getPathDirStatus(path_start);
if (ds == DILLEGAL) {
/* Could happen if some other process/thread is
* messing with the filesystem.
*/
- free(cpath);
return -1;
} else if (ds == DMISSING) {
int err;
@@ -148,11 +132,11 @@ dirCreateHierarchy(const char *path, int mode,
char *secontext = NULL;
if (sehnd) {
- selabel_lookup(sehnd, &secontext, cpath, mode);
+ selabel_lookup(sehnd, &secontext, path_start, mode);
setfscreatecon(secontext);
}
- err = mkdir(cpath, mode);
+ err = mkdir(path_start, mode);
if (secontext) {
freecon(secontext);
@@ -160,22 +144,17 @@ dirCreateHierarchy(const char *path, int mode,
}
if (err != 0) {
- free(cpath);
return -1;
}
- if (timestamp != NULL && utime(cpath, timestamp)) {
- free(cpath);
+ if (timestamp != NULL && utime(path_start, timestamp)) {
return -1;
}
}
// else, this directory already exists.
-
- /* Repair the path and continue.
- */
+
+ // Repair the path and continue.
*p = '/';
}
- free(cpath);
-
return 0;
}
diff --git a/otafault/Android.mk b/otafault/Android.mk
new file mode 100644
index 000000000..75617a146
--- /dev/null
+++ b/otafault/Android.mk
@@ -0,0 +1,58 @@
+# Copyright 2015 The ANdroid Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific languae governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+empty :=
+space := $(empty) $(empty)
+comma := ,
+
+ifneq ($(TARGET_INJECT_FAULTS),)
+TARGET_INJECT_FAULTS := $(subst $(comma),$(space),$(strip $(TARGET_INJECT_FAULTS)))
+endif
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := ota_io.cpp
+LOCAL_MODULE_TAGS := eng
+LOCAL_MODULE := libotafault
+LOCAL_CLANG := true
+
+ifneq ($(TARGET_INJECT_FAULTS),)
+$(foreach ft,$(TARGET_INJECT_FAULTS),\
+ $(eval LOCAL_CFLAGS += -DTARGET_$(ft)_FAULT=$(TARGET_$(ft)_FAULT_FILE)))
+LOCAL_CFLAGS += -Wno-unused-parameter
+LOCAL_CFLAGS += -DTARGET_INJECT_FAULTS
+endif
+
+LOCAL_STATIC_LIBRARIES := libc
+
+include $(BUILD_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := ota_io.cpp test.cpp
+LOCAL_MODULE_TAGS := tests
+LOCAL_MODULE := otafault_test
+LOCAL_STATIC_LIBRARIES := libc
+LOCAL_FORCE_STATIC_EXECUTABLE := true
+LOCAL_CFLAGS += -Wno-unused-parameter -Wno-writable-strings
+
+ifneq ($(TARGET_INJECT_FAULTS),)
+$(foreach ft,$(TARGET_INJECT_FAULTS),\
+ $(eval LOCAL_CFLAGS += -DTARGET_$(ft)_FAULT=$(TARGET_$(ft)_FAULT_FILE)))
+LOCAL_CFLAGS += -DTARGET_INJECT_FAULTS
+endif
+
+include $(BUILD_EXECUTABLE)
diff --git a/otafault/ota_io.cpp b/otafault/ota_io.cpp
new file mode 100644
index 000000000..02e80f9bf
--- /dev/null
+++ b/otafault/ota_io.cpp
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#if defined (TARGET_INJECT_FAULTS)
+#include <map>
+#endif
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "ota_io.h"
+
+#if defined (TARGET_INJECT_FAULTS)
+static std::map<int, const char*> FilenameCache;
+static std::string FaultFileName =
+#if defined (TARGET_READ_FAULT)
+ TARGET_READ_FAULT;
+#elif defined (TARGET_WRITE_FAULT)
+ TARGET_WRITE_FAULT;
+#elif defined (TARGET_FSYNC_FAULT)
+ TARGET_FSYNC_FAULT;
+#endif // defined (TARGET_READ_FAULT)
+#endif // defined (TARGET_INJECT_FAULTS)
+
+int ota_open(const char* path, int oflags) {
+#if defined (TARGET_INJECT_FAULTS)
+ // Let the caller handle errors; we do not care if open succeeds or fails
+ int fd = open(path, oflags);
+ FilenameCache[fd] = path;
+ return fd;
+#else
+ return open(path, oflags);
+#endif
+}
+
+int ota_open(const char* path, int oflags, mode_t mode) {
+#if defined (TARGET_INJECT_FAULTS)
+ int fd = open(path, oflags, mode);
+ FilenameCache[fd] = path;
+ return fd;
+#else
+ return open(path, oflags, mode);
+#endif
+}
+
+FILE* ota_fopen(const char* path, const char* mode) {
+#if defined (TARGET_INJECT_FAULTS)
+ FILE* fh = fopen(path, mode);
+ FilenameCache[(intptr_t)fh] = path;
+ return fh;
+#else
+ return fopen(path, mode);
+#endif
+}
+
+int ota_close(int fd) {
+#if defined (TARGET_INJECT_FAULTS)
+ // descriptors can be reused, so make sure not to leave them in the cahce
+ FilenameCache.erase(fd);
+#endif
+ return close(fd);
+}
+
+int ota_fclose(FILE* fh) {
+#if defined (TARGET_INJECT_FAULTS)
+ FilenameCache.erase((intptr_t)fh);
+#endif
+ return fclose(fh);
+}
+
+size_t ota_fread(void* ptr, size_t size, size_t nitems, FILE* stream) {
+#if defined (TARGET_READ_FAULT)
+ if (FilenameCache.find((intptr_t)stream) != FilenameCache.end()
+ && FilenameCache[(intptr_t)stream] == FaultFileName) {
+ FaultFileName = "";
+ errno = EIO;
+ return 0;
+ } else {
+ return fread(ptr, size, nitems, stream);
+ }
+#else
+ return fread(ptr, size, nitems, stream);
+#endif
+}
+
+ssize_t ota_read(int fd, void* buf, size_t nbyte) {
+#if defined (TARGET_READ_FAULT)
+ if (FilenameCache.find(fd) != FilenameCache.end()
+ && FilenameCache[fd] == FaultFileName) {
+ FaultFileName = "";
+ errno = EIO;
+ return -1;
+ } else {
+ return read(fd, buf, nbyte);
+ }
+#else
+ return read(fd, buf, nbyte);
+#endif
+}
+
+size_t ota_fwrite(const void* ptr, size_t size, size_t count, FILE* stream) {
+#if defined (TARGET_WRITE_FAULT)
+ if (FilenameCache.find((intptr_t)stream) != FilenameCache.end()
+ && FilenameCache[(intptr_t)stream] == FaultFileName) {
+ FaultFileName = "";
+ errno = EIO;
+ return 0;
+ } else {
+ return fwrite(ptr, size, count, stream);
+ }
+#else
+ return fwrite(ptr, size, count, stream);
+#endif
+}
+
+ssize_t ota_write(int fd, const void* buf, size_t nbyte) {
+#if defined (TARGET_WRITE_FAULT)
+ if (FilenameCache.find(fd) != FilenameCache.end()
+ && FilenameCache[fd] == FaultFileName) {
+ FaultFileName = "";
+ errno = EIO;
+ return -1;
+ } else {
+ return write(fd, buf, nbyte);
+ }
+#else
+ return write(fd, buf, nbyte);
+#endif
+}
+
+int ota_fsync(int fd) {
+#if defined (TARGET_FSYNC_FAULT)
+ if (FilenameCache.find(fd) != FilenameCache.end()
+ && FilenameCache[fd] == FaultFileName) {
+ FaultFileName = "";
+ errno = EIO;
+ return -1;
+ } else {
+ return fsync(fd);
+ }
+#else
+ return fsync(fd);
+#endif
+}
diff --git a/otafault/ota_io.h b/otafault/ota_io.h
new file mode 100644
index 000000000..641a5ae0a
--- /dev/null
+++ b/otafault/ota_io.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Provide a series of proxy functions for basic file accessors.
+ * The behavior of these functions can be changed to return different
+ * errors under a variety of conditions.
+ */
+
+#ifndef _UPDATER_OTA_IO_H_
+#define _UPDATER_OTA_IO_H_
+
+#include <stdio.h>
+#include <sys/stat.h>
+
+int ota_open(const char* path, int oflags);
+
+int ota_open(const char* path, int oflags, mode_t mode);
+
+FILE* ota_fopen(const char* filename, const char* mode);
+
+int ota_close(int fd);
+
+int ota_fclose(FILE* fh);
+
+size_t ota_fread(void* ptr, size_t size, size_t nitems, FILE* stream);
+
+ssize_t ota_read(int fd, void* buf, size_t nbyte);
+
+size_t ota_fwrite(const void* ptr, size_t size, size_t count, FILE* stream);
+
+ssize_t ota_write(int fd, const void* buf, size_t nbyte);
+
+int ota_fsync(int fd);
+
+#endif
diff --git a/otafault/test.cpp b/otafault/test.cpp
new file mode 100644
index 000000000..a0f731517
--- /dev/null
+++ b/otafault/test.cpp
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+#include "ota_io.h"
+
+int main(int argc, char **argv) {
+ int fd = open("testdata/test.file", O_RDWR);
+ char buf[8];
+ char *out = "321";
+ int readv = ota_read(fd, buf, 4);
+ printf("Read returned %d\n", readv);
+ int writev = ota_write(fd, out, 4);
+ printf("Write returned %d\n", writev);
+ return 0;
+}
diff --git a/print_sha1.h b/print_sha1.h
index 9e37c5fe3..fa3d7e009 100644
--- a/print_sha1.h
+++ b/print_sha1.h
@@ -20,9 +20,9 @@
#include <stdint.h>
#include <string>
-#include "mincrypt/sha.h"
+#include "openssl/sha.h"
-static std::string print_sha1(const uint8_t sha1[SHA_DIGEST_SIZE], size_t len) {
+static std::string print_sha1(const uint8_t sha1[SHA_DIGEST_LENGTH], size_t len) {
const char* hex = "0123456789abcdef";
std::string result = "";
for (size_t i = 0; i < len; ++i) {
@@ -32,11 +32,11 @@ static std::string print_sha1(const uint8_t sha1[SHA_DIGEST_SIZE], size_t len) {
return result;
}
-static std::string print_sha1(const uint8_t sha1[SHA_DIGEST_SIZE]) {
- return print_sha1(sha1, SHA_DIGEST_SIZE);
+static std::string print_sha1(const uint8_t sha1[SHA_DIGEST_LENGTH]) {
+ return print_sha1(sha1, SHA_DIGEST_LENGTH);
}
-static std::string short_sha1(const uint8_t sha1[SHA_DIGEST_SIZE]) {
+static std::string short_sha1(const uint8_t sha1[SHA_DIGEST_LENGTH]) {
return print_sha1(sha1, 4);
}
diff --git a/tests/Android.mk b/tests/Android.mk
index 4ce00b457..262fb8bfd 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -16,11 +16,40 @@
LOCAL_PATH := $(call my-dir)
+# Unit tests
include $(CLEAR_VARS)
LOCAL_CLANG := true
+LOCAL_MODULE := recovery_unit_test
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
LOCAL_STATIC_LIBRARIES := libverifier
-LOCAL_SRC_FILES := asn1_decoder_test.cpp
-LOCAL_MODULE := asn1_decoder_test
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/..
+LOCAL_SRC_FILES := unit/asn1_decoder_test.cpp
+LOCAL_C_INCLUDES := bootable/recovery
+include $(BUILD_NATIVE_TEST)
+
+# Component tests
+include $(CLEAR_VARS)
+LOCAL_CLANG := true
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+LOCAL_MODULE := recovery_component_test
+LOCAL_C_INCLUDES := bootable/recovery
+LOCAL_SRC_FILES := component/verifier_test.cpp
+LOCAL_FORCE_STATIC_EXECUTABLE := true
+LOCAL_STATIC_LIBRARIES := \
+ libbase \
+ libverifier \
+ libmincrypt \
+ libminui \
+ libminzip \
+ libcutils \
+ libc
+
+testdata_out_path := $(TARGET_OUT_DATA_NATIVE_TESTS)/recovery
+testdata_files := $(call find-subdir-files, testdata/*)
+
+GEN := $(addprefix $(testdata_out_path)/, $(testdata_files))
+$(GEN): PRIVATE_PATH := $(LOCAL_PATH)
+$(GEN): PRIVATE_CUSTOM_TOOL = cp $< $@
+$(GEN): $(testdata_out_path)/% : $(LOCAL_PATH)/%
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
include $(BUILD_NATIVE_TEST)
diff --git a/verifier_test.cpp b/tests/component/verifier_test.cpp
index 21633dc20..d6f1e0bb9 100644
--- a/verifier_test.cpp
+++ b/tests/component/verifier_test.cpp
@@ -1,13 +1,13 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
- * Licensed under the Apache License, Version 2.0 (the "License");
+ * Licensed under the Apache License, version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
- * Unless required by applicable law or agreed to in writing, software
+ * Unless required by applicable law or agree to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
@@ -16,19 +16,33 @@
#include <errno.h>
#include <fcntl.h>
-#include <stdarg.h>
+#include <gtest/gtest.h>
#include <stdio.h>
#include <stdlib.h>
-#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <android-base/stringprintf.h>
+
#include "common.h"
-#include "verifier.h"
-#include "ui.h"
#include "mincrypt/sha.h"
#include "mincrypt/sha256.h"
#include "minzip/SysUtil.h"
+#include "ui.h"
+#include "verifier.h"
+
+#if defined(__LP64__)
+#define NATIVE_TEST_PATH "/nativetest64"
+#else
+#define NATIVE_TEST_PATH "/nativetest"
+#endif
+
+static const char* DATA_PATH = getenv("ANDROID_DATA");
+static const char* TESTDATA_PATH = "/recovery/testdata/";
// This is build/target/product/security/testkey.x509.pem after being
// dumped out by dumpkey.jar.
@@ -120,19 +134,17 @@ ECPublicKey test_ec_key =
RecoveryUI* ui = NULL;
-// verifier expects to find a UI object; we provide one that does
-// nothing but print.
-class FakeUI : public RecoveryUI {
+class MockUI : public RecoveryUI {
void Init() { }
void SetStage(int, int) { }
void SetLocale(const char*) { }
- void SetBackground(Icon icon) { }
+ void SetBackground(Icon /*icon*/) { }
- void SetProgressType(ProgressType determinate) { }
- void ShowProgress(float portion, float seconds) { }
- void SetProgress(float fraction) { }
+ void SetProgressType(ProgressType /*determinate*/) { }
+ void ShowProgress(float /*portion*/, float /*seconds*/) { }
+ void SetProgress(float /*fraction*/) { }
- void ShowText(bool visible) { }
+ void ShowText(bool /*visible*/) { }
bool IsTextVisible() { return false; }
bool WasTextEverVisible() { return false; }
void Print(const char* fmt, ...) {
@@ -149,9 +161,10 @@ class FakeUI : public RecoveryUI {
}
void ShowFile(const char*) { }
- void StartMenu(const char* const * headers, const char* const * items,
- int initial_selection) { }
- int SelectMenu(int sel) { return 0; }
+ void StartMenu(const char* const* /*headers*/,
+ const char* const* /*items*/,
+ int /*initial_selection*/) { }
+ int SelectMenu(int /*sel*/) { return 0; }
void EndMenu() { }
};
@@ -163,100 +176,93 @@ ui_print(const char* format, ...) {
va_end(ap);
}
-static Certificate* add_certificate(Certificate** certsp, int* num_keys,
- Certificate::KeyType key_type) {
- int i = *num_keys;
- *num_keys = *num_keys + 1;
- *certsp = (Certificate*) realloc(*certsp, *num_keys * sizeof(Certificate));
- Certificate* certs = *certsp;
- certs[i].rsa = NULL;
- certs[i].ec = NULL;
- certs[i].key_type = key_type;
- certs[i].hash_len = SHA_DIGEST_SIZE;
- return &certs[i];
-}
-
-int main(int argc, char **argv) {
- if (argc < 2) {
- fprintf(stderr, "Usage: %s [-sha256] [-ec | -f4 | -file <keys>] <package>\n", argv[0]);
- return 2;
- }
- Certificate* certs = NULL;
- int num_keys = 0;
+class VerifierTest : public testing::TestWithParam<std::vector<std::string>> {
+ public:
+ MemMapping memmap;
+ std::vector<Certificate> certs;
- int argn = 1;
- while (argn < argc) {
- if (strcmp(argv[argn], "-sha256") == 0) {
- if (num_keys == 0) {
- fprintf(stderr, "May only specify -sha256 after key type\n");
- return 2;
+ virtual void SetUp() {
+ std::vector<std::string> args = GetParam();
+ std::string package = android::base::StringPrintf("%s%s%s%s", DATA_PATH, NATIVE_TEST_PATH,
+ TESTDATA_PATH, args[0].c_str());
+ for (auto it = ++(args.cbegin()); it != args.cend(); ++it) {
+ if (it->substr(it->length() - 3, it->length()) == "256") {
+ if (certs.empty()) {
+ FAIL() << "May only specify -sha256 after key type\n";
+ }
+ certs.back().hash_len = SHA256_DIGEST_SIZE;
+ } else if (*it == "ec") {
+ certs.emplace_back(SHA_DIGEST_SIZE, Certificate::EC,
+ nullptr, std::unique_ptr<ECPublicKey>(new ECPublicKey(test_ec_key)));
+ } else if (*it == "e3") {
+ certs.emplace_back(SHA_DIGEST_SIZE, Certificate::RSA,
+ std::unique_ptr<RSAPublicKey>(new RSAPublicKey(test_key)), nullptr);
+ } else if (*it == "f4") {
+ certs.emplace_back(SHA_DIGEST_SIZE, Certificate::RSA,
+ std::unique_ptr<RSAPublicKey>(new RSAPublicKey(test_f4_key)), nullptr);
}
- ++argn;
- Certificate* cert = &certs[num_keys - 1];
- cert->hash_len = SHA256_DIGEST_SIZE;
- } else if (strcmp(argv[argn], "-ec") == 0) {
- ++argn;
- Certificate* cert = add_certificate(&certs, &num_keys, Certificate::EC);
- cert->ec = &test_ec_key;
- } else if (strcmp(argv[argn], "-e3") == 0) {
- ++argn;
- Certificate* cert = add_certificate(&certs, &num_keys, Certificate::RSA);
- cert->rsa = &test_key;
- } else if (strcmp(argv[argn], "-f4") == 0) {
- ++argn;
- Certificate* cert = add_certificate(&certs, &num_keys, Certificate::RSA);
- cert->rsa = &test_f4_key;
- } else if (strcmp(argv[argn], "-file") == 0) {
- if (certs != NULL) {
- fprintf(stderr, "Cannot specify -file with other certs specified\n");
- return 2;
- }
- ++argn;
- certs = load_keys(argv[argn], &num_keys);
- ++argn;
- } else if (argv[argn][0] == '-') {
- fprintf(stderr, "Unknown argument %s\n", argv[argn]);
- return 2;
- } else {
- break;
+ }
+ if (certs.empty()) {
+ certs.emplace_back(SHA_DIGEST_SIZE, Certificate::RSA,
+ std::unique_ptr<RSAPublicKey>(new RSAPublicKey(test_key)), nullptr);
+ }
+ if (sysMapFile(package.c_str(), &memmap) != 0) {
+ FAIL() << "Failed to mmap " << package << ": " << strerror(errno) << "\n";
}
}
- if (argn == argc) {
- fprintf(stderr, "Must specify package to verify\n");
- return 2;
+ static void SetUpTestCase() {
+ ui = new MockUI();
}
+};
- if (num_keys == 0) {
- certs = (Certificate*) calloc(1, sizeof(Certificate));
- if (certs == NULL) {
- fprintf(stderr, "Failure allocating memory for default certificate\n");
- return 1;
- }
- certs->key_type = Certificate::RSA;
- certs->rsa = &test_key;
- certs->ec = NULL;
- certs->hash_len = SHA_DIGEST_SIZE;
- num_keys = 1;
- }
+class VerifierSuccessTest : public VerifierTest {
+};
- ui = new FakeUI();
+class VerifierFailureTest : public VerifierTest {
+};
- MemMapping map;
- if (sysMapFile(argv[argn], &map) != 0) {
- fprintf(stderr, "failed to mmap %s: %s\n", argv[argn], strerror(errno));
- return 4;
- }
+TEST_P(VerifierSuccessTest, VerifySucceed) {
+ ASSERT_EQ(verify_file(memmap.addr, memmap.length, certs), VERIFY_SUCCESS);
+}
- int result = verify_file(map.addr, map.length, certs, num_keys);
- if (result == VERIFY_SUCCESS) {
- printf("VERIFIED\n");
- return 0;
- } else if (result == VERIFY_FAILURE) {
- printf("NOT VERIFIED\n");
- return 1;
- } else {
- printf("bad return value\n");
- return 3;
- }
+TEST_P(VerifierFailureTest, VerifyFailure) {
+ ASSERT_EQ(verify_file(memmap.addr, memmap.length, certs), VERIFY_FAILURE);
}
+
+INSTANTIATE_TEST_CASE_P(SingleKeySuccess, VerifierSuccessTest,
+ ::testing::Values(
+ std::vector<std::string>({"otasigned.zip", "e3"}),
+ std::vector<std::string>({"otasigned_f4.zip", "f4"}),
+ std::vector<std::string>({"otasigned_sha256.zip", "e3", "sha256"}),
+ std::vector<std::string>({"otasigned_f4_sha256.zip", "f4", "sha256"}),
+ std::vector<std::string>({"otasigned_ecdsa_sha256.zip", "ec", "sha256"})));
+
+INSTANTIATE_TEST_CASE_P(MultiKeySuccess, VerifierSuccessTest,
+ ::testing::Values(
+ std::vector<std::string>({"otasigned.zip", "f4", "e3"}),
+ std::vector<std::string>({"otasigned_f4.zip", "ec", "f4"}),
+ std::vector<std::string>({"otasigned_sha256.zip", "ec", "e3", "e3", "sha256"}),
+ std::vector<std::string>({"otasigned_f4_sha256.zip", "ec", "sha256", "e3", "f4", "sha256"}),
+ std::vector<std::string>({"otasigned_ecdsa_sha256.zip", "f4", "sha256", "e3", "ec", "sha256"})));
+
+INSTANTIATE_TEST_CASE_P(WrongKey, VerifierFailureTest,
+ ::testing::Values(
+ std::vector<std::string>({"otasigned.zip", "f4"}),
+ std::vector<std::string>({"otasigned_f4.zip", "e3"}),
+ std::vector<std::string>({"otasigned_ecdsa_sha256.zip", "e3", "sha256"})));
+
+INSTANTIATE_TEST_CASE_P(WrongHash, VerifierFailureTest,
+ ::testing::Values(
+ std::vector<std::string>({"otasigned.zip", "e3", "sha256"}),
+ std::vector<std::string>({"otasigned_f4.zip", "f4", "sha256"}),
+ std::vector<std::string>({"otasigned_sha256.zip"}),
+ std::vector<std::string>({"otasigned_f4_sha256.zip", "f4"}),
+ std::vector<std::string>({"otasigned_ecdsa_sha256.zip"})));
+
+INSTANTIATE_TEST_CASE_P(BadPackage, VerifierFailureTest,
+ ::testing::Values(
+ std::vector<std::string>({"random.zip"}),
+ std::vector<std::string>({"fake-eocd.zip"}),
+ std::vector<std::string>({"alter-metadata.zip"}),
+ std::vector<std::string>({"alter-footer.zip"})));
diff --git a/testdata/alter-footer.zip b/tests/testdata/alter-footer.zip
index f497ec000..f497ec000 100644
--- a/testdata/alter-footer.zip
+++ b/tests/testdata/alter-footer.zip
Binary files differ
diff --git a/testdata/alter-metadata.zip b/tests/testdata/alter-metadata.zip
index 1c71fbc49..1c71fbc49 100644
--- a/testdata/alter-metadata.zip
+++ b/tests/testdata/alter-metadata.zip
Binary files differ
diff --git a/testdata/fake-eocd.zip b/tests/testdata/fake-eocd.zip
index 15dc0a946..15dc0a946 100644
--- a/testdata/fake-eocd.zip
+++ b/tests/testdata/fake-eocd.zip
Binary files differ
diff --git a/testdata/jarsigned.zip b/tests/testdata/jarsigned.zip
index 8b1ef8bdd..8b1ef8bdd 100644
--- a/testdata/jarsigned.zip
+++ b/tests/testdata/jarsigned.zip
Binary files differ
diff --git a/testdata/otasigned.zip b/tests/testdata/otasigned.zip
index a6bc53e41..a6bc53e41 100644
--- a/testdata/otasigned.zip
+++ b/tests/testdata/otasigned.zip
Binary files differ
diff --git a/testdata/otasigned_ecdsa_sha256.zip b/tests/testdata/otasigned_ecdsa_sha256.zip
index 999fcdd0f..999fcdd0f 100644
--- a/testdata/otasigned_ecdsa_sha256.zip
+++ b/tests/testdata/otasigned_ecdsa_sha256.zip
Binary files differ
diff --git a/testdata/otasigned_f4.zip b/tests/testdata/otasigned_f4.zip
index dd1e4dd40..dd1e4dd40 100644
--- a/testdata/otasigned_f4.zip
+++ b/tests/testdata/otasigned_f4.zip
Binary files differ
diff --git a/testdata/otasigned_f4_sha256.zip b/tests/testdata/otasigned_f4_sha256.zip
index 3af408c40..3af408c40 100644
--- a/testdata/otasigned_f4_sha256.zip
+++ b/tests/testdata/otasigned_f4_sha256.zip
Binary files differ
diff --git a/testdata/otasigned_sha256.zip b/tests/testdata/otasigned_sha256.zip
index 0ed4409b3..0ed4409b3 100644
--- a/testdata/otasigned_sha256.zip
+++ b/tests/testdata/otasigned_sha256.zip
Binary files differ
diff --git a/testdata/random.zip b/tests/testdata/random.zip
index 18c0b3b9f..18c0b3b9f 100644
--- a/testdata/random.zip
+++ b/tests/testdata/random.zip
Binary files differ
diff --git a/testdata/test_f4.pk8 b/tests/testdata/test_f4.pk8
index 3052613c5..3052613c5 100644
--- a/testdata/test_f4.pk8
+++ b/tests/testdata/test_f4.pk8
Binary files differ
diff --git a/testdata/test_f4.x509.pem b/tests/testdata/test_f4.x509.pem
index 814abcf99..814abcf99 100644
--- a/testdata/test_f4.x509.pem
+++ b/tests/testdata/test_f4.x509.pem
diff --git a/testdata/test_f4_sha256.x509.pem b/tests/testdata/test_f4_sha256.x509.pem
index 9d5376b45..9d5376b45 100644
--- a/testdata/test_f4_sha256.x509.pem
+++ b/tests/testdata/test_f4_sha256.x509.pem
diff --git a/testdata/testkey.pk8 b/tests/testdata/testkey.pk8
index 586c1bd5c..586c1bd5c 100644
--- a/testdata/testkey.pk8
+++ b/tests/testdata/testkey.pk8
Binary files differ
diff --git a/testdata/testkey.x509.pem b/tests/testdata/testkey.x509.pem
index e242d83e2..e242d83e2 100644
--- a/testdata/testkey.x509.pem
+++ b/tests/testdata/testkey.x509.pem
diff --git a/testdata/testkey_ecdsa.pk8 b/tests/testdata/testkey_ecdsa.pk8
index 9a521c8cf..9a521c8cf 100644
--- a/testdata/testkey_ecdsa.pk8
+++ b/tests/testdata/testkey_ecdsa.pk8
Binary files differ
diff --git a/testdata/testkey_ecdsa.x509.pem b/tests/testdata/testkey_ecdsa.x509.pem
index b12283645..b12283645 100644
--- a/testdata/testkey_ecdsa.x509.pem
+++ b/tests/testdata/testkey_ecdsa.x509.pem
diff --git a/testdata/testkey_sha256.x509.pem b/tests/testdata/testkey_sha256.x509.pem
index 002ce8968..002ce8968 100644
--- a/testdata/testkey_sha256.x509.pem
+++ b/tests/testdata/testkey_sha256.x509.pem
diff --git a/testdata/unsigned.zip b/tests/testdata/unsigned.zip
index 24e3eadac..24e3eadac 100644
--- a/testdata/unsigned.zip
+++ b/tests/testdata/unsigned.zip
Binary files differ
diff --git a/tests/asn1_decoder_test.cpp b/tests/unit/asn1_decoder_test.cpp
index af96d87d2..af96d87d2 100644
--- a/tests/asn1_decoder_test.cpp
+++ b/tests/unit/asn1_decoder_test.cpp
diff --git a/uncrypt/uncrypt.cpp b/uncrypt/uncrypt.cpp
index de7e48182..705744eb6 100644
--- a/uncrypt/uncrypt.cpp
+++ b/uncrypt/uncrypt.cpp
@@ -42,6 +42,7 @@
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
+#include <libgen.h>
#include <linux/fs.h>
#include <stdarg.h>
#include <stdio.h>
@@ -52,9 +53,13 @@
#include <sys/types.h>
#include <unistd.h>
+#include <algorithm>
#include <memory>
+#include <vector>
#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <cutils/android_reboot.h>
#include <cutils/properties.h>
@@ -63,59 +68,39 @@
#define LOG_TAG "uncrypt"
#include <log/log.h>
+#include "bootloader.h"
#include "unique_fd.h"
#define WINDOW_SIZE 5
-static const std::string cache_block_map = "/cache/recovery/block.map";
-static const std::string status_file = "/cache/recovery/uncrypt_status";
-static const std::string uncrypt_file = "/cache/recovery/uncrypt_file";
+static const std::string CACHE_BLOCK_MAP = "/cache/recovery/block.map";
+static const std::string COMMAND_FILE = "/cache/recovery/command";
+static const std::string STATUS_FILE = "/cache/recovery/uncrypt_status";
+static const std::string UNCRYPT_PATH_FILE = "/cache/recovery/uncrypt_file";
static struct fstab* fstab = NULL;
static int write_at_offset(unsigned char* buffer, size_t size, int wfd, off64_t offset) {
if (TEMP_FAILURE_RETRY(lseek64(wfd, offset, SEEK_SET)) == -1) {
- ALOGE("error seeking to offset %" PRId64 ": %s\n", offset, strerror(errno));
+ ALOGE("error seeking to offset %" PRId64 ": %s", offset, strerror(errno));
return -1;
}
- size_t written = 0;
- while (written < size) {
- ssize_t wrote = TEMP_FAILURE_RETRY(write(wfd, buffer + written, size - written));
- if (wrote == -1) {
- ALOGE("error writing offset %" PRId64 ": %s\n",
- offset + static_cast<off64_t>(written), strerror(errno));
- return -1;
- }
- written += wrote;
+ if (!android::base::WriteFully(wfd, buffer, size)) {
+ ALOGE("error writing offset %" PRId64 ": %s", offset, strerror(errno));
+ return -1;
}
return 0;
}
-static void add_block_to_ranges(int** ranges, int* range_alloc, int* range_used, int new_block) {
- // If the current block start is < 0, set the start to the new
- // block. (This only happens for the very first block of the very
- // first range.)
- if ((*ranges)[*range_used*2-2] < 0) {
- (*ranges)[*range_used*2-2] = new_block;
- (*ranges)[*range_used*2-1] = new_block;
- }
-
- if (new_block == (*ranges)[*range_used*2-1]) {
+static void add_block_to_ranges(std::vector<int>& ranges, int new_block) {
+ if (!ranges.empty() && new_block == ranges.back()) {
// If the new block comes immediately after the current range,
// all we have to do is extend the current range.
- ++(*ranges)[*range_used*2-1];
+ ++ranges.back();
} else {
// We need to start a new range.
-
- // If there isn't enough room in the array, we need to expand it.
- if (*range_used >= *range_alloc) {
- *range_alloc *= 2;
- *ranges = reinterpret_cast<int*>(realloc(*ranges, *range_alloc * 2 * sizeof(int)));
- }
-
- ++*range_used;
- (*ranges)[*range_used*2-2] = new_block;
- (*ranges)[*range_used*2-1] = new_block+1;
+ ranges.push_back(new_block);
+ ranges.push_back(new_block + 1);
}
}
@@ -125,13 +110,13 @@ static struct fstab* read_fstab() {
// The fstab path is always "/fstab.${ro.hardware}".
char fstab_path[PATH_MAX+1] = "/fstab.";
if (!property_get("ro.hardware", fstab_path+strlen(fstab_path), "")) {
- ALOGE("failed to get ro.hardware\n");
+ ALOGE("failed to get ro.hardware");
return NULL;
}
fstab = fs_mgr_read_fstab(fstab_path);
if (!fstab) {
- ALOGE("failed to read %s\n", fstab_path);
+ ALOGE("failed to read %s", fstab_path);
return NULL;
}
@@ -168,77 +153,77 @@ static const char* find_block_device(const char* path, bool* encryptable, bool*
}
// Parse uncrypt_file to find the update package name.
-static bool find_uncrypt_package(std::string& package_name)
-{
- if (!android::base::ReadFileToString(uncrypt_file, &package_name)) {
- ALOGE("failed to open \"%s\": %s\n", uncrypt_file.c_str(), strerror(errno));
+static bool find_uncrypt_package(const std::string& uncrypt_path_file, std::string* package_name) {
+ CHECK(package_name != nullptr);
+ std::string uncrypt_path;
+ if (!android::base::ReadFileToString(uncrypt_path_file, &uncrypt_path)) {
+ ALOGE("failed to open \"%s\": %s", uncrypt_path_file.c_str(), strerror(errno));
return false;
}
// Remove the trailing '\n' if present.
- package_name = android::base::Trim(package_name);
-
+ *package_name = android::base::Trim(uncrypt_path);
return true;
}
static int produce_block_map(const char* path, const char* map_file, const char* blk_dev,
bool encrypted, int status_fd) {
- int mapfd = open(map_file, O_WRONLY | O_CREAT | O_SYNC, S_IRUSR | S_IWUSR);
- if (mapfd == -1) {
- ALOGE("failed to open %s\n", map_file);
+ std::string err;
+ if (!android::base::RemoveFileIfExists(map_file, &err)) {
+ ALOGE("failed to remove the existing map file %s: %s", map_file, err.c_str());
+ return -1;
+ }
+ std::string tmp_map_file = std::string(map_file) + ".tmp";
+ unique_fd mapfd(open(tmp_map_file.c_str(), O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR));
+ if (!mapfd) {
+ ALOGE("failed to open %s: %s\n", tmp_map_file.c_str(), strerror(errno));
return -1;
}
- std::unique_ptr<FILE, int(*)(FILE*)> mapf(fdopen(mapfd, "w"), fclose);
// Make sure we can write to the status_file.
if (!android::base::WriteStringToFd("0\n", status_fd)) {
- ALOGE("failed to update \"%s\"\n", status_file.c_str());
+ ALOGE("failed to update \"%s\"\n", STATUS_FILE.c_str());
return -1;
}
struct stat sb;
if (stat(path, &sb) != 0) {
- ALOGE("failed to stat %s\n", path);
+ ALOGE("failed to stat %s", path);
return -1;
}
- ALOGI(" block size: %ld bytes\n", static_cast<long>(sb.st_blksize));
+ ALOGI(" block size: %ld bytes", static_cast<long>(sb.st_blksize));
int blocks = ((sb.st_size-1) / sb.st_blksize) + 1;
- ALOGI(" file size: %" PRId64 " bytes, %d blocks\n", sb.st_size, blocks);
+ ALOGI(" file size: %" PRId64 " bytes, %d blocks", sb.st_size, blocks);
- int range_alloc = 1;
- int range_used = 1;
- int* ranges = reinterpret_cast<int*>(malloc(range_alloc * 2 * sizeof(int)));
- ranges[0] = -1;
- ranges[1] = -1;
+ std::vector<int> ranges;
- fprintf(mapf.get(), "%s\n%" PRId64 " %ld\n",
- blk_dev, sb.st_size, static_cast<long>(sb.st_blksize));
+ std::string s = android::base::StringPrintf("%s\n%" PRId64 " %ld\n",
+ blk_dev, sb.st_size, static_cast<long>(sb.st_blksize));
+ if (!android::base::WriteStringToFd(s, mapfd.get())) {
+ ALOGE("failed to write %s: %s", tmp_map_file.c_str(), strerror(errno));
+ return -1;
+ }
- unsigned char* buffers[WINDOW_SIZE];
+ std::vector<std::vector<unsigned char>> buffers;
if (encrypted) {
- for (size_t i = 0; i < WINDOW_SIZE; ++i) {
- buffers[i] = reinterpret_cast<unsigned char*>(malloc(sb.st_blksize));
- }
+ buffers.resize(WINDOW_SIZE, std::vector<unsigned char>(sb.st_blksize));
}
int head_block = 0;
int head = 0, tail = 0;
- int fd = open(path, O_RDONLY);
- unique_fd fd_holder(fd);
- if (fd == -1) {
- ALOGE("failed to open fd for reading: %s\n", strerror(errno));
+ unique_fd fd(open(path, O_RDONLY));
+ if (!fd) {
+ ALOGE("failed to open %s for reading: %s", path, strerror(errno));
return -1;
}
- int wfd = -1;
- unique_fd wfd_holder(wfd);
+ unique_fd wfd(-1);
if (encrypted) {
wfd = open(blk_dev, O_WRONLY);
- wfd_holder = unique_fd(wfd);
- if (wfd == -1) {
- ALOGE("failed to open fd for writing: %s\n", strerror(errno));
+ if (!wfd) {
+ ALOGE("failed to open fd for writing: %s", strerror(errno));
return -1;
}
}
@@ -256,13 +241,13 @@ static int produce_block_map(const char* path, const char* map_file, const char*
if ((tail+1) % WINDOW_SIZE == head) {
// write out head buffer
int block = head_block;
- if (ioctl(fd, FIBMAP, &block) != 0) {
- ALOGE("failed to find block %d\n", head_block);
+ if (ioctl(fd.get(), FIBMAP, &block) != 0) {
+ ALOGE("failed to find block %d", head_block);
return -1;
}
- add_block_to_ranges(&ranges, &range_alloc, &range_used, block);
+ add_block_to_ranges(ranges, block);
if (encrypted) {
- if (write_at_offset(buffers[head], sb.st_blksize, wfd,
+ if (write_at_offset(buffers[head].data(), sb.st_blksize, wfd.get(),
static_cast<off64_t>(sb.st_blksize) * block) != 0) {
return -1;
}
@@ -273,17 +258,13 @@ static int produce_block_map(const char* path, const char* map_file, const char*
// read next block to tail
if (encrypted) {
- size_t so_far = 0;
- while (so_far < static_cast<size_t>(sb.st_blksize) && pos < sb.st_size) {
- ssize_t this_read =
- TEMP_FAILURE_RETRY(read(fd, buffers[tail] + so_far, sb.st_blksize - so_far));
- if (this_read == -1) {
- ALOGE("failed to read: %s\n", strerror(errno));
- return -1;
- }
- so_far += this_read;
- pos += this_read;
+ size_t to_read = static_cast<size_t>(
+ std::min(static_cast<off64_t>(sb.st_blksize), sb.st_size - pos));
+ if (!android::base::ReadFully(fd.get(), buffers[tail].data(), to_read)) {
+ ALOGE("failed to read: %s", strerror(errno));
+ return -1;
}
+ pos += to_read;
} else {
// If we're not encrypting; we don't need to actually read
// anything, just skip pos forward as if we'd read a
@@ -296,13 +277,13 @@ static int produce_block_map(const char* path, const char* map_file, const char*
while (head != tail) {
// write out head buffer
int block = head_block;
- if (ioctl(fd, FIBMAP, &block) != 0) {
- ALOGE("failed to find block %d\n", head_block);
+ if (ioctl(fd.get(), FIBMAP, &block) != 0) {
+ ALOGE("failed to find block %d", head_block);
return -1;
}
- add_block_to_ranges(&ranges, &range_alloc, &range_used, block);
+ add_block_to_ranges(ranges, block);
if (encrypted) {
- if (write_at_offset(buffers[head], sb.st_blksize, wfd,
+ if (write_at_offset(buffers[head].data(), sb.st_blksize, wfd.get(),
static_cast<off64_t>(sb.st_blksize) * block) != 0) {
return -1;
}
@@ -311,54 +292,118 @@ static int produce_block_map(const char* path, const char* map_file, const char*
++head_block;
}
- fprintf(mapf.get(), "%d\n", range_used);
- for (int i = 0; i < range_used; ++i) {
- fprintf(mapf.get(), "%d %d\n", ranges[i*2], ranges[i*2+1]);
+ if (!android::base::WriteStringToFd(
+ android::base::StringPrintf("%zu\n", ranges.size() / 2), mapfd.get())) {
+ ALOGE("failed to write %s: %s", tmp_map_file.c_str(), strerror(errno));
+ return -1;
+ }
+ for (size_t i = 0; i < ranges.size(); i += 2) {
+ if (!android::base::WriteStringToFd(
+ android::base::StringPrintf("%d %d\n", ranges[i], ranges[i+1]), mapfd.get())) {
+ ALOGE("failed to write %s: %s", tmp_map_file.c_str(), strerror(errno));
+ return -1;
+ }
}
- if (fsync(mapfd) == -1) {
- ALOGE("failed to fsync \"%s\": %s\n", map_file, strerror(errno));
+ if (fsync(mapfd.get()) == -1) {
+ ALOGE("failed to fsync \"%s\": %s", tmp_map_file.c_str(), strerror(errno));
return -1;
}
+ if (close(mapfd.get() == -1)) {
+ ALOGE("failed to close %s: %s", tmp_map_file.c_str(), strerror(errno));
+ return -1;
+ }
+ mapfd = -1;
+
if (encrypted) {
- if (fsync(wfd) == -1) {
- ALOGE("failed to fsync \"%s\": %s\n", blk_dev, strerror(errno));
+ if (fsync(wfd.get()) == -1) {
+ ALOGE("failed to fsync \"%s\": %s", blk_dev, strerror(errno));
return -1;
}
+ if (close(wfd.get()) == -1) {
+ ALOGE("failed to close %s: %s", blk_dev, strerror(errno));
+ return -1;
+ }
+ wfd = -1;
}
+ if (rename(tmp_map_file.c_str(), map_file) == -1) {
+ ALOGE("failed to rename %s to %s: %s", tmp_map_file.c_str(), map_file, strerror(errno));
+ return -1;
+ }
+ // Sync dir to make rename() result written to disk.
+ std::string file_name = map_file;
+ std::string dir_name = dirname(&file_name[0]);
+ unique_fd dfd(open(dir_name.c_str(), O_RDONLY | O_DIRECTORY));
+ if (!dfd) {
+ ALOGE("failed to open dir %s: %s", dir_name.c_str(), strerror(errno));
+ return -1;
+ }
+ if (fsync(dfd.get()) == -1) {
+ ALOGE("failed to fsync %s: %s", dir_name.c_str(), strerror(errno));
+ return -1;
+ }
+ if (close(dfd.get() == -1)) {
+ ALOGE("failed to close %s: %s", dir_name.c_str(), strerror(errno));
+ return -1;
+ }
+ dfd = -1;
return 0;
}
-static void wipe_misc() {
- ALOGI("removing old commands from misc");
+static std::string get_misc_blk_device() {
+ struct fstab* fstab = read_fstab();
+ if (fstab == nullptr) {
+ return "";
+ }
for (int i = 0; i < fstab->num_entries; ++i) {
- struct fstab_rec* v = &fstab->recs[i];
- if (!v->mount_point) continue;
- if (strcmp(v->mount_point, "/misc") == 0) {
- int fd = open(v->blk_device, O_WRONLY | O_SYNC);
- unique_fd fd_holder(fd);
-
- uint8_t zeroes[1088]; // sizeof(bootloader_message) from recovery
- memset(zeroes, 0, sizeof(zeroes));
-
- size_t written = 0;
- size_t size = sizeof(zeroes);
- while (written < size) {
- ssize_t w = TEMP_FAILURE_RETRY(write(fd, zeroes, size-written));
- if (w == -1) {
- ALOGE("zero write failed: %s\n", strerror(errno));
- return;
- } else {
- written += w;
- }
- }
- if (fsync(fd) == -1) {
- ALOGE("failed to fsync \"%s\": %s\n", v->blk_device, strerror(errno));
- return;
- }
+ fstab_rec* v = &fstab->recs[i];
+ if (v->mount_point != nullptr && strcmp(v->mount_point, "/misc") == 0) {
+ return v->blk_device;
}
}
+ return "";
+}
+
+static int read_bootloader_message(bootloader_message* out) {
+ std::string misc_blk_device = get_misc_blk_device();
+ if (misc_blk_device.empty()) {
+ ALOGE("failed to find /misc partition.");
+ return -1;
+ }
+ unique_fd fd(open(misc_blk_device.c_str(), O_RDONLY));
+ if (!fd) {
+ ALOGE("failed to open %s: %s", misc_blk_device.c_str(), strerror(errno));
+ return -1;
+ }
+ if (!android::base::ReadFully(fd.get(), out, sizeof(*out))) {
+ ALOGE("failed to read %s: %s", misc_blk_device.c_str(), strerror(errno));
+ return -1;
+ }
+ return 0;
+}
+
+static int write_bootloader_message(const bootloader_message* in) {
+ std::string misc_blk_device = get_misc_blk_device();
+ if (misc_blk_device.empty()) {
+ ALOGE("failed to find /misc partition.");
+ return -1;
+ }
+ unique_fd fd(open(misc_blk_device.c_str(), O_WRONLY | O_SYNC));
+ if (!fd) {
+ ALOGE("failed to open %s: %s", misc_blk_device.c_str(), strerror(errno));
+ return -1;
+ }
+ if (!android::base::WriteFully(fd.get(), in, sizeof(*in))) {
+ ALOGE("failed to write %s: %s", misc_blk_device.c_str(), strerror(errno));
+ return -1;
+ }
+ // TODO: O_SYNC and fsync() duplicates each other?
+ if (fsync(fd.get()) == -1) {
+ ALOGE("failed to fsync %s: %s", misc_blk_device.c_str(), strerror(errno));
+ return -1;
+ }
+ return 0;
}
static void reboot_to_recovery() {
@@ -370,7 +415,7 @@ static void reboot_to_recovery() {
ALOGE("reboot didn't succeed?");
}
-int uncrypt(const char* input_path, const char* map_file, int status_fd) {
+static int uncrypt(const char* input_path, const char* map_file, int status_fd) {
ALOGI("update package is \"%s\"", input_path);
@@ -397,8 +442,8 @@ int uncrypt(const char* input_path, const char* map_file, int status_fd) {
// If the filesystem it's on isn't encrypted, we only produce the
// block map, we don't rewrite the file contents (it would be
// pointless to do so).
- ALOGI("encryptable: %s\n", encryptable ? "yes" : "no");
- ALOGI(" encrypted: %s\n", encrypted ? "yes" : "no");
+ ALOGI("encryptable: %s", encryptable ? "yes" : "no");
+ ALOGI(" encrypted: %s", encrypted ? "yes" : "no");
// Recovery supports installing packages from 3 paths: /cache,
// /data, and /sdcard. (On a particular device, other locations
@@ -417,56 +462,113 @@ int uncrypt(const char* input_path, const char* map_file, int status_fd) {
return 0;
}
-int main(int argc, char** argv) {
-
- if (argc != 3 && argc != 1 && (argc == 2 && strcmp(argv[1], "--reboot") != 0)) {
- fprintf(stderr, "usage: %s [--reboot] [<transform_path> <map_file>]\n", argv[0]);
- return 2;
+static int uncrypt_wrapper(const char* input_path, const char* map_file,
+ const std::string& status_file) {
+ // The pipe has been created by the system server.
+ unique_fd status_fd(open(status_file.c_str(), O_WRONLY | O_CREAT | O_SYNC, S_IRUSR | S_IWUSR));
+ if (!status_fd) {
+ ALOGE("failed to open pipe \"%s\": %s", status_file.c_str(), strerror(errno));
+ return 1;
}
- // When uncrypt is started with "--reboot", it wipes misc and reboots.
- // Otherwise it uncrypts the package and writes the block map.
- if (argc == 2) {
- if (read_fstab() == NULL) {
- return 1;
- }
- wipe_misc();
- reboot_to_recovery();
- } else {
- // The pipe has been created by the system server.
- int status_fd = open(status_file.c_str(), O_WRONLY | O_CREAT | O_SYNC, S_IRUSR | S_IWUSR);
- if (status_fd == -1) {
- ALOGE("failed to open pipe \"%s\": %s\n", status_file.c_str(), strerror(errno));
+ std::string package;
+ if (input_path == nullptr) {
+ if (!find_uncrypt_package(UNCRYPT_PATH_FILE, &package)) {
+ android::base::WriteStringToFd("-1\n", status_fd.get());
return 1;
}
- unique_fd status_fd_holder(status_fd);
+ input_path = package.c_str();
+ }
+ CHECK(map_file != nullptr);
+ int status = uncrypt(input_path, map_file, status_fd.get());
+ if (status != 0) {
+ android::base::WriteStringToFd("-1\n", status_fd.get());
+ return 1;
+ }
+ android::base::WriteStringToFd("100\n", status_fd.get());
+ return 0;
+}
+
+static int clear_bcb(const std::string& status_file) {
+ unique_fd status_fd(open(status_file.c_str(), O_WRONLY | O_CREAT | O_SYNC, S_IRUSR | S_IWUSR));
+ if (!status_fd) {
+ ALOGE("failed to open pipe \"%s\": %s", status_file.c_str(), strerror(errno));
+ return 1;
+ }
+ bootloader_message boot = {};
+ if (write_bootloader_message(&boot) != 0) {
+ android::base::WriteStringToFd("-1\n", status_fd.get());
+ return 1;
+ }
+ android::base::WriteStringToFd("100\n", status_fd.get());
+ return 0;
+}
- std::string package;
- const char* input_path;
- const char* map_file;
+static int setup_bcb(const std::string& command_file, const std::string& status_file) {
+ unique_fd status_fd(open(status_file.c_str(), O_WRONLY | O_CREAT | O_SYNC, S_IRUSR | S_IWUSR));
+ if (!status_fd) {
+ ALOGE("failed to open pipe \"%s\": %s", status_file.c_str(), strerror(errno));
+ return 1;
+ }
+ std::string content;
+ if (!android::base::ReadFileToString(command_file, &content)) {
+ ALOGE("failed to read \"%s\": %s", command_file.c_str(), strerror(errno));
+ android::base::WriteStringToFd("-1\n", status_fd.get());
+ return 1;
+ }
+ bootloader_message boot = {};
+ strlcpy(boot.command, "boot-recovery", sizeof(boot.command));
+ strlcpy(boot.recovery, "recovery\n", sizeof(boot.recovery));
+ strlcat(boot.recovery, content.c_str(), sizeof(boot.recovery));
+ if (write_bootloader_message(&boot) != 0) {
+ ALOGE("failed to set bootloader message");
+ android::base::WriteStringToFd("-1\n", status_fd.get());
+ return 1;
+ }
+ android::base::WriteStringToFd("100\n", status_fd.get());
+ return 0;
+}
+
+static int read_bcb() {
+ bootloader_message boot;
+ if (read_bootloader_message(&boot) != 0) {
+ ALOGE("failed to get bootloader message");
+ return 1;
+ }
+ printf("bcb command: %s\n", boot.command);
+ printf("bcb recovery:\n%s\n", boot.recovery);
+ return 0;
+}
+static void usage(const char* exename) {
+ fprintf(stderr, "Usage of %s:\n", exename);
+ fprintf(stderr, "%s [<package_path> <map_file>] Uncrypt ota package.\n", exename);
+ fprintf(stderr, "%s --reboot Clear BCB data and reboot to recovery.\n", exename);
+ fprintf(stderr, "%s --clear-bcb Clear BCB data in misc partition.\n", exename);
+ fprintf(stderr, "%s --setup-bcb Setup BCB data by command file.\n", exename);
+ fprintf(stderr, "%s --read-bcb Read BCB data from misc partition.\n", exename);
+}
+
+int main(int argc, char** argv) {
+ if (argc == 2) {
+ if (strcmp(argv[1], "--reboot") == 0) {
+ reboot_to_recovery();
+ } else if (strcmp(argv[1], "--clear-bcb") == 0) {
+ return clear_bcb(STATUS_FILE);
+ } else if (strcmp(argv[1], "--setup-bcb") == 0) {
+ return setup_bcb(COMMAND_FILE, STATUS_FILE);
+ } else if (strcmp(argv[1], "--read-bcb") == 0) {
+ return read_bcb();
+ }
+ } else if (argc == 1 || argc == 3) {
+ const char* input_path = nullptr;
+ const char* map_file = CACHE_BLOCK_MAP.c_str();
if (argc == 3) {
- // when command-line args are given this binary is being used
- // for debugging.
input_path = argv[1];
map_file = argv[2];
- } else {
- if (!find_uncrypt_package(package)) {
- android::base::WriteStringToFd("-1\n", status_fd);
- return 1;
- }
- input_path = package.c_str();
- map_file = cache_block_map.c_str();
}
-
- int status = uncrypt(input_path, map_file, status_fd);
- if (status != 0) {
- android::base::WriteStringToFd("-1\n", status_fd);
- return 1;
- }
-
- android::base::WriteStringToFd("100\n", status_fd);
+ return uncrypt_wrapper(input_path, map_file, STATUS_FILE);
}
-
- return 0;
+ usage(argv[0]);
+ return 2;
}
diff --git a/uncrypt/uncrypt.rc b/uncrypt/uncrypt.rc
index 5f4c47936..b07c1dada 100644
--- a/uncrypt/uncrypt.rc
+++ b/uncrypt/uncrypt.rc
@@ -7,3 +7,13 @@ service pre-recovery /system/bin/uncrypt --reboot
class main
disabled
oneshot
+
+service setup-bcb /system/bin/uncrypt --setup-bcb
+ class main
+ disabled
+ oneshot
+
+service clear-bcb /system/bin/uncrypt --clear-bcb
+ class main
+ disabled
+ oneshot \ No newline at end of file
diff --git a/updater/Android.mk b/updater/Android.mk
index dcf437474..d7aa613e9 100644
--- a/updater/Android.mk
+++ b/updater/Android.mk
@@ -45,8 +45,8 @@ LOCAL_STATIC_LIBRARIES += \
endif
LOCAL_STATIC_LIBRARIES += $(TARGET_RECOVERY_UPDATER_LIBS) $(TARGET_RECOVERY_UPDATER_EXTRA_LIBS)
-LOCAL_STATIC_LIBRARIES += libapplypatch libbase libedify libmtdutils libminzip libz
-LOCAL_STATIC_LIBRARIES += libmincrypt libbz
+LOCAL_STATIC_LIBRARIES += libapplypatch libbase libotafault libedify libmtdutils libminzip libz
+LOCAL_STATIC_LIBRARIES += libbz
LOCAL_STATIC_LIBRARIES += libcutils liblog libc
LOCAL_STATIC_LIBRARIES += libselinux
tune2fs_static_libraries := \
diff --git a/updater/blockimg.cpp b/updater/blockimg.cpp
index c6daf7db5..44de4e031 100644
--- a/updater/blockimg.cpp
+++ b/updater/blockimg.cpp
@@ -43,8 +43,9 @@
#include "applypatch/applypatch.h"
#include "edify/expr.h"
#include "install.h"
-#include "mincrypt/sha.h"
+#include "openssl/sha.h"
#include "minzip/Hash.h"
+#include "otafault/ota_io.h"
#include "print_sha1.h"
#include "unique_fd.h"
#include "updater.h"
@@ -139,7 +140,7 @@ static bool range_overlaps(const RangeSet& r1, const RangeSet& r2) {
static int read_all(int fd, uint8_t* data, size_t size) {
size_t so_far = 0;
while (so_far < size) {
- ssize_t r = TEMP_FAILURE_RETRY(read(fd, data+so_far, size-so_far));
+ ssize_t r = TEMP_FAILURE_RETRY(ota_read(fd, data+so_far, size-so_far));
if (r == -1) {
fprintf(stderr, "read failed: %s\n", strerror(errno));
return -1;
@@ -156,7 +157,7 @@ static int read_all(int fd, std::vector<uint8_t>& buffer, size_t size) {
static int write_all(int fd, const uint8_t* data, size_t size) {
size_t written = 0;
while (written < size) {
- ssize_t w = TEMP_FAILURE_RETRY(write(fd, data+written, size-written));
+ ssize_t w = TEMP_FAILURE_RETRY(ota_write(fd, data+written, size-written));
if (w == -1) {
fprintf(stderr, "write failed: %s\n", strerror(errno));
return -1;
@@ -407,10 +408,10 @@ static int LoadSrcTgtVersion1(CommandParameters& params, RangeSet& tgt, size_t&
static int VerifyBlocks(const std::string& expected, const std::vector<uint8_t>& buffer,
const size_t blocks, bool printerror) {
- uint8_t digest[SHA_DIGEST_SIZE];
+ uint8_t digest[SHA_DIGEST_LENGTH];
const uint8_t* data = buffer.data();
- SHA_hash(data, blocks * BLOCKSIZE, digest);
+ SHA1(data, blocks * BLOCKSIZE, digest);
std::string hexdigest = print_sha1(digest);
@@ -553,7 +554,7 @@ static int LoadStash(const std::string& base, const std::string& id, bool verify
return -1;
}
- int fd = TEMP_FAILURE_RETRY(open(fn.c_str(), O_RDONLY));
+ int fd = TEMP_FAILURE_RETRY(ota_open(fn.c_str(), O_RDONLY));
unique_fd fd_holder(fd);
if (fd == -1) {
@@ -610,7 +611,7 @@ static int WriteStash(const std::string& base, const std::string& id, int blocks
fprintf(stderr, " writing %d blocks to %s\n", blocks, cn.c_str());
- int fd = TEMP_FAILURE_RETRY(open(fn.c_str(), O_WRONLY | O_CREAT | O_TRUNC, STASH_FILE_MODE));
+ int fd = TEMP_FAILURE_RETRY(ota_open(fn.c_str(), O_WRONLY | O_CREAT | O_TRUNC, STASH_FILE_MODE));
unique_fd fd_holder(fd);
if (fd == -1) {
@@ -622,7 +623,7 @@ static int WriteStash(const std::string& base, const std::string& id, int blocks
return -1;
}
- if (fsync(fd) == -1) {
+ if (ota_fsync(fd) == -1) {
fprintf(stderr, "fsync \"%s\" failed: %s\n", fn.c_str(), strerror(errno));
return -1;
}
@@ -634,7 +635,7 @@ static int WriteStash(const std::string& base, const std::string& id, int blocks
}
std::string dname = GetStashFileName(base, "", "");
- int dfd = TEMP_FAILURE_RETRY(open(dname.c_str(), O_RDONLY | O_DIRECTORY));
+ int dfd = TEMP_FAILURE_RETRY(ota_open(dname.c_str(), O_RDONLY | O_DIRECTORY));
unique_fd dfd_holder(dfd);
if (dfd == -1) {
@@ -642,7 +643,7 @@ static int WriteStash(const std::string& base, const std::string& id, int blocks
return -1;
}
- if (fsync(dfd) == -1) {
+ if (ota_fsync(dfd) == -1) {
fprintf(stderr, "fsync \"%s\" failed: %s\n", dname.c_str(), strerror(errno));
return -1;
}
@@ -662,10 +663,8 @@ static int CreateStash(State* state, int maxblocks, const char* blockdev, std::s
// Stash directory should be different for each partition to avoid conflicts
// when updating multiple partitions at the same time, so we use the hash of
// the block device name as the base directory
- SHA_CTX ctx;
- SHA_init(&ctx);
- SHA_update(&ctx, blockdev, strlen(blockdev));
- const uint8_t* digest = SHA_final(&ctx);
+ uint8_t digest[SHA_DIGEST_LENGTH];
+ SHA1(reinterpret_cast<const uint8_t*>(blockdev), strlen(blockdev), digest);
base = print_sha1(digest);
std::string dirname = GetStashFileName(base, "", "");
@@ -1348,7 +1347,7 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg
return StringValue(strdup(""));
}
- params.fd = TEMP_FAILURE_RETRY(open(blockdev_filename->data, O_RDWR));
+ params.fd = TEMP_FAILURE_RETRY(ota_open(blockdev_filename->data, O_RDWR));
unique_fd fd_holder(params.fd);
if (params.fd == -1) {
@@ -1467,7 +1466,7 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg
}
if (params.canwrite) {
- if (fsync(params.fd) == -1) {
+ if (ota_fsync(params.fd) == -1) {
fprintf(stderr, "fsync failed: %s\n", strerror(errno));
goto pbiudone;
}
@@ -1492,7 +1491,7 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg
rc = 0;
pbiudone:
- if (fsync(params.fd) == -1) {
+ if (ota_fsync(params.fd) == -1) {
fprintf(stderr, "fsync failed: %s\n", strerror(errno));
}
// params.fd will be automatically closed because of the fd_holder above.
@@ -1616,7 +1615,7 @@ Value* RangeSha1Fn(const char* name, State* state, int /* argc */, Expr* argv[])
return StringValue(strdup(""));
}
- int fd = open(blockdev_filename->data, O_RDWR);
+ int fd = ota_open(blockdev_filename->data, O_RDWR);
unique_fd fd_holder(fd);
if (fd < 0) {
ErrorAbort(state, "open \"%s\" failed: %s", blockdev_filename->data, strerror(errno));
@@ -1627,7 +1626,7 @@ Value* RangeSha1Fn(const char* name, State* state, int /* argc */, Expr* argv[])
parse_range(ranges->data, rs);
SHA_CTX ctx;
- SHA_init(&ctx);
+ SHA1_Init(&ctx);
std::vector<uint8_t> buffer(BLOCKSIZE);
for (size_t i = 0; i < rs.count; ++i) {
@@ -1643,10 +1642,11 @@ Value* RangeSha1Fn(const char* name, State* state, int /* argc */, Expr* argv[])
return StringValue(strdup(""));
}
- SHA_update(&ctx, buffer.data(), BLOCKSIZE);
+ SHA1_Update(&ctx, buffer.data(), BLOCKSIZE);
}
}
- const uint8_t* digest = SHA_final(&ctx);
+ uint8_t digest[SHA_DIGEST_LENGTH];
+ SHA1_Final(digest, &ctx);
return StringValue(strdup(print_sha1(digest).c_str()));
}
@@ -1669,7 +1669,7 @@ Value* CheckFirstBlockFn(const char* name, State* state, int argc, Expr* argv[])
return StringValue(strdup(""));
}
- int fd = open(arg_filename->data, O_RDONLY);
+ int fd = ota_open(arg_filename->data, O_RDONLY);
unique_fd fd_holder(fd);
if (fd == -1) {
ErrorAbort(state, "open \"%s\" failed: %s", arg_filename->data, strerror(errno));
diff --git a/updater/install.cpp b/updater/install.cpp
index b09086964..413e147a1 100644
--- a/updater/install.cpp
+++ b/updater/install.cpp
@@ -34,6 +34,9 @@
#include <linux/xattr.h>
#include <inttypes.h>
+#include <memory>
+#include <vector>
+
#include <android-base/parseint.h>
#include <android-base/strings.h>
#include <android-base/stringprintf.h>
@@ -44,10 +47,11 @@
#include "cutils/misc.h"
#include "cutils/properties.h"
#include "edify/expr.h"
-#include "mincrypt/sha.h"
+#include "openssl/sha.h"
#include "minzip/DirUtil.h"
#include "mtdutils/mounts.h"
#include "mtdutils/mtdutils.h"
+#include "otafault/ota_io.h"
#include "updater.h"
#include "install.h"
#include "tune2fs.h"
@@ -91,10 +95,10 @@ void uiPrintf(State* state, const char* format, ...) {
// Take a sha-1 digest and return it as a newly-allocated hex string.
char* PrintSha1(const uint8_t* digest) {
- char* buffer = reinterpret_cast<char*>(malloc(SHA_DIGEST_SIZE*2 + 1));
+ char* buffer = reinterpret_cast<char*>(malloc(SHA_DIGEST_LENGTH*2 + 1));
const char* alphabet = "0123456789abcdef";
size_t i;
- for (i = 0; i < SHA_DIGEST_SIZE; ++i) {
+ for (i = 0; i < SHA_DIGEST_LENGTH; ++i) {
buffer[i*2] = alphabet[(digest[i] >> 4) & 0xf];
buffer[i*2+1] = alphabet[digest[i] & 0xf];
}
@@ -439,8 +443,7 @@ Value* DeleteFn(const char* name, State* state, int argc, Expr* argv[]) {
for (int i = 0; i < argc; ++i) {
paths[i] = Evaluate(state, argv[i]);
if (paths[i] == NULL) {
- int j;
- for (j = 0; j < i; ++i) {
+ for (int j = 0; j < i; ++j) {
free(paths[j]);
}
free(paths);
@@ -555,18 +558,18 @@ Value* PackageExtractFileFn(const char* name, State* state,
}
{
- int fd = TEMP_FAILURE_RETRY(open(dest_path, O_WRONLY | O_CREAT | O_TRUNC | O_SYNC,
+ int fd = TEMP_FAILURE_RETRY(ota_open(dest_path, O_WRONLY | O_CREAT | O_TRUNC | O_SYNC,
S_IRUSR | S_IWUSR));
if (fd == -1) {
printf("%s: can't open %s for write: %s\n", name, dest_path, strerror(errno));
goto done2;
}
success = mzExtractZipEntryToFile(za, entry, fd);
- if (fsync(fd) == -1) {
+ if (ota_fsync(fd) == -1) {
printf("fsync of \"%s\" failed: %s\n", dest_path, strerror(errno));
success = false;
}
- if (close(fd) == -1) {
+ if (ota_close(fd) == -1) {
printf("close of \"%s\" failed: %s\n", dest_path, strerror(errno));
success = false;
}
@@ -581,13 +584,13 @@ Value* PackageExtractFileFn(const char* name, State* state,
// as the result.
char* zip_path;
+ if (ReadArgs(state, argv, 1, &zip_path) < 0) return NULL;
+
Value* v = reinterpret_cast<Value*>(malloc(sizeof(Value)));
v->type = VAL_BLOB;
v->size = -1;
v->data = NULL;
- if (ReadArgs(state, argv, 1, &zip_path) < 0) return NULL;
-
ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip;
const ZipEntry* entry = mzFindZipEntry(za, zip_path);
if (entry == NULL) {
@@ -993,21 +996,21 @@ Value* FileGetPropFn(const char* name, State* state, int argc, Expr* argv[]) {
}
FILE* f;
- f = fopen(filename, "rb");
+ f = ota_fopen(filename, "rb");
if (f == NULL) {
ErrorAbort(state, "%s: failed to open %s: %s", name, filename, strerror(errno));
goto done;
}
- if (fread(buffer, 1, st.st_size, f) != static_cast<size_t>(st.st_size)) {
+ if (ota_fread(buffer, 1, st.st_size, f) != static_cast<size_t>(st.st_size)) {
ErrorAbort(state, "%s: failed to read %lld bytes from %s",
name, (long long)st.st_size+1, filename);
- fclose(f);
+ ota_fclose(f);
goto done;
}
buffer[st.st_size] = '\0';
- fclose(f);
+ ota_fclose(f);
char* line;
line = strtok(buffer, "\n");
@@ -1102,7 +1105,7 @@ Value* WriteRawImageFn(const char* name, State* state, int argc, Expr* argv[]) {
if (contents->type == VAL_STRING) {
// we're given a filename as the contents
char* filename = contents->data;
- FILE* f = fopen(filename, "rb");
+ FILE* f = ota_fopen(filename, "rb");
if (f == NULL) {
printf("%s: can't open %s: %s\n", name, filename, strerror(errno));
result = strdup("");
@@ -1112,12 +1115,12 @@ Value* WriteRawImageFn(const char* name, State* state, int argc, Expr* argv[]) {
success = true;
char* buffer = reinterpret_cast<char*>(malloc(BUFSIZ));
int read;
- while (success && (read = fread(buffer, 1, BUFSIZ, f)) > 0) {
+ while (success && (read = ota_fread(buffer, 1, BUFSIZ, f)) > 0) {
int wrote = mtd_write_data(ctx, buffer, read);
success = success && (wrote == read);
}
free(buffer);
- fclose(f);
+ ota_fclose(f);
} else {
// we're given a blob as the contents
ssize_t wrote = mtd_write_data(ctx, contents->data, contents->size);
@@ -1193,44 +1196,40 @@ Value* ApplyPatchFn(const char* name, State* state, int argc, Expr* argv[]) {
}
int patchcount = (argc-4) / 2;
- Value** patches = ReadValueVarArgs(state, argc-4, argv+4);
+ std::unique_ptr<Value*, decltype(&free)> arg_values(ReadValueVarArgs(state, argc-4, argv+4),
+ free);
+ if (!arg_values) {
+ return nullptr;
+ }
+ std::vector<std::unique_ptr<Value, decltype(&FreeValue)>> patch_shas;
+ std::vector<std::unique_ptr<Value, decltype(&FreeValue)>> patches;
+ // Protect values by unique_ptrs first to get rid of memory leak.
+ for (int i = 0; i < patchcount * 2; i += 2) {
+ patch_shas.emplace_back(arg_values.get()[i], FreeValue);
+ patches.emplace_back(arg_values.get()[i+1], FreeValue);
+ }
- int i;
- for (i = 0; i < patchcount; ++i) {
- if (patches[i*2]->type != VAL_STRING) {
+ for (int i = 0; i < patchcount; ++i) {
+ if (patch_shas[i]->type != VAL_STRING) {
ErrorAbort(state, "%s(): sha-1 #%d is not string", name, i);
- break;
+ return nullptr;
}
- if (patches[i*2+1]->type != VAL_BLOB) {
+ if (patches[i]->type != VAL_BLOB) {
ErrorAbort(state, "%s(): patch #%d is not blob", name, i);
- break;
- }
- }
- if (i != patchcount) {
- for (i = 0; i < patchcount*2; ++i) {
- FreeValue(patches[i]);
+ return nullptr;
}
- free(patches);
- return NULL;
}
- char** patch_sha_str = reinterpret_cast<char**>(malloc(patchcount * sizeof(char*)));
- for (i = 0; i < patchcount; ++i) {
- patch_sha_str[i] = patches[i*2]->data;
- patches[i*2]->data = NULL;
- FreeValue(patches[i*2]);
- patches[i] = patches[i*2+1];
+ std::vector<char*> patch_sha_str;
+ std::vector<Value*> patch_ptrs;
+ for (int i = 0; i < patchcount; ++i) {
+ patch_sha_str.push_back(patch_shas[i]->data);
+ patch_ptrs.push_back(patches[i].get());
}
int result = applypatch(source_filename, target_filename,
target_sha1, target_size,
- patchcount, patch_sha_str, patches, NULL);
-
- for (i = 0; i < patchcount; ++i) {
- FreeValue(patches[i]);
- }
- free(patch_sha_str);
- free(patches);
+ patchcount, patch_sha_str.data(), patch_ptrs.data(), NULL);
return StringValue(strdup(result == 0 ? "t" : ""));
}
@@ -1349,24 +1348,27 @@ Value* Sha1CheckFn(const char* name, State* state, int argc, Expr* argv[]) {
return ErrorAbort(state, "%s() expects at least 1 arg", name);
}
- Value** args = ReadValueVarArgs(state, argc, argv);
- if (args == NULL) {
- return NULL;
+ std::unique_ptr<Value*, decltype(&free)> arg_values(ReadValueVarArgs(state, argc, argv), free);
+ if (arg_values == nullptr) {
+ return nullptr;
+ }
+ std::vector<std::unique_ptr<Value, decltype(&FreeValue)>> args;
+ for (int i = 0; i < argc; ++i) {
+ args.emplace_back(arg_values.get()[i], FreeValue);
}
if (args[0]->size < 0) {
return StringValue(strdup(""));
}
- uint8_t digest[SHA_DIGEST_SIZE];
- SHA_hash(args[0]->data, args[0]->size, digest);
- FreeValue(args[0]);
+ uint8_t digest[SHA_DIGEST_LENGTH];
+ SHA1(reinterpret_cast<uint8_t*>(args[0]->data), args[0]->size, digest);
if (argc == 1) {
return StringValue(PrintSha1(digest));
}
int i;
- uint8_t* arg_digest = reinterpret_cast<uint8_t*>(malloc(SHA_DIGEST_SIZE));
+ uint8_t arg_digest[SHA_DIGEST_LENGTH];
for (i = 1; i < argc; ++i) {
if (args[i]->type != VAL_STRING) {
printf("%s(): arg %d is not a string; skipping",
@@ -1375,22 +1377,16 @@ Value* Sha1CheckFn(const char* name, State* state, int argc, Expr* argv[]) {
// Warn about bad args and skip them.
printf("%s(): error parsing \"%s\" as sha-1; skipping",
name, args[i]->data);
- } else if (memcmp(digest, arg_digest, SHA_DIGEST_SIZE) == 0) {
+ } else if (memcmp(digest, arg_digest, SHA_DIGEST_LENGTH) == 0) {
break;
}
- FreeValue(args[i]);
}
if (i >= argc) {
// Didn't match any of the hex strings; return false.
return StringValue(strdup(""));
}
- // Found a match; free all the remaining arguments and return the
- // matched one.
- int j;
- for (j = i+1; j < argc; ++j) {
- FreeValue(args[j]);
- }
- return args[i];
+ // Found a match.
+ return args[i].release();
}
// Read a local file and return its contents (the Value* returned
@@ -1402,21 +1398,22 @@ Value* ReadFileFn(const char* name, State* state, int argc, Expr* argv[]) {
char* filename;
if (ReadArgs(state, argv, 1, &filename) < 0) return NULL;
- Value* v = reinterpret_cast<Value*>(malloc(sizeof(Value)));
+ Value* v = static_cast<Value*>(malloc(sizeof(Value)));
+ if (v == nullptr) {
+ return nullptr;
+ }
v->type = VAL_BLOB;
+ v->size = -1;
+ v->data = nullptr;
FileContents fc;
if (LoadFileContents(filename, &fc) != 0) {
- free(filename);
- v->size = -1;
- v->data = NULL;
- free(fc.data);
- return v;
+ v->data = static_cast<char*>(malloc(fc.data.size()));
+ if (v->data != nullptr) {
+ memcpy(v->data, fc.data.data(), fc.data.size());
+ v->size = fc.data.size();
+ }
}
-
- v->size = fc.size;
- v->data = (char*)fc.data;
-
free(filename);
return v;
}
@@ -1443,10 +1440,10 @@ Value* RebootNowFn(const char* name, State* state, int argc, Expr* argv[]) {
// zero out the 'command' field of the bootloader message.
memset(buffer, 0, sizeof(((struct bootloader_message*)0)->command));
- FILE* f = fopen(filename, "r+b");
+ FILE* f = ota_fopen(filename, "r+b");
fseek(f, offsetof(struct bootloader_message, command), SEEK_SET);
- fwrite(buffer, sizeof(((struct bootloader_message*)0)->command), 1, f);
- fclose(f);
+ ota_fwrite(buffer, sizeof(((struct bootloader_message*)0)->command), 1, f);
+ ota_fclose(f);
free(filename);
strcpy(buffer, "reboot,");
@@ -1485,7 +1482,7 @@ Value* SetStageFn(const char* name, State* state, int argc, Expr* argv[]) {
// bootloader message that the main recovery uses to save its
// arguments in case of the device restarting midway through
// package installation.
- FILE* f = fopen(filename, "r+b");
+ FILE* f = ota_fopen(filename, "r+b");
fseek(f, offsetof(struct bootloader_message, stage), SEEK_SET);
int to_write = strlen(stagestr)+1;
int max_size = sizeof(((struct bootloader_message*)0)->stage);
@@ -1493,8 +1490,8 @@ Value* SetStageFn(const char* name, State* state, int argc, Expr* argv[]) {
to_write = max_size;
stagestr[max_size-1] = 0;
}
- fwrite(stagestr, to_write, 1, f);
- fclose(f);
+ ota_fwrite(stagestr, to_write, 1, f);
+ ota_fclose(f);
free(stagestr);
return StringValue(filename);
@@ -1511,10 +1508,10 @@ Value* GetStageFn(const char* name, State* state, int argc, Expr* argv[]) {
if (ReadArgs(state, argv, 1, &filename) < 0) return NULL;
char buffer[sizeof(((struct bootloader_message*)0)->stage)];
- FILE* f = fopen(filename, "rb");
+ FILE* f = ota_fopen(filename, "rb");
fseek(f, offsetof(struct bootloader_message, stage), SEEK_SET);
- fread(buffer, sizeof(buffer), 1, f);
- fclose(f);
+ ota_fread(buffer, sizeof(buffer), 1, f);
+ ota_fclose(f);
buffer[sizeof(buffer)-1] = '\0';
return StringValue(strdup(buffer));
@@ -1531,13 +1528,13 @@ Value* WipeBlockDeviceFn(const char* name, State* state, int argc, Expr* argv[])
size_t len;
android::base::ParseUint(len_str, &len);
- int fd = open(filename, O_WRONLY, 0644);
+ int fd = ota_open(filename, O_WRONLY, 0644);
int success = wipe_block_device(fd, len);
free(filename);
free(len_str);
- close(fd);
+ ota_close(fd);
return StringValue(strdup(success ? "t" : ""));
}
diff --git a/verifier.cpp b/verifier.cpp
index 61e5adf0b..9a2d60c66 100644
--- a/verifier.cpp
+++ b/verifier.cpp
@@ -113,7 +113,7 @@ static bool read_pkcs7(uint8_t* pkcs7_der, size_t pkcs7_der_len, uint8_t** sig_d
// or no key matches the signature).
int verify_file(unsigned char* addr, size_t length,
- const Certificate* pKeys, unsigned int numKeys) {
+ const std::vector<Certificate>& keys) {
ui->SetProgress(0.0);
// An archive with a whole-file signature will end in six bytes:
@@ -176,8 +176,7 @@ int verify_file(unsigned char* addr, size_t length,
return VERIFY_FAILURE;
}
- size_t i;
- for (i = 4; i < eocd_size-3; ++i) {
+ for (size_t i = 4; i < eocd_size-3; ++i) {
if (eocd[i ] == 0x50 && eocd[i+1] == 0x4b &&
eocd[i+2] == 0x05 && eocd[i+3] == 0x06) {
// if the sequence $50 $4b $05 $06 appears anywhere after
@@ -193,8 +192,8 @@ int verify_file(unsigned char* addr, size_t length,
bool need_sha1 = false;
bool need_sha256 = false;
- for (i = 0; i < numKeys; ++i) {
- switch (pKeys[i].hash_len) {
+ for (const auto& key : keys) {
+ switch (key.hash_len) {
case SHA_DIGEST_SIZE: need_sha1 = true; break;
case SHA256_DIGEST_SIZE: need_sha256 = true; break;
}
@@ -225,7 +224,7 @@ int verify_file(unsigned char* addr, size_t length,
const uint8_t* sha1 = SHA_final(&sha1_ctx);
const uint8_t* sha256 = SHA256_final(&sha256_ctx);
- uint8_t* sig_der = NULL;
+ uint8_t* sig_der = nullptr;
size_t sig_der_length = 0;
size_t signature_size = signature_start - FOOTER_SIZE;
@@ -240,9 +239,10 @@ int verify_file(unsigned char* addr, size_t length,
* any key can match, we need to try each before determining a verification
* failure has happened.
*/
- for (i = 0; i < numKeys; ++i) {
+ size_t i = 0;
+ for (const auto& key : keys) {
const uint8_t* hash;
- switch (pKeys[i].hash_len) {
+ switch (key.hash_len) {
case SHA_DIGEST_SIZE: hash = sha1; break;
case SHA256_DIGEST_SIZE: hash = sha256; break;
default: continue;
@@ -250,15 +250,15 @@ int verify_file(unsigned char* addr, size_t length,
// The 6 bytes is the "(signature_start) $ff $ff (comment_size)" that
// the signing tool appends after the signature itself.
- if (pKeys[i].key_type == Certificate::RSA) {
+ if (key.key_type == Certificate::RSA) {
if (sig_der_length < RSANUMBYTES) {
// "signature" block isn't big enough to contain an RSA block.
LOGI("signature is too short for RSA key %zu\n", i);
continue;
}
- if (!RSA_verify(pKeys[i].rsa, sig_der, RSANUMBYTES,
- hash, pKeys[i].hash_len)) {
+ if (!RSA_verify(key.rsa.get(), sig_der, RSANUMBYTES,
+ hash, key.hash_len)) {
LOGI("failed to verify against RSA key %zu\n", i);
continue;
}
@@ -266,8 +266,8 @@ int verify_file(unsigned char* addr, size_t length,
LOGI("whole-file signature verified against RSA key %zu\n", i);
free(sig_der);
return VERIFY_SUCCESS;
- } else if (pKeys[i].key_type == Certificate::EC
- && pKeys[i].hash_len == SHA256_DIGEST_SIZE) {
+ } else if (key.key_type == Certificate::EC
+ && key.hash_len == SHA256_DIGEST_SIZE) {
p256_int r, s;
if (!dsa_sig_unpack(sig_der, sig_der_length, &r, &s)) {
LOGI("Not a DSA signature block for EC key %zu\n", i);
@@ -276,7 +276,7 @@ int verify_file(unsigned char* addr, size_t length,
p256_int p256_hash;
p256_from_bin(hash, &p256_hash);
- if (!p256_ecdsa_verify(&(pKeys[i].ec->x), &(pKeys[i].ec->y),
+ if (!p256_ecdsa_verify(&(key.ec->x), &(key.ec->y),
&p256_hash, &r, &s)) {
LOGI("failed to verify against EC key %zu\n", i);
continue;
@@ -286,8 +286,9 @@ int verify_file(unsigned char* addr, size_t length,
free(sig_der);
return VERIFY_SUCCESS;
} else {
- LOGI("Unknown key type %d\n", pKeys[i].key_type);
+ LOGI("Unknown key type %d\n", key.key_type);
}
+ i++;
}
free(sig_der);
LOGE("failed to verify whole-file signature\n");
@@ -323,140 +324,122 @@ int verify_file(unsigned char* addr, size_t length,
// 4: 2048-bit RSA key with e=65537 and SHA-256 hash
// 5: 256-bit EC key using the NIST P-256 curve parameters and SHA-256 hash
//
-// Returns NULL if the file failed to parse, or if it contain zero keys.
-Certificate*
-load_keys(const char* filename, int* numKeys) {
- Certificate* out = NULL;
- *numKeys = 0;
-
- FILE* f = fopen(filename, "r");
- if (f == NULL) {
+// Returns true on success, and appends the found keys (at least one) to certs.
+// Otherwise returns false if the file failed to parse, or if it contains zero
+// keys. The contents in certs would be unspecified on failure.
+bool load_keys(const char* filename, std::vector<Certificate>& certs) {
+ std::unique_ptr<FILE, decltype(&fclose)> f(fopen(filename, "r"), fclose);
+ if (!f) {
LOGE("opening %s: %s\n", filename, strerror(errno));
- goto exit;
+ return false;
}
- {
- int i;
- bool done = false;
- while (!done) {
- ++*numKeys;
- out = (Certificate*)realloc(out, *numKeys * sizeof(Certificate));
- Certificate* cert = out + (*numKeys - 1);
- memset(cert, '\0', sizeof(Certificate));
-
- char start_char;
- if (fscanf(f, " %c", &start_char) != 1) goto exit;
- if (start_char == '{') {
- // a version 1 key has no version specifier.
- cert->key_type = Certificate::RSA;
- cert->rsa = (RSAPublicKey*)malloc(sizeof(RSAPublicKey));
- cert->rsa->exponent = 3;
- cert->hash_len = SHA_DIGEST_SIZE;
- } else if (start_char == 'v') {
- int version;
- if (fscanf(f, "%d {", &version) != 1) goto exit;
- switch (version) {
- case 2:
- cert->key_type = Certificate::RSA;
- cert->rsa = (RSAPublicKey*)malloc(sizeof(RSAPublicKey));
- cert->rsa->exponent = 65537;
- cert->hash_len = SHA_DIGEST_SIZE;
- break;
- case 3:
- cert->key_type = Certificate::RSA;
- cert->rsa = (RSAPublicKey*)malloc(sizeof(RSAPublicKey));
- cert->rsa->exponent = 3;
- cert->hash_len = SHA256_DIGEST_SIZE;
- break;
- case 4:
- cert->key_type = Certificate::RSA;
- cert->rsa = (RSAPublicKey*)malloc(sizeof(RSAPublicKey));
- cert->rsa->exponent = 65537;
- cert->hash_len = SHA256_DIGEST_SIZE;
- break;
- case 5:
- cert->key_type = Certificate::EC;
- cert->ec = (ECPublicKey*)calloc(1, sizeof(ECPublicKey));
- cert->hash_len = SHA256_DIGEST_SIZE;
- break;
- default:
- goto exit;
- }
+ while (true) {
+ certs.emplace_back(0, Certificate::RSA, nullptr, nullptr);
+ Certificate& cert = certs.back();
+
+ char start_char;
+ if (fscanf(f.get(), " %c", &start_char) != 1) return false;
+ if (start_char == '{') {
+ // a version 1 key has no version specifier.
+ cert.key_type = Certificate::RSA;
+ cert.rsa = std::unique_ptr<RSAPublicKey>(new RSAPublicKey);
+ cert.rsa->exponent = 3;
+ cert.hash_len = SHA_DIGEST_SIZE;
+ } else if (start_char == 'v') {
+ int version;
+ if (fscanf(f.get(), "%d {", &version) != 1) return false;
+ switch (version) {
+ case 2:
+ cert.key_type = Certificate::RSA;
+ cert.rsa = std::unique_ptr<RSAPublicKey>(new RSAPublicKey);
+ cert.rsa->exponent = 65537;
+ cert.hash_len = SHA_DIGEST_SIZE;
+ break;
+ case 3:
+ cert.key_type = Certificate::RSA;
+ cert.rsa = std::unique_ptr<RSAPublicKey>(new RSAPublicKey);
+ cert.rsa->exponent = 3;
+ cert.hash_len = SHA256_DIGEST_SIZE;
+ break;
+ case 4:
+ cert.key_type = Certificate::RSA;
+ cert.rsa = std::unique_ptr<RSAPublicKey>(new RSAPublicKey);
+ cert.rsa->exponent = 65537;
+ cert.hash_len = SHA256_DIGEST_SIZE;
+ break;
+ case 5:
+ cert.key_type = Certificate::EC;
+ cert.ec = std::unique_ptr<ECPublicKey>(new ECPublicKey);
+ cert.hash_len = SHA256_DIGEST_SIZE;
+ break;
+ default:
+ return false;
}
+ }
- if (cert->key_type == Certificate::RSA) {
- RSAPublicKey* key = cert->rsa;
- if (fscanf(f, " %i , 0x%x , { %u",
- &(key->len), &(key->n0inv), &(key->n[0])) != 3) {
- goto exit;
- }
- if (key->len != RSANUMWORDS) {
- LOGE("key length (%d) does not match expected size\n", key->len);
- goto exit;
- }
- for (i = 1; i < key->len; ++i) {
- if (fscanf(f, " , %u", &(key->n[i])) != 1) goto exit;
- }
- if (fscanf(f, " } , { %u", &(key->rr[0])) != 1) goto exit;
- for (i = 1; i < key->len; ++i) {
- if (fscanf(f, " , %u", &(key->rr[i])) != 1) goto exit;
- }
- fscanf(f, " } } ");
-
- LOGI("read key e=%d hash=%d\n", key->exponent, cert->hash_len);
- } else if (cert->key_type == Certificate::EC) {
- ECPublicKey* key = cert->ec;
- int key_len;
- unsigned int byte;
- uint8_t x_bytes[P256_NBYTES];
- uint8_t y_bytes[P256_NBYTES];
- if (fscanf(f, " %i , { %u", &key_len, &byte) != 2) goto exit;
- if (key_len != P256_NBYTES) {
- LOGE("Key length (%d) does not match expected size %d\n", key_len, P256_NBYTES);
- goto exit;
- }
- x_bytes[P256_NBYTES - 1] = byte;
- for (i = P256_NBYTES - 2; i >= 0; --i) {
- if (fscanf(f, " , %u", &byte) != 1) goto exit;
- x_bytes[i] = byte;
- }
- if (fscanf(f, " } , { %u", &byte) != 1) goto exit;
- y_bytes[P256_NBYTES - 1] = byte;
- for (i = P256_NBYTES - 2; i >= 0; --i) {
- if (fscanf(f, " , %u", &byte) != 1) goto exit;
- y_bytes[i] = byte;
- }
- fscanf(f, " } } ");
- p256_from_bin(x_bytes, &key->x);
- p256_from_bin(y_bytes, &key->y);
- } else {
- LOGE("Unknown key type %d\n", cert->key_type);
- goto exit;
+ if (cert.key_type == Certificate::RSA) {
+ RSAPublicKey* key = cert.rsa.get();
+ if (fscanf(f.get(), " %i , 0x%x , { %u", &(key->len), &(key->n0inv),
+ &(key->n[0])) != 3) {
+ return false;
}
-
- // if the line ends in a comma, this file has more keys.
- switch (fgetc(f)) {
- case ',':
- // more keys to come.
- break;
-
- case EOF:
- done = true;
- break;
-
- default:
- LOGE("unexpected character between keys\n");
- goto exit;
+ if (key->len != RSANUMWORDS) {
+ LOGE("key length (%d) does not match expected size\n", key->len);
+ return false;
+ }
+ for (int i = 1; i < key->len; ++i) {
+ if (fscanf(f.get(), " , %u", &(key->n[i])) != 1) return false;
+ }
+ if (fscanf(f.get(), " } , { %u", &(key->rr[0])) != 1) return false;
+ for (int i = 1; i < key->len; ++i) {
+ if (fscanf(f.get(), " , %u", &(key->rr[i])) != 1) return false;
+ }
+ fscanf(f.get(), " } } ");
+
+ LOGI("read key e=%d hash=%d\n", key->exponent, cert.hash_len);
+ } else if (cert.key_type == Certificate::EC) {
+ ECPublicKey* key = cert.ec.get();
+ int key_len;
+ unsigned int byte;
+ uint8_t x_bytes[P256_NBYTES];
+ uint8_t y_bytes[P256_NBYTES];
+ if (fscanf(f.get(), " %i , { %u", &key_len, &byte) != 2) return false;
+ if (key_len != P256_NBYTES) {
+ LOGE("Key length (%d) does not match expected size %d\n", key_len, P256_NBYTES);
+ return false;
+ }
+ x_bytes[P256_NBYTES - 1] = byte;
+ for (int i = P256_NBYTES - 2; i >= 0; --i) {
+ if (fscanf(f.get(), " , %u", &byte) != 1) return false;
+ x_bytes[i] = byte;
+ }
+ if (fscanf(f.get(), " } , { %u", &byte) != 1) return false;
+ y_bytes[P256_NBYTES - 1] = byte;
+ for (int i = P256_NBYTES - 2; i >= 0; --i) {
+ if (fscanf(f.get(), " , %u", &byte) != 1) return false;
+ y_bytes[i] = byte;
}
+ fscanf(f.get(), " } } ");
+ p256_from_bin(x_bytes, &key->x);
+ p256_from_bin(y_bytes, &key->y);
+ } else {
+ LOGE("Unknown key type %d\n", cert.key_type);
+ return false;
}
- }
- fclose(f);
- return out;
+ // if the line ends in a comma, this file has more keys.
+ int ch = fgetc(f.get());
+ if (ch == ',') {
+ // more keys to come.
+ continue;
+ } else if (ch == EOF) {
+ break;
+ } else {
+ LOGE("unexpected character between keys\n");
+ return false;
+ }
+ }
-exit:
- if (f) fclose(f);
- free(out);
- *numKeys = 0;
- return NULL;
+ return true;
}
diff --git a/verifier.h b/verifier.h
index 15f8d98e4..4eafc7565 100644
--- a/verifier.h
+++ b/verifier.h
@@ -17,6 +17,9 @@
#ifndef _RECOVERY_VERIFIER_H
#define _RECOVERY_VERIFIER_H
+#include <memory>
+#include <vector>
+
#include "mincrypt/p256.h"
#include "mincrypt/rsa.h"
@@ -25,17 +28,25 @@ typedef struct {
p256_int y;
} ECPublicKey;
-typedef struct {
+struct Certificate {
typedef enum {
RSA,
EC,
} KeyType;
+ Certificate(int hash_len_, KeyType key_type_,
+ std::unique_ptr<RSAPublicKey>&& rsa_,
+ std::unique_ptr<ECPublicKey>&& ec_) :
+ hash_len(hash_len_),
+ key_type(key_type_),
+ rsa(std::move(rsa_)),
+ ec(std::move(ec_)) { }
+
int hash_len; // SHA_DIGEST_SIZE (SHA-1) or SHA256_DIGEST_SIZE (SHA-256)
KeyType key_type;
- RSAPublicKey* rsa;
- ECPublicKey* ec;
-} Certificate;
+ std::unique_ptr<RSAPublicKey> rsa;
+ std::unique_ptr<ECPublicKey> ec;
+};
/* addr and length define a an update package file that has been
* loaded (or mmap'ed, or whatever) into memory. Verify that the file
@@ -43,9 +54,9 @@ typedef struct {
* one of the constants below.
*/
int verify_file(unsigned char* addr, size_t length,
- const Certificate *pKeys, unsigned int numKeys);
+ const std::vector<Certificate>& keys);
-Certificate* load_keys(const char* filename, int* numKeys);
+bool load_keys(const char* filename, std::vector<Certificate>& certs);
#define VERIFY_SUCCESS 0
#define VERIFY_FAILURE 1
diff --git a/verifier_test.sh b/verifier_test.sh
deleted file mode 100755
index 4761cef4a..000000000
--- a/verifier_test.sh
+++ /dev/null
@@ -1,121 +0,0 @@
-#!/bin/bash
-#
-# A test suite for recovery's package signature verifier. Run in a
-# client where you have done envsetup, lunch, etc.
-#
-# TODO: find some way to get this run regularly along with the rest of
-# the tests.
-
-EMULATOR_PORT=5580
-DATA_DIR=$ANDROID_BUILD_TOP/bootable/recovery/testdata
-
-WORK_DIR=/data/local/tmp
-
-# set to 0 to use a device instead
-USE_EMULATOR=0
-
-# ------------------------
-
-if [ "$USE_EMULATOR" == 1 ]; then
- emulator -wipe-data -noaudio -no-window -port $EMULATOR_PORT &
- pid_emulator=$!
- ADB="adb -s emulator-$EMULATOR_PORT "
-else
- ADB="adb -d "
-fi
-
-echo "waiting to connect to device"
-$ADB wait-for-device
-
-# run a command on the device; exit with the exit status of the device
-# command.
-run_command() {
- $ADB shell "$@" \; echo \$? | awk '{if (b) {print a}; a=$0; b=1} END {exit a}'
-}
-
-testname() {
- echo
- echo "::: testing $1 :::"
- testname="$1"
-}
-
-fail() {
- echo
- echo FAIL: $testname
- echo
- [ "$open_pid" == "" ] || kill $open_pid
- [ "$pid_emulator" == "" ] || kill $pid_emulator
- exit 1
-}
-
-
-cleanup() {
- # not necessary if we're about to kill the emulator, but nice for
- # running on real devices or already-running emulators.
- run_command rm $WORK_DIR/verifier_test
- run_command rm $WORK_DIR/package.zip
-
- [ "$pid_emulator" == "" ] || kill $pid_emulator
-}
-
-$ADB push $ANDROID_PRODUCT_OUT/system/bin/verifier_test \
- $WORK_DIR/verifier_test
-
-expect_succeed() {
- testname "$1 (should succeed)"
- $ADB push $DATA_DIR/$1 $WORK_DIR/package.zip
- shift
- run_command $WORK_DIR/verifier_test "$@" $WORK_DIR/package.zip || fail
-}
-
-expect_fail() {
- testname "$1 (should fail)"
- $ADB push $DATA_DIR/$1 $WORK_DIR/package.zip
- shift
- run_command $WORK_DIR/verifier_test "$@" $WORK_DIR/package.zip && fail
-}
-
-# not signed at all
-expect_fail unsigned.zip
-# signed in the pre-donut way
-expect_fail jarsigned.zip
-
-# success cases
-expect_succeed otasigned.zip -e3
-expect_succeed otasigned_f4.zip -f4
-expect_succeed otasigned_sha256.zip -e3 -sha256
-expect_succeed otasigned_f4_sha256.zip -f4 -sha256
-expect_succeed otasigned_ecdsa_sha256.zip -ec -sha256
-
-# success with multiple keys
-expect_succeed otasigned.zip -f4 -e3
-expect_succeed otasigned_f4.zip -ec -f4
-expect_succeed otasigned_sha256.zip -ec -e3 -e3 -sha256
-expect_succeed otasigned_f4_sha256.zip -ec -sha256 -e3 -f4 -sha256
-expect_succeed otasigned_ecdsa_sha256.zip -f4 -sha256 -e3 -ec -sha256
-
-# verified against different key
-expect_fail otasigned.zip -f4
-expect_fail otasigned_f4.zip -e3
-expect_fail otasigned_ecdsa_sha256.zip -e3 -sha256
-
-# verified against right key but wrong hash algorithm
-expect_fail otasigned.zip -e3 -sha256
-expect_fail otasigned_f4.zip -f4 -sha256
-expect_fail otasigned_sha256.zip
-expect_fail otasigned_f4_sha256.zip -f4
-expect_fail otasigned_ecdsa_sha256.zip
-
-# various other cases
-expect_fail random.zip
-expect_fail fake-eocd.zip
-expect_fail alter-metadata.zip
-expect_fail alter-footer.zip
-
-# --------------- cleanup ----------------------
-
-cleanup
-
-echo
-echo PASS
-echo