Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b2d7f534 authored by Winson's avatar Winson
Browse files

Signature policy for overlayable items

Add encoding/decoding of new policy for overlays. Signature enforces
that an overlay package is signed with the same key as the actor of
the target resource, so that an overlay can be installed by the user
as a normal app but restricted to those built by the author of the
actor (which can be the same as the target).

This also enforces that a valid policy is specified.

This doesn't implement the actors nor the signature check.

Bug: 119402606

Test: ResourceParserTest ParseOverlayablePolicy
Test: ProtoSerializerTest SerializeAndDeserializeOverlayable
Test: aapt2_tests

Change-Id: I8495ad790c2ebd51759bc6eba81149680c209475
parent c20de154
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -1647,6 +1647,10 @@ struct ResTable_overlayable_policy_header
    // The overlay must reside of the product partition or must have existed on the product
    // partition before an upgrade to overlay these resources.
    POLICY_PRODUCT_PARTITION = 0x00000008,

    // The overlay must be signed with the same signature as the actor of the target resource,
    // which can be separate or the same as the target package with the resource.
    POLICY_SIGNATURE = 0x00000010,
  };
  uint32_t policy_flags;

+14 −0
Original line number Diff line number Diff line
@@ -1113,6 +1113,13 @@ bool ResourceParser::ParseOverlayable(xml::XmlPullParser* parser, ParsedResource
    const std::string& element_name = parser->element_name();
    const std::string& element_namespace = parser->element_namespace();
    if (element_namespace.empty() && element_name == "item") {
      if (current_policies == OverlayableItem::Policy::kNone) {
        diag_->Error(DiagMessage(element_source)
                         << "<item> within an <overlayable> must be inside a <policy> block");
        error = true;
        continue;
      }

      // Items specify the name and type of resource that should be overlayable
      Maybe<StringPiece> item_name = xml::FindNonEmptyAttribute(parser, "name");
      if (!item_name) {
@@ -1169,6 +1176,8 @@ bool ResourceParser::ParseOverlayable(xml::XmlPullParser* parser, ParsedResource
            current_policies |= OverlayableItem::Policy::kSystem;
          } else if (trimmed_part == "vendor") {
            current_policies |= OverlayableItem::Policy::kVendor;
          } else if (trimmed_part == "signature") {
            current_policies |= OverlayableItem::Policy::kSignature;
          } else {
            diag_->Error(DiagMessage(element_source)
                         << "<policy> has unsupported type '" << trimmed_part << "'");
@@ -1176,6 +1185,11 @@ bool ResourceParser::ParseOverlayable(xml::XmlPullParser* parser, ParsedResource
            continue;
          }
        }
      } else {
        diag_->Error(DiagMessage(element_source)
                         << "<policy> must have a 'type' attribute");
        error = true;
        continue;
      }
    } else if (!ShouldIgnoreElement(element_namespace, element_name)) {
      diag_->Error(DiagMessage(element_source) << "invalid element <" << element_name << "> "
+34 −14
Original line number Diff line number Diff line
@@ -894,8 +894,10 @@ TEST_F(ResourceParserTest, ParsePlatformIndependentNewline) {
TEST_F(ResourceParserTest, ParseOverlayable) {
  std::string input = R"(
      <overlayable name="Name" actor="overlay://theme">
          <policy type="signature">
            <item type="string" name="foo" />
            <item type="drawable" name="bar" />
          </policy>
      </overlayable>)";
  ASSERT_TRUE(TestParse(input));

@@ -906,7 +908,7 @@ TEST_F(ResourceParserTest, ParseOverlayable) {
  OverlayableItem& result_overlayable_item = search_result.value().entry->overlayable_item.value();
  EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name"));
  EXPECT_THAT(result_overlayable_item.overlayable->actor, Eq("overlay://theme"));
  EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kNone));
  EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kSignature));

  search_result = table_.FindResource(test::ParseNameOrDie("drawable/bar"));
  ASSERT_TRUE(search_result);
@@ -915,7 +917,7 @@ TEST_F(ResourceParserTest, ParseOverlayable) {
  result_overlayable_item = search_result.value().entry->overlayable_item.value();
  EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name"));
  EXPECT_THAT(result_overlayable_item.overlayable->actor, Eq("overlay://theme"));
  EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kNone));
  EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kSignature));
}

TEST_F(ResourceParserTest, ParseOverlayableRequiresName) {
@@ -931,7 +933,6 @@ TEST_F(ResourceParserTest, ParseOverlayableBadActorFail) {
TEST_F(ResourceParserTest, ParseOverlayablePolicy) {
  std::string input = R"(
      <overlayable name="Name">
        <item type="string" name="foo" />
        <policy type="product">
          <item type="string" name="bar" />
        </policy>
@@ -944,23 +945,18 @@ TEST_F(ResourceParserTest, ParseOverlayablePolicy) {
        <policy type="public">
          <item type="string" name="faz" />
        </policy>
        <policy type="signature">
          <item type="string" name="foz" />
        </policy>
      </overlayable>)";
  ASSERT_TRUE(TestParse(input));

  auto search_result = table_.FindResource(test::ParseNameOrDie("string/foo"));
  auto search_result = table_.FindResource(test::ParseNameOrDie("string/bar"));
  ASSERT_TRUE(search_result);
  ASSERT_THAT(search_result.value().entry, NotNull());
  ASSERT_TRUE(search_result.value().entry->overlayable_item);
  OverlayableItem result_overlayable_item = search_result.value().entry->overlayable_item.value();
  EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name"));
  EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kNone));

  search_result = table_.FindResource(test::ParseNameOrDie("string/bar"));
  ASSERT_TRUE(search_result);
  ASSERT_THAT(search_result.value().entry, NotNull());
  ASSERT_TRUE(search_result.value().entry->overlayable_item);
  result_overlayable_item = search_result.value().entry->overlayable_item.value();
  EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name"));
  EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kProduct));

  search_result = table_.FindResource(test::ParseNameOrDie("string/fiz"));
@@ -986,6 +982,30 @@ TEST_F(ResourceParserTest, ParseOverlayablePolicy) {
  result_overlayable_item = search_result.value().entry->overlayable_item.value();
  EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name"));
  EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kPublic));

  search_result = table_.FindResource(test::ParseNameOrDie("string/foz"));
  ASSERT_TRUE(search_result);
  ASSERT_THAT(search_result.value().entry, NotNull());
  ASSERT_TRUE(search_result.value().entry->overlayable_item);
  result_overlayable_item = search_result.value().entry->overlayable_item.value();
  EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name"));
  EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kSignature));
}

TEST_F(ResourceParserTest, ParseOverlayableNoPolicyError) {
  std::string input = R"(
      <overlayable name="Name">
        <item type="string" name="foo" />
      </overlayable>)";
  EXPECT_FALSE(TestParse(input));

  input = R"(
      <overlayable name="Name">
        <policy>
          <item name="foo" />
        </policy>
      </overlayable>)";
  EXPECT_FALSE(TestParse(input));
}

TEST_F(ResourceParserTest, ParseOverlayableBadPolicyError) {
+3 −0
Original line number Diff line number Diff line
@@ -92,6 +92,9 @@ struct OverlayableItem {

    // The resource can be overlaid by any overlay on the product partition.
    kProduct = 0x08,

    // The resource can be overlaid by any overlay signed with the same signature as its actor.
    kSignature = 0x010,
  };

  std::shared_ptr<Overlayable> overlayable;
+2 −2
Original line number Diff line number Diff line
@@ -138,10 +138,10 @@ message AllowNew {

// Represents a set of overlayable resources.
message Overlayable {
  // The name of the <overlyabale>.
  // The name of the <overlayable>.
  string name = 1;

  // The location of the <overlyabale> declaration in the source.
  // The location of the <overlayable> declaration in the source.
  Source source = 2;

  // The component responsible for enabling and disabling overlays targeting this <overlayable>.
Loading