| /* |
| * Copyright (C) 2016 The Android Open Source Project |
| * |
| * Permission is hereby granted, free of charge, to any person |
| * obtaining a copy of this software and associated documentation |
| * files (the "Software"), to deal in the Software without |
| * restriction, including without limitation the rights to use, copy, |
| * modify, merge, publish, distribute, sublicense, and/or sell copies |
| * of the Software, and to permit persons to whom the Software is |
| * furnished to do so, subject to the following conditions: |
| * |
| * The above copyright notice and this permission notice shall be |
| * included in all copies or substantial portions of the Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
| * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
| * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS |
| * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN |
| * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
| * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
| * SOFTWARE. |
| */ |
| |
| #include <string.h> |
| |
| #include <gtest/gtest.h> |
| |
| #include "libavb.h" |
| |
| TEST(UtilTest, RSAPublicKeyHeaderByteswap) { |
| AvbRSAPublicKeyHeader h; |
| AvbRSAPublicKeyHeader s; |
| uint32_t n32; |
| uint64_t n64; |
| |
| n32 = 0x11223344; |
| n64 = 0x1122334455667788; |
| |
| h.key_num_bits = htobe32(n32); |
| n32++; |
| h.n0inv = htobe32(n32); |
| n32++; |
| |
| EXPECT_NE(0, avb_rsa_public_key_header_validate_and_byteswap(&h, &s)); |
| |
| n32 = 0x11223344; |
| n64 = 0x1122334455667788; |
| |
| EXPECT_EQ(n32, s.key_num_bits); |
| n32++; |
| EXPECT_EQ(n32, s.n0inv); |
| n32++; |
| } |
| |
| TEST(UtilTest, FooterByteswap) { |
| AvbFooter h; |
| AvbFooter s; |
| AvbFooter other; |
| AvbFooter bad; |
| uint64_t n64; |
| |
| n64 = 0x1122334455667788; |
| |
| memcpy(h.magic, AVB_FOOTER_MAGIC, AVB_FOOTER_MAGIC_LEN); |
| h.version_major = htobe32(AVB_FOOTER_MAJOR_VERSION); |
| h.version_minor = htobe32(AVB_FOOTER_MINOR_VERSION); |
| h.original_image_size = htobe64(n64); |
| n64++; |
| h.vbmeta_offset = htobe64(n64); |
| n64++; |
| h.vbmeta_size = htobe64(n64); |
| n64++; |
| |
| EXPECT_NE(0, avb_footer_validate_and_byteswap(&h, &s)); |
| |
| n64 = 0x1122334455667788; |
| |
| EXPECT_EQ((uint32_t)AVB_FOOTER_MAJOR_VERSION, s.version_major); |
| EXPECT_EQ((uint32_t)AVB_FOOTER_MINOR_VERSION, s.version_minor); |
| EXPECT_EQ(n64, s.original_image_size); |
| n64++; |
| EXPECT_EQ(n64, s.vbmeta_offset); |
| n64++; |
| EXPECT_EQ(n64, s.vbmeta_size); |
| n64++; |
| |
| // Check that the struct still validates if minor is bigger than |
| // what we expect. |
| other = h; |
| h.version_minor = htobe32(AVB_FOOTER_MINOR_VERSION + 1); |
| EXPECT_NE(0, avb_footer_validate_and_byteswap(&other, &s)); |
| |
| // Check for bad magic. |
| bad = h; |
| bad.magic[0] = 'x'; |
| EXPECT_EQ(0, avb_footer_validate_and_byteswap(&bad, &s)); |
| |
| // Check for bad major version. |
| bad = h; |
| bad.version_major = htobe32(AVB_FOOTER_MAJOR_VERSION + 1); |
| EXPECT_EQ(0, avb_footer_validate_and_byteswap(&bad, &s)); |
| } |
| |
| TEST(UtilTest, KernelCmdlineDescriptorByteswap) { |
| AvbKernelCmdlineDescriptor h; |
| AvbKernelCmdlineDescriptor s; |
| AvbKernelCmdlineDescriptor bad; |
| uint64_t nbf; |
| |
| // Specify 44 bytes of data past the end of the descriptor struct. |
| nbf = 44 + sizeof(AvbKernelCmdlineDescriptor) - sizeof(AvbDescriptor); |
| h.parent_descriptor.num_bytes_following = htobe64(nbf); |
| h.parent_descriptor.tag = htobe64(AVB_DESCRIPTOR_TAG_KERNEL_CMDLINE); |
| h.kernel_cmdline_length = htobe32(44); |
| |
| EXPECT_NE(0, avb_kernel_cmdline_descriptor_validate_and_byteswap(&h, &s)); |
| |
| EXPECT_EQ(AVB_DESCRIPTOR_TAG_KERNEL_CMDLINE, s.parent_descriptor.tag); |
| EXPECT_EQ(nbf, s.parent_descriptor.num_bytes_following); |
| EXPECT_EQ(44UL, s.kernel_cmdline_length); |
| |
| // Check for bad tag. |
| bad = h; |
| bad.parent_descriptor.tag = htobe64(0xf00dd00d); |
| EXPECT_EQ(0, avb_kernel_cmdline_descriptor_validate_and_byteswap(&bad, &s)); |
| |
| // Doesn't fit in 45 bytes. |
| bad = h; |
| bad.kernel_cmdline_length = htobe32(45); |
| EXPECT_EQ(0, avb_kernel_cmdline_descriptor_validate_and_byteswap(&bad, &s)); |
| } |
| |
| TEST(UtilTest, HashtreeDescriptorByteswap) { |
| AvbHashtreeDescriptor h; |
| AvbHashtreeDescriptor s; |
| AvbHashtreeDescriptor bad; |
| uint64_t nbf; |
| uint32_t n32; |
| uint64_t n64; |
| |
| // Specify 40 bytes of data past the end of the descriptor struct. |
| nbf = 40 + sizeof(AvbHashtreeDescriptor) - sizeof(AvbDescriptor); |
| h.parent_descriptor.num_bytes_following = htobe64(nbf); |
| h.parent_descriptor.tag = htobe64(AVB_DESCRIPTOR_TAG_HASHTREE); |
| h.partition_name_len = htobe32(10); |
| h.salt_len = htobe32(10); |
| h.root_digest_len = htobe32(10); |
| |
| n32 = 0x11223344; |
| n64 = 0x1122334455667788; |
| |
| h.dm_verity_version = htobe32(n32); |
| n32++; |
| h.image_size = htobe64(n64); |
| n64++; |
| h.tree_offset = htobe64(n64); |
| n64++; |
| h.tree_size = htobe64(n64); |
| n64++; |
| h.data_block_size = htobe32(n32); |
| n32++; |
| h.hash_block_size = htobe32(n32); |
| n32++; |
| |
| EXPECT_NE(0, avb_hashtree_descriptor_validate_and_byteswap(&h, &s)); |
| |
| n32 = 0x11223344; |
| n64 = 0x1122334455667788; |
| |
| EXPECT_EQ(n32, s.dm_verity_version); |
| n32++; |
| EXPECT_EQ(n64, s.image_size); |
| n64++; |
| EXPECT_EQ(n64, s.tree_offset); |
| n64++; |
| EXPECT_EQ(n64, s.tree_size); |
| n64++; |
| EXPECT_EQ(n32, s.data_block_size); |
| n32++; |
| EXPECT_EQ(n32, s.hash_block_size); |
| n32++; |
| |
| EXPECT_EQ(AVB_DESCRIPTOR_TAG_HASHTREE, s.parent_descriptor.tag); |
| EXPECT_EQ(nbf, s.parent_descriptor.num_bytes_following); |
| EXPECT_EQ(10UL, s.partition_name_len); |
| EXPECT_EQ(10UL, s.salt_len); |
| EXPECT_EQ(10UL, s.root_digest_len); |
| |
| // Check for bad tag. |
| bad = h; |
| bad.parent_descriptor.tag = htobe64(0xf00dd00d); |
| EXPECT_EQ(0, avb_hashtree_descriptor_validate_and_byteswap(&bad, &s)); |
| |
| // Doesn't fit in 40 bytes (30 + 10 + 10 = 50). |
| bad = h; |
| bad.partition_name_len = htobe32(30); |
| EXPECT_EQ(0, avb_hashtree_descriptor_validate_and_byteswap(&bad, &s)); |
| |
| // Doesn't fit in 40 bytes (10 + 30 + 10 = 50). |
| bad = h; |
| bad.salt_len = htobe32(30); |
| EXPECT_EQ(0, avb_hashtree_descriptor_validate_and_byteswap(&bad, &s)); |
| |
| // Doesn't fit in 40 bytes (10 + 10 + 30 = 50). |
| bad = h; |
| bad.root_digest_len = htobe32(30); |
| EXPECT_EQ(0, avb_hashtree_descriptor_validate_and_byteswap(&bad, &s)); |
| } |
| |
| TEST(UtilTest, HashDescriptorByteswap) { |
| AvbHashDescriptor h; |
| AvbHashDescriptor s; |
| AvbHashDescriptor bad; |
| uint64_t nbf; |
| |
| // Specify 44 bytes of data past the end of the descriptor struct. |
| nbf = 44 + sizeof(AvbHashDescriptor) - sizeof(AvbDescriptor); |
| h.parent_descriptor.num_bytes_following = htobe64(nbf); |
| h.parent_descriptor.tag = htobe64(AVB_DESCRIPTOR_TAG_HASH); |
| h.partition_name_len = htobe32(10); |
| h.salt_len = htobe32(10); |
| h.digest_len = htobe32(10); |
| |
| EXPECT_NE(0, avb_hash_descriptor_validate_and_byteswap(&h, &s)); |
| |
| EXPECT_EQ(AVB_DESCRIPTOR_TAG_HASH, s.parent_descriptor.tag); |
| EXPECT_EQ(nbf, s.parent_descriptor.num_bytes_following); |
| EXPECT_EQ(10UL, s.partition_name_len); |
| EXPECT_EQ(10UL, s.salt_len); |
| EXPECT_EQ(10UL, s.digest_len); |
| |
| // Check for bad tag. |
| bad = h; |
| bad.parent_descriptor.tag = htobe64(0xf00dd00d); |
| EXPECT_EQ(0, avb_hash_descriptor_validate_and_byteswap(&bad, &s)); |
| |
| // Doesn't fit in 44 bytes (30 + 10 + 10 = 50). |
| bad = h; |
| bad.partition_name_len = htobe32(30); |
| EXPECT_EQ(0, avb_hash_descriptor_validate_and_byteswap(&bad, &s)); |
| |
| // Doesn't fit in 44 bytes (10 + 30 + 10 = 50). |
| bad = h; |
| bad.salt_len = htobe32(30); |
| EXPECT_EQ(0, avb_hash_descriptor_validate_and_byteswap(&bad, &s)); |
| |
| // Doesn't fit in 44 bytes (10 + 10 + 30 = 50). |
| bad = h; |
| bad.digest_len = htobe32(30); |
| EXPECT_EQ(0, avb_hash_descriptor_validate_and_byteswap(&bad, &s)); |
| } |
| |
| TEST(UtilTest, ChainPartitionDescriptorByteswap) { |
| AvbChainPartitionDescriptor h; |
| AvbChainPartitionDescriptor s; |
| AvbChainPartitionDescriptor bad; |
| uint64_t nbf; |
| |
| // Specify 36 bytes of data past the end of the descriptor struct. |
| nbf = 36 + sizeof(AvbChainPartitionDescriptor) - sizeof(AvbDescriptor); |
| h.parent_descriptor.num_bytes_following = htobe64(nbf); |
| h.parent_descriptor.tag = htobe64(AVB_DESCRIPTOR_TAG_CHAIN_PARTITION); |
| h.rollback_index_slot = htobe32(42); |
| h.partition_name_len = htobe32(16); |
| h.public_key_len = htobe32(17); |
| |
| EXPECT_NE(0, avb_chain_partition_descriptor_validate_and_byteswap(&h, &s)); |
| |
| EXPECT_EQ(AVB_DESCRIPTOR_TAG_CHAIN_PARTITION, s.parent_descriptor.tag); |
| EXPECT_EQ(nbf, s.parent_descriptor.num_bytes_following); |
| EXPECT_EQ(42UL, s.rollback_index_slot); |
| EXPECT_EQ(16UL, s.partition_name_len); |
| EXPECT_EQ(17UL, s.public_key_len); |
| |
| // Check for bad tag. |
| bad = h; |
| bad.parent_descriptor.tag = htobe64(0xf00dd00d); |
| EXPECT_EQ(0, avb_chain_partition_descriptor_validate_and_byteswap(&bad, &s)); |
| |
| // Check for bad rollback index slot (must be at least 1). |
| bad = h; |
| bad.rollback_index_slot = htobe32(0); |
| EXPECT_EQ(0, avb_chain_partition_descriptor_validate_and_byteswap(&bad, &s)); |
| |
| // Doesn't fit in 40 bytes (24 + 17 = 41). |
| bad = h; |
| bad.partition_name_len = htobe32(24); |
| EXPECT_EQ(0, avb_chain_partition_descriptor_validate_and_byteswap(&bad, &s)); |
| |
| // Doesn't fit in 40 bytes (16 + 25 = 41). |
| bad = h; |
| bad.public_key_len = htobe32(25); |
| EXPECT_EQ(0, avb_chain_partition_descriptor_validate_and_byteswap(&bad, &s)); |
| } |
| |
| TEST(UtilTest, PropertyDescriptorByteswap) { |
| AvbPropertyDescriptor h; |
| AvbPropertyDescriptor s; |
| AvbPropertyDescriptor bad; |
| uint64_t nbf; |
| |
| // Specify 40 bytes of data past the end of the descriptor struct. |
| nbf = 40 + sizeof(AvbPropertyDescriptor) - sizeof(AvbDescriptor); |
| h.parent_descriptor.num_bytes_following = htobe64(nbf); |
| h.parent_descriptor.tag = htobe64(AVB_DESCRIPTOR_TAG_PROPERTY); |
| h.key_num_bytes = htobe64(16); |
| h.value_num_bytes = htobe64(17); |
| |
| EXPECT_NE(0, avb_property_descriptor_validate_and_byteswap(&h, &s)); |
| |
| EXPECT_EQ(AVB_DESCRIPTOR_TAG_PROPERTY, s.parent_descriptor.tag); |
| EXPECT_EQ(nbf, s.parent_descriptor.num_bytes_following); |
| EXPECT_EQ(16UL, s.key_num_bytes); |
| EXPECT_EQ(17UL, s.value_num_bytes); |
| |
| // Check for bad tag. |
| bad = h; |
| bad.parent_descriptor.tag = htobe64(0xf00dd00d); |
| EXPECT_EQ(0, avb_property_descriptor_validate_and_byteswap(&bad, &s)); |
| |
| // Doesn't fit in 40 bytes (22 + 17 + 2 = 41). |
| bad = h; |
| bad.key_num_bytes = htobe64(22); |
| EXPECT_EQ(0, avb_property_descriptor_validate_and_byteswap(&bad, &s)); |
| |
| // Doesn't fit in 40 bytes (16 + 23 + 2 = 41). |
| bad = h; |
| bad.value_num_bytes = htobe64(23); |
| EXPECT_EQ(0, avb_property_descriptor_validate_and_byteswap(&bad, &s)); |
| } |
| |
| TEST(UtilTest, DescriptorByteswap) { |
| AvbDescriptor h; |
| AvbDescriptor s; |
| uint64_t n64; |
| |
| n64 = 0x1122334455667788; |
| |
| h.num_bytes_following = htobe64(n64); |
| n64++; |
| h.tag = htobe64(n64); |
| n64++; |
| |
| EXPECT_NE(0, avb_descriptor_validate_and_byteswap(&h, &s)); |
| |
| n64 = 0x1122334455667788; |
| |
| EXPECT_EQ(n64, s.num_bytes_following); |
| n64++; |
| EXPECT_EQ(n64, s.tag); |
| n64++; |
| |
| // Check that we catch if |num_bytes_following| isn't divisble by 8. |
| h.num_bytes_following = htobe64(7); |
| EXPECT_EQ(0, avb_descriptor_validate_and_byteswap(&h, &s)); |
| } |
| |
| TEST(UtilTest, SafeAddition) { |
| uint64_t value; |
| uint64_t pow2_60 = 1ULL << 60; |
| |
| value = 2; |
| EXPECT_NE(0, avb_safe_add_to(&value, 5)); |
| EXPECT_EQ(7UL, value); |
| |
| /* These should not overflow */ |
| value = 1 * pow2_60; |
| EXPECT_NE(0, avb_safe_add_to(&value, 2 * pow2_60)); |
| EXPECT_EQ(3 * pow2_60, value); |
| value = 7 * pow2_60; |
| EXPECT_NE(0, avb_safe_add_to(&value, 8 * pow2_60)); |
| EXPECT_EQ(15 * pow2_60, value); |
| value = 9 * pow2_60; |
| EXPECT_NE(0, avb_safe_add_to(&value, 3 * pow2_60)); |
| EXPECT_EQ(12 * pow2_60, value); |
| value = 0xfffffffffffffffcUL; |
| EXPECT_NE(0, avb_safe_add_to(&value, 2)); |
| EXPECT_EQ(0xfffffffffffffffeUL, value); |
| |
| /* These should overflow. */ |
| value = 8 * pow2_60; |
| EXPECT_EQ(0, avb_safe_add_to(&value, 8 * pow2_60)); |
| value = 0xfffffffffffffffcUL; |
| EXPECT_EQ(0, avb_safe_add_to(&value, 4)); |
| } |
| |
| static int avb_validate_utf8z(const char* data) { |
| return avb_validate_utf8(reinterpret_cast<const uint8_t*>(data), |
| strlen(data)); |
| } |
| |
| TEST(UtilTest, UTF8Validation) { |
| // These should succeed. |
| EXPECT_NE(0, avb_validate_utf8z("foo bar")); |
| // Encoding of U+00E6 LATIN SMALL LETTER AE: æ |
| EXPECT_NE(0, avb_validate_utf8z("foo \xC3\xA6 bar")); |
| // Encoding of U+20AC EURO SIGN: € |
| EXPECT_NE(0, avb_validate_utf8z("foo \xE2\x82\xAC bar")); |
| // Encoding of U+1F466 BOY: 👦 |
| EXPECT_NE(0, avb_validate_utf8z("foo \xF0\x9F\x91\xA6 bar")); |
| // All three runes following each other. |
| EXPECT_NE(0, avb_validate_utf8z("\xC3\xA6\xE2\x82\xAC\xF0\x9F\x91\xA6")); |
| |
| // These should fail. |
| EXPECT_EQ(0, avb_validate_utf8z("foo \xF8 bar")); |
| EXPECT_EQ(0, avb_validate_utf8z("\xF8")); |
| // Stops in the middle of Unicode rune. |
| EXPECT_EQ(0, avb_validate_utf8z("foo \xC3")); |
| } |
| |
| TEST(UtilTest, StrConcat) { |
| char buf[8]; |
| |
| // These should succeed. |
| EXPECT_NE(0, avb_str_concat(buf, sizeof buf, "foo", 3, "bar1", 4)); |
| |
| // This should fail: Insufficient space. |
| EXPECT_EQ(0, avb_str_concat(buf, sizeof buf, "foo0", 4, "bar1", 4)); |
| } |
| |
| TEST(UtilTest, StrStr) { |
| const char* haystack = "abc def abcabc"; |
| |
| EXPECT_EQ(nullptr, avb_strstr(haystack, "needle")); |
| EXPECT_EQ(haystack, avb_strstr(haystack, "abc")); |
| EXPECT_EQ(haystack + 4, avb_strstr(haystack, "def")); |
| EXPECT_EQ(haystack, avb_strstr(haystack, haystack)); |
| } |
| |
| TEST(UtilTest, StrReplace) { |
| // We don't care about leaking strings from avb_replace(). |
| EXPECT_EQ("OK blah bah $(FOO OK blah", |
| std::string(avb_replace("$(FOO) blah bah $(FOO $(FOO) blah", |
| "$(FOO)", "OK"))); |
| EXPECT_EQ("OK", std::string(avb_replace("$(FOO)", "$(FOO)", "OK"))); |
| EXPECT_EQ(" OK", std::string(avb_replace(" $(FOO)", "$(FOO)", "OK"))); |
| EXPECT_EQ("OK ", std::string(avb_replace("$(FOO) ", "$(FOO)", "OK"))); |
| EXPECT_EQ("LONGSTRINGLONGSTRING", |
| std::string(avb_replace("$(FOO)$(FOO)", "$(FOO)", "LONGSTRING"))); |
| } |
| |
| TEST(UtilTest, Crc32) { |
| /* Compare with output of crc32(1): |
| * |
| * $ (echo -n foobar > /tmp/crc32_input); crc32 /tmp/crc32_input |
| * 9ef61f95 |
| */ |
| EXPECT_EQ(uint32_t(0x9ef61f95), avb_crc32((const uint8_t*)"foobar", 6)); |
| } |
| |
| TEST(UtilTest, htobe32) { |
| EXPECT_EQ(avb_htobe32(0x12345678), htobe32(0x12345678)); |
| } |
| |
| TEST(UtilTest, be32toh) { |
| EXPECT_EQ(avb_be32toh(0x12345678), be32toh(0x12345678)); |
| } |
| |
| TEST(UtilTest, htobe64) { |
| EXPECT_EQ(avb_htobe64(0x123456789abcdef0), htobe64(0x123456789abcdef0)); |
| } |
| |
| TEST(UtilTest, be64toh) { |
| EXPECT_EQ(avb_be64toh(0x123456789abcdef0), be64toh(0x123456789abcdef0)); |
| } |