blob: 6ede493661e13df6d638fe5173ce54c46330ef9c [file] [log] [blame]
Andreas Gampee1a40392018-11-30 09:47:17 -08001/*
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#define LOG_TAG "apexd"
18
Andreas Gampef7663552019-01-03 09:22:11 -080019#include "apexd_prepostinstall.h"
Andreas Gampee1a40392018-11-30 09:47:17 -080020
21#include <algorithm>
22#include <vector>
23
24#include <fcntl.h>
25#include <sys/mount.h>
Andreas Gampeb48122e2018-12-11 15:48:42 -080026#include <sys/stat.h>
Andreas Gampee1a40392018-11-30 09:47:17 -080027#include <sys/types.h>
28#include <sys/wait.h>
29#include <unistd.h>
30
31#include <android-base/logging.h>
32#include <android-base/macros.h>
33#include <android-base/scopeguard.h>
34#include <android-base/strings.h>
35
36#include "apex_file.h"
37#include "apexd.h"
38#include "apexd_private.h"
39#include "apexd_utils.h"
40#include "string_log.h"
41
42namespace android {
43namespace apex {
44
45namespace {
46
Nick Kralevich3501c7b2019-02-28 10:20:44 -080047void CloseSTDDescriptors() {
48 // exec()d process will reopen STD* file descriptors as
49 // /dev/null
50 close(STDIN_FILENO);
51 close(STDOUT_FILENO);
52 close(STDERR_FILENO);
Andreas Gampee1a40392018-11-30 09:47:17 -080053}
54
Andreas Gampef7663552019-01-03 09:22:11 -080055template <typename Fn>
Andreas Gampe17739142019-01-09 16:00:26 -080056Status StageFnInstall(const std::vector<ApexFile>& apexes, Fn fn,
57 const char* arg, const char* name) {
Andreas Gampee44b5792018-12-13 15:48:45 -080058 // TODO: Support a session with more than one pre-install hook.
59 const ApexFile* hook_file = nullptr;
60 for (const ApexFile& f : apexes) {
Andreas Gampef7663552019-01-03 09:22:11 -080061 if (!(f.GetManifest().*fn)().empty()) {
Andreas Gampee44b5792018-12-13 15:48:45 -080062 if (hook_file != nullptr) {
Andreas Gampef7663552019-01-03 09:22:11 -080063 return Status::Fail(StringLog() << "Missing support for multiple "
64 << name << " hooks");
Andreas Gampee44b5792018-12-13 15:48:45 -080065 }
66 hook_file = &f;
67 }
Andreas Gampea00c5452018-12-10 13:38:33 -080068 }
Andreas Gampee44b5792018-12-13 15:48:45 -080069 CHECK(hook_file != nullptr);
Andreas Gampef7663552019-01-03 09:22:11 -080070 LOG(VERBOSE) << name << " for " << hook_file->GetPath();
Andreas Gampea00c5452018-12-10 13:38:33 -080071
Andreas Gampee44b5792018-12-13 15:48:45 -080072 std::vector<const ApexFile*> mounted_apexes;
73 std::vector<std::string> activation_dirs;
74 auto preinstall_guard = android::base::make_scope_guard([&]() {
75 for (const ApexFile* f : mounted_apexes) {
76 Status st = apexd_private::UnmountPackage(*f);
77 if (!st.Ok()) {
Andreas Gampef7663552019-01-03 09:22:11 -080078 LOG(ERROR) << "Failed to unmount " << f->GetPath() << " after " << name
79 << ": " << st.ErrorMessage();
Andreas Gampee44b5792018-12-13 15:48:45 -080080 }
81 }
82 for (const std::string& active_point : activation_dirs) {
83 if (0 != rmdir(active_point.c_str())) {
84 PLOG(ERROR) << "Could not delete temporary active point "
85 << active_point;
86 }
Andreas Gampe4510d492018-12-12 15:56:05 -080087 }
Andreas Gampee1a40392018-11-30 09:47:17 -080088 });
89
Andreas Gampee44b5792018-12-13 15:48:45 -080090 for (const ApexFile& apex : apexes) {
91 // 1) Mount the package, if necessary.
92 std::string mount_point =
93 apexd_private::GetPackageMountPoint(apex.GetManifest());
Andreas Gampee1a40392018-11-30 09:47:17 -080094
Abhijeet Kaur216e36c2019-01-04 10:15:01 +000095 if (!apexd_private::IsMounted(apex.GetManifest().name(), apex.GetPath())) {
Andreas Gampee44b5792018-12-13 15:48:45 -080096 Status mountStatus = apexd_private::MountPackage(apex, mount_point);
97 if (!mountStatus.Ok()) {
98 return mountStatus;
99 }
100 mounted_apexes.push_back(&apex);
Andreas Gampee1a40392018-11-30 09:47:17 -0800101 }
Andreas Gampee1a40392018-11-30 09:47:17 -0800102
Andreas Gampee44b5792018-12-13 15:48:45 -0800103 // 2) Ensure there is an activation point, and we will clean it up.
104 std::string active_point =
105 apexd_private::GetActiveMountPoint(apex.GetManifest());
106 if (0 == mkdir(active_point.c_str(), kMkdirMode)) {
107 activation_dirs.emplace_back(std::move(active_point));
108 } else {
Andreas Gampeb48122e2018-12-11 15:48:42 -0800109 int saved_errno = errno;
Andreas Gampeb48122e2018-12-11 15:48:42 -0800110 if (saved_errno != EEXIST) {
111 return Status::Fail(StringLog()
112 << "Unable to create mount point" << active_point
113 << ": " << strerror(saved_errno));
114 }
115 }
116 }
117
118 // 3) Create invocation args.
Andreas Gampee1a40392018-11-30 09:47:17 -0800119 std::vector<std::string> args{
Andreas Gampef7663552019-01-03 09:22:11 -0800120 "/system/bin/apexd", arg,
Andreas Gampee44b5792018-12-13 15:48:45 -0800121 hook_file->GetPath(), // Make the APEX with hook first.
Andreas Gampee1a40392018-11-30 09:47:17 -0800122 };
Andreas Gampee44b5792018-12-13 15:48:45 -0800123 for (const ApexFile& apex : apexes) {
124 if (&apex != hook_file) {
125 args.push_back(apex.GetPath());
126 }
127 }
128
Andreas Gampee1a40392018-11-30 09:47:17 -0800129 std::string error_msg;
130 int res = ForkAndRun(args, &error_msg);
131 return res == 0 ? Status::Success() : Status::Fail(error_msg);
132}
133
Andreas Gampef7663552019-01-03 09:22:11 -0800134template <typename Fn>
135int RunFnInstall(char** in_argv, Fn fn, const char* name) {
Nick Kralevich3501c7b2019-02-28 10:20:44 -0800136 // 1) Unshare.
Andreas Gampee1a40392018-11-30 09:47:17 -0800137 if (unshare(CLONE_NEWNS) != 0) {
Andreas Gampef7663552019-01-03 09:22:11 -0800138 PLOG(ERROR) << "Failed to unshare() for apex " << name;
Andreas Gampee1a40392018-11-30 09:47:17 -0800139 _exit(200);
140 }
141
Nick Kralevich3501c7b2019-02-28 10:20:44 -0800142 // 2) Make everything private, so that our (and hook's) changes do not
Andreas Gampe4ead9492019-02-08 13:08:43 -0800143 // propagate.
144 if (mount(nullptr, "/", nullptr, MS_PRIVATE | MS_REC, nullptr) == -1) {
Andreas Gampee1a40392018-11-30 09:47:17 -0800145 PLOG(ERROR) << "Failed to mount private.";
146 _exit(201);
147 }
148
Andreas Gampee44b5792018-12-13 15:48:45 -0800149 std::string hook_path;
Andreas Gampee1a40392018-11-30 09:47:17 -0800150 {
Andreas Gampef7663552019-01-03 09:22:11 -0800151 auto bind_fn = [&fn, name](const std::string& apex) {
152 std::string hook;
Andreas Gampee44b5792018-12-13 15:48:45 -0800153 std::string mount_point;
154 std::string active_point;
155 {
156 StatusOr<ApexFile> apex_file = ApexFile::Open(apex);
157 if (!apex_file.Ok()) {
Andreas Gampef7663552019-01-03 09:22:11 -0800158 LOG(ERROR) << "Could not open apex " << apex << " for " << name
159 << ": " << apex_file.ErrorMessage();
Andreas Gampee44b5792018-12-13 15:48:45 -0800160 _exit(202);
161 }
162 const ApexManifest& manifest = apex_file->GetManifest();
Andreas Gampef7663552019-01-03 09:22:11 -0800163 hook = (manifest.*fn)();
Andreas Gampee44b5792018-12-13 15:48:45 -0800164 mount_point = apexd_private::GetPackageMountPoint(manifest);
165 active_point = apexd_private::GetActiveMountPoint(manifest);
166 }
167
Nick Kralevich3501c7b2019-02-28 10:20:44 -0800168 // 3) Activate the new apex.
Andreas Gampee44b5792018-12-13 15:48:45 -0800169 Status bind_status = apexd_private::BindMount(active_point, mount_point);
170 if (!bind_status.Ok()) {
171 LOG(ERROR) << "Failed to bind-mount " << mount_point << " to "
172 << active_point << ": " << bind_status.ErrorMessage();
173 _exit(203);
174 }
175
Andreas Gampef7663552019-01-03 09:22:11 -0800176 return std::make_pair(active_point, hook);
Andreas Gampee44b5792018-12-13 15:48:45 -0800177 };
178
179 // First/main APEX.
Andreas Gampef7663552019-01-03 09:22:11 -0800180 auto [active_point, hook] = bind_fn(in_argv[2]);
181 hook_path = active_point + "/" + hook;
Andreas Gampee44b5792018-12-13 15:48:45 -0800182
183 for (size_t i = 3;; ++i) {
184 if (in_argv[i] == nullptr) {
185 break;
186 }
187 bind_fn(in_argv[i]); // Ignore result, hook will be empty.
Andreas Gampee1a40392018-11-30 09:47:17 -0800188 }
Andreas Gampee1a40392018-11-30 09:47:17 -0800189 }
190
Nick Kralevich3501c7b2019-02-28 10:20:44 -0800191 // 4) Run the hook.
Andreas Gampee1a40392018-11-30 09:47:17 -0800192
193 // For now, just run sh. But this probably needs to run the new linker.
194 std::vector<std::string> args{
Andreas Gampee44b5792018-12-13 15:48:45 -0800195 hook_path,
Andreas Gampee1a40392018-11-30 09:47:17 -0800196 };
197 std::vector<const char*> argv;
198 argv.resize(args.size() + 1, nullptr);
199 std::transform(args.begin(), args.end(), argv.begin(),
200 [](const std::string& in) { return in.c_str(); });
201
202 LOG(ERROR) << "execv of " << android::base::Join(args, " ");
203
Nick Kralevich3501c7b2019-02-28 10:20:44 -0800204 // Close all file descriptors. They are coming from the caller, we do not
205 // want to pass them on across our fork/exec into a different domain.
206 CloseSTDDescriptors();
207
Andreas Gampee1a40392018-11-30 09:47:17 -0800208 execv(argv[0], const_cast<char**>(argv.data()));
209 PLOG(ERROR) << "execv of " << android::base::Join(args, " ") << " failed";
210 _exit(204);
211}
212
Andreas Gampef7663552019-01-03 09:22:11 -0800213} // namespace
214
Andreas Gampe17739142019-01-09 16:00:26 -0800215Status StagePreInstall(const std::vector<ApexFile>& apexes) {
Abhijeet Kaur216e36c2019-01-04 10:15:01 +0000216 return StageFnInstall(apexes, &ApexManifest::preinstallhook, "--pre-install",
217 "pre-install");
Andreas Gampef7663552019-01-03 09:22:11 -0800218}
219
220int RunPreInstall(char** in_argv) {
Abhijeet Kaur216e36c2019-01-04 10:15:01 +0000221 return RunFnInstall(in_argv, &ApexManifest::preinstallhook, "pre-install");
Andreas Gampef7663552019-01-03 09:22:11 -0800222}
223
Andreas Gampe17739142019-01-09 16:00:26 -0800224Status StagePostInstall(const std::vector<ApexFile>& apexes) {
Abhijeet Kaur216e36c2019-01-04 10:15:01 +0000225 return StageFnInstall(apexes, &ApexManifest::postinstallhook,
Andreas Gampef7663552019-01-03 09:22:11 -0800226 "--post-install", "post-install");
227}
228
229int RunPostInstall(char** in_argv) {
Abhijeet Kaur216e36c2019-01-04 10:15:01 +0000230 return RunFnInstall(in_argv, &ApexManifest::postinstallhook, "post-install");
Andreas Gampef7663552019-01-03 09:22:11 -0800231}
232
Andreas Gampee1a40392018-11-30 09:47:17 -0800233} // namespace apex
234} // namespace android