blob: 312f4acbda9f16ee32eccc6a6db471e1561b6cf8 [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 Mitchell2ed8bfa2021-01-08 13:34:28 -0800164 const auto target = GetTargetContainer(target_path);
165 if (!target) {
166 return error("failed to load target '%s'" + target_path);
Mårten Kongstad02751232018-04-27 13:16:32 +0200167 }
168
Ryan Mitchell2ed8bfa2021-01-08 13:34:28 -0800169 const auto overlay = OverlayResourceContainer::FromPath(overlay_path);
170 if (!overlay) {
171 return error("failed to load apk overlay '%s'" + overlay_path);
Mårten Kongstad02751232018-04-27 13:16:32 +0200172 }
173
Ryan Mitchell6a2ca782021-01-19 13:51:15 -0800174 const auto idmap = Idmap::FromContainers(*GetPointer(*target), **overlay, overlay_name,
175 policy_bitmask, enforce_overlayable);
Mårten Kongstad02751232018-04-27 13:16:32 +0200176 if (!idmap) {
Mårten Kongstadce424902019-03-01 08:35:37 +0100177 return error(idmap.GetErrorMessage());
Mårten Kongstad02751232018-04-27 13:16:32 +0200178 }
179
Ryan Mitchella9093052020-03-26 17:15:01 -0700180 // idmap files are mapped with mmap in libandroidfw. Deleting and recreating the idmap guarantees
181 // that existing memory maps will continue to be valid and unaffected.
182 unlink(idmap_path.c_str());
183
Mårten Kongstadb8779022018-11-29 09:53:17 +0100184 umask(kIdmapFilePermissionMask);
Mårten Kongstad02751232018-04-27 13:16:32 +0200185 std::ofstream fout(idmap_path);
186 if (fout.fail()) {
187 return error("failed to open idmap path " + idmap_path);
188 }
Ryan Mitchella9093052020-03-26 17:15:01 -0700189
Mårten Kongstad02751232018-04-27 13:16:32 +0200190 BinaryStreamVisitor visitor(fout);
Mårten Kongstadce424902019-03-01 08:35:37 +0100191 (*idmap)->accept(&visitor);
Mårten Kongstad02751232018-04-27 13:16:32 +0200192 fout.close();
193 if (fout.fail()) {
Ryan Mitchella9093052020-03-26 17:15:01 -0700194 unlink(idmap_path.c_str());
Mårten Kongstad02751232018-04-27 13:16:32 +0200195 return error("failed to write to idmap path " + idmap_path);
196 }
197
Jooyung Han16bac852020-08-10 12:53:14 +0900198 *_aidl_return = idmap_path;
Mårten Kongstad02751232018-04-27 13:16:32 +0200199 return ok();
200}
201
Ryan Mitchell2ed8bfa2021-01-08 13:34:28 -0800202idmap2::Result<Idmap2Service::TargetResourceContainerPtr> Idmap2Service::GetTargetContainer(
203 const std::string& target_path) {
204 if (target_path == kFrameworkPath) {
205 if (framework_apk_cache_ == nullptr) {
206 // Initialize the framework APK cache.
207 auto target = TargetResourceContainer::FromPath(target_path);
208 if (!target) {
209 return target.GetError();
210 }
211 framework_apk_cache_ = std::move(*target);
212 }
213 return {framework_apk_cache_.get()};
214 }
215
216 auto target = TargetResourceContainer::FromPath(target_path);
217 if (!target) {
218 return target.GetError();
219 }
220 return {std::move(*target)};
221}
222
Ryan Mitchell6a2ca782021-01-19 13:51:15 -0800223Status Idmap2Service::createFabricatedOverlay(
224 const os::FabricatedOverlayInternal& overlay,
225 std::optional<os::FabricatedOverlayInfo>* _aidl_return) {
226 idmap2::FabricatedOverlay::Builder builder(overlay.packageName, overlay.overlayName,
227 overlay.targetPackageName);
228 if (!overlay.targetOverlayable.empty()) {
229 builder.SetOverlayable(overlay.targetOverlayable);
230 }
231
232 for (const auto& res : overlay.entries) {
233 builder.SetResourceValue(res.resourceName, res.dataType, res.data);
234 }
235
236 // Generate the file path of the fabricated overlay and ensure it does not collide with an
237 // existing path. Re-registering a fabricated overlay will always result in an updated path.
238 std::string path;
239 std::string file_name;
240 do {
241 constexpr size_t kSuffixLength = 4;
242 const std::string random_suffix = RandomStringForPath(kSuffixLength);
243 file_name = StringPrintf("%s-%s-%s.frro", overlay.packageName.c_str(),
244 overlay.overlayName.c_str(), random_suffix.c_str());
245 path = StringPrintf("%s/%s", kIdmapCacheDir, file_name.c_str());
246
247 // Invoking std::filesystem::exists with a file name greater than 255 characters will cause this
248 // process to abort since the name exceeds the maximum file name size.
249 const size_t kMaxFileNameLength = 255;
250 if (file_name.size() > kMaxFileNameLength) {
251 return error(
252 base::StringPrintf("fabricated overlay file name '%s' longer than %zu characters",
253 file_name.c_str(), kMaxFileNameLength));
254 }
255 } while (std::filesystem::exists(path));
256
257 const uid_t uid = IPCThreadState::self()->getCallingUid();
258 if (!UidHasWriteAccessToPath(uid, path)) {
259 return error(base::StringPrintf("will not write to %s: calling uid %d lacks write access",
260 path.c_str(), uid));
261 }
262
263 // Persist the fabricated overlay.
264 umask(kIdmapFilePermissionMask);
265 std::ofstream fout(path);
266 if (fout.fail()) {
267 return error("failed to open frro path " + path);
268 }
269 const auto frro = builder.Build();
270 if (!frro) {
271 return error(StringPrintf("failed to serialize '%s:%s': %s", overlay.packageName.c_str(),
272 overlay.overlayName.c_str(), frro.GetErrorMessage().c_str()));
273 }
274 auto result = frro->ToBinaryStream(fout);
275 if (!result) {
276 unlink(path.c_str());
277 return error("failed to write to frro path " + path + ": " + result.GetErrorMessage());
278 }
279 if (fout.fail()) {
280 unlink(path.c_str());
281 return error("failed to write to frro path " + path);
282 }
283
284 os::FabricatedOverlayInfo out_info;
285 out_info.packageName = overlay.packageName;
286 out_info.overlayName = overlay.overlayName;
287 out_info.targetPackageName = overlay.targetPackageName;
288 out_info.targetOverlayable = overlay.targetOverlayable;
289 out_info.path = path;
290 *_aidl_return = out_info;
291 return ok();
292}
293
294Status Idmap2Service::getFabricatedOverlayInfos(
295 std::vector<os::FabricatedOverlayInfo>* _aidl_return) {
296 for (const auto& entry : std::filesystem::directory_iterator(kIdmapCacheDir)) {
297 if (!android::IsFabricatedOverlay(entry.path())) {
298 continue;
299 }
300
301 const auto overlay = FabricatedOverlayContainer::FromPath(entry.path());
302 if (!overlay) {
303 // This is a sign something went wrong.
304 LOG(ERROR) << "Failed to open '" << entry.path() << "': " << overlay.GetErrorMessage();
305 continue;
306 }
307
308 const auto info = (*overlay)->GetManifestInfo();
309 os::FabricatedOverlayInfo out_info;
310 out_info.packageName = info.package_name;
311 out_info.overlayName = info.name;
312 out_info.targetPackageName = info.target_package;
313 out_info.targetOverlayable = info.target_name;
314 out_info.path = entry.path();
315 _aidl_return->emplace_back(std::move(out_info));
316 }
317
318 return ok();
319}
320
321binder::Status Idmap2Service::deleteFabricatedOverlay(const std::string& overlay_path,
322 bool* _aidl_return) {
323 SYSTRACE << "Idmap2Service::deleteFabricatedOverlay " << overlay_path;
324 const uid_t uid = IPCThreadState::self()->getCallingUid();
325
326 if (!UidHasWriteAccessToPath(uid, overlay_path)) {
327 *_aidl_return = false;
328 return error(base::StringPrintf("failed to unlink %s: calling uid %d lacks write access",
329 overlay_path.c_str(), uid));
330 }
331
332 const std::string idmap_path = Idmap::CanonicalIdmapPathFor(kIdmapCacheDir, overlay_path);
333 if (!UidHasWriteAccessToPath(uid, idmap_path)) {
334 *_aidl_return = false;
335 return error(base::StringPrintf("failed to unlink %s: calling uid %d lacks write access",
336 idmap_path.c_str(), uid));
337 }
338
339 if (unlink(overlay_path.c_str()) != 0) {
340 *_aidl_return = false;
341 return error("failed to unlink " + overlay_path + ": " + strerror(errno));
342 }
343
344 if (unlink(idmap_path.c_str()) != 0) {
345 *_aidl_return = false;
346 return error("failed to unlink " + idmap_path + ": " + strerror(errno));
347 }
348
349 *_aidl_return = true;
350 return ok();
351}
352
Mårten Kongstad0eba72a2018-11-29 08:23:14 +0100353} // namespace android::os