blob: a8aa03309b16934a2aa367017e4aea320348379f [file] [log] [blame]
felkachang1039d612022-06-21 15:09:47 +08001/*
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
30using PolicyBitmask = android::ResTable_overlayable_policy_header::PolicyBitmask;
31using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags;
32using android::idmap2::BinaryStreamVisitor;
33using android::idmap2::Idmap;
34using android::idmap2::OverlayResourceContainer;
35
36namespace android::self_targeting {
37
38constexpr const mode_t kIdmapFilePermission = S_IRUSR | S_IWUSR; // u=rw-, g=---, o=---
39
40extern "C" bool
felkachanga8fc0152022-09-22 20:00:34 +080041CreateFrroFile(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,
felkachang1039d612022-06-21 15:09:47 +080045 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
felkachanga8fc0152022-09-22 20:00:34 +080094static 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
felkachang1039d612022-06-21 15:09:47 +0800129extern "C" bool
130CreateIdmapFile(std::string& out_err, const std::string& targetPath, const std::string& overlayPath,
felkachanga8fc0152022-09-22 20:00:34 +0800131 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) {
felkachang1039d612022-06-21 15:09:47 +0800134 // 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.
felkachanga8fc0152022-09-22 20:00:34 +0800155 const auto fulfilled_policies = GetFulfilledPolicy(isSystem, isVendor, isProduct,
156 isTargetSignature, isOdm, isOem);
felkachang1039d612022-06-21 15:09:47 +0800157
158 const auto idmap = Idmap::FromContainers(**target, **overlay, overlayName,
felkachanga8fc0152022-09-22 20:00:34 +0800159 fulfilled_policies, true /* enforce_overlayable */);
felkachang1039d612022-06-21 15:09:47 +0800160 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
189extern "C" bool
190GetFabricatedOverlayInfo(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