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::IdmapConstraints;
35 using android::idmap2::OverlayResourceContainer;
36
37 namespace android::self_targeting {
38
39 constexpr const mode_t kIdmapFilePermission = S_IRUSR | S_IWUSR; // u=rw-, g=---, o=---
40
41 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)42 CreateFrroFile(std::string& out_err_result, const std::string& packageName,
43 const std::string& overlayName, const std::string& targetPackageName,
44 const std::optional<std::string>& targetOverlayable,
45 const std::vector<FabricatedOverlayEntryParameters>& entries_params,
46 const std::string& frro_file_path) {
47 android::idmap2::FabricatedOverlay::Builder builder(packageName, overlayName,
48 targetPackageName);
49 if (targetOverlayable.has_value()) {
50 builder.SetOverlayable(targetOverlayable.value_or(std::string()));
51 }
52 for (const auto& entry_params : entries_params) {
53 const auto dataType = entry_params.data_type;
54 if (entry_params.data_binary_value.has_value()) {
55 builder.SetResourceValue(entry_params.resource_name, *entry_params.data_binary_value,
56 entry_params.binary_data_offset, entry_params.binary_data_size,
57 entry_params.configuration, entry_params.nine_patch);
58 } else if (dataType >= Res_value::TYPE_FIRST_INT && dataType <= Res_value::TYPE_LAST_INT) {
59 builder.SetResourceValue(entry_params.resource_name, dataType,
60 entry_params.data_value, entry_params.configuration);
61 } else if (dataType == Res_value::TYPE_STRING) {
62 builder.SetResourceValue(entry_params.resource_name, dataType,
63 entry_params.data_string_value , entry_params.configuration);
64 } else {
65 out_err_result = base::StringPrintf("Unsupported data type %d", dataType);
66 return false;
67 }
68 }
69
70 const auto frro = builder.Build();
71 std::ofstream fout(frro_file_path);
72 if (fout.fail()) {
73 out_err_result = base::StringPrintf("open output stream fail %s", std::strerror(errno));
74 return false;
75 }
76 auto result = frro->ToBinaryStream(fout);
77 if (!result) {
78 unlink(frro_file_path.c_str());
79 out_err_result = base::StringPrintf("to stream fail %s", result.GetErrorMessage().c_str());
80 return false;
81 }
82 fout.close();
83 if (fout.fail()) {
84 unlink(frro_file_path.c_str());
85 out_err_result = base::StringPrintf("output stream fail %s", std::strerror(errno));
86 return false;
87 }
88 if (chmod(frro_file_path.c_str(), kIdmapFilePermission) == -1) {
89 out_err_result = base::StringPrintf("Failed to change the file permission %s",
90 frro_file_path.c_str());
91 return false;
92 }
93 return true;
94 }
95
GetFulfilledPolicy(const bool isSystem,const bool isVendor,const bool isProduct,const bool isTargetSignature,const bool isOdm,const bool isOem)96 static PolicyBitmask GetFulfilledPolicy(const bool isSystem, const bool isVendor,
97 const bool isProduct, const bool isTargetSignature,
98 const bool isOdm, const bool isOem) {
99 auto fulfilled_policy = static_cast<PolicyBitmask>(PolicyFlags::PUBLIC);
100
101 if (isSystem) {
102 fulfilled_policy |= PolicyFlags::SYSTEM_PARTITION;
103 }
104 if (isVendor) {
105 fulfilled_policy |= PolicyFlags::VENDOR_PARTITION;
106 }
107 if (isProduct) {
108 fulfilled_policy |= PolicyFlags::PRODUCT_PARTITION;
109 }
110 if (isOdm) {
111 fulfilled_policy |= PolicyFlags::ODM_PARTITION;
112 }
113 if (isOem) {
114 fulfilled_policy |= PolicyFlags::OEM_PARTITION;
115 }
116 if (isTargetSignature) {
117 fulfilled_policy |= PolicyFlags::SIGNATURE;
118 }
119
120 // Not support actor_signature and config_overlay_signature
121 fulfilled_policy &=
122 ~(PolicyFlags::ACTOR_SIGNATURE | PolicyFlags::CONFIG_SIGNATURE);
123
124 ALOGV(
125 "fulfilled_policy = 0x%08x, isSystem = %d, isVendor = %d, isProduct = %d,"
126 " isTargetSignature = %d, isOdm = %d, isOem = %d,",
127 fulfilled_policy, isSystem, isVendor, isProduct, isTargetSignature, isOdm, isOem);
128 return fulfilled_policy;
129 }
130
131 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)132 CreateIdmapFile(std::string& out_err, const std::string& targetPath, const std::string& overlayPath,
133 const std::string& idmapPath, const std::string& overlayName,
134 const bool isSystem, const bool isVendor, const bool isProduct,
135 const bool isTargetSignature, const bool isOdm, const bool isOem) {
136 // idmap files are mapped with mmap in libandroidfw. Deleting and recreating the idmap
137 // guarantees that existing memory maps will continue to be valid and unaffected. The file must
138 // be deleted before attempting to create the idmap, so that if idmap creation fails, the
139 // overlay will no longer be usable.
140 unlink(idmapPath.c_str());
141
142 const auto target = idmap2::TargetResourceContainer::FromPath(targetPath);
143 if (!target) {
144 out_err = base::StringPrintf("Failed to load target %s because of %s", targetPath.c_str(),
145 target.GetErrorMessage().c_str());
146 return false;
147 }
148
149 const auto overlay = OverlayResourceContainer::FromPath(overlayPath);
150 if (!overlay) {
151 out_err = base::StringPrintf("Failed to load overlay %s because of %s", overlayPath.c_str(),
152 overlay.GetErrorMessage().c_str());
153 return false;
154 }
155
156 // Overlay self target process. Only allow self-targeting types.
157 const auto fulfilled_policies = GetFulfilledPolicy(isSystem, isVendor, isProduct,
158 isTargetSignature, isOdm, isOem);
159 auto constraints = std::make_unique<const IdmapConstraints>();
160 const auto idmap = Idmap::FromContainers(**target, **overlay, overlayName,
161 fulfilled_policies, true /* enforce_overlayable */,
162 std::move(constraints));
163 if (!idmap) {
164 out_err = base::StringPrintf("Failed to create idmap because of %s",
165 idmap.GetErrorMessage().c_str());
166 return false;
167 }
168
169 std::ofstream fout(idmapPath.c_str());
170 if (fout.fail()) {
171 out_err = base::StringPrintf("Failed to create idmap %s because of %s", idmapPath.c_str(),
172 strerror(errno));
173 return false;
174 }
175
176 BinaryStreamVisitor visitor(fout);
177 (*idmap)->accept(&visitor);
178 fout.close();
179 if (fout.fail()) {
180 unlink(idmapPath.c_str());
181 out_err = base::StringPrintf("Failed to write idmap %s because of %s", idmapPath.c_str(),
182 strerror(errno));
183 return false;
184 }
185 if (chmod(idmapPath.c_str(), kIdmapFilePermission) == -1) {
186 out_err = base::StringPrintf("Failed to change the file permission %s", idmapPath.c_str());
187 return false;
188 }
189 return true;
190 }
191
192 extern "C" bool
GetFabricatedOverlayInfo(std::string & out_err,const std::string & overlay_path,OverlayManifestInfo & out_info)193 GetFabricatedOverlayInfo(std::string& out_err, const std::string& overlay_path,
194 OverlayManifestInfo& out_info) {
195 const auto overlay = idmap2::FabricatedOverlayContainer::FromPath(overlay_path);
196 if (!overlay) {
197 out_err = base::StringPrintf("Failed to write idmap %s because of %s",
198 overlay_path.c_str(), strerror(errno));
199 return false;
200 }
201
202 out_info = (*overlay)->GetManifestInfo();
203
204 return true;
205 }
206
207 } // namespace android::self_targeting
208
209