From 0f942f99cac4f5f61b40847d20ecb3a94c96c843 Mon Sep 17 00:00:00 2001 From: Zoran Jovanovic Date: Tue, 9 Jun 2020 18:51:57 +0200 Subject: [PATCH] OMS: Add config_signature policy handling Alongside SIGNATURE and ACTOR_SIGNATURE policies, add CONFIG_SIGNATURE policy to overlayable that overlay fulfills if it is signed with the same certificate as the reference package whose package name is declared in 'config-signature' tag of SystemConfig and is vetted by OMS that it's a system pre-installed package. BUG: 158726924 TEST: regular aapt2, idmap2, OMS tests Merged-In: I645ee72271496008742886274be0d63a2985201b Change-Id: I645ee72271496008742886274be0d63a2985201b --- .../aidl/android/os/OverlayablePolicy.aidl | 1 + cmds/idmap2/libidmap2/ResourceMapping.cpp | 7 +- .../include/idmap2/Policies.h | 4 +- cmds/idmap2/tests/R.h | 38 ++++---- cmds/idmap2/tests/ResourceMappingTests.cpp | 18 +++- cmds/idmap2/tests/TestConstants.h | 8 +- .../data/overlay/overlay-no-name-static.apk | Bin 3477 -> 3485 bytes .../tests/data/overlay/overlay-no-name.apk | Bin 3389 -> 3393 bytes .../tests/data/overlay/overlay-shared.apk | Bin 3757 -> 3757 bytes .../tests/data/overlay/overlay-static-1.apk | Bin 3469 -> 3477 bytes .../tests/data/overlay/overlay-static-2.apk | Bin 3469 -> 3477 bytes cmds/idmap2/tests/data/overlay/overlay.apk | Bin 3489 -> 3489 bytes .../signature-overlay/signature-overlay.apk | Bin 1315 -> 1299 bytes .../res/values/values.xml | 1 + .../system-overlay-invalid.apk | Bin 1827 -> 1907 bytes .../data/system-overlay/system-overlay.apk | Bin 1319 -> 1387 bytes .../data/target/res/values/overlayable.xml | 4 + .../tests/data/target/res/values/values.xml | 1 + .../data/target/target-no-overlayable.apk | Bin 2311 -> 2391 bytes cmds/idmap2/tests/data/target/target.apk | Bin 5097 -> 5201 bytes .../java/com/android/server/SystemConfig.java | 36 +++++++ .../include/androidfw/ResourceTypes.h | 4 + .../content/pm/PackageManagerInternal.java | 1 + .../com/android/server/om/IdmapManager.java | 34 +++++-- .../server/om/OverlayActorEnforcer.java | 20 ++-- .../server/om/OverlayManagerService.java | 11 ++- .../server/om/OverlayableInfoCallback.java | 83 ----------------- .../server/om/PackageManagerHelper.java | 68 +++++++++++++- .../server/pm/PackageManagerService.java | 67 +++++++------ .../server/pm/PackageManagerServiceUtils.java | 12 +++ .../server/om/OverlayActorEnforcerTests.kt | 10 +- .../OverlayManagerServiceImplRebootTests.java | 10 +- .../om/OverlayManagerServiceImplTests.java | 88 ++++++++++++++++++ .../OverlayManagerServiceImplTestsBase.java | 53 +++++++++-- tools/aapt2/Resources.proto | 1 + .../format/binary/TableFlattener_test.cpp | 4 +- tools/aapt2/format/proto/ProtoDeserialize.cpp | 3 + tools/aapt2/format/proto/ProtoSerialize.cpp | 3 + 38 files changed, 415 insertions(+), 175 deletions(-) delete mode 100644 services/core/java/com/android/server/om/OverlayableInfoCallback.java diff --git a/cmds/idmap2/idmap2d/aidl/android/os/OverlayablePolicy.aidl b/cmds/idmap2/idmap2d/aidl/android/os/OverlayablePolicy.aidl index 02b27a8800b61..403d8c55de164 100644 --- a/cmds/idmap2/idmap2d/aidl/android/os/OverlayablePolicy.aidl +++ b/cmds/idmap2/idmap2d/aidl/android/os/OverlayablePolicy.aidl @@ -29,4 +29,5 @@ interface OverlayablePolicy { const int ODM_PARTITION = 0x00000020; const int OEM_PARTITION = 0x00000040; const int ACTOR_SIGNATURE = 0x00000080; + const int CONFIG_SIGNATURE = 0x0000100; } diff --git a/cmds/idmap2/libidmap2/ResourceMapping.cpp b/cmds/idmap2/libidmap2/ResourceMapping.cpp index 34589a1c39dcc..fd8b4eb86b4a4 100644 --- a/cmds/idmap2/libidmap2/ResourceMapping.cpp +++ b/cmds/idmap2/libidmap2/ResourceMapping.cpp @@ -61,10 +61,13 @@ Result CheckOverlayable(const LoadedPackage& target_package, const ResourceId& target_resource) { static constexpr const PolicyBitmask sDefaultPolicies = PolicyFlags::ODM_PARTITION | PolicyFlags::OEM_PARTITION | PolicyFlags::SYSTEM_PARTITION | - PolicyFlags::VENDOR_PARTITION | PolicyFlags::PRODUCT_PARTITION | PolicyFlags::SIGNATURE; + PolicyFlags::VENDOR_PARTITION | PolicyFlags::PRODUCT_PARTITION | PolicyFlags::SIGNATURE | + PolicyFlags::CONFIG_SIGNATURE; // If the resource does not have an overlayable definition, allow the resource to be overlaid if - // the overlay is preinstalled or signed with the same signature as the target. + // the overlay is preinstalled, signed with the same signature as the target or signed with the + // same signature as reference package defined in SystemConfig under 'overlay-config-signature' + // tag. if (!target_package.DefinesOverlayable()) { return (sDefaultPolicies & fulfilled_policies) != 0 ? Result({}) diff --git a/cmds/idmap2/libidmap2_policies/include/idmap2/Policies.h b/cmds/idmap2/libidmap2_policies/include/idmap2/Policies.h index 5bd353af4ad3b..8046319824908 100644 --- a/cmds/idmap2/libidmap2_policies/include/idmap2/Policies.h +++ b/cmds/idmap2/libidmap2_policies/include/idmap2/Policies.h @@ -37,16 +37,18 @@ constexpr const char* kPolicyOdm = "odm"; constexpr const char* kPolicyOem = "oem"; constexpr const char* kPolicyProduct = "product"; constexpr const char* kPolicyPublic = "public"; +constexpr const char* kPolicyConfigSignature = "config_signature"; constexpr const char* kPolicySignature = "signature"; constexpr const char* kPolicySystem = "system"; constexpr const char* kPolicyVendor = "vendor"; -inline static const std::array, 8> kPolicyStringToFlag = { +inline static const std::array, 9> kPolicyStringToFlag = { std::pair{kPolicyActor, PolicyFlags::ACTOR_SIGNATURE}, {kPolicyOdm, PolicyFlags::ODM_PARTITION}, {kPolicyOem, PolicyFlags::OEM_PARTITION}, {kPolicyProduct, PolicyFlags::PRODUCT_PARTITION}, {kPolicyPublic, PolicyFlags::PUBLIC}, + {kPolicyConfigSignature, PolicyFlags::CONFIG_SIGNATURE}, {kPolicySignature, PolicyFlags::SIGNATURE}, {kPolicySystem, PolicyFlags::SYSTEM_PARTITION}, {kPolicyVendor, PolicyFlags::VENDOR_PARTITION}, diff --git a/cmds/idmap2/tests/R.h b/cmds/idmap2/tests/R.h index aed263a49aa3d..89b43466ba5e6 100644 --- a/cmds/idmap2/tests/R.h +++ b/cmds/idmap2/tests/R.h @@ -41,16 +41,17 @@ namespace R::target { constexpr ResourceId not_overlayable = 0x7f020003; constexpr ResourceId other = 0x7f020004; constexpr ResourceId policy_actor = 0x7f020005; - constexpr ResourceId policy_odm = 0x7f020006; - constexpr ResourceId policy_oem = 0x7f020007; - constexpr ResourceId policy_product = 0x7f020008; - constexpr ResourceId policy_public = 0x7f020009; - constexpr ResourceId policy_signature = 0x7f02000a; - constexpr ResourceId policy_system = 0x7f02000b; - constexpr ResourceId policy_system_vendor = 0x7f02000c; - constexpr ResourceId str1 = 0x7f02000d; - constexpr ResourceId str3 = 0x7f02000f; - constexpr ResourceId str4 = 0x7f020010; + constexpr ResourceId policy_config_signature = 0x7f020006; + constexpr ResourceId policy_odm = 0x7f020007; + constexpr ResourceId policy_oem = 0x7f020008; + constexpr ResourceId policy_product = 0x7f020009; + constexpr ResourceId policy_public = 0x7f02000a; + constexpr ResourceId policy_signature = 0x7f02000b; + constexpr ResourceId policy_system = 0x7f02000c; + constexpr ResourceId policy_system_vendor = 0x7f02000d; + constexpr ResourceId str1 = 0x7f02000e; + constexpr ResourceId str3 = 0x7f020010; + constexpr ResourceId str4 = 0x7f020011; namespace literal { inline const std::string str1 = hexify(R::target::string::str1); @@ -92,14 +93,15 @@ namespace R::system_overlay_invalid::string { constexpr ResourceId not_overlayable = 0x7f010000; constexpr ResourceId other = 0x7f010001; constexpr ResourceId policy_actor = 0x7f010002; - constexpr ResourceId policy_odm = 0x7f010003; - constexpr ResourceId policy_oem = 0x7f010004; - constexpr ResourceId policy_product = 0x7f010005; - constexpr ResourceId policy_public = 0x7f010006; - constexpr ResourceId policy_signature = 0x7f010007; - constexpr ResourceId policy_system = 0x7f010008; - constexpr ResourceId policy_system_vendor = 0x7f010009; -}; + constexpr ResourceId policy_config_signature = 0x7f010003; + constexpr ResourceId policy_odm = 0x7f010004; + constexpr ResourceId policy_oem = 0x7f010005; + constexpr ResourceId policy_product = 0x7f010006; + constexpr ResourceId policy_public = 0x7f010007; + constexpr ResourceId policy_signature = 0x7f010008; + constexpr ResourceId policy_system = 0x7f010009; + constexpr ResourceId policy_system_vendor = 0x7f01000a; +} // clang-format on } // namespace android::idmap2 diff --git a/cmds/idmap2/tests/ResourceMappingTests.cpp b/cmds/idmap2/tests/ResourceMappingTests.cpp index de039f440e33f..3ec6ac24b238e 100644 --- a/cmds/idmap2/tests/ResourceMappingTests.cpp +++ b/cmds/idmap2/tests/ResourceMappingTests.cpp @@ -237,7 +237,7 @@ TEST(ResourceMappingTests, ResourcesFromApkAssetsPolicySystemPublicInvalidIgnore ASSERT_TRUE(resources) << resources.GetErrorMessage(); auto& res = *resources; - ASSERT_EQ(res.GetTargetToOverlayMap().size(), 10U); + ASSERT_EQ(res.GetTargetToOverlayMap().size(), 11U); ASSERT_RESULT(MappingExists(res, R::target::string::not_overlayable, Res_value::TYPE_REFERENCE, R::system_overlay_invalid::string::not_overlayable, false /* rewrite */)); @@ -256,6 +256,10 @@ TEST(ResourceMappingTests, ResourcesFromApkAssetsPolicySystemPublicInvalidIgnore ASSERT_RESULT(MappingExists(res, R::target::string::policy_public, Res_value::TYPE_REFERENCE, R::system_overlay_invalid::string::policy_public, false /* rewrite */)); + ASSERT_RESULT(MappingExists(res, R::target::string::policy_config_signature, + Res_value::TYPE_REFERENCE, + R::system_overlay_invalid::string::policy_config_signature, + false /* rewrite */)); ASSERT_RESULT(MappingExists(res, R::target::string::policy_signature, Res_value::TYPE_REFERENCE, R::system_overlay_invalid::string::policy_signature, false /* rewrite */)); @@ -298,8 +302,9 @@ TEST(ResourceMappingTests, ResourcesFromApkAssetsDefaultPoliciesPublicFail) { ASSERT_EQ(resources->GetTargetToOverlayMap().size(), 0U); } -// Overlays that are pre-installed or are signed with the same signature as the target can overlay -// packages that have not defined overlayable resources. +// Overlays that are pre-installed or are signed with the same signature as the target or are signed +// with the same signature as the reference package can overlay packages that have not defined +// overlayable resources. TEST(ResourceMappingTests, ResourcesFromApkAssetsDefaultPolicies) { auto CheckEntries = [&](const PolicyBitmask& fulfilled_policies) -> void { auto resources = TestGetResourceMapping("/target/target-no-overlayable.apk", @@ -309,7 +314,7 @@ TEST(ResourceMappingTests, ResourcesFromApkAssetsDefaultPolicies) { ASSERT_TRUE(resources) << resources.GetErrorMessage(); auto& res = *resources; - ASSERT_EQ(resources->GetTargetToOverlayMap().size(), 10U); + ASSERT_EQ(resources->GetTargetToOverlayMap().size(), 11U); ASSERT_RESULT(MappingExists(res, R::target::string::not_overlayable, Res_value::TYPE_REFERENCE, R::system_overlay_invalid::string::not_overlayable, false /* rewrite */)); @@ -330,6 +335,10 @@ TEST(ResourceMappingTests, ResourcesFromApkAssetsDefaultPolicies) { ASSERT_RESULT(MappingExists(res, R::target::string::policy_public, Res_value::TYPE_REFERENCE, R::system_overlay_invalid::string::policy_public, false /* rewrite */)); + ASSERT_RESULT(MappingExists(res, R::target::string::policy_config_signature, + Res_value::TYPE_REFERENCE, + R::system_overlay_invalid::string::policy_config_signature, + false /* rewrite */)); ASSERT_RESULT(MappingExists(res, R::target::string::policy_signature, Res_value::TYPE_REFERENCE, R::system_overlay_invalid::string::policy_signature, false /* rewrite */)); @@ -342,6 +351,7 @@ TEST(ResourceMappingTests, ResourcesFromApkAssetsDefaultPolicies) { }; CheckEntries(PolicyFlags::SIGNATURE); + CheckEntries(PolicyFlags::CONFIG_SIGNATURE); CheckEntries(PolicyFlags::PRODUCT_PARTITION); CheckEntries(PolicyFlags::SYSTEM_PARTITION); CheckEntries(PolicyFlags::VENDOR_PARTITION); diff --git a/cmds/idmap2/tests/TestConstants.h b/cmds/idmap2/tests/TestConstants.h index 6bc924e5ac3cd..641a7a8d45aa1 100644 --- a/cmds/idmap2/tests/TestConstants.h +++ b/cmds/idmap2/tests/TestConstants.h @@ -19,11 +19,11 @@ namespace android::idmap2::TestConstants { -constexpr const auto TARGET_CRC = 0x41c60c8c; -constexpr const auto TARGET_CRC_STRING = "41c60c8c"; +constexpr const auto TARGET_CRC = 0x7c2d4719; +constexpr const auto TARGET_CRC_STRING = "7c2d4719"; -constexpr const auto OVERLAY_CRC = 0xc054fb26; -constexpr const auto OVERLAY_CRC_STRING = "c054fb26"; +constexpr const auto OVERLAY_CRC = 0x5afff726; +constexpr const auto OVERLAY_CRC_STRING = "5afff726"; } // namespace android::idmap2::TestConstants diff --git a/cmds/idmap2/tests/data/overlay/overlay-no-name-static.apk b/cmds/idmap2/tests/data/overlay/overlay-no-name-static.apk index 7c25985e5a61298b55ce10d3c227f46c7057c5bb..dab25b1f81317f6d7366993527bba85fb1d8f4f5 100644 GIT binary patch delta 723 zcmbO#Jy*Iuz?+$c0SGvNNRc7SPW0j~Mg|5IpqMaF)G;rmC_gjBH!&|WEw#8ruOc^R z>ZJXC(vAYh_J5Tu-so)5$kZaLDiqqa*<+@V)e;33L07IRFJ#!Y|EbRx?&NdTtl*i~ z)HF$bq2EmLhWl%#-zl89G{yh^yEo?d-<&xYx1>HII`rhqrKh{LEUKx|xsm;V_Xe~2 z1N9wj<`2aFn9V=Te(VAJ4yOGF#GW6M%3d_jt!~~cp1(q`)xX7mk$lZyeKkDow)a=} zd$n&GpC>;umaTj*Vm&o-GOe^D>#=;u?lZD89?q{3&HWs? z_5IECCpKSRd(_|W@ZPJdyGUNhvhn>!ul1!}WnSC1XMIl1@DJnsX9>y+~GZSI`i5&DtQMejr_!b{&Bu5T(9p1`p6%Hb|F8it+Vi4;~dTFCWO0nB2ug91=YcrrhaSpC#VXZ2VdMOyt|I{u#f zakGNQhAl5Vb#!lbv~VOTDy1Adf5hi}N|nbO9UYsN;~O@8Qn@zmUc>sVt~_0#UB$2N zS(Uz98@*jCV8zd-6qD8Ma+y9a%jbMlKWKD=!TkZBO=J28rh5l=P2_Xr$vdcA!P@sF=QI-b3F>+WMKmi=E4mAvNAk@(+|Z+Ap}pP~9@$K#yfaF@_I`d=6Kb!H#F zzTwg&y$fYGvRzaEvAkt{#dgXi&`x_)4!Z++f>R%qHPr7t_rsLhU+NVNA7iRC;xVm?a*51Pl zeNw(XdmH_zHz_^!4ATuAiQ)^{KGG@<%Usq5aqjutdV}!-bN&2>Z_Qua`?RF$@9u58 zoTS2MeV!BhzW8t0h3D7XH@cn|wKbpAz4c#)p5wJ^iRTR`u1r30J@CYpg+6+ZEg!$$ zzSC>|^CI&*Pk-5pFWLC`8rwegpSI00>+PzO>Rvu%M~%|WKN+&(y zP33?Bnya|>{RSqUFH8&!BA`?R2M;F)@Th14mFP3X>|O&D?f|ALHMlg0!N<%1vP!=q zH%EW6A*a;j?L2~D_nqdEV)+M@ocxYWS|`Ap5okCFKvJmB>UE({fV>8vs3ce%M*L!# YY{07lHX)itpET3 diff --git a/cmds/idmap2/tests/data/overlay/overlay-no-name.apk b/cmds/idmap2/tests/data/overlay/overlay-no-name.apk index c75f3e1dbddfe53947511311ecd9fa02e2b72099..c8b95c2601ad9ea333a4320bc1d00a92c37e0045 100644 GIT binary patch delta 647 zcmdlhbx=w=z?+$c0SGvNNRgpPR?{Mmk%1wBnSnug@_KHu`l%DodL4EUX+3Xp&29Aq ze{rrLfn7xtANa+r%GTs~6twZG*z6@LffuIkD0+CQ{o}$K_P=SfZV70<;7zYPXZ!u! z%ueGM*yEcWw_x~j8lX{q#_2K5h2_YN-imB?f+Ilx-MEPw3V$5F+k>)X#IY(74Eu7)Yo zzL^~G_S^5=S|j=hONuzxuc(tyPb-SM1=rpqe))Yqo0cPySo=6=rsO zm&8g=zSeuP;f&P0C8i%-bqub*jc=&e{b(jOclxx`t1rw{das=8pWXQUUg$jY(~olx znR4f?49dQKT6JCI4~v9*IzKZ+?0inP_fB23f9~E#aaXO@7u|ok_spE~A8e@MuepkA z-)~@Sd|_f>5CPIfn^!SPGBN{WX7Vwnw_ti3^G^`Hc@v8SSYq>8)+4Mu$Z7IFBIM z{%js8mNmfSF}aUTT06j-5vUFXAnC_v^}5g}Kwbk-R1z!>BUVg4&!Y)8;5UyHowO6V>z?+$c0SGu47#ij?PRY1z8pX)K5W~#CAPf|B%u6ZC&rI=6%*#wmEiTck z$jzBL(b4;`gGfudboS!V6*rojx~jfRh&j5rYTBX;lf^e)6`Q?8CGf&z_m407Kf3=^ zzLLLvCGW(hycu`5e}1<2%)6>jr7u0*qHnGBTs^DTPqY3WN9KYBmqe~m#-Sw<4KKEn(tj+U(XDpuggG*~2 zQ%UFS<+sv2qwDPN-T6^6>063Vl(`zSk*>_ge-FAh9*AN${V`oA|M;TfOJ$X!R>4nd zm)yP_^LD{u3o7PRQG2xP5_T+Hi)J5mk#mN+|%bFW* z`Tk2x+Bw@AX4Kf&JeN_6kr@~*lTR_d1=G8je}d@E+gK#P5}Plw9%1D{j=0GSxlQGO z0-CG1_WcIN;1?za1`$vM!$J4tFWf3%)1-N%n07EtzQLq1Ii80XER@e9#kgW}7mv0g v&q4IZ^)&#^kc8_8F_r++%;XJhl9S&<_5BCx+do-~SCOrS8>9dLi7Wj0 diff --git a/cmds/idmap2/tests/data/overlay/overlay-shared.apk b/cmds/idmap2/tests/data/overlay/overlay-shared.apk index 93dcc82f93584f77a551c90a8175755b843672c4..0a8b7372172e92f79c466bc02f6d99886b2ebdeb 100644 GIT binary patch delta 591 zcmZ20yH-{@z?+$c0SGvNNRi?AkF^{3F)}cu0L6qS%kzrWPYvGfci2H-PWR_Jhb93g zPQ?rj4WSnTswO6#0t#7+_MAK%mNX$lKvngA!zaZlHH`BQm|r+}=UETG`@{pwJIy!m zE-uc#?I?BDV!?*aOr8kG3e&X_pMM|GG*nu4MEj##jlld}Zj9zfm_PdL5qR%1ZP#uW zuGlMv2RUQ1w%-VB@UKtn;rsv7BKeNP{Qa^g)9O>Rd)g08k9cbI?ZV-PGptvC?MO0N zR@HC$w%{>;XyfFI{bloRihb70lQdOXXY|@o{4nG6vRchO{hxP6)t<8YIx8jS-JFBEsrN6qANvt7jlZS#lcm+On2UC6%g_Fv zb@X}fyyTafKhx6cybt<3`FVcFl!rnO_i5VpCfr}KPk3grf&bQofA>)%c=KOIO-5#5 zOi$Kiegmc@Sbl=&%_6KKV2RDzY}eS>p=n_<2d@=al`F43m~Q6{1k<;9-N3X8p9`4I H=5qo7XA%PS delta 591 zcmZ20yH-{@z?+$c0SGu47#ij?9{<9oy^oQBAq6NVJXxMstbS_nZZBp>5!=aUlaqyf zU0fU;51vxmDB_))Bjj@Q)&%p)H=80^4<5R7Du2U?_K2UXbxrpZR;TBs-7QpIU_9r| z-RkG_EQ^g^A8@ti)yPSl#uO&lzfJV@AI3s2pAN~7PJ4vjA7Kv+bC|zFeO^cUquzp( zyWO8$a2F1qb3nPgT~@We+k#5 z9~Z>D@z@`<+r@Tm$b`TwuP2+m9H*{q|32ZzlY*ywjGE8n*Y1&HJ(fL3vUvYjEA@BU z`Lkv0c~g!CTSNxyOX|(-wwNxw*DB8Qi+`4E`=1tkn?+bfz!ICa*{-p%L({@!4qhv;Dpy{6Fx}1@2&QlIx`AmGJ{K^Z H&F2IF_}m2! diff --git a/cmds/idmap2/tests/data/overlay/overlay-static-1.apk b/cmds/idmap2/tests/data/overlay/overlay-static-1.apk index 5b8a6e4a90ed68c406af3a5d8a5607bde9daf056..fd41182f84936793abd12a2ae9ae9923df23e8a0 100644 GIT binary patch delta 741 zcmeB`o+>RJ;LXg!00bOBq{zT`_K@2KMg|5EpqTLF|J-8rQzzN`OFIf2yu8kw!JT)2IU?zP zgzeX>A=m5Kr54RUTt9Dv-DS;te09G2f8L6kRV#e=Sbnvgn*GIj{d^y?H?7Nlb7z@b zux?28s?C=ftaq8t&a_+Vdw<)P z<41q>>7L#xpP>Ex&ch|ewG$Y2D&6&T{cuD$IsMJH2kV3O*lympdXn1V{W-htSgik{ zTOc<7lW>@c=%e@ztp`Mz%%`6;{h!_Cc)H#0jZF7SyH5-IV^;Am{S@;c=EeOiG56=6 z%6}d5W!IB>t~aCikk2O5#b?&I85h1k^Fb0dN;kh`)M8`?#_eP==C@#)jpZkZ-ps@* z!Ke&ms4uG&vi}Op1l2eQI5{rtH85lNOvn^xgfTfPfFS#w{fE>+L zT>E|l6V4YVU~&PaAUJq9*?~tz6R1R=A!hd)pl}B;MXAB1K@2`-29P!S6}dV3lNC9o zCNJj^1iNiFj}*&4pycFxY|`2R-i$!QK>(6EeO9jveFEe)07WIi;xOXZWO-gqumRq@ QQjDUL(|8rx?r?)-0j^dPSpWb4 delta 698 zcmbO#-78%m;LXg!00bNi3=Q)cpB;0$xQda1K?Eo!3>0MdM$gDNFb$i)%l`=80X>~nQr^YAc zzLfuPX2z@1rJR@de4kVK+*ZDLS)-Gy<;e`ce&$Q{OR8S0JatcC&1p(5;GcJpyMpz7 z!eI}01-9}BoO>EO_AHFbTD@%9@3NBaI+^NI|D4h*tbd5ce%xA}`Q-RZv%13{6+d=< zyOYVjU+H#f>lxmxDfxtF=CRUx-_jx4$bANV!ztrNT+ zzGTmT{pi?r;^A|?&#{#+F%C0$asK!Q*7Kq^=JPtY{&P{g_AN2rXzr`zE8i!2e_a@& z_t^6B@9jIg?pE&%|NE%TM*K_C@-@7Fd^VXjpINiZ*swP32PbOmZhp_G#mEed=E*Y5 zZ^1MV%TEx!nS)h=Q4z>cUwX%F1}g&t2=g&8G8Cm2=a&{Grxxoa78NINc4k|~$^lCz zlRt7>f(_B-kz%|(*@H&~%*zMzI3{=Tn8^VZc5RKaKMYJqbAV||8kEf7;K$^9JlYU9 f@Jca$nXJyM3DSV-0Jv%(gMV@!uOizOZjcxNCE6cD diff --git a/cmds/idmap2/tests/data/overlay/overlay-static-2.apk b/cmds/idmap2/tests/data/overlay/overlay-static-2.apk index 698a1fd6e70218b200b5bfdfc1d073381336c6da..b24765fc666a2c986faa5fac3a712dabb7a16679 100644 GIT binary patch delta 713 zcmeB`o+>RJ;LXg!00bOBq{#40LbQA{BLjm7P)vC8e{Qk*sgvyer5y#1-v8B8d!x|c zh?C2vMN51WwWmzE;L7D>xM+ccf;EfwKlS;|PxutMPSwm3netQRisnzI53|2Y#p^jW zS?`^F(>%W{EnPooO;lXbs@LIuQCA;X`u#NBz-ia4T)>)lK)!(cozAn4M!_8{`wzx% zIJa-3o7C#n3;+9>xYoxXoVVfMy8MdjAGv=YWM{AZ;$I@Z|NYMye_V9s=RVk;8oT}G zPXFF@RV$)iZMe*MPhxGT?1HM_JXiVd^PPFHG0ty(#oF7o*Emi0S6N^2|8(o#^sX1| zDSZ!jN4#8o?tU)LpLw8a+5LOv!g*h>o+!Ec;mx0GZ}PR4 zZ+UrpnqJJB?>BbM`OUEJ$z1E0qC6fUh47`;E4kiPCcW8oSL{z|*Y@R4cCX6R{BwHQ zY5h;D-ZQ0tY?{AekyFS1L+e=bR12p1to!M*J~+nmOXBm2$*&g6{5rAxSAdqjxP|zy z?X#}_-1%qjxgALl7P-EgbyMSvO0@B*Gg)@R-;eOfGoZ%m=2whbjLg93oh;7$7EH6V z`~=aPnOP;k5}W1N4zqH=62Rn_+?H}cj^-+^eZPTe;|mioMSv0s96Xuqz@s7$RHDxi zvwICtxC5AI)Zo$}h9L7~K~~|(TAYHDm-7gMZQacy#l*-07Jkphr4!)I2s9W3Ac@as q^}5g}Kwbk-R1z!>BmROkNl&)s9nh{| zpY3MFWVnOb{{gSd6W*&~?xkDrY+oJyW%7;SZ{k*mZy#O%s%!mS@8tV_pYzue)Ab#wq%JPVUQD zD^`78DtN`PP`3VuRan$T)mwU7uZ29DzF@D*U6+|Frd*s}lb-s+%yz2f#+j$>Keg#O zpLuuZd-Ce-C6DtiK6rD@@a-9s=Lu4INzdQ$&Wd`@R>rqAUhTvD83$jxtf;P?Y7{$F z=61dD?|3Qy%**+?*XMF>ZHb*=csjv4|IEV)hO!eFW-9&lbp3FUYh(Rl1@`|F9=(++ zu633A^gng=Y5qrD-Saj-Kb&`rtL^VkmTeDqHa%A}-gs^PsUx@S-uR{k*Y^Cj`?S(- z%BiWJ=Y0HoJLc%Wy?0iB+aY+KwfTl*HnaWYoU;nXtN;0&(Kr6Xf*QS=tGM?421e@_ zCSVi;>7vxlEKCxN%)pqREYJKFO!Kq+1kszhSs@ae)z}WRa=_BYe?D*e;CM{158@dU~w4nlX>!e9xbqb u9$qP?uPl=#S*5iR`hn_zR{zlzuA0HhzyQL0Fs)!(U~(R>BHI;i5C;IGd>WYm diff --git a/cmds/idmap2/tests/data/overlay/overlay.apk b/cmds/idmap2/tests/data/overlay/overlay.apk index 1db303ff05b54b93770d8b7a7cc7ef7b660049ae..870575efa10ccbb92506845b77c9816dd9695d5f 100644 GIT binary patch delta 610 zcmZ1|y->P7z?+$c0SGvNNRi?8yiHb{j&?LabshFXmA@o8()x@MzKp{)%lL~)yr{f|GTAle zFKFI*R#LuCsnK6JKdt=vvuoR$O{5AP5@jb#)Ng3{kQK4#yw|Byy1i4xYDIF7@{TKcn-(+7Kf{sx?{ndyA6&NowyDnkJ9Vw097lZ8 z)YCVd#cPeyLtZ~@y4dk5_Su%hTkS(w{o3qrRi@28vwKHkiE820$o`!Y-*#+yUHq_i z&bceEg0HQtzpn7ONZj`DoG;ZS7gIy$);1oO^*i$XQ$YjQ^%+0;O4*E-7rCs=@e2{$ zEB8Kl{nVMVmlqj4**~ptRqf6lQ!js?xm);Hw@*!IOjf&YSpSNm6PsWDG=1jt&feBE z`_#UVq4Nr-ZZ7)vnO!baYWAhISHuE)wN1S=Ox27$moDfkVHTvwQs6X zcr*F@MZ@P^-!k`l-wW5V%l{(d?SInT_-iy*n$r3DQ%iZKb9_(j{w(lD`f9mSG2gS5 z&(8dpMvihOMTX7)7_}IgfssF1oB1u6mS*`0qBo1PN`NIc8?hZ`Wrrq@$$z-5z^W{H Y?7?(3Pav2+&*KKBC3s!HbUd#U04nPL!TP7z?+$c0SGu47#ij?-ky{wvY(NGAq6NV3>08o38A9ui zNPl#!5lUtK(oy|rW`*KC&e^-FUHEKG3=eX~WNnWObaFW6K0TlDoWyp62l?Tfy!UV7 zJ*NCnJLaj;w+qK7oMFAnwj=3D@ZR%t%69y04_!FeFLWR9T zi|5UH!TV#5<=V4vGrAAW$d`Q_^1G-|J6+zWT)k)di|=hauJBpMybXRjBmMH-VzDo8 z?M-_l`k5cEwtBuw;Plb|wYG9odu3OKXH8$ReCj7-FW-)uFwGT4e?QdA3B}87yQ8S! z`cL!N>%fFP$7ULSk6yod(XLP19{$Kw(6()zYWj21#Y-_OcFtLG^`qCKu-_I_YL(?H zA3GndQMfee{6(YZUe_}BX4_p)uDSRk($H4*{+ToGs&6{)G)PW2j#0ZcUGP}r$PA49$=b|s!L&5XPY}IXoK*rWvDt|2Fe^JWc})Jp dZ3R|k$zu@000002mk;GApnSuYXRW_005W-kr*6*ZWBQihX2XhWHAYG zE(J)YKtdE0c8e$|fEI)jM1g25n_T4E%HANkqs$XTh-cs-cmOJ%fJfjB;5%n$*=12A z*wMdp=0BJD=j?2vR3BSXP)}brq~E3_yj(K z@8E#ikHIEYhg#`>sTLaR9a$;0mO5i??_6uRZRR2C6C!fG#2#tF`@}Oke|TSD&tj!B zDj&Hw#~#7$@?PN2SWk&MV%LdYV=albUFSsI{)ebi@%;CGL5HsO6{{6H9{Rk{IawpO z?Yu)W#xM)&jA3rTWQ?gRER+^19?+Ydk?D~Jj1~S<>dd@@e$+hhdK2cQ?>YEu z$J8s#Ssh2ErfZ@1e!eNbwKG|x&$nEqDLnSCGt(2!W*r(|(VPFtslMAj(S@#lLscJk z?H=ob^{$Gn-vQ}ENOg~SOCj{YUGTgW!kcyoORxe8UGzy^@RR4dSG0TE)kTfBXAAp) z(T?}u;@Z)FpAvc}a@V|b)?+1`(SOtLUBT@}Zl{rJcDIphIv%R{2TL8Ds3X*LsH$bZ zrIL8AW}el{J-_0&W4%_bUZ`p7ls$?6ylLBuTvDu^OC#5+X|cJ~(%ds?^uFwIxZ<1q z0#Hi>1ONa4000002q6GVX}IA)0ssI&0ssIG00ICGa%FRGb#h~6b1q?Wb7Qkk0!ji6 p000O800mLk;gh8VIRgkG0F&Va8UYfM`~)EefCK;l004ag6g&U` delta 619 zcmbQtwU|pHz?+$cfq?@E85-s@GQhz^37Pu7%MK!K|0C7caPFS4S43f{qmzh;XSaq% zgBXj>A_tSeLvd5O*B((=y7-Q|Lr3}p#R>+kc@6Flcpq3FPtNHHW9qLvKl6Xgv-yt; z7lp`M2VHQ8-?oJL>iNvW_t>`|RQ@3KR23ECda0S(0;IBVGMA5`4>zBzYQ z-_~o+^{KO7@kVNH4YNwleeWc_Blel$YhfiW+oSU`j{QDjTvcB&KS4ifsj-&)&g}>0 z9eDfk+=u6Dp1a6yeC?yZG3>~#b>55e{y2v$t@v5Je?j`XudJ(0t?j;BUXI?RmUp}I zc#2P=(JPtE}C?bY77_e5;=(^+@(pU&#rt@Zz) zm%IKe4qn++**Ei7s?1wGH~lNu`Sm~VMy$WQLR{)rRjB_X`}|wql&4S0etzjhsZ>uw(Y2f%or0Zavuv;a;5z_j2km$~Di0}}%S2=g&8 zGZdv3=a&{Grxxoa78NHmY_?d DgG3m) diff --git a/cmds/idmap2/tests/data/system-overlay-invalid/res/values/values.xml b/cmds/idmap2/tests/data/system-overlay-invalid/res/values/values.xml index 7119d82830615..ebaf49c347621 100644 --- a/cmds/idmap2/tests/data/system-overlay-invalid/res/values/values.xml +++ b/cmds/idmap2/tests/data/system-overlay-invalid/res/values/values.xml @@ -26,6 +26,7 @@ policy_odm policy_oem policy_actor + policy_config_signature not_overlayable diff --git a/cmds/idmap2/tests/data/system-overlay-invalid/system-overlay-invalid.apk b/cmds/idmap2/tests/data/system-overlay-invalid/system-overlay-invalid.apk index bd990983693c96f3c9998032c34f0a55dc1525ee..a63daf86caf58b9e1ddc414ac9832239707ea404 100644 GIT binary patch delta 362 zcmZ3?_nD6`z?+$c0SGvNNReS9-wQ@(Al>dJ#Bl;B4#Ip4j0{Do#rdU0$*IM9iABZ9 z3``6>U@1nRMn(o15W&C=G6e*HY>&ygEaH;RKu!P<#{zL45Z3|mL?B)`c_xdFq_}uN zeokg`WqfjeURq{)d~s%aUSdgUQR?IgOyw+03XFR;^D_H03R2tbGF~Po0R|hOJ3y}I zo*c-mFUrUi!e9X8f<=I$4M6MwlyRPXhE;`e!Q{8Bixq$Y#J~l_K$;mu2Y53w0VyDW X1l{BXY<4`zK{xpon=#u1HjoMc=QKkA delta 331 zcmey&x0sJFz?+$c0SGu47#ij?ZsdExSP!HRFL?640w@l`d<={XMXAO4rA5i9#d?WF z#mNjz3_M^dMxaJU1{sDYK$;6=3J3rNT_7wlDFh^?fLIfV&4Ab$h(mxl1&GUmxE+Z3 z`SbEi;`7T=i*gbxCs#7bOkU4a#>T+Fq`=s*S(DkH(Uu|`CTB9~fK23LU}6$rumD;J zayZxILT2sB8(3L*Wq@3;2vD?U@(S)a{(x+PbuT!zUKGgT@tX-qm%+%ifhPsB9qKl60o{}b;7wv zj^}no|8l;1!1H3@!4H|cm9`c zJT~`t&pNZv#4ji2FD`y*6?jf#>fYyFm$MCzzdLhky|DB03yD|1_^n;Xq)rA@x7C(qpD3=Eoc>JNQj+rO*ESm)BZq zCSF?76Un+;`Ph-l?*jufq-^ zt>8TP{*R1*80>4VGnUQm z;qbGVY5jbjW$}BJMy)7LmBq{M^=_$O@G|4+BhwAMdIyXv7}r1GU9&l#`%Poe%&UfB!EJcD)H~ z_NB!SXB+3An9)4RF!SaNo)acA_Zj4SBEuU^nCoXge!D_I|1-d_)vsq%oqOiJ zE}m6&{`y_7)MC#5e!u(PvVWiN)vGrz + + + + diff --git a/cmds/idmap2/tests/data/target/res/values/values.xml b/cmds/idmap2/tests/data/target/res/values/values.xml index 5230e25e626be..00909a9e481c2 100644 --- a/cmds/idmap2/tests/data/target/res/values/values.xml +++ b/cmds/idmap2/tests/data/target/res/values/values.xml @@ -37,6 +37,7 @@ policy_system policy_system_vendor policy_actor + policy_config_signature other diff --git a/cmds/idmap2/tests/data/target/target-no-overlayable.apk b/cmds/idmap2/tests/data/target/target-no-overlayable.apk index 58504a74a83a0a4229a2d7b89da8624ff646a87d..cc3491de894d8adf7a5c66723579e48716f9f1bf 100644 GIT binary patch delta 421 zcmZn{x-P^Q;LXg!00bOBq{uLl?>;Y(QvJ=;qQK6;puj%ymlQ9E#Rycw$RNXzGx;X7 z^kf@G33Gp-NDL5X0&x`(cLDKSAYKc^M}YV|5Z?mgr$GDxh`#{w4+e(GUMyyk;^GDQ zIho0o@yYplX_@Kq#hK}Oi6x~)sgvtj$|f5zS+X!GFs|5K$dt|~m;tm}45$|jfb5dV zFPYU%!+_jmAT9vnMj)OD#7ls93lN_M;!8k$6Nn!G@pB-44aDy!JF?j0wR`?#1=a@6 z6rfrrAQqiGkttk|ktu}X2hd)y2vBszWL~z(j1HUUvNSJIA!h=A%0c1D>06Yy- Ab^rhX delta 351 zcmY+=ze~eV5Ww+!FF#C&7AaMvt)MtL)of0+=p+p^sC2GV7Y7H$#X)os1)=4(E-p?T zgi-`Ib#W1)4k}pC4*nHRe$zqlg%5YRJ08isXHT=4xazpV2}F)AO*`|ICKS4d8v|ct z;J1JBvq@$cF;bM6B$v!5hkQpvvk(P2;;chaf69ZhHy%uL5sj~@|n LcpivLEK}qc&^twS diff --git a/cmds/idmap2/tests/data/target/target.apk b/cmds/idmap2/tests/data/target/target.apk index c80e5eb65ff214ba5b7b15ce6dc28c311e6f2dde..4a58c5e28f4994a3ee32203631c0a1866cfbba16 100644 GIT binary patch delta 635 zcmaKq&r2IY6vt;~vq?5hqVBr+(I`ZVs25ui1hJ`sUJ43&5OXO=Sfd2g$gUCf&?0ye zFY$pl(L)ct^bpeg1@=}Cwos%8QAE(v77M-Prr%i-np0=?!`t_L@68*A_oMeqUwCR< z@h~huzAjb@Unnr;KLI`jo7xnC(^keLVaA!Aa|%V<$~gmB+p(BnK{v!v&shiCCQVJy zD-j!=gz_5X!6w)N2jBzv1kS(}_zh}6!4W?2h%mBM1)+L*Np%k%k#Stq}+ zoLw#2IXV%?sz~y5OJ!fNdD|+AqBy`^_+O{E+B-4>*8(eG3zWb+@DY3lU%_{932wko za0mWUQ62kl^EK-CKE)+7-Ysno6#|%4Rx&0R)2xOYxC+$wAdSdN+VxHFG=1}3@DNq~ zRtQhcOaQBxWNMBUse9o{Nqgeqx0PxLCP3$HiBvliZ&lIC+L0sAMhiUqKh0a$LQR_N zAoDaD)D80M!Omn|@ik?o>zbdI^k{dZhb)w}USu|g11_e4_Vh_P9dxa~aBYt<8f=~t fS~Q-yfkWf5_@&d49*azktMZ1-gMAPC+>qV_-7{~x delta 529 zcmYk(KS)AB90%~b_k8M!KH@#AK?%#D8jKpsAuOpOBEz7_)ey-c$P{Tzs3~ZWUo8!_ zI7FMdv_!N-LlKep^4n;vrO?^+SJos>T-}}RR_p9{Oy7ieU)xyy1jOF)vL4Q=y zmEIkE9R0ySEtqOyOwt)=nPhf3mq{eEeG8dvf+@^dU*b5=nU|$7XqA`AhH;ugia$7p zNfhFchIJq~gcG=c8+d>kyut^z>}f;vrsXKEPTLq$eEd@{AE_D6=P00fD6Dx0C$V)N z7GV`OVHZkp45x4oS5SdlxT76y6c-n1+nN_~Bnr5x(-w0*b9q5CbGV9J_{0)|IuN(*z#Td81}!itf69w)6BX2_0R zzw3C?`ii3|^EEPSQx42a??7<> mNamedActors = null; + // Package name of the package pre-installed on a read-only + // partition that is used to verify if an overlay package fulfills + // the 'config_signature' policy by comparing their signatures: + // if the overlay package is signed with the same certificate as + // the package declared in 'config-signature' tag, then the + // overlay package fulfills the 'config_signature' policy. + private String mOverlayConfigSignaturePackage; + public static SystemConfig getInstance() { if (!isSystemProcess()) { Slog.wtf(TAG, "SystemConfig is being accessed by a process other than " @@ -433,6 +442,12 @@ public class SystemConfig { return mNamedActors != null ? mNamedActors : Collections.emptyMap(); } + @Nullable + public String getOverlayConfigSignaturePackage() { + return TextUtils.isEmpty(mOverlayConfigSignaturePackage) + ? null : mOverlayConfigSignaturePackage; + } + /** * Only use for testing. Do NOT use in production code. * @param readPermissions false to create an empty SystemConfig; true to read the permissions. @@ -1151,6 +1166,27 @@ public class SystemConfig { } XmlUtils.skipCurrentTag(parser); } break; + case "overlay-config-signature": { + if (allowAll) { + String pkgName = parser.getAttributeValue(null, "package"); + if (pkgName == null) { + Slog.w(TAG, "<" + name + "> without package in " + permFile + + " at " + parser.getPositionDescription()); + } else { + if (TextUtils.isEmpty(mOverlayConfigSignaturePackage)) { + mOverlayConfigSignaturePackage = pkgName.intern(); + } else { + throw new IllegalStateException("Reference signature package " + + "defined as both " + + mOverlayConfigSignaturePackage + + " and " + pkgName); + } + } + } else { + logNotAllowedInPartition(name, permFile, parser); + } + XmlUtils.skipCurrentTag(parser); + } break; case "rollback-whitelisted-app": { String pkgname = parser.getAttributeValue(null, "package"); if (pkgname == null) { diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h index e351a46d633ac..e10a7f3f5c61b 100644 --- a/libs/androidfw/include/androidfw/ResourceTypes.h +++ b/libs/androidfw/include/androidfw/ResourceTypes.h @@ -1717,6 +1717,10 @@ struct ResTable_overlayable_policy_header // The overlay must be signed with the same signature as the actor declared for the target // resource ACTOR_SIGNATURE = 0x00000080, + + // The overlay must be signed with the same signature as the reference package declared + // in the SystemConfig + CONFIG_SIGNATURE = 0x00000100, }; using PolicyBitmask = uint32_t; diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java index b241bd16d3eea..ad1986a6669fb 100644 --- a/services/core/java/android/content/pm/PackageManagerInternal.java +++ b/services/core/java/android/content/pm/PackageManagerInternal.java @@ -69,6 +69,7 @@ public abstract class PackageManagerInternal { public static final int PACKAGE_WIFI = 13; public static final int PACKAGE_COMPANION = 14; public static final int PACKAGE_RETAIL_DEMO = 15; + public static final int PACKAGE_OVERLAY_CONFIG_SIGNATURE = 16; @IntDef(flag = true, prefix = "RESOLVE_", value = { RESOLVE_NON_BROWSER_ONLY, diff --git a/services/core/java/com/android/server/om/IdmapManager.java b/services/core/java/com/android/server/om/IdmapManager.java index d6b1b27360caa..cb6e960b721de 100644 --- a/services/core/java/com/android/server/om/IdmapManager.java +++ b/services/core/java/com/android/server/om/IdmapManager.java @@ -27,6 +27,7 @@ import android.content.pm.PackageInfo; import android.os.Build.VERSION_CODES; import android.os.OverlayablePolicy; import android.os.SystemProperties; +import android.text.TextUtils; import android.util.Slog; import java.io.IOException; @@ -53,11 +54,20 @@ final class IdmapManager { } private final IdmapDaemon mIdmapDaemon; - private final OverlayableInfoCallback mOverlayableCallback; + private final PackageManagerHelper mPackageManager; - IdmapManager(final IdmapDaemon idmapDaemon, final OverlayableInfoCallback verifyCallback) { - mOverlayableCallback = verifyCallback; + /** + * Package name of the reference package defined in 'config-signature' tag of + * SystemConfig or empty String if tag not defined. This package is vetted on scan by + * PackageManagerService that it's a system package and is used to check if overlay matches + * its signature in order to fulfill the config_signature policy. + */ + private final String mConfigSignaturePackage; + + IdmapManager(final IdmapDaemon idmapDaemon, final PackageManagerHelper packageManager) { + mPackageManager = packageManager; mIdmapDaemon = idmapDaemon; + mConfigSignaturePackage = packageManager.getConfigSignaturePackage(); } /** @@ -139,7 +149,7 @@ final class IdmapManager { int fulfilledPolicies = OverlayablePolicy.PUBLIC; // Overlay matches target signature - if (mOverlayableCallback.signaturesMatching(targetPackage.packageName, + if (mPackageManager.signaturesMatching(targetPackage.packageName, overlayPackage.packageName, userId)) { fulfilledPolicies |= OverlayablePolicy.SIGNATURE; } @@ -149,6 +159,16 @@ final class IdmapManager { fulfilledPolicies |= OverlayablePolicy.ACTOR_SIGNATURE; } + // If SystemConfig defines 'config-signature' package, given that + // this package is vetted by OverlayManagerService that it's a + // preinstalled package, check if overlay matches its signature. + if (!TextUtils.isEmpty(mConfigSignaturePackage) + && mPackageManager.signaturesMatching(mConfigSignaturePackage, + overlayPackage.packageName, + userId)) { + fulfilledPolicies |= OverlayablePolicy.CONFIG_SIGNATURE; + } + // Vendor partition (/vendor) if (ai.isVendor()) { return fulfilledPolicies | OverlayablePolicy.VENDOR_PARTITION; @@ -183,12 +203,12 @@ final class IdmapManager { String targetOverlayableName = overlayPackage.targetOverlayableName; if (targetOverlayableName != null) { try { - OverlayableInfo overlayableInfo = mOverlayableCallback.getOverlayableForTarget( + OverlayableInfo overlayableInfo = mPackageManager.getOverlayableForTarget( targetPackage.packageName, targetOverlayableName, userId); if (overlayableInfo != null && overlayableInfo.actor != null) { String actorPackageName = OverlayActorEnforcer.getPackageNameForActor( - overlayableInfo.actor, mOverlayableCallback.getNamedActors()).first; - if (mOverlayableCallback.signaturesMatching(actorPackageName, + overlayableInfo.actor, mPackageManager.getNamedActors()).first; + if (mPackageManager.signaturesMatching(actorPackageName, overlayPackage.packageName, userId)) { return true; } diff --git a/services/core/java/com/android/server/om/OverlayActorEnforcer.java b/services/core/java/com/android/server/om/OverlayActorEnforcer.java index 2bc34998785b3..8c03c6ce3092b 100644 --- a/services/core/java/com/android/server/om/OverlayActorEnforcer.java +++ b/services/core/java/com/android/server/om/OverlayActorEnforcer.java @@ -45,7 +45,7 @@ public class OverlayActorEnforcer { // By default, the reason is not logged to prevent leaks of why it failed private static final boolean DEBUG_REASON = false; - private final OverlayableInfoCallback mOverlayableCallback; + private final PackageManagerHelper mPackageManager; /** * @return nullable actor result with {@link ActorState} failure status @@ -79,8 +79,8 @@ public class OverlayActorEnforcer { return Pair.create(packageName, ActorState.ALLOWED); } - public OverlayActorEnforcer(@NonNull OverlayableInfoCallback overlayableCallback) { - mOverlayableCallback = overlayableCallback; + public OverlayActorEnforcer(@NonNull PackageManagerHelper packageManager) { + mPackageManager = packageManager; } void enforceActor(@NonNull OverlayInfo overlayInfo, @NonNull String methodName, @@ -110,7 +110,7 @@ public class OverlayActorEnforcer { return ActorState.ALLOWED; } - String[] callingPackageNames = mOverlayableCallback.getPackagesForUid(callingUid); + String[] callingPackageNames = mPackageManager.getPackagesForUid(callingUid); if (ArrayUtils.isEmpty(callingPackageNames)) { return ActorState.NO_PACKAGES_FOR_UID; } @@ -125,12 +125,12 @@ public class OverlayActorEnforcer { if (TextUtils.isEmpty(targetOverlayableName)) { try { - if (mOverlayableCallback.doesTargetDefineOverlayable(targetPackageName, userId)) { + if (mPackageManager.doesTargetDefineOverlayable(targetPackageName, userId)) { return ActorState.MISSING_TARGET_OVERLAYABLE_NAME; } else { // If there's no overlayable defined, fallback to the legacy permission check try { - mOverlayableCallback.enforcePermission( + mPackageManager.enforcePermission( android.Manifest.permission.CHANGE_OVERLAY_PACKAGES, methodName); // If the previous method didn't throw, check passed @@ -146,7 +146,7 @@ public class OverlayActorEnforcer { OverlayableInfo targetOverlayable; try { - targetOverlayable = mOverlayableCallback.getOverlayableForTarget(targetPackageName, + targetOverlayable = mPackageManager.getOverlayableForTarget(targetPackageName, targetOverlayableName, userId); } catch (IOException e) { return ActorState.UNABLE_TO_GET_TARGET; @@ -160,7 +160,7 @@ public class OverlayActorEnforcer { if (TextUtils.isEmpty(actor)) { // If there's no actor defined, fallback to the legacy permission check try { - mOverlayableCallback.enforcePermission( + mPackageManager.enforcePermission( android.Manifest.permission.CHANGE_OVERLAY_PACKAGES, methodName); // If the previous method didn't throw, check passed @@ -170,7 +170,7 @@ public class OverlayActorEnforcer { } } - Map> namedActors = mOverlayableCallback.getNamedActors(); + Map> namedActors = mPackageManager.getNamedActors(); Pair actorUriPair = getPackageNameForActor(actor, namedActors); ActorState actorUriState = actorUriPair.second; if (actorUriState != ActorState.ALLOWED) { @@ -178,7 +178,7 @@ public class OverlayActorEnforcer { } String packageName = actorUriPair.first; - PackageInfo packageInfo = mOverlayableCallback.getPackageInfo(packageName, userId); + PackageInfo packageInfo = mPackageManager.getPackageInfo(packageName, userId); if (packageInfo == null) { return ActorState.MISSING_APP_INFO; } diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java index 3968153998749..0f8c9c789a3f5 100644 --- a/services/core/java/com/android/server/om/OverlayManagerService.java +++ b/services/core/java/com/android/server/om/OverlayManagerService.java @@ -1053,8 +1053,7 @@ public final class OverlayManagerService extends SystemService { } } - private static final class PackageManagerHelperImpl implements PackageManagerHelper, - OverlayableInfoCallback { + private static final class PackageManagerHelperImpl implements PackageManagerHelper { private final Context mContext; private final IPackageManager mPackageManager; @@ -1127,6 +1126,14 @@ public final class OverlayManagerService extends SystemService { return overlays; } + @Override + public String getConfigSignaturePackage() { + final String[] pkgs = mPackageManagerInternal.getKnownPackageNames( + PackageManagerInternal.PACKAGE_OVERLAY_CONFIG_SIGNATURE, + UserHandle.USER_SYSTEM); + return (pkgs.length == 0) ? null : pkgs[0]; + } + @Nullable @Override public OverlayableInfo getOverlayableForTarget(@NonNull String packageName, diff --git a/services/core/java/com/android/server/om/OverlayableInfoCallback.java b/services/core/java/com/android/server/om/OverlayableInfoCallback.java deleted file mode 100644 index 5066ecdd6316f..0000000000000 --- a/services/core/java/com/android/server/om/OverlayableInfoCallback.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (C) 2020 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. - */ - -package com.android.server.om; - - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.content.om.OverlayableInfo; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; - -import com.android.server.pm.PackageManagerServiceUtils; - -import java.io.IOException; -import java.util.Map; - -/** - * Delegate to the system for querying information about overlayables and packages. - */ -public interface OverlayableInfoCallback { - - /** - * Read from the APK and AndroidManifest of a package to return the overlayable defined for - * a given name. - * - * @throws IOException if the target can't be read - */ - @Nullable - OverlayableInfo getOverlayableForTarget(@NonNull String packageName, - @NonNull String targetOverlayableName, int userId) - throws IOException; - - /** - * @see PackageManager#getPackagesForUid(int) - */ - @Nullable - String[] getPackagesForUid(int uid); - - /** - * @param userId user to filter package visibility by - * @see PackageManager#getPackageInfo(String, int) - */ - @Nullable - PackageInfo getPackageInfo(@NonNull String packageName, int userId); - - /** - * @return map of system pre-defined, uniquely named actors; keys are namespace, - * value maps actor name to package name - */ - @NonNull - Map> getNamedActors(); - - /** - * @return true if the target package has declared an overlayable - */ - boolean doesTargetDefineOverlayable(String targetPackageName, int userId) throws IOException; - - /** - * @throws SecurityException containing message if the caller doesn't have the given - * permission - */ - void enforcePermission(String permission, String message) throws SecurityException; - - /** - * @return true if {@link PackageManagerServiceUtils#compareSignatures} run on both packages - * in the system returns {@link PackageManager#SIGNATURE_MATCH} - */ - boolean signaturesMatching(@NonNull String pkgName1, @NonNull String pkgName2, int userId); -} diff --git a/services/core/java/com/android/server/om/PackageManagerHelper.java b/services/core/java/com/android/server/om/PackageManagerHelper.java index ec9c5e64e390f..b1a8b4ee4d9fd 100644 --- a/services/core/java/com/android/server/om/PackageManagerHelper.java +++ b/services/core/java/com/android/server/om/PackageManagerHelper.java @@ -17,11 +17,17 @@ package com.android.server.om; import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.om.OverlayableInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; +import com.android.server.pm.PackageManagerServiceUtils; + +import java.io.IOException; import java.util.List; +import java.util.Map; /** * Delegate for {@link PackageManager} and {@link PackageManagerInternal} functionality, @@ -30,7 +36,65 @@ import java.util.List; * @hide */ interface PackageManagerHelper { - PackageInfo getPackageInfo(@NonNull String packageName, int userId); - boolean signaturesMatching(@NonNull String pkgName1, @NonNull String pkgName2, int userId); + /** + * @return true if the target package has declared an overlayable + */ + boolean doesTargetDefineOverlayable(String targetPackageName, int userId) throws IOException; + + /** + * @throws SecurityException containing message if the caller doesn't have the given + * permission + */ + void enforcePermission(String permission, String message) throws SecurityException; + + /** + * Returns the package name of the reference package defined in 'overlay-config-signature' tag + * of SystemConfig. This package is vetted on scan by PackageManagerService that it's a system + * package and is used to check if overlay matches its signature in order to fulfill the + * config_signature policy. + */ + @Nullable + String getConfigSignaturePackage(); + + /** + * @return map of system pre-defined, uniquely named actors; keys are namespace, + * value maps actor name to package name + */ + @NonNull + Map> getNamedActors(); + + /** + * @see PackageManagerInternal#getOverlayPackages(int) + */ List getOverlayPackages(int userId); + + /** + * Read from the APK and AndroidManifest of a package to return the overlayable defined for + * a given name. + * + * @throws IOException if the target can't be read + */ + @Nullable + OverlayableInfo getOverlayableForTarget(@NonNull String packageName, + @NonNull String targetOverlayableName, int userId) + throws IOException; + + /** + * @see PackageManager#getPackagesForUid(int) + */ + @Nullable + String[] getPackagesForUid(int uid); + + /** + * @param userId user to filter package visibility by + * @see PackageManager#getPackageInfo(String, int) + */ + @Nullable + PackageInfo getPackageInfo(@NonNull String packageName, int userId); + + /** + * @return true if {@link PackageManagerServiceUtils#compareSignatures} run on both packages + * in the system returns {@link PackageManager#SIGNATURE_MATCH} + */ + boolean signaturesMatching(@NonNull String pkgName1, @NonNull String pkgName2, int userId); } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 4f0c707a1dae8..fddd46a9c026b 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -120,6 +120,7 @@ import static com.android.server.pm.InstructionSets.getDexCodeInstructionSet; import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets; import static com.android.server.pm.InstructionSets.getPreferredInstructionSet; import static com.android.server.pm.PackageManagerServiceCompilerMapping.getDefaultCompilerFilter; +import static com.android.server.pm.PackageManagerServiceUtils.comparePackageSignatures; import static com.android.server.pm.PackageManagerServiceUtils.compareSignatures; import static com.android.server.pm.PackageManagerServiceUtils.compressedFileExists; import static com.android.server.pm.PackageManagerServiceUtils.decompressFile; @@ -1114,6 +1115,7 @@ public class PackageManagerService extends IPackageManager.Stub public @Nullable String storageManagerPackage; public @Nullable String defaultTextClassifierPackage; public @Nullable String systemTextClassifierPackage; + public @Nullable String overlayConfigSignaturePackage; public ViewCompiler viewCompiler; public @Nullable String wellbeingPackage; public @Nullable String retailDemoPackage; @@ -1646,6 +1648,7 @@ public class PackageManagerService extends IPackageManager.Stub final @Nullable String mServicesExtensionPackageName; final @Nullable String mSharedSystemSharedLibraryPackageName; final @Nullable String mRetailDemoPackage; + final @Nullable String mOverlayConfigSignaturePackage; private final PackageUsage mPackageUsage = new PackageUsage(); private final CompilerStats mCompilerStats = new CompilerStats(); @@ -2808,6 +2811,7 @@ public class PackageManagerService extends IPackageManager.Stub mIncidentReportApproverPackage = testParams.incidentReportApproverPackage; mServicesExtensionPackageName = testParams.servicesExtensionPackageName; mSharedSystemSharedLibraryPackageName = testParams.sharedSystemSharedLibraryPackageName; + mOverlayConfigSignaturePackage = testParams.overlayConfigSignaturePackage; mResolveComponentName = testParams.resolveComponentName; mPackages.putAll(testParams.packages); @@ -3373,6 +3377,7 @@ public class PackageManagerService extends IPackageManager.Stub mAppPredictionServicePackage = getAppPredictionServicePackageName(); mIncidentReportApproverPackage = getIncidentReportApproverPackageName(); mRetailDemoPackage = getRetailDemoPackageName(); + mOverlayConfigSignaturePackage = getOverlayConfigSignaturePackageName(); // Now that we know all of the shared libraries, update all clients to have // the correct library paths. @@ -12096,12 +12101,8 @@ public class PackageManagerService extends IPackageManager.Stub if (sharedUserSetting != null && sharedUserSetting.isPrivileged()) { // Exempt SharedUsers signed with the platform key. PackageSetting platformPkgSetting = mSettings.mPackages.get("android"); - if ((platformPkgSetting.signatures.mSigningDetails - != PackageParser.SigningDetails.UNKNOWN) - && (compareSignatures( - platformPkgSetting.signatures.mSigningDetails.signatures, - pkg.getSigningDetails().signatures) - != PackageManager.SIGNATURE_MATCH)) { + if (!comparePackageSignatures(platformPkgSetting, + pkg.getSigningDetails().signatures)) { throw new PackageManagerException("Apps that share a user with a " + "privileged app must themselves be marked as privileged. " + pkg.getPackageName() + " shares privileged user " + @@ -12148,12 +12149,8 @@ public class PackageManagerService extends IPackageManager.Stub if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.Q) { final PackageSetting platformPkgSetting = mSettings.getPackageLPr("android"); - if ((platformPkgSetting.signatures.mSigningDetails - != PackageParser.SigningDetails.UNKNOWN) - && (compareSignatures( - platformPkgSetting.signatures.mSigningDetails.signatures, - pkg.getSigningDetails().signatures) - != PackageManager.SIGNATURE_MATCH)) { + if (!comparePackageSignatures(platformPkgSetting, + pkg.getSigningDetails().signatures)) { throw new PackageManagerException("Overlay " + pkg.getPackageName() + " must target Q or later, " @@ -12162,24 +12159,35 @@ public class PackageManagerService extends IPackageManager.Stub } // A non-preloaded overlay package, without , will - // only be used if it is signed with the same certificate as its target. If the - // target is already installed, check this here to augment the last line of - // defence which is OMS. + // only be used if it is signed with the same certificate as its target OR if + // it is signed with the same certificate as a reference package declared + // in 'config-signature' tag of SystemConfig. + // If the target is already installed or 'config-signature' tag in SystemConfig + // is set, check this here to augment the last line of defence which is OMS. if (pkg.getOverlayTargetName() == null) { final PackageSetting targetPkgSetting = mSettings.getPackageLPr(pkg.getOverlayTarget()); if (targetPkgSetting != null) { - if ((targetPkgSetting.signatures.mSigningDetails - != PackageParser.SigningDetails.UNKNOWN) - && (compareSignatures( - targetPkgSetting.signatures.mSigningDetails.signatures, - pkg.getSigningDetails().signatures) - != PackageManager.SIGNATURE_MATCH)) { - throw new PackageManagerException("Overlay " - + pkg.getPackageName() + " and target " - + pkg.getOverlayTarget() + " signed with" - + " different certificates, and the overlay lacks" - + " "); + if (!comparePackageSignatures(targetPkgSetting, + pkg.getSigningDetails().signatures)) { + // check reference signature + if (mOverlayConfigSignaturePackage == null) { + throw new PackageManagerException("Overlay " + + pkg.getPackageName() + " and target " + + pkg.getOverlayTarget() + " signed with" + + " different certificates, and the overlay lacks" + + " "); + } + final PackageSetting refPkgSetting = + mSettings.getPackageLPr(mOverlayConfigSignaturePackage); + if (!comparePackageSignatures(refPkgSetting, + pkg.getSigningDetails().signatures)) { + throw new PackageManagerException("Overlay " + + pkg.getPackageName() + " signed with a different " + + "certificate than both the reference package and " + + "target " + pkg.getOverlayTarget() + ", and the " + + "overlay lacks "); + } } } } @@ -20712,6 +20720,11 @@ public class PackageManagerService extends IPackageManager.Stub return ensureSystemPackageName(contentCaptureServiceComponentName.getPackageName()); } + public String getOverlayConfigSignaturePackageName() { + return ensureSystemPackageName(SystemConfig.getInstance() + .getOverlayConfigSignaturePackage()); + } + @Nullable private String getRetailDemoPackageName() { final String predefinedPkgName = mContext.getString(R.string.config_retailDemoPackage); @@ -24228,6 +24241,8 @@ public class PackageManagerService extends IPackageManager.Stub return TextUtils.isEmpty(mRetailDemoPackage) ? ArrayUtils.emptyArray(String.class) : new String[] {mRetailDemoPackage}; + case PackageManagerInternal.PACKAGE_OVERLAY_CONFIG_SIGNATURE: + return filterOnlySystemPackages(getOverlayConfigSignaturePackageName()); default: return ArrayUtils.emptyArray(String.class); } diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java index 03f4708c09c4a..de0e4b53adabf 100644 --- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java +++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java @@ -487,6 +487,18 @@ public class PackageManagerServiceUtils { return PackageManager.SIGNATURE_NO_MATCH; } + /** + * Returns true if the signature set of the package is identical to the specified signature + * set or if the signing details of the package are unknown. + */ + public static boolean comparePackageSignatures(PackageSetting pkgSetting, + Signature[] signatures) { + return pkgSetting.signatures.mSigningDetails + == PackageParser.SigningDetails.UNKNOWN + || compareSignatures(pkgSetting.signatures.mSigningDetails.signatures, signatures) + == PackageManager.SIGNATURE_MATCH; + } + /** * Used for backward compatibility to make sure any packages with * certificate chains get upgraded to the new style. {@code existingSigs} diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayActorEnforcerTests.kt b/services/tests/servicestests/src/com/android/server/om/OverlayActorEnforcerTests.kt index e08eea298aaf7..08392737350af 100644 --- a/services/tests/servicestests/src/com/android/server/om/OverlayActorEnforcerTests.kt +++ b/services/tests/servicestests/src/com/android/server/om/OverlayActorEnforcerTests.kt @@ -160,7 +160,7 @@ class OverlayActorEnforcerTests { private val hasPermission: Boolean = false, private val overlayableInfo: OverlayableInfo? = null, private vararg val packageNames: String = arrayOf("com.test.actor.one") - ) : OverlayableInfoCallback { + ) : PackageManagerHelper { override fun getNamedActors() = if (isActor) { mapOf(NAMESPACE to mapOf(ACTOR_NAME to ACTOR_PKG_NAME)) @@ -195,6 +195,14 @@ class OverlayActorEnforcerTests { } } + override fun getConfigSignaturePackage(): String { + throw UnsupportedOperationException() + } + + override fun getOverlayPackages(userId: Int): MutableList { + throw UnsupportedOperationException() + } + override fun signaturesMatching(pkgName1: String, pkgName2: String, userId: Int): Boolean { throw UnsupportedOperationException() } diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplRebootTests.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplRebootTests.java index b7692f912e393..e281f2b206f59 100644 --- a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplRebootTests.java +++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplRebootTests.java @@ -44,9 +44,9 @@ public class OverlayManagerServiceImplRebootTests extends OverlayManagerServiceI @Test public void testUpdateOverlaysForUser() { final OverlayManagerServiceImpl impl = getImpl(); - addSystemPackage(target(TARGET), USER); - addSystemPackage(target("some.other.target"), USER);; - addSystemPackage(overlay(OVERLAY, TARGET), USER); + addPackage(target(TARGET), USER); + addPackage(target("some.other.target"), USER); + addPackage(overlay(OVERLAY, TARGET), USER); // do nothing, expect no change final List a = impl.updateOverlaysForUser(USER); @@ -54,7 +54,7 @@ public class OverlayManagerServiceImplRebootTests extends OverlayManagerServiceI assertTrue(a.contains(TARGET)); // upgrade overlay, keep target - addSystemPackage(overlay(OVERLAY, TARGET), USER); + addPackage(overlay(OVERLAY, TARGET), USER); final List b = impl.updateOverlaysForUser(USER); assertEquals(1, b.size()); @@ -66,7 +66,7 @@ public class OverlayManagerServiceImplRebootTests extends OverlayManagerServiceI assertTrue(c.contains(TARGET)); // upgrade overlay, switch to new target - addSystemPackage(overlay(OVERLAY, "some.other.target"), USER); + addPackage(overlay(OVERLAY, "some.other.target"), USER); final List d = impl.updateOverlaysForUser(USER); assertEquals(2, d.size()); assertTrue(d.containsAll(Arrays.asList(TARGET, "some.other.target"))); diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java index f4c5506c7001b..c1d862ab2ad4b 100644 --- a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java +++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java @@ -19,6 +19,7 @@ package com.android.server.om; import static android.content.om.OverlayInfo.STATE_DISABLED; import static android.content.om.OverlayInfo.STATE_ENABLED; import static android.content.om.OverlayInfo.STATE_MISSING_TARGET; +import static android.os.OverlayablePolicy.CONFIG_SIGNATURE; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -49,6 +50,10 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes private static final String OVERLAY3 = OVERLAY + "3"; private static final int USER3 = USER2 + 1; + private static final String CONFIG_SIGNATURE_REFERENCE_PKG = "com.dummy.ref"; + private static final String CERT_CONFIG_OK = "config_certificate_ok"; + private static final String CERT_CONFIG_NOK = "config_certificate_nok"; + @Test public void testGetOverlayInfo() { installNewPackage(overlay(OVERLAY, TARGET), USER); @@ -204,4 +209,87 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes impl.setEnabled(OVERLAY, true, USER); assertEquals(0, listener.count); } + + @Test + public void testConfigSignaturePolicyOk() { + setConfigSignaturePackageName(CONFIG_SIGNATURE_REFERENCE_PKG); + reinitializeImpl(); + + addPackage(target(CONFIG_SIGNATURE_REFERENCE_PKG).setCertificate(CERT_CONFIG_OK), USER); + installNewPackage(target(TARGET), USER); + installNewPackage(overlay(OVERLAY, TARGET).setCertificate(CERT_CONFIG_OK), USER); + + final DummyIdmapDaemon idmapd = getIdmapd(); + final DummyDeviceState state = getState(); + String overlayPath = state.select(OVERLAY, USER).apkPath; + assertTrue(idmapd.idmapExists(overlayPath, USER)); + + DummyIdmapDaemon.IdmapHeader idmap = idmapd.getIdmap(overlayPath); + assertTrue((CONFIG_SIGNATURE & idmap.policies) == CONFIG_SIGNATURE); + } + + @Test + public void testConfigSignaturePolicyCertNok() { + setConfigSignaturePackageName(CONFIG_SIGNATURE_REFERENCE_PKG); + reinitializeImpl(); + + addPackage(target(CONFIG_SIGNATURE_REFERENCE_PKG).setCertificate(CERT_CONFIG_OK), USER); + installNewPackage(target(TARGET), USER); + installNewPackage(overlay(OVERLAY, TARGET).setCertificate(CERT_CONFIG_NOK), USER); + + final DummyIdmapDaemon idmapd = getIdmapd(); + final DummyDeviceState state = getState(); + String overlayPath = state.select(OVERLAY, USER).apkPath; + assertTrue(idmapd.idmapExists(overlayPath, USER)); + + DummyIdmapDaemon.IdmapHeader idmap = idmapd.getIdmap(overlayPath); + assertTrue((CONFIG_SIGNATURE & idmap.policies) == 0); + } + + @Test + public void testConfigSignaturePolicyNoConfig() { + addPackage(target(CONFIG_SIGNATURE_REFERENCE_PKG).setCertificate(CERT_CONFIG_OK), USER); + installNewPackage(target(TARGET), USER); + installNewPackage(overlay(OVERLAY, TARGET).setCertificate(CERT_CONFIG_NOK), USER); + + final DummyIdmapDaemon idmapd = getIdmapd(); + final DummyDeviceState state = getState(); + String overlayPath = state.select(OVERLAY, USER).apkPath; + assertTrue(idmapd.idmapExists(overlayPath, USER)); + + DummyIdmapDaemon.IdmapHeader idmap = idmapd.getIdmap(overlayPath); + assertTrue((CONFIG_SIGNATURE & idmap.policies) == 0); + } + + @Test + public void testConfigSignaturePolicyNoRefPkg() { + installNewPackage(target(TARGET), USER); + installNewPackage(overlay(OVERLAY, TARGET).setCertificate(CERT_CONFIG_NOK), USER); + + final DummyIdmapDaemon idmapd = getIdmapd(); + final DummyDeviceState state = getState(); + String overlayPath = state.select(OVERLAY, USER).apkPath; + assertTrue(idmapd.idmapExists(overlayPath, USER)); + + DummyIdmapDaemon.IdmapHeader idmap = idmapd.getIdmap(overlayPath); + assertTrue((CONFIG_SIGNATURE & idmap.policies) == 0); + } + + @Test + public void testConfigSignaturePolicyRefPkgNotSystem() { + setConfigSignaturePackageName(CONFIG_SIGNATURE_REFERENCE_PKG); + reinitializeImpl(); + + addPackage(app(CONFIG_SIGNATURE_REFERENCE_PKG).setCertificate(CERT_CONFIG_OK), USER); + installNewPackage(target(TARGET), USER); + installNewPackage(overlay(OVERLAY, TARGET).setCertificate(CERT_CONFIG_NOK), USER); + + final DummyIdmapDaemon idmapd = getIdmapd(); + final DummyDeviceState state = getState(); + String overlayPath = state.select(OVERLAY, USER).apkPath; + assertTrue(idmapd.idmapExists(overlayPath, USER)); + + DummyIdmapDaemon.IdmapHeader idmap = idmapd.getIdmap(overlayPath); + assertTrue((CONFIG_SIGNATURE & idmap.policies) == 0); + } } diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java index 733310b2508a2..2faf29f453759 100644 --- a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java +++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java @@ -27,6 +27,7 @@ import android.content.om.OverlayInfo.State; import android.content.om.OverlayableInfo; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; +import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; @@ -52,6 +53,7 @@ class OverlayManagerServiceImplTestsBase { private DummyPackageManagerHelper mPackageManager; private DummyIdmapDaemon mIdmapDaemon; private OverlayConfig mOverlayConfig; + private String mConfigSignaturePackageName; @Before public void setUp() { @@ -83,6 +85,18 @@ class OverlayManagerServiceImplTestsBase { return mListener; } + DummyIdmapDaemon getIdmapd() { + return mIdmapDaemon; + } + + DummyDeviceState getState() { + return mState; + } + + void setConfigSignaturePackageName(String packageName) { + mConfigSignaturePackageName = packageName; + } + void assertState(@State int expected, final String overlayPackageName, int userId) { final OverlayInfo info = mImpl.getOverlayInfo(overlayPackageName, userId); if (info == null) { @@ -102,9 +116,14 @@ class OverlayManagerServiceImplTestsBase { assertEquals(expected, actual); } + DummyDeviceState.PackageBuilder app(String packageName) { + return new DummyDeviceState.PackageBuilder(packageName, null /* targetPackageName */, + null /* targetOverlayableName */, "data"); + } + DummyDeviceState.PackageBuilder target(String packageName) { return new DummyDeviceState.PackageBuilder(packageName, null /* targetPackageName */, - null /* targetOverlayableName */); + null /* targetOverlayableName */, ""); } DummyDeviceState.PackageBuilder overlay(String packageName, String targetPackageName) { @@ -114,10 +133,10 @@ class OverlayManagerServiceImplTestsBase { DummyDeviceState.PackageBuilder overlay(String packageName, String targetPackageName, String targetOverlayableName) { return new DummyDeviceState.PackageBuilder(packageName, targetPackageName, - targetOverlayableName); + targetOverlayableName, ""); } - void addSystemPackage(DummyDeviceState.PackageBuilder pkg, int userId) { + void addPackage(DummyDeviceState.PackageBuilder pkg, int userId) { mState.add(pkg, userId); } @@ -242,15 +261,17 @@ class OverlayManagerServiceImplTestsBase { private String packageName; private String targetPackage; private String certificate = "[default]"; + private String partition; private int version = 0; private ArrayList overlayableNames = new ArrayList<>(); private String targetOverlayableName; private PackageBuilder(String packageName, String targetPackage, - String targetOverlayableName) { + String targetOverlayableName, String partition) { this.packageName = packageName; this.targetPackage = targetPackage; this.targetOverlayableName = targetOverlayableName; + this.partition = partition; } PackageBuilder setCertificate(String certificate) { @@ -269,9 +290,19 @@ class OverlayManagerServiceImplTestsBase { } Package build() { - final String apkPath = String.format("%s/%s/base.apk", - targetPackage == null ? "/system/app/:" : "/vendor/overlay/:", - packageName); + String path = ""; + if (TextUtils.isEmpty(partition)) { + if (targetPackage == null) { + path = "/system/app"; + } else { + path = "/vendor/overlay"; + } + } else { + String type = targetPackage == null ? "app" : "overlay"; + path = String.format("%s/%s", partition, type); + } + + final String apkPath = String.format("%s/%s/base.apk", path, packageName); final Package newPackage = new Package(packageName, targetPackage, targetOverlayableName, version, apkPath, certificate); newPackage.overlayableNames.addAll(overlayableNames); @@ -302,8 +333,7 @@ class OverlayManagerServiceImplTestsBase { } } - static final class DummyPackageManagerHelper implements PackageManagerHelper, - OverlayableInfoCallback { + final class DummyPackageManagerHelper implements PackageManagerHelper { private final DummyDeviceState mState; private DummyPackageManagerHelper(DummyDeviceState state) { @@ -343,6 +373,11 @@ class OverlayManagerServiceImplTestsBase { .collect(Collectors.toList()); } + @Override + public @NonNull String getConfigSignaturePackage() { + return mConfigSignaturePackageName; + } + @Nullable @Override public OverlayableInfo getOverlayableForTarget(@NonNull String packageName, diff --git a/tools/aapt2/Resources.proto b/tools/aapt2/Resources.proto index ab9ce66b0ae3a..b1e1a77e12240 100644 --- a/tools/aapt2/Resources.proto +++ b/tools/aapt2/Resources.proto @@ -168,6 +168,7 @@ message OverlayableItem { ODM = 6; OEM = 7; ACTOR = 8; + CONFIG_SIGNATURE = 9; } // The location of the declaration in source. diff --git a/tools/aapt2/format/binary/TableFlattener_test.cpp b/tools/aapt2/format/binary/TableFlattener_test.cpp index 59627ce579afe..6932baf76c75c 100644 --- a/tools/aapt2/format/binary/TableFlattener_test.cpp +++ b/tools/aapt2/format/binary/TableFlattener_test.cpp @@ -776,6 +776,7 @@ TEST_F(TableFlattenerTest, FlattenMultipleOverlayable) { OverlayableItem overlayable_item_three(group_one); overlayable_item_three.policies |= PolicyFlags::SIGNATURE; overlayable_item_three.policies |= PolicyFlags::ACTOR_SIGNATURE; + overlayable_item_three.policies |= PolicyFlags::CONFIG_SIGNATURE; std::unique_ptr table = test::ResourceTableBuilder() @@ -830,7 +831,8 @@ TEST_F(TableFlattenerTest, FlattenMultipleOverlayable) { EXPECT_EQ(result_overlayable.overlayable->name, "OtherName"); EXPECT_EQ(result_overlayable.overlayable->actor, "overlay://customization"); EXPECT_EQ(result_overlayable.policies, PolicyFlags::SIGNATURE - | PolicyFlags::ACTOR_SIGNATURE); + | PolicyFlags::ACTOR_SIGNATURE + | PolicyFlags::CONFIG_SIGNATURE); } TEST_F(TableFlattenerTest, FlattenOverlayableNoPolicyFails) { diff --git a/tools/aapt2/format/proto/ProtoDeserialize.cpp b/tools/aapt2/format/proto/ProtoDeserialize.cpp index 2fd01d7f3dee4..7eb8ebd9a0433 100644 --- a/tools/aapt2/format/proto/ProtoDeserialize.cpp +++ b/tools/aapt2/format/proto/ProtoDeserialize.cpp @@ -404,6 +404,9 @@ bool DeserializeOverlayableItemFromPb(const pb::OverlayableItem& pb_overlayable, case pb::OverlayableItem::ACTOR: out_overlayable->policies |= PolicyFlags::ACTOR_SIGNATURE; break; + case pb::OverlayableItem::CONFIG_SIGNATURE: + out_overlayable->policies |= PolicyFlags::CONFIG_SIGNATURE; + break; default: *out_error = "unknown overlayable policy"; return false; diff --git a/tools/aapt2/format/proto/ProtoSerialize.cpp b/tools/aapt2/format/proto/ProtoSerialize.cpp index ba6df22af9d3a..831229ffa3832 100644 --- a/tools/aapt2/format/proto/ProtoSerialize.cpp +++ b/tools/aapt2/format/proto/ProtoSerialize.cpp @@ -325,6 +325,9 @@ static void SerializeOverlayableItemToPb(const OverlayableItem& overlayable_item if (overlayable_item.policies & PolicyFlags::ACTOR_SIGNATURE) { pb_overlayable_item->add_policy(pb::OverlayableItem::ACTOR); } + if (overlayable_item.policies & PolicyFlags::CONFIG_SIGNATURE) { + pb_overlayable_item->add_policy(pb::OverlayableItem::CONFIG_SIGNATURE); + } if (source_pool != nullptr) { SerializeSourceToPb(overlayable_item.source, source_pool,