1  /*
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  
17  #include "idmap2d/Idmap2Service.h"
18  
19  #include <sys/stat.h>   // umask
20  #include <sys/types.h>  // umask
21  
22  #include <cerrno>
23  #include <cstring>
24  #include <filesystem>
25  #include <fstream>
26  #include <limits>
27  #include <memory>
28  #include <ostream>
29  #include <string>
30  #include <utility>
31  #include <vector>
32  
33  #include "android-base/macros.h"
34  #include "android-base/stringprintf.h"
35  #include "binder/IPCThreadState.h"
36  #include "idmap2/BinaryStreamVisitor.h"
37  #include "idmap2/FileUtils.h"
38  #include "idmap2/Idmap.h"
39  #include "idmap2/PrettyPrintVisitor.h"
40  #include "idmap2/Result.h"
41  #include "idmap2/SysTrace.h"
42  #include <fcntl.h>
43  
44  using android::base::StringPrintf;
45  using android::binder::Status;
46  using android::idmap2::BinaryStreamVisitor;
47  using android::idmap2::FabricatedOverlayContainer;
48  using android::idmap2::Idmap;
49  using android::idmap2::IdmapHeader;
50  using android::idmap2::OverlayResourceContainer;
51  using android::idmap2::PrettyPrintVisitor;
52  using android::idmap2::TargetResourceContainer;
53  using android::idmap2::utils::kIdmapCacheDir;
54  using android::idmap2::utils::kIdmapFilePermissionMask;
55  using android::idmap2::utils::RandomStringForPath;
56  using android::idmap2::utils::UidHasWriteAccessToPath;
57  
58  using PolicyBitmask = android::ResTable_overlayable_policy_header::PolicyBitmask;
59  
60  namespace {
61  
62  constexpr const char* kFrameworkPath = "/system/framework/framework-res.apk";
63  
ok()64  Status ok() {
65    return Status::ok();
66  }
67  
error(const std::string & msg)68  Status error(const std::string& msg) {
69    LOG(ERROR) << msg;
70    return Status::fromExceptionCode(Status::EX_NONE, msg.c_str());
71  }
72  
ConvertAidlArgToPolicyBitmask(int32_t arg)73  PolicyBitmask ConvertAidlArgToPolicyBitmask(int32_t arg) {
74    return static_cast<PolicyBitmask>(arg);
75  }
76  
77  }  // namespace
78  
79  namespace android::os {
80  
getIdmapPath(const std::string & overlay_path,int32_t user_id ATTRIBUTE_UNUSED,std::string * _aidl_return)81  Status Idmap2Service::getIdmapPath(const std::string& overlay_path,
82                                     int32_t user_id ATTRIBUTE_UNUSED, std::string* _aidl_return) {
83    assert(_aidl_return);
84    SYSTRACE << "Idmap2Service::getIdmapPath " << overlay_path;
85    *_aidl_return = Idmap::CanonicalIdmapPathFor(kIdmapCacheDir, overlay_path);
86    return ok();
87  }
88  
removeIdmap(const std::string & overlay_path,int32_t user_id ATTRIBUTE_UNUSED,bool * _aidl_return)89  Status Idmap2Service::removeIdmap(const std::string& overlay_path, int32_t user_id ATTRIBUTE_UNUSED,
90                                    bool* _aidl_return) {
91    assert(_aidl_return);
92    SYSTRACE << "Idmap2Service::removeIdmap " << overlay_path;
93    const uid_t uid = IPCThreadState::self()->getCallingUid();
94    const std::string idmap_path = Idmap::CanonicalIdmapPathFor(kIdmapCacheDir, overlay_path);
95    if (!UidHasWriteAccessToPath(uid, idmap_path)) {
96      *_aidl_return = false;
97      return error(base::StringPrintf("failed to unlink %s: calling uid %d lacks write access",
98                                      idmap_path.c_str(), uid));
99    }
100    if (unlink(idmap_path.c_str()) != 0) {
101      *_aidl_return = false;
102      return error("failed to unlink " + idmap_path + ": " + strerror(errno));
103    }
104    *_aidl_return = true;
105    return ok();
106  }
107  
verifyIdmap(const std::string & target_path,const std::string & overlay_path,const std::string & overlay_name,int32_t fulfilled_policies,bool enforce_overlayable,int32_t user_id ATTRIBUTE_UNUSED,bool * _aidl_return)108  Status Idmap2Service::verifyIdmap(const std::string& target_path, const std::string& overlay_path,
109                                    const std::string& overlay_name, int32_t fulfilled_policies,
110                                    bool enforce_overlayable, int32_t user_id ATTRIBUTE_UNUSED,
111                                    bool* _aidl_return) {
112    SYSTRACE << "Idmap2Service::verifyIdmap " << overlay_path;
113    assert(_aidl_return);
114  
115    const std::string idmap_path = Idmap::CanonicalIdmapPathFor(kIdmapCacheDir, overlay_path);
116    std::ifstream fin(idmap_path);
117    const std::unique_ptr<const IdmapHeader> header = IdmapHeader::FromBinaryStream(fin);
118    fin.close();
119    if (!header) {
120      *_aidl_return = false;
121      LOG(WARNING) << "failed to parse idmap header of '" << idmap_path << "'";
122      return ok();
123    }
124  
125    const auto target = GetTargetContainer(target_path);
126    if (!target) {
127      *_aidl_return = false;
128      LOG(WARNING) << "failed to load target '" << target_path << "'";
129      return ok();
130    }
131  
132    const auto overlay = OverlayResourceContainer::FromPath(overlay_path);
133    if (!overlay) {
134      *_aidl_return = false;
135      LOG(WARNING) << "failed to load overlay '" << overlay_path << "'";
136      return ok();
137    }
138  
139    auto up_to_date =
140        header->IsUpToDate(*GetPointer(*target), **overlay, overlay_name,
141                           ConvertAidlArgToPolicyBitmask(fulfilled_policies), enforce_overlayable);
142  
143    *_aidl_return = static_cast<bool>(up_to_date);
144    if (!up_to_date) {
145      LOG(WARNING) << "idmap '" << idmap_path
146                   << "' not up to date : " << up_to_date.GetErrorMessage();
147    }
148    return ok();
149  }
150  
createIdmap(const std::string & target_path,const std::string & overlay_path,const std::string & overlay_name,int32_t fulfilled_policies,bool enforce_overlayable,int32_t user_id ATTRIBUTE_UNUSED,std::optional<std::string> * _aidl_return)151  Status Idmap2Service::createIdmap(const std::string& target_path, const std::string& overlay_path,
152                                    const std::string& overlay_name, int32_t fulfilled_policies,
153                                    bool enforce_overlayable, int32_t user_id ATTRIBUTE_UNUSED,
154                                    std::optional<std::string>* _aidl_return) {
155    assert(_aidl_return);
156    SYSTRACE << "Idmap2Service::createIdmap " << target_path << " " << overlay_path;
157    _aidl_return->reset();
158  
159    const PolicyBitmask policy_bitmask = ConvertAidlArgToPolicyBitmask(fulfilled_policies);
160  
161    const std::string idmap_path = Idmap::CanonicalIdmapPathFor(kIdmapCacheDir, overlay_path);
162    const uid_t uid = IPCThreadState::self()->getCallingUid();
163    if (!UidHasWriteAccessToPath(uid, idmap_path)) {
164      return error(base::StringPrintf("will not write to %s: calling uid %d lacks write accesss",
165                                      idmap_path.c_str(), uid));
166    }
167  
168    // idmap files are mapped with mmap in libandroidfw. Deleting and recreating the idmap guarantees
169    // that existing memory maps will continue to be valid and unaffected. The file must be deleted
170    // before attempting to create the idmap, so that if idmap  creation fails, the overlay will no
171    // longer be usable.
172    unlink(idmap_path.c_str());
173  
174    const auto target = GetTargetContainer(target_path);
175    if (!target) {
176      return error("failed to load target '%s'" + target_path);
177    }
178  
179    const auto overlay = OverlayResourceContainer::FromPath(overlay_path);
180    if (!overlay) {
181      return error("failed to load apk overlay '%s'" + overlay_path);
182    }
183  
184    const auto idmap = Idmap::FromContainers(*GetPointer(*target), **overlay, overlay_name,
185                                             policy_bitmask, enforce_overlayable);
186    if (!idmap) {
187      return error(idmap.GetErrorMessage());
188    }
189  
190    umask(kIdmapFilePermissionMask);
191    std::ofstream fout(idmap_path);
192    if (fout.fail()) {
193      return error("failed to open idmap path " + idmap_path);
194    }
195  
196    BinaryStreamVisitor visitor(fout);
197    (*idmap)->accept(&visitor);
198    fout.close();
199    if (fout.fail()) {
200      unlink(idmap_path.c_str());
201      return error("failed to write to idmap path " + idmap_path);
202    }
203  
204    *_aidl_return = idmap_path;
205    return ok();
206  }
207  
GetTargetContainer(const std::string & target_path)208  idmap2::Result<Idmap2Service::TargetResourceContainerPtr> Idmap2Service::GetTargetContainer(
209      const std::string& target_path) {
210    if (target_path == kFrameworkPath) {
211      if (framework_apk_cache_ == nullptr) {
212        // Initialize the framework APK cache.
213        auto target = TargetResourceContainer::FromPath(target_path);
214        if (!target) {
215          return target.GetError();
216        }
217        framework_apk_cache_ = std::move(*target);
218      }
219      return {framework_apk_cache_.get()};
220    }
221  
222    auto target = TargetResourceContainer::FromPath(target_path);
223    if (!target) {
224      return target.GetError();
225    }
226    return {std::move(*target)};
227  }
228  
createFabricatedOverlay(const os::FabricatedOverlayInternal & overlay,std::optional<os::FabricatedOverlayInfo> * _aidl_return)229  Status Idmap2Service::createFabricatedOverlay(
230      const os::FabricatedOverlayInternal& overlay,
231      std::optional<os::FabricatedOverlayInfo>* _aidl_return) {
232    idmap2::FabricatedOverlay::Builder builder(overlay.packageName, overlay.overlayName,
233                                               overlay.targetPackageName);
234    if (!overlay.targetOverlayable.empty()) {
235      builder.SetOverlayable(overlay.targetOverlayable);
236    }
237  
238    for (const auto& res : overlay.entries) {
239      if (res.dataType == Res_value::TYPE_STRING) {
240        builder.SetResourceValue(res.resourceName, res.dataType, res.stringData.value(),
241              res.configuration.value_or(std::string()));
242      } else if (res.binaryData.has_value()) {
243        builder.SetResourceValue(res.resourceName, res.binaryData->get(),
244              res.configuration.value_or(std::string()));
245      } else {
246        builder.SetResourceValue(res.resourceName, res.dataType, res.data,
247              res.configuration.value_or(std::string()));
248      }
249    }
250  
251    // Generate the file path of the fabricated overlay and ensure it does not collide with an
252    // existing path. Re-registering a fabricated overlay will always result in an updated path.
253    std::string path;
254    std::string file_name;
255    do {
256      constexpr size_t kSuffixLength = 4;
257      const std::string random_suffix = RandomStringForPath(kSuffixLength);
258      file_name = StringPrintf("%s-%s-%s.frro", overlay.packageName.c_str(),
259                               overlay.overlayName.c_str(), random_suffix.c_str());
260      path = StringPrintf("%s/%s", kIdmapCacheDir, file_name.c_str());
261  
262      // Invoking std::filesystem::exists with a file name greater than 255 characters will cause this
263      // process to abort since the name exceeds the maximum file name size.
264      const size_t kMaxFileNameLength = 255;
265      if (file_name.size() > kMaxFileNameLength) {
266        return error(
267            base::StringPrintf("fabricated overlay file name '%s' longer than %zu characters",
268                               file_name.c_str(), kMaxFileNameLength));
269      }
270    } while (std::filesystem::exists(path));
271    builder.setFrroPath(path);
272  
273    const uid_t uid = IPCThreadState::self()->getCallingUid();
274    if (!UidHasWriteAccessToPath(uid, path)) {
275      return error(base::StringPrintf("will not write to %s: calling uid %d lacks write access",
276                                      path.c_str(), uid));
277    }
278  
279    const auto frro = builder.Build();
280    if (!frro) {
281      return error(StringPrintf("failed to serialize '%s:%s': %s", overlay.packageName.c_str(),
282                                overlay.overlayName.c_str(), frro.GetErrorMessage().c_str()));
283    }
284    // Persist the fabricated overlay.
285    umask(kIdmapFilePermissionMask);
286    std::ofstream fout(path);
287    if (fout.fail()) {
288      return error("failed to open frro path " + path);
289    }
290    auto result = frro->ToBinaryStream(fout);
291    if (!result) {
292      unlink(path.c_str());
293      return error("failed to write to frro path " + path + ": " + result.GetErrorMessage());
294    }
295    if (fout.fail()) {
296      unlink(path.c_str());
297      return error("failed to write to frro path " + path);
298    }
299  
300    os::FabricatedOverlayInfo out_info;
301    out_info.packageName = overlay.packageName;
302    out_info.overlayName = overlay.overlayName;
303    out_info.targetPackageName = overlay.targetPackageName;
304    out_info.targetOverlayable = overlay.targetOverlayable;
305    out_info.path = path;
306    *_aidl_return = out_info;
307    return ok();
308  }
309  
acquireFabricatedOverlayIterator(int32_t * _aidl_return)310  Status Idmap2Service::acquireFabricatedOverlayIterator(int32_t* _aidl_return) {
311    std::lock_guard l(frro_iter_mutex_);
312    if (frro_iter_.has_value()) {
313      LOG(WARNING) << "active ffro iterator was not previously released";
314    }
315    frro_iter_ = std::filesystem::directory_iterator(kIdmapCacheDir);
316    if (frro_iter_id_ == std::numeric_limits<int32_t>::max()) {
317      frro_iter_id_ = 0;
318    } else {
319      ++frro_iter_id_;
320    }
321    *_aidl_return = frro_iter_id_;
322    return ok();
323  }
324  
releaseFabricatedOverlayIterator(int32_t iteratorId)325  Status Idmap2Service::releaseFabricatedOverlayIterator(int32_t iteratorId) {
326    std::lock_guard l(frro_iter_mutex_);
327    if (!frro_iter_.has_value()) {
328      LOG(WARNING) << "no active ffro iterator to release";
329    } else if (frro_iter_id_ != iteratorId) {
330      LOG(WARNING) << "incorrect iterator id in a call to release";
331    } else {
332      frro_iter_.reset();
333    }
334    return ok();
335  }
336  
nextFabricatedOverlayInfos(int32_t iteratorId,std::vector<os::FabricatedOverlayInfo> * _aidl_return)337  Status Idmap2Service::nextFabricatedOverlayInfos(int32_t iteratorId,
338      std::vector<os::FabricatedOverlayInfo>* _aidl_return) {
339    std::lock_guard l(frro_iter_mutex_);
340  
341    constexpr size_t kMaxEntryCount = 100;
342    if (!frro_iter_.has_value()) {
343      return error("no active frro iterator");
344    } else if (frro_iter_id_ != iteratorId) {
345      return error("incorrect iterator id in a call to next");
346    }
347  
348    size_t count = 0;
349    auto& entry_iter = *frro_iter_;
350    auto entry_iter_end = end(*frro_iter_);
351    for (; entry_iter != entry_iter_end && count < kMaxEntryCount; ++entry_iter) {
352      auto& entry = *entry_iter;
353      if (!entry.is_regular_file() || !android::IsFabricatedOverlay(entry.path().native())) {
354        continue;
355      }
356  
357      const auto overlay = FabricatedOverlayContainer::FromPath(entry.path().native());
358      if (!overlay) {
359        LOG(WARNING) << "Failed to open '" << entry.path() << "': " << overlay.GetErrorMessage();
360        continue;
361      }
362  
363      auto info = (*overlay)->GetManifestInfo();
364      os::FabricatedOverlayInfo out_info;
365      out_info.packageName = std::move(info.package_name);
366      out_info.overlayName = std::move(info.name);
367      out_info.targetPackageName = std::move(info.target_package);
368      out_info.targetOverlayable = std::move(info.target_name);
369      out_info.path = entry.path();
370      _aidl_return->emplace_back(std::move(out_info));
371      count++;
372    }
373    return ok();
374  }
375  
deleteFabricatedOverlay(const std::string & overlay_path,bool * _aidl_return)376  binder::Status Idmap2Service::deleteFabricatedOverlay(const std::string& overlay_path,
377                                                        bool* _aidl_return) {
378    SYSTRACE << "Idmap2Service::deleteFabricatedOverlay " << overlay_path;
379    const uid_t uid = IPCThreadState::self()->getCallingUid();
380  
381    if (!UidHasWriteAccessToPath(uid, overlay_path)) {
382      *_aidl_return = false;
383      return error(base::StringPrintf("failed to unlink %s: calling uid %d lacks write access",
384                                      overlay_path.c_str(), uid));
385    }
386  
387    const std::string idmap_path = Idmap::CanonicalIdmapPathFor(kIdmapCacheDir, overlay_path);
388    if (!UidHasWriteAccessToPath(uid, idmap_path)) {
389      *_aidl_return = false;
390      return error(base::StringPrintf("failed to unlink %s: calling uid %d lacks write access",
391                                      idmap_path.c_str(), uid));
392    }
393  
394    if (unlink(overlay_path.c_str()) != 0) {
395      *_aidl_return = false;
396      return error("failed to unlink " + overlay_path + ": " + strerror(errno));
397    }
398  
399    if (unlink(idmap_path.c_str()) != 0) {
400      *_aidl_return = false;
401      return error("failed to unlink " + idmap_path + ": " + strerror(errno));
402    }
403  
404    *_aidl_return = true;
405    return ok();
406  }
407  
dumpIdmap(const std::string & overlay_path,std::string * _aidl_return)408  binder::Status Idmap2Service::dumpIdmap(const std::string& overlay_path,
409                                          std::string* _aidl_return) {
410    assert(_aidl_return);
411  
412    const auto idmap_path = Idmap::CanonicalIdmapPathFor(kIdmapCacheDir, overlay_path);
413    std::ifstream fin(idmap_path);
414    const auto idmap = Idmap::FromBinaryStream(fin);
415    fin.close();
416    if (!idmap) {
417      return error(idmap.GetErrorMessage());
418    }
419  
420    std::stringstream stream;
421    PrettyPrintVisitor visitor(stream);
422    (*idmap)->accept(&visitor);
423    *_aidl_return = stream.str();
424  
425    return ok();
426  }
427  
428  }  // namespace android::os
429