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 #define LOG_TAG "apexd"
18
19 #include "apexd_prepostinstall.h"
20
21 #include <algorithm>
22 #include <vector>
23
24 #include <fcntl.h>
25 #include <sys/mount.h>
26 #include <sys/stat.h>
27 #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
42 namespace android {
43 namespace apex {
44
45 namespace {
46
CloseSTDDescriptors()47 void 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);
53 }
54
55 template <typename Fn>
StageFnInstall(const std::vector<ApexFile> & apexes,Fn fn,const char * arg,const char * name)56 Status StageFnInstall(const std::vector<ApexFile>& apexes, Fn fn,
57 const char* arg, const char* name) {
58 // TODO: Support a session with more than one pre-install hook.
59 const ApexFile* hook_file = nullptr;
60 for (const ApexFile& f : apexes) {
61 if (!(f.GetManifest().*fn)().empty()) {
62 if (hook_file != nullptr) {
63 return Status::Fail(StringLog() << "Missing support for multiple "
64 << name << " hooks");
65 }
66 hook_file = &f;
67 }
68 }
69 CHECK(hook_file != nullptr);
70 LOG(VERBOSE) << name << " for " << hook_file->GetPath();
71
72 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()) {
78 LOG(ERROR) << "Failed to unmount " << f->GetPath() << " after " << name
79 << ": " << st.ErrorMessage();
80 }
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 }
87 }
88 });
89
90 for (const ApexFile& apex : apexes) {
91 // 1) Mount the package, if necessary.
92 std::string mount_point =
93 apexd_private::GetPackageMountPoint(apex.GetManifest());
94
95 if (!apexd_private::IsMounted(apex.GetManifest().name(), apex.GetPath())) {
96 Status mountStatus = apexd_private::MountPackage(apex, mount_point);
97 if (!mountStatus.Ok()) {
98 return mountStatus;
99 }
100 mounted_apexes.push_back(&apex);
101 }
102
103 // 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 {
109 int saved_errno = errno;
110 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.
119 std::vector<std::string> args{
120 "/system/bin/apexd", arg,
121 hook_file->GetPath(), // Make the APEX with hook first.
122 };
123 for (const ApexFile& apex : apexes) {
124 if (&apex != hook_file) {
125 args.push_back(apex.GetPath());
126 }
127 }
128
129 std::string error_msg;
130 int res = ForkAndRun(args, &error_msg);
131 return res == 0 ? Status::Success() : Status::Fail(error_msg);
132 }
133
134 template <typename Fn>
RunFnInstall(char ** in_argv,Fn fn,const char * name)135 int RunFnInstall(char** in_argv, Fn fn, const char* name) {
136 // 1) Unshare.
137 if (unshare(CLONE_NEWNS) != 0) {
138 PLOG(ERROR) << "Failed to unshare() for apex " << name;
139 _exit(200);
140 }
141
142 // 2) Make everything private, so that our (and hook's) changes do not
143 // propagate.
144 if (mount(nullptr, "/", nullptr, MS_PRIVATE | MS_REC, nullptr) == -1) {
145 PLOG(ERROR) << "Failed to mount private.";
146 _exit(201);
147 }
148
149 std::string hook_path;
150 {
151 auto bind_fn = [&fn, name](const std::string& apex) {
152 std::string hook;
153 std::string mount_point;
154 std::string active_point;
155 {
156 StatusOr<ApexFile> apex_file = ApexFile::Open(apex);
157 if (!apex_file.Ok()) {
158 LOG(ERROR) << "Could not open apex " << apex << " for " << name
159 << ": " << apex_file.ErrorMessage();
160 _exit(202);
161 }
162 const ApexManifest& manifest = apex_file->GetManifest();
163 hook = (manifest.*fn)();
164 mount_point = apexd_private::GetPackageMountPoint(manifest);
165 active_point = apexd_private::GetActiveMountPoint(manifest);
166 }
167
168 // 3) Activate the new apex.
169 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
176 return std::make_pair(active_point, hook);
177 };
178
179 // First/main APEX.
180 auto [active_point, hook] = bind_fn(in_argv[2]);
181 hook_path = active_point + "/" + hook;
182
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.
188 }
189 }
190
191 // 4) Run the hook.
192
193 // For now, just run sh. But this probably needs to run the new linker.
194 std::vector<std::string> args{
195 hook_path,
196 };
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
204 // 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
208 execv(argv[0], const_cast<char**>(argv.data()));
209 PLOG(ERROR) << "execv of " << android::base::Join(args, " ") << " failed";
210 _exit(204);
211 }
212
213 } // namespace
214
StagePreInstall(const std::vector<ApexFile> & apexes)215 Status StagePreInstall(const std::vector<ApexFile>& apexes) {
216 return StageFnInstall(apexes, &ApexManifest::preinstallhook, "--pre-install",
217 "pre-install");
218 }
219
RunPreInstall(char ** in_argv)220 int RunPreInstall(char** in_argv) {
221 return RunFnInstall(in_argv, &ApexManifest::preinstallhook, "pre-install");
222 }
223
StagePostInstall(const std::vector<ApexFile> & apexes)224 Status StagePostInstall(const std::vector<ApexFile>& apexes) {
225 return StageFnInstall(apexes, &ApexManifest::postinstallhook,
226 "--post-install", "post-install");
227 }
228
RunPostInstall(char ** in_argv)229 int RunPostInstall(char** in_argv) {
230 return RunFnInstall(in_argv, &ApexManifest::postinstallhook, "post-install");
231 }
232
233 } // namespace apex
234 } // namespace android
235