blob: 05336baf9217f033161aaae23b6b2e401c983460 [file] [log] [blame]
Mårten Kongstad02751232018-04-27 13:16:32 +02001/*
2 * Copyright (C) 2018 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
Ryan Mitchell52e1f7a2019-04-12 12:31:42 -070017#include "idmap2d/Idmap2Service.h"
18
Mårten Kongstad02751232018-04-27 13:16:32 +020019#include <sys/stat.h> // umask
20#include <sys/types.h> // umask
Mårten Kongstad02751232018-04-27 13:16:32 +020021
22#include <cerrno>
23#include <cstring>
Ryan Mitchell6a2ca782021-01-19 13:51:15 -080024#include <filesystem>
Mårten Kongstad02751232018-04-27 13:16:32 +020025#include <fstream>
26#include <memory>
27#include <ostream>
28#include <string>
29
30#include "android-base/macros.h"
Mårten Kongstadd10d06d2019-01-07 17:26:25 -080031#include "android-base/stringprintf.h"
Mårten Kongstad1da49dc2019-01-14 10:03:53 +010032#include "binder/IPCThreadState.h"
Mårten Kongstad02751232018-04-27 13:16:32 +020033#include "idmap2/BinaryStreamVisitor.h"
34#include "idmap2/FileUtils.h"
35#include "idmap2/Idmap.h"
Ryan Mitchella7070132020-05-13 14:17:52 -070036#include "idmap2/Result.h"
Mårten Kongstad4cbb0072018-11-30 16:22:05 +010037#include "idmap2/SysTrace.h"
Mårten Kongstad02751232018-04-27 13:16:32 +020038
Mårten Kongstad1da49dc2019-01-14 10:03:53 +010039using android::IPCThreadState;
Ryan Mitchella7070132020-05-13 14:17:52 -070040using android::base::StringPrintf;
Mårten Kongstad02751232018-04-27 13:16:32 +020041using android::binder::Status;
42using android::idmap2::BinaryStreamVisitor;
Ryan Mitchell6a2ca782021-01-19 13:51:15 -080043using android::idmap2::FabricatedOverlay;
44using android::idmap2::FabricatedOverlayContainer;
Mårten Kongstad02751232018-04-27 13:16:32 +020045using android::idmap2::Idmap;
46using android::idmap2::IdmapHeader;
Ryan Mitchell2ed8bfa2021-01-08 13:34:28 -080047using android::idmap2::OverlayResourceContainer;
48using android::idmap2::TargetResourceContainer;
Mårten Kongstad1da49dc2019-01-14 10:03:53 +010049using android::idmap2::utils::kIdmapCacheDir;
Mårten Kongstadb8779022018-11-29 09:53:17 +010050using android::idmap2::utils::kIdmapFilePermissionMask;
Ryan Mitchell6a2ca782021-01-19 13:51:15 -080051using android::idmap2::utils::RandomStringForPath;
Mårten Kongstad1da49dc2019-01-14 10:03:53 +010052using android::idmap2::utils::UidHasWriteAccessToPath;
Mårten Kongstad02751232018-04-27 13:16:32 +020053
Winson62ac8b52019-12-04 08:36:48 -080054using PolicyBitmask = android::ResTable_overlayable_policy_header::PolicyBitmask;
55
Mårten Kongstad02751232018-04-27 13:16:32 +020056namespace {
57
Ryan Mitchell7d53f192020-04-24 17:45:25 -070058constexpr const char* kFrameworkPath = "/system/framework/framework-res.apk";
59
Mårten Kongstad02751232018-04-27 13:16:32 +020060Status ok() {
61 return Status::ok();
62}
63
64Status error(const std::string& msg) {
65 LOG(ERROR) << msg;
66 return Status::fromExceptionCode(Status::EX_NONE, msg.c_str());
67}
68
Mårten Kongstadd10d06d2019-01-07 17:26:25 -080069PolicyBitmask ConvertAidlArgToPolicyBitmask(int32_t arg) {
70 return static_cast<PolicyBitmask>(arg);
71}
Ryan Mitchell6a2ca782021-01-19 13:51:15 -080072
Mårten Kongstad02751232018-04-27 13:16:32 +020073} // namespace
74
Mårten Kongstad0eba72a2018-11-29 08:23:14 +010075namespace android::os {
Mårten Kongstad02751232018-04-27 13:16:32 +020076
Ryan Mitchell2ed8bfa2021-01-08 13:34:28 -080077Status Idmap2Service::getIdmapPath(const std::string& overlay_path,
Mårten Kongstad02751232018-04-27 13:16:32 +020078 int32_t user_id ATTRIBUTE_UNUSED, std::string* _aidl_return) {
79 assert(_aidl_return);
Ryan Mitchell2ed8bfa2021-01-08 13:34:28 -080080 SYSTRACE << "Idmap2Service::getIdmapPath " << overlay_path;
81 *_aidl_return = Idmap::CanonicalIdmapPathFor(kIdmapCacheDir, overlay_path);
Mårten Kongstad02751232018-04-27 13:16:32 +020082 return ok();
83}
84
Ryan Mitchell2ed8bfa2021-01-08 13:34:28 -080085Status Idmap2Service::removeIdmap(const std::string& overlay_path, int32_t user_id ATTRIBUTE_UNUSED,
86 bool* _aidl_return) {
Mårten Kongstad02751232018-04-27 13:16:32 +020087 assert(_aidl_return);
Ryan Mitchell2ed8bfa2021-01-08 13:34:28 -080088 SYSTRACE << "Idmap2Service::removeIdmap " << overlay_path;
Mårten Kongstad1da49dc2019-01-14 10:03:53 +010089 const uid_t uid = IPCThreadState::self()->getCallingUid();
Ryan Mitchell2ed8bfa2021-01-08 13:34:28 -080090 const std::string idmap_path = Idmap::CanonicalIdmapPathFor(kIdmapCacheDir, overlay_path);
Mårten Kongstad1da49dc2019-01-14 10:03:53 +010091 if (!UidHasWriteAccessToPath(uid, idmap_path)) {
92 *_aidl_return = false;
93 return error(base::StringPrintf("failed to unlink %s: calling uid %d lacks write access",
94 idmap_path.c_str(), uid));
95 }
Mårten Kongstadb8779022018-11-29 09:53:17 +010096 if (unlink(idmap_path.c_str()) != 0) {
Mårten Kongstad02751232018-04-27 13:16:32 +020097 *_aidl_return = false;
98 return error("failed to unlink " + idmap_path + ": " + strerror(errno));
99 }
Mårten Kongstadb8779022018-11-29 09:53:17 +0100100 *_aidl_return = true;
101 return ok();
Mårten Kongstad02751232018-04-27 13:16:32 +0200102}
103
Ryan Mitchell2ed8bfa2021-01-08 13:34:28 -0800104Status Idmap2Service::verifyIdmap(const std::string& target_path, const std::string& overlay_path,
Ryan Mitchell6a2ca782021-01-19 13:51:15 -0800105 const std::string& overlay_name, int32_t fulfilled_policies,
106 bool enforce_overlayable, int32_t user_id ATTRIBUTE_UNUSED,
107 bool* _aidl_return) {
Ryan Mitchell2ed8bfa2021-01-08 13:34:28 -0800108 SYSTRACE << "Idmap2Service::verifyIdmap " << overlay_path;
Mårten Kongstadef0695d2018-12-04 14:36:48 +0100109 assert(_aidl_return);
Ryan Mitchell038a2842020-06-08 14:41:07 -0700110
Ryan Mitchell2ed8bfa2021-01-08 13:34:28 -0800111 const std::string idmap_path = Idmap::CanonicalIdmapPathFor(kIdmapCacheDir, overlay_path);
Mårten Kongstadef0695d2018-12-04 14:36:48 +0100112 std::ifstream fin(idmap_path);
113 const std::unique_ptr<const IdmapHeader> header = IdmapHeader::FromBinaryStream(fin);
114 fin.close();
hg.choia3a68132020-01-15 17:12:48 +0900115 if (!header) {
116 *_aidl_return = false;
Ryan Mitchell2ed8bfa2021-01-08 13:34:28 -0800117 LOG(WARNING) << "failed to parse idmap header of '" << idmap_path << "'";
118 return ok();
hg.choia3a68132020-01-15 17:12:48 +0900119 }
120
Ryan Mitchell2ed8bfa2021-01-08 13:34:28 -0800121 const auto target = GetTargetContainer(target_path);
122 if (!target) {
Ryan Mitchella7070132020-05-13 14:17:52 -0700123 *_aidl_return = false;
Ryan Mitchell2ed8bfa2021-01-08 13:34:28 -0800124 LOG(WARNING) << "failed to load target '" << target_path << "'";
125 return ok();
126 }
127
128 const auto overlay = OverlayResourceContainer::FromPath(overlay_path);
129 if (!overlay) {
130 *_aidl_return = false;
131 LOG(WARNING) << "failed to load overlay '" << overlay_path << "'";
132 return ok();
Ryan Mitchella7070132020-05-13 14:17:52 -0700133 }
134
135 auto up_to_date =
Ryan Mitchell6a2ca782021-01-19 13:51:15 -0800136 header->IsUpToDate(*GetPointer(*target), **overlay, overlay_name,
Ryan Mitchell038a2842020-06-08 14:41:07 -0700137 ConvertAidlArgToPolicyBitmask(fulfilled_policies), enforce_overlayable);
Ryan Mitchella7070132020-05-13 14:17:52 -0700138
Ryan Mitchell038a2842020-06-08 14:41:07 -0700139 *_aidl_return = static_cast<bool>(up_to_date);
Ryan Mitchell2ed8bfa2021-01-08 13:34:28 -0800140 if (!up_to_date) {
141 LOG(WARNING) << "idmap '" << idmap_path
142 << "' not up to date : " << up_to_date.GetErrorMessage();
143 }
144 return ok();
Mårten Kongstadef0695d2018-12-04 14:36:48 +0100145}
146
Ryan Mitchell2ed8bfa2021-01-08 13:34:28 -0800147Status Idmap2Service::createIdmap(const std::string& target_path, const std::string& overlay_path,
Ryan Mitchell6a2ca782021-01-19 13:51:15 -0800148 const std::string& overlay_name, int32_t fulfilled_policies,
149 bool enforce_overlayable, int32_t user_id ATTRIBUTE_UNUSED,
Jooyung Han16bac852020-08-10 12:53:14 +0900150 std::optional<std::string>* _aidl_return) {
Mårten Kongstad02751232018-04-27 13:16:32 +0200151 assert(_aidl_return);
Ryan Mitchell2ed8bfa2021-01-08 13:34:28 -0800152 SYSTRACE << "Idmap2Service::createIdmap " << target_path << " " << overlay_path;
Jooyung Han605e39f2020-01-23 13:29:22 +0900153 _aidl_return->reset();
Mårten Kongstad02751232018-04-27 13:16:32 +0200154
Mårten Kongstadd10d06d2019-01-07 17:26:25 -0800155 const PolicyBitmask policy_bitmask = ConvertAidlArgToPolicyBitmask(fulfilled_policies);
156
Ryan Mitchell2ed8bfa2021-01-08 13:34:28 -0800157 const std::string idmap_path = Idmap::CanonicalIdmapPathFor(kIdmapCacheDir, overlay_path);
Mårten Kongstad1da49dc2019-01-14 10:03:53 +0100158 const uid_t uid = IPCThreadState::self()->getCallingUid();
159 if (!UidHasWriteAccessToPath(uid, idmap_path)) {
160 return error(base::StringPrintf("will not write to %s: calling uid %d lacks write accesss",
161 idmap_path.c_str(), uid));
162 }
163
Ryan Mitchellb49cb5e2021-02-10 11:27:29 -0800164 // idmap files are mapped with mmap in libandroidfw. Deleting and recreating the idmap guarantees
165 // that existing memory maps will continue to be valid and unaffected. The file must be deleted
166 // before attempting to create the idmap, so that if idmap creation fails, the overlay will no
167 // longer be usable.
168 unlink(idmap_path.c_str());
169
Ryan Mitchell2ed8bfa2021-01-08 13:34:28 -0800170 const auto target = GetTargetContainer(target_path);
171 if (!target) {
172 return error("failed to load target '%s'" + target_path);
Mårten Kongstad02751232018-04-27 13:16:32 +0200173 }
174
Ryan Mitchell2ed8bfa2021-01-08 13:34:28 -0800175 const auto overlay = OverlayResourceContainer::FromPath(overlay_path);
176 if (!overlay) {
177 return error("failed to load apk overlay '%s'" + overlay_path);
Mårten Kongstad02751232018-04-27 13:16:32 +0200178 }
179
Ryan Mitchell6a2ca782021-01-19 13:51:15 -0800180 const auto idmap = Idmap::FromContainers(*GetPointer(*target), **overlay, overlay_name,
181 policy_bitmask, enforce_overlayable);
Mårten Kongstad02751232018-04-27 13:16:32 +0200182 if (!idmap) {
Mårten Kongstadce424902019-03-01 08:35:37 +0100183 return error(idmap.GetErrorMessage());
Mårten Kongstad02751232018-04-27 13:16:32 +0200184 }
185
Mårten Kongstadb8779022018-11-29 09:53:17 +0100186 umask(kIdmapFilePermissionMask);
Mårten Kongstad02751232018-04-27 13:16:32 +0200187 std::ofstream fout(idmap_path);
188 if (fout.fail()) {
189 return error("failed to open idmap path " + idmap_path);
190 }
Ryan Mitchella9093052020-03-26 17:15:01 -0700191
Mårten Kongstad02751232018-04-27 13:16:32 +0200192 BinaryStreamVisitor visitor(fout);
Mårten Kongstadce424902019-03-01 08:35:37 +0100193 (*idmap)->accept(&visitor);
Mårten Kongstad02751232018-04-27 13:16:32 +0200194 fout.close();
195 if (fout.fail()) {
Ryan Mitchella9093052020-03-26 17:15:01 -0700196 unlink(idmap_path.c_str());
Mårten Kongstad02751232018-04-27 13:16:32 +0200197 return error("failed to write to idmap path " + idmap_path);
198 }
199
Jooyung Han16bac852020-08-10 12:53:14 +0900200 *_aidl_return = idmap_path;
Mårten Kongstad02751232018-04-27 13:16:32 +0200201 return ok();
202}
203
Ryan Mitchell2ed8bfa2021-01-08 13:34:28 -0800204idmap2::Result<Idmap2Service::TargetResourceContainerPtr> Idmap2Service::GetTargetContainer(
205 const std::string& target_path) {
206 if (target_path == kFrameworkPath) {
207 if (framework_apk_cache_ == nullptr) {
208 // Initialize the framework APK cache.
209 auto target = TargetResourceContainer::FromPath(target_path);
210 if (!target) {
211 return target.GetError();
212 }
213 framework_apk_cache_ = std::move(*target);
214 }
215 return {framework_apk_cache_.get()};
216 }
217
218 auto target = TargetResourceContainer::FromPath(target_path);
219 if (!target) {
220 return target.GetError();
221 }
222 return {std::move(*target)};
223}
224
Ryan Mitchell6a2ca782021-01-19 13:51:15 -0800225Status Idmap2Service::createFabricatedOverlay(
226 const os::FabricatedOverlayInternal& overlay,
227 std::optional<os::FabricatedOverlayInfo>* _aidl_return) {
228 idmap2::FabricatedOverlay::Builder builder(overlay.packageName, overlay.overlayName,
229 overlay.targetPackageName);
230 if (!overlay.targetOverlayable.empty()) {
231 builder.SetOverlayable(overlay.targetOverlayable);
232 }
233
234 for (const auto& res : overlay.entries) {
235 builder.SetResourceValue(res.resourceName, res.dataType, res.data);
236 }
237
238 // Generate the file path of the fabricated overlay and ensure it does not collide with an
239 // existing path. Re-registering a fabricated overlay will always result in an updated path.
240 std::string path;
241 std::string file_name;
242 do {
243 constexpr size_t kSuffixLength = 4;
244 const std::string random_suffix = RandomStringForPath(kSuffixLength);
245 file_name = StringPrintf("%s-%s-%s.frro", overlay.packageName.c_str(),
246 overlay.overlayName.c_str(), random_suffix.c_str());
247 path = StringPrintf("%s/%s", kIdmapCacheDir, file_name.c_str());
248
249 // Invoking std::filesystem::exists with a file name greater than 255 characters will cause this
250 // process to abort since the name exceeds the maximum file name size.
251 const size_t kMaxFileNameLength = 255;
252 if (file_name.size() > kMaxFileNameLength) {
253 return error(
254 base::StringPrintf("fabricated overlay file name '%s' longer than %zu characters",
255 file_name.c_str(), kMaxFileNameLength));
256 }
257 } while (std::filesystem::exists(path));
258
259 const uid_t uid = IPCThreadState::self()->getCallingUid();
260 if (!UidHasWriteAccessToPath(uid, path)) {
261 return error(base::StringPrintf("will not write to %s: calling uid %d lacks write access",
262 path.c_str(), uid));
263 }
264
265 // Persist the fabricated overlay.
266 umask(kIdmapFilePermissionMask);
267 std::ofstream fout(path);
268 if (fout.fail()) {
269 return error("failed to open frro path " + path);
270 }
271 const auto frro = builder.Build();
272 if (!frro) {
273 return error(StringPrintf("failed to serialize '%s:%s': %s", overlay.packageName.c_str(),
274 overlay.overlayName.c_str(), frro.GetErrorMessage().c_str()));
275 }
276 auto result = frro->ToBinaryStream(fout);
277 if (!result) {
278 unlink(path.c_str());
279 return error("failed to write to frro path " + path + ": " + result.GetErrorMessage());
280 }
281 if (fout.fail()) {
282 unlink(path.c_str());
283 return error("failed to write to frro path " + path);
284 }
285
286 os::FabricatedOverlayInfo out_info;
287 out_info.packageName = overlay.packageName;
288 out_info.overlayName = overlay.overlayName;
289 out_info.targetPackageName = overlay.targetPackageName;
290 out_info.targetOverlayable = overlay.targetOverlayable;
291 out_info.path = path;
292 *_aidl_return = out_info;
293 return ok();
294}
295
296Status Idmap2Service::getFabricatedOverlayInfos(
297 std::vector<os::FabricatedOverlayInfo>* _aidl_return) {
298 for (const auto& entry : std::filesystem::directory_iterator(kIdmapCacheDir)) {
299 if (!android::IsFabricatedOverlay(entry.path())) {
300 continue;
301 }
302
303 const auto overlay = FabricatedOverlayContainer::FromPath(entry.path());
304 if (!overlay) {
305 // This is a sign something went wrong.
306 LOG(ERROR) << "Failed to open '" << entry.path() << "': " << overlay.GetErrorMessage();
307 continue;
308 }
309
310 const auto info = (*overlay)->GetManifestInfo();
311 os::FabricatedOverlayInfo out_info;
312 out_info.packageName = info.package_name;
313 out_info.overlayName = info.name;
314 out_info.targetPackageName = info.target_package;
315 out_info.targetOverlayable = info.target_name;
316 out_info.path = entry.path();
317 _aidl_return->emplace_back(std::move(out_info));
318 }
319
320 return ok();
321}
322
323binder::Status Idmap2Service::deleteFabricatedOverlay(const std::string& overlay_path,
324 bool* _aidl_return) {
325 SYSTRACE << "Idmap2Service::deleteFabricatedOverlay " << overlay_path;
326 const uid_t uid = IPCThreadState::self()->getCallingUid();
327
328 if (!UidHasWriteAccessToPath(uid, overlay_path)) {
329 *_aidl_return = false;
330 return error(base::StringPrintf("failed to unlink %s: calling uid %d lacks write access",
331 overlay_path.c_str(), uid));
332 }
333
334 const std::string idmap_path = Idmap::CanonicalIdmapPathFor(kIdmapCacheDir, overlay_path);
335 if (!UidHasWriteAccessToPath(uid, idmap_path)) {
336 *_aidl_return = false;
337 return error(base::StringPrintf("failed to unlink %s: calling uid %d lacks write access",
338 idmap_path.c_str(), uid));
339 }
340
341 if (unlink(overlay_path.c_str()) != 0) {
342 *_aidl_return = false;
343 return error("failed to unlink " + overlay_path + ": " + strerror(errno));
344 }
345
346 if (unlink(idmap_path.c_str()) != 0) {
347 *_aidl_return = false;
348 return error("failed to unlink " + idmap_path + ": " + strerror(errno));
349 }
350
351 *_aidl_return = true;
352 return ok();
353}
354
Mårten Kongstad0eba72a2018-11-29 08:23:14 +0100355} // namespace android::os