summaryrefslogtreecommitdiffstats
path: root/tests/component
diff options
context:
space:
mode:
Diffstat (limited to 'tests/component')
-rw-r--r--tests/component/imgdiff_test.cpp9
-rw-r--r--tests/component/updater_test.cpp120
-rw-r--r--tests/component/verifier_test.cpp208
3 files changed, 223 insertions, 114 deletions
diff --git a/tests/component/imgdiff_test.cpp b/tests/component/imgdiff_test.cpp
index be2dd385b..2f648501c 100644
--- a/tests/component/imgdiff_test.cpp
+++ b/tests/component/imgdiff_test.cpp
@@ -18,13 +18,14 @@
#include <vector>
#include <android-base/file.h>
+#include <android-base/memory.h>
#include <android-base/test_utils.h>
#include <applypatch/imgdiff.h>
#include <applypatch/imgpatch.h>
#include <gtest/gtest.h>
#include <ziparchive/zip_writer.h>
-#include "applypatch/utils.h"
+using android::base::get_unaligned;
static ssize_t MemorySink(const unsigned char* data, ssize_t len, void* token) {
std::string* s = static_cast<std::string*>(token);
@@ -41,7 +42,7 @@ static void verify_patch_header(const std::string& patch, size_t* num_normal, si
ASSERT_GE(size, 12U);
ASSERT_EQ("IMGDIFF2", std::string(data, 8));
- const int num_chunks = Read4(data + 8);
+ const int num_chunks = get_unaligned<int32_t>(data + 8);
ASSERT_GE(num_chunks, 0);
size_t normal = 0;
@@ -51,7 +52,7 @@ static void verify_patch_header(const std::string& patch, size_t* num_normal, si
size_t pos = 12;
for (int i = 0; i < num_chunks; ++i) {
ASSERT_LE(pos + 4, size);
- int type = Read4(data + pos);
+ int type = get_unaligned<int32_t>(data + pos);
pos += 4;
if (type == CHUNK_NORMAL) {
pos += 24;
@@ -59,7 +60,7 @@ static void verify_patch_header(const std::string& patch, size_t* num_normal, si
normal++;
} else if (type == CHUNK_RAW) {
ASSERT_LE(pos + 4, size);
- ssize_t data_len = Read4(data + pos);
+ ssize_t data_len = get_unaligned<int32_t>(data + pos);
ASSERT_GT(data_len, 0);
pos += 4 + data_len;
ASSERT_LE(pos, size);
diff --git a/tests/component/updater_test.cpp b/tests/component/updater_test.cpp
index 8c4bdbaa4..4f8349e2f 100644
--- a/tests/component/updater_test.cpp
+++ b/tests/component/updater_test.cpp
@@ -20,6 +20,7 @@
#include <unistd.h>
#include <string>
+#include <vector>
#include <android-base/file.h>
#include <android-base/properties.h>
@@ -27,12 +28,17 @@
#include <android-base/strings.h>
#include <android-base/test_utils.h>
#include <bootloader_message/bootloader_message.h>
+#include <bsdiff.h>
#include <gtest/gtest.h>
#include <ziparchive/zip_archive.h>
+#include <ziparchive/zip_writer.h>
#include "common/test_constants.h"
#include "edify/expr.h"
#include "error_code.h"
+#include "otautil/SysUtil.h"
+#include "print_sha1.h"
+#include "updater/blockimg.h"
#include "updater/install.h"
#include "updater/updater.h"
@@ -64,12 +70,19 @@ static void expect(const char* expected, const char* expr_str, CauseCode cause_c
ASSERT_EQ(cause_code, state.cause_code);
}
+static std::string get_sha1(const std::string& content) {
+ uint8_t digest[SHA_DIGEST_LENGTH];
+ SHA1(reinterpret_cast<const uint8_t*>(content.c_str()), content.size(), digest);
+ return print_sha1(digest);
+}
+
class UpdaterTest : public ::testing::Test {
- protected:
- virtual void SetUp() {
- RegisterBuiltins();
- RegisterInstallFunctions();
- }
+ protected:
+ virtual void SetUp() override {
+ RegisterBuiltins();
+ RegisterInstallFunctions();
+ RegisterBlockImageFunctions();
+ }
};
TEST_F(UpdaterTest, getprop) {
@@ -447,3 +460,100 @@ TEST_F(UpdaterTest, show_progress) {
// recovery-updater protocol expects 3 tokens ("progress <frac> <secs>").
ASSERT_EQ(3U, android::base::Split(cmd, " ").size());
}
+
+TEST_F(UpdaterTest, block_image_update) {
+ // Create a zip file with new_data and patch_data.
+ TemporaryFile zip_file;
+ FILE* zip_file_ptr = fdopen(zip_file.fd, "wb");
+ ZipWriter zip_writer(zip_file_ptr);
+
+ // Add a dummy new data.
+ ASSERT_EQ(0, zip_writer.StartEntry("new_data", 0));
+ ASSERT_EQ(0, zip_writer.FinishEntry());
+
+ // Generate and add the patch data.
+ std::string src_content = std::string(4096, 'a') + std::string(4096, 'c');
+ std::string tgt_content = std::string(4096, 'b') + std::string(4096, 'd');
+ TemporaryFile patch_file;
+ ASSERT_EQ(0, bsdiff::bsdiff(reinterpret_cast<const uint8_t*>(src_content.data()),
+ src_content.size(), reinterpret_cast<const uint8_t*>(tgt_content.data()),
+ tgt_content.size(), patch_file.path, nullptr));
+ std::string patch_content;
+ ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch_content));
+ ASSERT_EQ(0, zip_writer.StartEntry("patch_data", 0));
+ ASSERT_EQ(0, zip_writer.WriteBytes(patch_content.data(), patch_content.size()));
+ ASSERT_EQ(0, zip_writer.FinishEntry());
+
+ // Add two transfer lists. The first one contains a bsdiff; and we expect the update to succeed.
+ std::string src_hash = get_sha1(src_content);
+ std::string tgt_hash = get_sha1(tgt_content);
+ std::vector<std::string> transfer_list = {
+ "4",
+ "2",
+ "0",
+ "2",
+ "stash " + src_hash + " 2,0,2",
+ android::base::StringPrintf("bsdiff 0 %zu %s %s 2,0,2 2 - %s:2,0,2", patch_content.size(),
+ src_hash.c_str(), tgt_hash.c_str(), src_hash.c_str()),
+ "free " + src_hash,
+ };
+ ASSERT_EQ(0, zip_writer.StartEntry("transfer_list", 0));
+ std::string commands = android::base::Join(transfer_list, '\n');
+ ASSERT_EQ(0, zip_writer.WriteBytes(commands.data(), commands.size()));
+ ASSERT_EQ(0, zip_writer.FinishEntry());
+
+ // Stash and free some blocks, then fail the 2nd update intentionally.
+ std::vector<std::string> fail_transfer_list = {
+ "4",
+ "2",
+ "0",
+ "2",
+ "stash " + tgt_hash + " 2,0,2",
+ "free " + tgt_hash,
+ "fail",
+ };
+ ASSERT_EQ(0, zip_writer.StartEntry("fail_transfer_list", 0));
+ std::string fail_commands = android::base::Join(fail_transfer_list, '\n');
+ ASSERT_EQ(0, zip_writer.WriteBytes(fail_commands.data(), fail_commands.size()));
+ ASSERT_EQ(0, zip_writer.FinishEntry());
+ ASSERT_EQ(0, zip_writer.Finish());
+ ASSERT_EQ(0, fclose(zip_file_ptr));
+
+ MemMapping map;
+ ASSERT_EQ(0, sysMapFile(zip_file.path, &map));
+ ZipArchiveHandle handle;
+ ASSERT_EQ(0, OpenArchiveFromMemory(map.addr, map.length, zip_file.path, &handle));
+
+ // Set up the handler, command_pipe, patch offset & length.
+ UpdaterInfo updater_info;
+ updater_info.package_zip = handle;
+ TemporaryFile temp_pipe;
+ updater_info.cmd_pipe = fopen(temp_pipe.path, "wb");
+ updater_info.package_zip_addr = map.addr;
+ updater_info.package_zip_len = map.length;
+
+ // Execute the commands in the 1st transfer list.
+ TemporaryFile update_file;
+ ASSERT_TRUE(android::base::WriteStringToFile(src_content, update_file.path));
+ std::string script = "block_image_update(\"" + std::string(update_file.path) +
+ R"(", package_extract_file("transfer_list"), "new_data", "patch_data"))";
+ expect("t", script.c_str(), kNoCause, &updater_info);
+ // The update_file should be patched correctly.
+ std::string updated_content;
+ ASSERT_TRUE(android::base::ReadFileToString(update_file.path, &updated_content));
+ ASSERT_EQ(tgt_hash, get_sha1(updated_content));
+
+ // Expect the 2nd update to fail, but expect the stashed blocks to be freed.
+ script = "block_image_update(\"" + std::string(update_file.path) +
+ R"(", package_extract_file("fail_transfer_list"), "new_data", "patch_data"))";
+ expect("", script.c_str(), kNoCause, &updater_info);
+ // Updater generates the stash name based on the input file name.
+ std::string name_digest = get_sha1(update_file.path);
+ std::string stash_base = "/cache/recovery/" + name_digest;
+ ASSERT_EQ(0, access(stash_base.c_str(), F_OK));
+ ASSERT_EQ(-1, access((stash_base + tgt_hash).c_str(), F_OK));
+ ASSERT_EQ(0, rmdir(stash_base.c_str()));
+
+ ASSERT_EQ(0, fclose(updater_info.cmd_pipe));
+ CloseArchive(handle);
+}
diff --git a/tests/component/verifier_test.cpp b/tests/component/verifier_test.cpp
index 4294d90eb..4993716f4 100644
--- a/tests/component/verifier_test.cpp
+++ b/tests/component/verifier_test.cpp
@@ -22,93 +22,34 @@
#include <sys/stat.h>
#include <sys/types.h>
-#include <memory>
#include <string>
#include <vector>
-#include <openssl/sha.h>
-
+#include <android-base/file.h>
#include <android-base/stringprintf.h>
-#include <ziparchive/zip_archive.h>
+#include <android-base/test_utils.h>
-#include "common.h"
#include "common/test_constants.h"
#include "otautil/SysUtil.h"
-#include "ui.h"
#include "verifier.h"
-RecoveryUI* ui = NULL;
-
-class MockUI : public RecoveryUI {
- bool Init(const std::string&) override {
- return true;
- }
- void SetStage(int, int) override {}
- void SetBackground(Icon /*icon*/) override {}
- void SetSystemUpdateText(bool /*security_update*/) override {}
-
- void SetProgressType(ProgressType /*determinate*/) override {}
- void ShowProgress(float /*portion*/, float /*seconds*/) override {}
- void SetProgress(float /*fraction*/) override {}
-
- void ShowText(bool /*visible*/) override {}
- bool IsTextVisible() override {
- return false;
- }
- bool WasTextEverVisible() override {
- return false;
- }
- void Print(const char* fmt, ...) override {
- va_list ap;
- va_start(ap, fmt);
- vfprintf(stderr, fmt, ap);
- va_end(ap);
- }
- void PrintOnScreenOnly(const char* fmt, ...) override {
- va_list ap;
- va_start(ap, fmt);
- vfprintf(stderr, fmt, ap);
- va_end(ap);
- }
- void ShowFile(const char*) override {}
-
- void StartMenu(const char* const* /*headers*/, const char* const* /*items*/,
- int /*initial_selection*/) override {}
- int SelectMenu(int /*sel*/) override {
- return 0;
- }
- void EndMenu() override {}
-};
-
-void
-ui_print(const char* format, ...) {
- va_list ap;
- va_start(ap, format);
- vfprintf(stdout, format, ap);
- va_end(ap);
-}
-
class VerifierTest : public testing::TestWithParam<std::vector<std::string>> {
- public:
- MemMapping memmap;
- std::vector<Certificate> certs;
-
- virtual void SetUp() {
- std::vector<std::string> args = GetParam();
- std::string package = from_testdata_base(args[0]);
- if (sysMapFile(package.c_str(), &memmap) != 0) {
- FAIL() << "Failed to mmap " << package << ": " << strerror(errno) << "\n";
- }
-
- for (auto it = ++(args.cbegin()); it != args.cend(); ++it) {
- std::string public_key_file = from_testdata_base("testkey_" + *it + ".txt");
- ASSERT_TRUE(load_keys(public_key_file.c_str(), certs));
- }
+ protected:
+ void SetUp() override {
+ std::vector<std::string> args = GetParam();
+ std::string package = from_testdata_base(args[0]);
+ if (sysMapFile(package.c_str(), &memmap) != 0) {
+ FAIL() << "Failed to mmap " << package << ": " << strerror(errno) << "\n";
}
- static void SetUpTestCase() {
- ui = new MockUI();
+ for (auto it = ++args.cbegin(); it != args.cend(); ++it) {
+ std::string public_key_file = from_testdata_base("testkey_" + *it + ".txt");
+ ASSERT_TRUE(load_keys(public_key_file.c_str(), certs));
}
+ }
+
+ MemMapping memmap;
+ std::vector<Certificate> certs;
};
class VerifierSuccessTest : public VerifierTest {
@@ -117,49 +58,106 @@ class VerifierSuccessTest : public VerifierTest {
class VerifierFailureTest : public VerifierTest {
};
+TEST(VerifierTest, load_keys_multiple_keys) {
+ std::string testkey_v4;
+ ASSERT_TRUE(android::base::ReadFileToString(from_testdata_base("testkey_v4.txt"), &testkey_v4));
+
+ std::string testkey_v3;
+ ASSERT_TRUE(android::base::ReadFileToString(from_testdata_base("testkey_v3.txt"), &testkey_v3));
+
+ std::string keys = testkey_v4 + "," + testkey_v3 + "," + testkey_v4;
+ TemporaryFile key_file1;
+ ASSERT_TRUE(android::base::WriteStringToFile(keys, key_file1.path));
+ std::vector<Certificate> certs;
+ ASSERT_TRUE(load_keys(key_file1.path, certs));
+ ASSERT_EQ(3U, certs.size());
+}
+
+TEST(VerifierTest, load_keys_invalid_keys) {
+ std::vector<Certificate> certs;
+ ASSERT_FALSE(load_keys("/doesntexist", certs));
+
+ // Empty file.
+ TemporaryFile key_file1;
+ ASSERT_FALSE(load_keys(key_file1.path, certs));
+
+ // Invalid contents.
+ ASSERT_TRUE(android::base::WriteStringToFile("invalid", key_file1.path));
+ ASSERT_FALSE(load_keys(key_file1.path, certs));
+
+ std::string testkey_v4;
+ ASSERT_TRUE(android::base::ReadFileToString(from_testdata_base("testkey_v4.txt"), &testkey_v4));
+
+ // Invalid key version: "v4 ..." => "v6 ...".
+ std::string invalid_key2(testkey_v4);
+ invalid_key2[1] = '6';
+ TemporaryFile key_file2;
+ ASSERT_TRUE(android::base::WriteStringToFile(invalid_key2, key_file2.path));
+ ASSERT_FALSE(load_keys(key_file2.path, certs));
+
+ // Invalid key content: inserted extra bytes ",2209831334".
+ std::string invalid_key3(testkey_v4);
+ invalid_key3.insert(invalid_key2.size() - 2, ",2209831334");
+ TemporaryFile key_file3;
+ ASSERT_TRUE(android::base::WriteStringToFile(invalid_key3, key_file3.path));
+ ASSERT_FALSE(load_keys(key_file3.path, certs));
+
+ // Invalid key: the last key must not end with an extra ','.
+ std::string invalid_key4 = testkey_v4 + ",";
+ TemporaryFile key_file4;
+ ASSERT_TRUE(android::base::WriteStringToFile(invalid_key4, key_file4.path));
+ ASSERT_FALSE(load_keys(key_file4.path, certs));
+
+ // Invalid key separator.
+ std::string invalid_key5 = testkey_v4 + ";" + testkey_v4;
+ TemporaryFile key_file5;
+ ASSERT_TRUE(android::base::WriteStringToFile(invalid_key5, key_file5.path));
+ ASSERT_FALSE(load_keys(key_file5.path, certs));
+}
+
TEST_P(VerifierSuccessTest, VerifySucceed) {
- ASSERT_EQ(verify_file(memmap.addr, memmap.length, certs), VERIFY_SUCCESS);
+ ASSERT_EQ(verify_file(memmap.addr, memmap.length, certs, nullptr), VERIFY_SUCCESS);
}
TEST_P(VerifierFailureTest, VerifyFailure) {
- ASSERT_EQ(verify_file(memmap.addr, memmap.length, certs), VERIFY_FAILURE);
+ ASSERT_EQ(verify_file(memmap.addr, memmap.length, certs, nullptr), VERIFY_FAILURE);
}
INSTANTIATE_TEST_CASE_P(SingleKeySuccess, VerifierSuccessTest,
- ::testing::Values(
- std::vector<std::string>({"otasigned_v1.zip", "v1"}),
- std::vector<std::string>({"otasigned_v2.zip", "v2"}),
- std::vector<std::string>({"otasigned_v3.zip", "v3"}),
- std::vector<std::string>({"otasigned_v4.zip", "v4"}),
- std::vector<std::string>({"otasigned_v5.zip", "v5"})));
+ ::testing::Values(
+ std::vector<std::string>({"otasigned_v1.zip", "v1"}),
+ std::vector<std::string>({"otasigned_v2.zip", "v2"}),
+ std::vector<std::string>({"otasigned_v3.zip", "v3"}),
+ std::vector<std::string>({"otasigned_v4.zip", "v4"}),
+ std::vector<std::string>({"otasigned_v5.zip", "v5"})));
INSTANTIATE_TEST_CASE_P(MultiKeySuccess, VerifierSuccessTest,
- ::testing::Values(
- std::vector<std::string>({"otasigned_v1.zip", "v1", "v2"}),
- std::vector<std::string>({"otasigned_v2.zip", "v5", "v2"}),
- std::vector<std::string>({"otasigned_v3.zip", "v5", "v1", "v3"}),
- std::vector<std::string>({"otasigned_v4.zip", "v5", "v1", "v4"}),
- std::vector<std::string>({"otasigned_v5.zip", "v4", "v1", "v5"})));
+ ::testing::Values(
+ std::vector<std::string>({"otasigned_v1.zip", "v1", "v2"}),
+ std::vector<std::string>({"otasigned_v2.zip", "v5", "v2"}),
+ std::vector<std::string>({"otasigned_v3.zip", "v5", "v1", "v3"}),
+ std::vector<std::string>({"otasigned_v4.zip", "v5", "v1", "v4"}),
+ std::vector<std::string>({"otasigned_v5.zip", "v4", "v1", "v5"})));
INSTANTIATE_TEST_CASE_P(WrongKey, VerifierFailureTest,
- ::testing::Values(
- std::vector<std::string>({"otasigned_v1.zip", "v2"}),
- std::vector<std::string>({"otasigned_v2.zip", "v1"}),
- std::vector<std::string>({"otasigned_v3.zip", "v5"}),
- std::vector<std::string>({"otasigned_v4.zip", "v5"}),
- std::vector<std::string>({"otasigned_v5.zip", "v3"})));
+ ::testing::Values(
+ std::vector<std::string>({"otasigned_v1.zip", "v2"}),
+ std::vector<std::string>({"otasigned_v2.zip", "v1"}),
+ std::vector<std::string>({"otasigned_v3.zip", "v5"}),
+ std::vector<std::string>({"otasigned_v4.zip", "v5"}),
+ std::vector<std::string>({"otasigned_v5.zip", "v3"})));
INSTANTIATE_TEST_CASE_P(WrongHash, VerifierFailureTest,
- ::testing::Values(
- std::vector<std::string>({"otasigned_v1.zip", "v3"}),
- std::vector<std::string>({"otasigned_v2.zip", "v4"}),
- std::vector<std::string>({"otasigned_v3.zip", "v1"}),
- std::vector<std::string>({"otasigned_v4.zip", "v2"})));
+ ::testing::Values(
+ std::vector<std::string>({"otasigned_v1.zip", "v3"}),
+ std::vector<std::string>({"otasigned_v2.zip", "v4"}),
+ std::vector<std::string>({"otasigned_v3.zip", "v1"}),
+ std::vector<std::string>({"otasigned_v4.zip", "v2"})));
INSTANTIATE_TEST_CASE_P(BadPackage, VerifierFailureTest,
- ::testing::Values(
- std::vector<std::string>({"random.zip", "v1"}),
- std::vector<std::string>({"fake-eocd.zip", "v1"}),
- std::vector<std::string>({"alter-metadata.zip", "v1"}),
- std::vector<std::string>({"alter-footer.zip", "v1"}),
- std::vector<std::string>({"signature-boundary.zip", "v1"})));
+ ::testing::Values(
+ std::vector<std::string>({"random.zip", "v1"}),
+ std::vector<std::string>({"fake-eocd.zip", "v1"}),
+ std::vector<std::string>({"alter-metadata.zip", "v1"}),
+ std::vector<std::string>({"alter-footer.zip", "v1"}),
+ std::vector<std::string>({"signature-boundary.zip", "v1"})));