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