1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <sys/stat.h>
18 
19 #include <fstream>
20 #include <optional>
21 
22 #define LOG_TAG "SelfTargeting"
23 
24 #include "androidfw/ResourceTypes.h"
25 #include "idmap2/BinaryStreamVisitor.h"
26 #include "idmap2/FabricatedOverlay.h"
27 #include "idmap2/Idmap.h"
28 #include "idmap2/Result.h"
29 
30 using PolicyBitmask = android::ResTable_overlayable_policy_header::PolicyBitmask;
31 using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags;
32 using android::idmap2::BinaryStreamVisitor;
33 using android::idmap2::Idmap;
34 using android::idmap2::OverlayResourceContainer;
35 
36 namespace android::self_targeting {
37 
38 constexpr const mode_t kIdmapFilePermission = S_IRUSR | S_IWUSR;  // u=rw-, g=---, o=---
39 
40 extern "C" bool
CreateFrroFile(std::string & out_err_result,const std::string & packageName,const std::string & overlayName,const std::string & targetPackageName,const std::optional<std::string> & targetOverlayable,const std::vector<FabricatedOverlayEntryParameters> & entries_params,const std::string & frro_file_path)41 CreateFrroFile(std::string& out_err_result, const std::string& packageName,
42                const std::string& overlayName, const std::string& targetPackageName,
43                const std::optional<std::string>& targetOverlayable,
44                const std::vector<FabricatedOverlayEntryParameters>& entries_params,
45                const std::string& frro_file_path) {
46     android::idmap2::FabricatedOverlay::Builder builder(packageName, overlayName,
47                                                         targetPackageName);
48     if (targetOverlayable.has_value()) {
49         builder.SetOverlayable(targetOverlayable.value_or(std::string()));
50     }
51     for (const auto& entry_params : entries_params) {
52         const auto dataType = entry_params.data_type;
53         if (entry_params.data_binary_value.has_value()) {
54             builder.SetResourceValue(entry_params.resource_name, *entry_params.data_binary_value,
55                                      entry_params.binary_data_offset, entry_params.binary_data_size,
56                                      entry_params.configuration, entry_params.nine_patch);
57         } else  if (dataType >= Res_value::TYPE_FIRST_INT && dataType <= Res_value::TYPE_LAST_INT) {
58            builder.SetResourceValue(entry_params.resource_name, dataType,
59                                     entry_params.data_value, entry_params.configuration);
60         } else if (dataType == Res_value::TYPE_STRING) {
61            builder.SetResourceValue(entry_params.resource_name, dataType,
62                                     entry_params.data_string_value , entry_params.configuration);
63         } else {
64             out_err_result = base::StringPrintf("Unsupported data type %d", dataType);
65             return false;
66         }
67     }
68 
69     const auto frro = builder.Build();
70     std::ofstream fout(frro_file_path);
71     if (fout.fail()) {
72         out_err_result = base::StringPrintf("open output stream fail %s", std::strerror(errno));
73         return false;
74     }
75     auto result = frro->ToBinaryStream(fout);
76     if (!result) {
77         unlink(frro_file_path.c_str());
78         out_err_result = base::StringPrintf("to stream fail %s", result.GetErrorMessage().c_str());
79         return false;
80     }
81     fout.close();
82     if (fout.fail()) {
83         unlink(frro_file_path.c_str());
84         out_err_result = base::StringPrintf("output stream fail %s", std::strerror(errno));
85         return false;
86     }
87     if (chmod(frro_file_path.c_str(), kIdmapFilePermission) == -1) {
88         out_err_result = base::StringPrintf("Failed to change the file permission %s",
89                                             frro_file_path.c_str());
90         return false;
91     }
92     return true;
93 }
94 
GetFulfilledPolicy(const bool isSystem,const bool isVendor,const bool isProduct,const bool isTargetSignature,const bool isOdm,const bool isOem)95 static PolicyBitmask GetFulfilledPolicy(const bool isSystem, const bool isVendor,
96                                         const bool isProduct, const bool isTargetSignature,
97                                         const bool isOdm, const bool isOem) {
98     auto fulfilled_policy = static_cast<PolicyBitmask>(PolicyFlags::PUBLIC);
99 
100     if (isSystem) {
101         fulfilled_policy |= PolicyFlags::SYSTEM_PARTITION;
102     }
103     if (isVendor) {
104         fulfilled_policy |= PolicyFlags::VENDOR_PARTITION;
105     }
106     if (isProduct) {
107         fulfilled_policy |= PolicyFlags::PRODUCT_PARTITION;
108     }
109     if (isOdm) {
110         fulfilled_policy |= PolicyFlags::ODM_PARTITION;
111     }
112     if (isOem) {
113         fulfilled_policy |= PolicyFlags::OEM_PARTITION;
114     }
115     if (isTargetSignature) {
116         fulfilled_policy |= PolicyFlags::SIGNATURE;
117     }
118 
119     // Not support actor_signature and config_overlay_signature
120     fulfilled_policy &=
121             ~(PolicyFlags::ACTOR_SIGNATURE | PolicyFlags::CONFIG_SIGNATURE);
122 
123     ALOGV(
124             "fulfilled_policy = 0x%08x, isSystem = %d, isVendor = %d, isProduct = %d,"
125             " isTargetSignature = %d, isOdm = %d, isOem = %d,",
126             fulfilled_policy, isSystem, isVendor, isProduct, isTargetSignature, isOdm, isOem);
127     return fulfilled_policy;
128 }
129 
130 extern "C" bool
CreateIdmapFile(std::string & out_err,const std::string & targetPath,const std::string & overlayPath,const std::string & idmapPath,const std::string & overlayName,const bool isSystem,const bool isVendor,const bool isProduct,const bool isTargetSignature,const bool isOdm,const bool isOem)131 CreateIdmapFile(std::string& out_err, const std::string& targetPath, const std::string& overlayPath,
132                 const std::string& idmapPath, const std::string& overlayName,
133                 const bool isSystem, const bool isVendor, const bool isProduct,
134                 const bool isTargetSignature, const bool isOdm, const bool isOem) {
135     // idmap files are mapped with mmap in libandroidfw. Deleting and recreating the idmap
136     // guarantees that existing memory maps will continue to be valid and unaffected. The file must
137     // be deleted before attempting to create the idmap, so that if idmap  creation fails, the
138     // overlay will no longer be usable.
139     unlink(idmapPath.c_str());
140 
141     const auto target = idmap2::TargetResourceContainer::FromPath(targetPath);
142     if (!target) {
143         out_err = base::StringPrintf("Failed to load target %s because of %s", targetPath.c_str(),
144                                      target.GetErrorMessage().c_str());
145         return false;
146     }
147 
148     const auto overlay = OverlayResourceContainer::FromPath(overlayPath);
149     if (!overlay) {
150         out_err = base::StringPrintf("Failed to load overlay %s because of %s", overlayPath.c_str(),
151                                      overlay.GetErrorMessage().c_str());
152         return false;
153     }
154 
155     // Overlay self target process. Only allow self-targeting types.
156     const auto fulfilled_policies = GetFulfilledPolicy(isSystem, isVendor, isProduct,
157                                                        isTargetSignature, isOdm, isOem);
158 
159     const auto idmap = Idmap::FromContainers(**target, **overlay, overlayName,
160                                              fulfilled_policies, true /* enforce_overlayable */);
161     if (!idmap) {
162         out_err = base::StringPrintf("Failed to create idmap because of %s",
163                                      idmap.GetErrorMessage().c_str());
164         return false;
165     }
166 
167     std::ofstream fout(idmapPath.c_str());
168     if (fout.fail()) {
169         out_err = base::StringPrintf("Failed to create idmap %s because of %s", idmapPath.c_str(),
170                                      strerror(errno));
171         return false;
172     }
173 
174     BinaryStreamVisitor visitor(fout);
175     (*idmap)->accept(&visitor);
176     fout.close();
177     if (fout.fail()) {
178         unlink(idmapPath.c_str());
179         out_err = base::StringPrintf("Failed to write idmap %s because of %s", idmapPath.c_str(),
180                                      strerror(errno));
181         return false;
182     }
183     if (chmod(idmapPath.c_str(), kIdmapFilePermission) == -1) {
184         out_err = base::StringPrintf("Failed to change the file permission %s", idmapPath.c_str());
185         return false;
186     }
187     return true;
188 }
189 
190 extern "C" bool
GetFabricatedOverlayInfo(std::string & out_err,const std::string & overlay_path,OverlayManifestInfo & out_info)191 GetFabricatedOverlayInfo(std::string& out_err, const std::string& overlay_path,
192                          OverlayManifestInfo& out_info) {
193     const auto overlay = idmap2::FabricatedOverlayContainer::FromPath(overlay_path);
194     if (!overlay) {
195         out_err = base::StringPrintf("Failed to write idmap %s because of %s",
196                                      overlay_path.c_str(), strerror(errno));
197         return false;
198     }
199 
200     out_info = (*overlay)->GetManifestInfo();
201 
202     return true;
203 }
204 
205 }  // namespace android::self_targeting
206 
207