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