1*33f37583SAndroid Build Coastguard Worker /* 2*33f37583SAndroid Build Coastguard Worker * Copyright (C) 2019 The Android Open Source Project 3*33f37583SAndroid Build Coastguard Worker * 4*33f37583SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License"); 5*33f37583SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License. 6*33f37583SAndroid Build Coastguard Worker * You may obtain a copy of the License at 7*33f37583SAndroid Build Coastguard Worker * 8*33f37583SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0 9*33f37583SAndroid Build Coastguard Worker * 10*33f37583SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software 11*33f37583SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS, 12*33f37583SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*33f37583SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and 14*33f37583SAndroid Build Coastguard Worker * limitations under the License. 15*33f37583SAndroid Build Coastguard Worker */ 16*33f37583SAndroid Build Coastguard Worker 17*33f37583SAndroid Build Coastguard Worker #pragma once 18*33f37583SAndroid Build Coastguard Worker 19*33f37583SAndroid Build Coastguard Worker #include <android-base/result.h> 20*33f37583SAndroid Build Coastguard Worker 21*33f37583SAndroid Build Coastguard Worker #include <functional> 22*33f37583SAndroid Build Coastguard Worker #include <optional> 23*33f37583SAndroid Build Coastguard Worker #include <string> 24*33f37583SAndroid Build Coastguard Worker #include <unordered_map> 25*33f37583SAndroid Build Coastguard Worker #include <unordered_set> 26*33f37583SAndroid Build Coastguard Worker #include <vector> 27*33f37583SAndroid Build Coastguard Worker 28*33f37583SAndroid Build Coastguard Worker #include "apex_constants.h" 29*33f37583SAndroid Build Coastguard Worker #include "apex_file.h" 30*33f37583SAndroid Build Coastguard Worker 31*33f37583SAndroid Build Coastguard Worker namespace android::apex { 32*33f37583SAndroid Build Coastguard Worker 33*33f37583SAndroid Build Coastguard Worker using ApexFileRef = std::reference_wrapper<const android::apex::ApexFile>; 34*33f37583SAndroid Build Coastguard Worker 35*33f37583SAndroid Build Coastguard Worker // This class serves as a ApexFile repository for all apexes on device. It also 36*33f37583SAndroid Build Coastguard Worker // provides information about the ApexFiles it hosts, such as which are 37*33f37583SAndroid Build Coastguard Worker // pre-installed and which are data. Such information can be used, for example, 38*33f37583SAndroid Build Coastguard Worker // to verify validity of an apex before trying to mount it. 39*33f37583SAndroid Build Coastguard Worker // 40*33f37583SAndroid Build Coastguard Worker // It's expected to have a single instance of this class in a process that 41*33f37583SAndroid Build Coastguard Worker // mounts apexes (e.g. apexd, otapreopt_chroot). 42*33f37583SAndroid Build Coastguard Worker class ApexFileRepository final { 43*33f37583SAndroid Build Coastguard Worker public: 44*33f37583SAndroid Build Coastguard Worker // c-tors and d-tor are exposed for testing. 45*33f37583SAndroid Build Coastguard Worker explicit ApexFileRepository( 46*33f37583SAndroid Build Coastguard Worker const std::string& decompression_dir = kApexDecompressedDir) decompression_dir_(decompression_dir)47*33f37583SAndroid Build Coastguard Worker : decompression_dir_(decompression_dir) {} ApexFileRepository(bool enforce_multi_install_partition,const std::vector<std::string> & multi_install_select_prop_prefixes)48*33f37583SAndroid Build Coastguard Worker explicit ApexFileRepository( 49*33f37583SAndroid Build Coastguard Worker bool enforce_multi_install_partition, 50*33f37583SAndroid Build Coastguard Worker const std::vector<std::string>& multi_install_select_prop_prefixes) 51*33f37583SAndroid Build Coastguard Worker : multi_install_select_prop_prefixes_(multi_install_select_prop_prefixes), 52*33f37583SAndroid Build Coastguard Worker enforce_multi_install_partition_(enforce_multi_install_partition) {} 53*33f37583SAndroid Build Coastguard Worker 54*33f37583SAndroid Build Coastguard Worker // Returns a singletone instance of this class. 55*33f37583SAndroid Build Coastguard Worker static ApexFileRepository& GetInstance(); 56*33f37583SAndroid Build Coastguard Worker 57*33f37583SAndroid Build Coastguard Worker // Populate instance by collecting pre-installed apex files from the given 58*33f37583SAndroid Build Coastguard Worker // |partition_to_prebuilt_dirs|. 59*33f37583SAndroid Build Coastguard Worker // Note: this call is **not thread safe** and is expected to be performed in a 60*33f37583SAndroid Build Coastguard Worker // single thread during initialization of apexd. After initialization is 61*33f37583SAndroid Build Coastguard Worker // finished, all queries to the instance are thread safe. 62*33f37583SAndroid Build Coastguard Worker android::base::Result<void> AddPreInstalledApex( 63*33f37583SAndroid Build Coastguard Worker const std::unordered_map<ApexPartition, std::string>& 64*33f37583SAndroid Build Coastguard Worker partition_to_prebuilt_dirs); 65*33f37583SAndroid Build Coastguard Worker 66*33f37583SAndroid Build Coastguard Worker // Populate instance by collecting host-provided apex files via 67*33f37583SAndroid Build Coastguard Worker // |metadata_partition|. Host can provide its apexes to a VM instance via the 68*33f37583SAndroid Build Coastguard Worker // virtual disk image which has partitions: (see 69*33f37583SAndroid Build Coastguard Worker // /packages/modules/Virtualization/microdroid for the details) 70*33f37583SAndroid Build Coastguard Worker // - metadata partition(/dev/block/vd*1) should be accessed by 71*33f37583SAndroid Build Coastguard Worker // setting the system property apexd.payload_metadata.prop. On microdroid, 72*33f37583SAndroid Build Coastguard Worker // this is /dev/block/by-name/payload-metadata. 73*33f37583SAndroid Build Coastguard Worker // - each subsequence partition(/dev/block/vd*{2,3,..}) represents an APEX 74*33f37583SAndroid Build Coastguard Worker // archive. 75*33f37583SAndroid Build Coastguard Worker // It will fail if there is more than one apex with the same name in 76*33f37583SAndroid Build Coastguard Worker // pre-installed and block apexes. Note: this call is **not thread safe** and 77*33f37583SAndroid Build Coastguard Worker // is expected to be performed in a single thread during initialization of 78*33f37583SAndroid Build Coastguard Worker // apexd. After initialization is finished, all queries to the instance are 79*33f37583SAndroid Build Coastguard Worker // thread safe. 80*33f37583SAndroid Build Coastguard Worker // This will return the number of block apexes that were added. 81*33f37583SAndroid Build Coastguard Worker android::base::Result<int> AddBlockApex( 82*33f37583SAndroid Build Coastguard Worker const std::string& metadata_partition); 83*33f37583SAndroid Build Coastguard Worker 84*33f37583SAndroid Build Coastguard Worker // Populate instance by collecting data apex files from the given |data_dir|. 85*33f37583SAndroid Build Coastguard Worker // Note: this call is **not thread safe** and is expected to be performed in a 86*33f37583SAndroid Build Coastguard Worker // single thread during initialization of apexd. After initialization is 87*33f37583SAndroid Build Coastguard Worker // finished, all queries to the instance are thread safe. 88*33f37583SAndroid Build Coastguard Worker android::base::Result<void> AddDataApex(const std::string& data_dir); 89*33f37583SAndroid Build Coastguard Worker 90*33f37583SAndroid Build Coastguard Worker // Populates instance by collecting pre-installed credential files (.avbpubkey 91*33f37583SAndroid Build Coastguard Worker // for now) and blocklist files from the given directories. They are needed 92*33f37583SAndroid Build Coastguard Worker // specifically for brand-new APEX. 93*33f37583SAndroid Build Coastguard Worker // Note: this call is **not thread safe** and 94*33f37583SAndroid Build Coastguard Worker // is expected to be performed in a single thread during initialization of 95*33f37583SAndroid Build Coastguard Worker // apexd. After initialization is finished, all queries to the instance are 96*33f37583SAndroid Build Coastguard Worker // thread safe. 97*33f37583SAndroid Build Coastguard Worker android::base::Result<void> AddBrandNewApexCredentialAndBlocklist( 98*33f37583SAndroid Build Coastguard Worker const std::unordered_map<ApexPartition, std::string>& 99*33f37583SAndroid Build Coastguard Worker partition_to_dir_map); 100*33f37583SAndroid Build Coastguard Worker 101*33f37583SAndroid Build Coastguard Worker // Returns the mapping partition of a specific apex. 102*33f37583SAndroid Build Coastguard Worker // For pre-installed APEX, it is the partition where the pre-installed package 103*33f37583SAndroid Build Coastguard Worker // resides. For brand-new APEX, it is the partition where the 104*33f37583SAndroid Build Coastguard Worker // credentials to verify the package reside. 105*33f37583SAndroid Build Coastguard Worker android::base::Result<ApexPartition> GetPartition(const ApexFile& apex) const; 106*33f37583SAndroid Build Coastguard Worker 107*33f37583SAndroid Build Coastguard Worker // Returns trusted public key for an apex with the given |name|. 108*33f37583SAndroid Build Coastguard Worker android::base::Result<const std::string> GetPublicKey( 109*33f37583SAndroid Build Coastguard Worker const std::string& name) const; 110*33f37583SAndroid Build Coastguard Worker 111*33f37583SAndroid Build Coastguard Worker // Returns path to the pre-installed version of an apex with the given |name|. 112*33f37583SAndroid Build Coastguard Worker // For brand-new APEX, returns Error. 113*33f37583SAndroid Build Coastguard Worker // For block APEX which is not set as factory, returns Error. 114*33f37583SAndroid Build Coastguard Worker android::base::Result<const std::string> GetPreinstalledPath( 115*33f37583SAndroid Build Coastguard Worker const std::string& name) const; 116*33f37583SAndroid Build Coastguard Worker 117*33f37583SAndroid Build Coastguard Worker // Returns path to the data version of an apex with the given |name|. 118*33f37583SAndroid Build Coastguard Worker android::base::Result<const std::string> GetDataPath( 119*33f37583SAndroid Build Coastguard Worker const std::string& name) const; 120*33f37583SAndroid Build Coastguard Worker 121*33f37583SAndroid Build Coastguard Worker // Returns root digest of an apex with the given |path| for block apexes. 122*33f37583SAndroid Build Coastguard Worker std::optional<std::string> GetBlockApexRootDigest( 123*33f37583SAndroid Build Coastguard Worker const std::string& path) const; 124*33f37583SAndroid Build Coastguard Worker 125*33f37583SAndroid Build Coastguard Worker // Returns timestamp to be used for the block apex of the given |path|. 126*33f37583SAndroid Build Coastguard Worker std::optional<int64_t> GetBlockApexLastUpdateSeconds( 127*33f37583SAndroid Build Coastguard Worker const std::string& path) const; 128*33f37583SAndroid Build Coastguard Worker 129*33f37583SAndroid Build Coastguard Worker // Checks whether there is a pre-installed version of an apex with the given 130*33f37583SAndroid Build Coastguard Worker // |name|. 131*33f37583SAndroid Build Coastguard Worker bool HasPreInstalledVersion(const std::string& name) const; 132*33f37583SAndroid Build Coastguard Worker 133*33f37583SAndroid Build Coastguard Worker // Checks whether there is a data version of an apex with the given |name|. 134*33f37583SAndroid Build Coastguard Worker bool HasDataVersion(const std::string& name) const; 135*33f37583SAndroid Build Coastguard Worker 136*33f37583SAndroid Build Coastguard Worker // Checks if given |apex| is pre-installed. 137*33f37583SAndroid Build Coastguard Worker bool IsPreInstalledApex(const ApexFile& apex) const; 138*33f37583SAndroid Build Coastguard Worker 139*33f37583SAndroid Build Coastguard Worker // Checks if given |apex| is decompressed from a pre-installed APEX 140*33f37583SAndroid Build Coastguard Worker bool IsDecompressedApex(const ApexFile& apex) const; 141*33f37583SAndroid Build Coastguard Worker 142*33f37583SAndroid Build Coastguard Worker // Checks if given |apex| is loaded from block device. 143*33f37583SAndroid Build Coastguard Worker bool IsBlockApex(const ApexFile& apex) const; 144*33f37583SAndroid Build Coastguard Worker 145*33f37583SAndroid Build Coastguard Worker // Returns reference to all pre-installed APEX on device 146*33f37583SAndroid Build Coastguard Worker std::vector<ApexFileRef> GetPreInstalledApexFiles() const; 147*33f37583SAndroid Build Coastguard Worker 148*33f37583SAndroid Build Coastguard Worker // Returns reference to all data APEX on device 149*33f37583SAndroid Build Coastguard Worker std::vector<ApexFileRef> GetDataApexFiles() const; 150*33f37583SAndroid Build Coastguard Worker 151*33f37583SAndroid Build Coastguard Worker // Returns the partition of the pre-installed public key which exactly matches 152*33f37583SAndroid Build Coastguard Worker // the |public_key|. 153*33f37583SAndroid Build Coastguard Worker std::optional<ApexPartition> GetBrandNewApexPublicKeyPartition( 154*33f37583SAndroid Build Coastguard Worker const std::string& public_key) const; 155*33f37583SAndroid Build Coastguard Worker 156*33f37583SAndroid Build Coastguard Worker // Returns the blocked version number of a specific brand-new APEX in a 157*33f37583SAndroid Build Coastguard Worker // specific partition. The brand-new APEX is only allowed when its version is 158*33f37583SAndroid Build Coastguard Worker // larger than the blocked version. 159*33f37583SAndroid Build Coastguard Worker // Returns |std::nullopt| if the |apex_name| is not configured in blocklist. 160*33f37583SAndroid Build Coastguard Worker std::optional<int64_t> GetBrandNewApexBlockedVersion( 161*33f37583SAndroid Build Coastguard Worker ApexPartition partition, const std::string& apex_name) const; 162*33f37583SAndroid Build Coastguard Worker 163*33f37583SAndroid Build Coastguard Worker // Group all ApexFiles on device by their package name 164*33f37583SAndroid Build Coastguard Worker std::unordered_map<std::string, std::vector<ApexFileRef>> AllApexFilesByName() 165*33f37583SAndroid Build Coastguard Worker const; 166*33f37583SAndroid Build Coastguard Worker 167*33f37583SAndroid Build Coastguard Worker // Returns a pre-installed version of apex with the given name. Caller is 168*33f37583SAndroid Build Coastguard Worker // expected to check if there is a pre-installed apex with the given name 169*33f37583SAndroid Build Coastguard Worker // using |HasPreinstalledVersion| function. 170*33f37583SAndroid Build Coastguard Worker ApexFileRef GetPreInstalledApex(const std::string& name) const; 171*33f37583SAndroid Build Coastguard Worker // Returns a data version of apex with the given name. Caller is 172*33f37583SAndroid Build Coastguard Worker // expected to check if there is a data apex with the given name 173*33f37583SAndroid Build Coastguard Worker // using |HasDataVersion| function. 174*33f37583SAndroid Build Coastguard Worker ApexFileRef GetDataApex(const std::string& name) const; 175*33f37583SAndroid Build Coastguard Worker 176*33f37583SAndroid Build Coastguard Worker // Returns if installation of brand-new APEX is enabled. IsBrandNewApexEnabled()177*33f37583SAndroid Build Coastguard Worker static inline bool IsBrandNewApexEnabled() { return enable_brand_new_apex_; }; 178*33f37583SAndroid Build Coastguard Worker 179*33f37583SAndroid Build Coastguard Worker // Enables installation of brand-new APEX. EnableBrandNewApex()180*33f37583SAndroid Build Coastguard Worker static inline void EnableBrandNewApex() { enable_brand_new_apex_ = true; }; 181*33f37583SAndroid Build Coastguard Worker 182*33f37583SAndroid Build Coastguard Worker // Clears ApexFileRepostiry. 183*33f37583SAndroid Build Coastguard Worker // Only use in tests. 184*33f37583SAndroid Build Coastguard Worker void Reset(const std::string& decompression_dir = kApexDecompressedDir) { 185*33f37583SAndroid Build Coastguard Worker pre_installed_store_.clear(); 186*33f37583SAndroid Build Coastguard Worker data_store_.clear(); 187*33f37583SAndroid Build Coastguard Worker partition_store_.clear(); 188*33f37583SAndroid Build Coastguard Worker brand_new_apex_blocked_version_.clear(); 189*33f37583SAndroid Build Coastguard Worker brand_new_apex_pubkeys_.clear(); 190*33f37583SAndroid Build Coastguard Worker block_apex_overrides_.clear(); 191*33f37583SAndroid Build Coastguard Worker decompression_dir_ = decompression_dir; 192*33f37583SAndroid Build Coastguard Worker block_disk_path_.reset(); 193*33f37583SAndroid Build Coastguard Worker enable_brand_new_apex_ = false; 194*33f37583SAndroid Build Coastguard Worker } 195*33f37583SAndroid Build Coastguard Worker 196*33f37583SAndroid Build Coastguard Worker private: 197*33f37583SAndroid Build Coastguard Worker // Non-copyable && non-moveable. 198*33f37583SAndroid Build Coastguard Worker ApexFileRepository(const ApexFileRepository&) = delete; 199*33f37583SAndroid Build Coastguard Worker ApexFileRepository& operator=(const ApexFileRepository&) = delete; 200*33f37583SAndroid Build Coastguard Worker ApexFileRepository& operator=(ApexFileRepository&&) = delete; 201*33f37583SAndroid Build Coastguard Worker ApexFileRepository(ApexFileRepository&&) = delete; 202*33f37583SAndroid Build Coastguard Worker 203*33f37583SAndroid Build Coastguard Worker // Scans apexes in the given directory and adds collected data into 204*33f37583SAndroid Build Coastguard Worker // |pre_installed_store_| and |partition_store_|. 205*33f37583SAndroid Build Coastguard Worker android::base::Result<void> ScanBuiltInDir(const std::string& dir, 206*33f37583SAndroid Build Coastguard Worker ApexPartition partition); 207*33f37583SAndroid Build Coastguard Worker 208*33f37583SAndroid Build Coastguard Worker std::unordered_map<std::string, ApexFile> pre_installed_store_, data_store_; 209*33f37583SAndroid Build Coastguard Worker 210*33f37583SAndroid Build Coastguard Worker // Map from APEX name to their partition. For pre-installed APEX, this is the 211*33f37583SAndroid Build Coastguard Worker // partition where it is pre-installed. For brand-new APEX, this is the 212*33f37583SAndroid Build Coastguard Worker // partition where its credential is pre-installed. 213*33f37583SAndroid Build Coastguard Worker std::unordered_map<std::string, ApexPartition> partition_store_; 214*33f37583SAndroid Build Coastguard Worker 215*33f37583SAndroid Build Coastguard Worker // Blocked versions for brand-new APEX mapped by their holding partition. 216*33f37583SAndroid Build Coastguard Worker std::unordered_map<ApexPartition, std::unordered_map<std::string, int64_t>> 217*33f37583SAndroid Build Coastguard Worker brand_new_apex_blocked_version_; 218*33f37583SAndroid Build Coastguard Worker 219*33f37583SAndroid Build Coastguard Worker // Map from trusted public keys for brand-new APEX to their holding partition. 220*33f37583SAndroid Build Coastguard Worker std::unordered_map<std::string, ApexPartition> brand_new_apex_pubkeys_; 221*33f37583SAndroid Build Coastguard Worker 222*33f37583SAndroid Build Coastguard Worker // Multi-installed APEX name -> all encountered public keys for this APEX. 223*33f37583SAndroid Build Coastguard Worker std::unordered_map<std::string, std::unordered_set<std::string>> 224*33f37583SAndroid Build Coastguard Worker multi_install_public_keys_; 225*33f37583SAndroid Build Coastguard Worker 226*33f37583SAndroid Build Coastguard Worker // Prefixes used when looking for multi-installed APEX sysprops. 227*33f37583SAndroid Build Coastguard Worker // Order matters: the first non-empty prop value is returned. 228*33f37583SAndroid Build Coastguard Worker std::vector<std::string> multi_install_select_prop_prefixes_ = 229*33f37583SAndroid Build Coastguard Worker kMultiApexSelectPrefix; 230*33f37583SAndroid Build Coastguard Worker 231*33f37583SAndroid Build Coastguard Worker // Allows multi-install APEXes outside of expected partitions. 232*33f37583SAndroid Build Coastguard Worker // Only set false in tests. 233*33f37583SAndroid Build Coastguard Worker bool enforce_multi_install_partition_ = true; 234*33f37583SAndroid Build Coastguard Worker 235*33f37583SAndroid Build Coastguard Worker // Disallows installation of brand-new APEX by default. 236*33f37583SAndroid Build Coastguard Worker inline static bool enable_brand_new_apex_ = false; 237*33f37583SAndroid Build Coastguard Worker 238*33f37583SAndroid Build Coastguard Worker // Decompression directory which will be used to determine if apex is 239*33f37583SAndroid Build Coastguard Worker // decompressed or not 240*33f37583SAndroid Build Coastguard Worker std::string decompression_dir_; 241*33f37583SAndroid Build Coastguard Worker 242*33f37583SAndroid Build Coastguard Worker // Disk path where block apexes are read from. AddBlockApex() sets this. 243*33f37583SAndroid Build Coastguard Worker std::optional<std::string> block_disk_path_; 244*33f37583SAndroid Build Coastguard Worker 245*33f37583SAndroid Build Coastguard Worker // Information from the metadata for block apexes, overriding the file data. 246*33f37583SAndroid Build Coastguard Worker struct BlockApexOverride { 247*33f37583SAndroid Build Coastguard Worker // Root digest for the APEX. When specified in block apex config, it 248*33f37583SAndroid Build Coastguard Worker // should be used/checked when activating the apex to avoid 249*33f37583SAndroid Build Coastguard Worker // TOCTOU(time-of-check to time-of-use). 250*33f37583SAndroid Build Coastguard Worker std::optional<std::string> block_apex_root_digest; 251*33f37583SAndroid Build Coastguard Worker // The last update time of the APEX. 252*33f37583SAndroid Build Coastguard Worker std::optional<int64_t> last_update_seconds; 253*33f37583SAndroid Build Coastguard Worker }; 254*33f37583SAndroid Build Coastguard Worker 255*33f37583SAndroid Build Coastguard Worker // Use "path" as key instead of APEX name because there can be multiple 256*33f37583SAndroid Build Coastguard Worker // versions of sharedlibs APEXes. 257*33f37583SAndroid Build Coastguard Worker std::unordered_map<std::string, BlockApexOverride> block_apex_overrides_; 258*33f37583SAndroid Build Coastguard Worker }; 259*33f37583SAndroid Build Coastguard Worker 260*33f37583SAndroid Build Coastguard Worker } // namespace android::apex 261