blob: e11510ee8314ac9ff054c250ee60a420bd1be961 [file] [log] [blame]
David Anderson491e4da2020-12-08 00:21:20 -08001/*
2 * Copyright (C) 2020 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 "snapuserd_transition.h"
18
19#include <sys/mman.h>
20#include <sys/socket.h>
21#include <sys/syscall.h>
22#include <sys/xattr.h>
23#include <unistd.h>
24
25#include <filesystem>
26#include <string>
David Anderson9fd88622021-03-05 14:10:55 -080027#include <string_view>
David Anderson491e4da2020-12-08 00:21:20 -080028
29#include <android-base/file.h>
30#include <android-base/logging.h>
31#include <android-base/parseint.h>
32#include <android-base/strings.h>
33#include <android-base/unique_fd.h>
34#include <cutils/sockets.h>
35#include <libsnapshot/snapshot.h>
David Anderson491e4da2020-12-08 00:21:20 -080036#include <private/android_filesystem_config.h>
David Anderson9fd88622021-03-05 14:10:55 -080037#include <procinfo/process_map.h>
David Anderson491e4da2020-12-08 00:21:20 -080038#include <selinux/android.h>
Akilesh Kailash36aeeb32021-07-26 06:59:18 +000039#include <snapuserd/snapuserd_client.h>
David Anderson491e4da2020-12-08 00:21:20 -080040
41#include "block_dev_initializer.h"
42#include "service_utils.h"
43#include "util.h"
44
45namespace android {
46namespace init {
47
48using namespace std::string_literals;
49
50using android::base::unique_fd;
51using android::snapshot::SnapshotManager;
52using android::snapshot::SnapuserdClient;
53
54static constexpr char kSnapuserdPath[] = "/system/bin/snapuserd";
55static constexpr char kSnapuserdFirstStagePidVar[] = "FIRST_STAGE_SNAPUSERD_PID";
56static constexpr char kSnapuserdFirstStageFdVar[] = "FIRST_STAGE_SNAPUSERD_FD";
David Anderson0e5ad5a2021-07-21 21:53:28 -070057static constexpr char kSnapuserdFirstStageInfoVar[] = "FIRST_STAGE_SNAPUSERD_INFO";
David Anderson491e4da2020-12-08 00:21:20 -080058static constexpr char kSnapuserdLabel[] = "u:object_r:snapuserd_exec:s0";
59static constexpr char kSnapuserdSocketLabel[] = "u:object_r:snapuserd_socket:s0";
60
Akilesh Kailash3b874452021-10-03 09:41:13 +000061void LaunchFirstStageSnapuserd(SnapshotDriver driver) {
David Anderson491e4da2020-12-08 00:21:20 -080062 SocketDescriptor socket_desc;
63 socket_desc.name = android::snapshot::kSnapuserdSocket;
64 socket_desc.type = SOCK_STREAM;
65 socket_desc.perm = 0660;
66 socket_desc.uid = AID_SYSTEM;
67 socket_desc.gid = AID_SYSTEM;
68
69 // We specify a label here even though it technically is not needed. During
70 // first_stage_mount there is no sepolicy loaded. Once sepolicy is loaded,
71 // we bypass the socket entirely.
72 auto socket = socket_desc.Create(kSnapuserdSocketLabel);
73 if (!socket.ok()) {
74 LOG(FATAL) << "Could not create snapuserd socket: " << socket.error();
75 }
76
77 pid_t pid = fork();
78 if (pid < 0) {
79 PLOG(FATAL) << "Cannot launch snapuserd; fork failed";
80 }
81 if (pid == 0) {
82 socket->Publish();
Akilesh Kailash3b874452021-10-03 09:41:13 +000083
84 if (driver == SnapshotDriver::DM_USER) {
85 char arg0[] = "/system/bin/snapuserd";
86 char arg1[] = "-user_snapshot";
87 char* const argv[] = {arg0, arg1, nullptr};
88 if (execv(arg0, argv) < 0) {
89 PLOG(FATAL) << "Cannot launch snapuserd; execv failed";
90 }
91 _exit(127);
92 } else {
93 char arg0[] = "/system/bin/snapuserd";
94 char* const argv[] = {arg0, nullptr};
95 if (execv(arg0, argv) < 0) {
96 PLOG(FATAL) << "Cannot launch snapuserd; execv failed";
97 }
98 _exit(127);
David Anderson491e4da2020-12-08 00:21:20 -080099 }
David Anderson491e4da2020-12-08 00:21:20 -0800100 }
101
David Anderson0e5ad5a2021-07-21 21:53:28 -0700102 auto client = SnapuserdClient::Connect(android::snapshot::kSnapuserdSocket, 10s);
103 if (!client) {
104 LOG(FATAL) << "Could not connect to first-stage snapuserd";
105 }
106 if (client->SupportsSecondStageSocketHandoff()) {
107 setenv(kSnapuserdFirstStageInfoVar, "socket", 1);
108 }
109
David Anderson491e4da2020-12-08 00:21:20 -0800110 setenv(kSnapuserdFirstStagePidVar, std::to_string(pid).c_str(), 1);
111
112 LOG(INFO) << "Relaunched snapuserd with pid: " << pid;
113}
114
115std::optional<pid_t> GetSnapuserdFirstStagePid() {
116 const char* pid_str = getenv(kSnapuserdFirstStagePidVar);
117 if (!pid_str) {
118 return {};
119 }
120
121 int pid = 0;
122 if (!android::base::ParseInt(pid_str, &pid)) {
123 LOG(FATAL) << "Could not parse pid in environment, " << kSnapuserdFirstStagePidVar << "="
124 << pid_str;
125 }
126 return {pid};
127}
128
129static void RelabelLink(const std::string& link) {
130 selinux_android_restorecon(link.c_str(), 0);
131
132 std::string path;
133 if (android::base::Readlink(link, &path)) {
134 selinux_android_restorecon(path.c_str(), 0);
135 }
136}
137
138static void RelabelDeviceMapper() {
139 selinux_android_restorecon("/dev/device-mapper", 0);
140
141 std::error_code ec;
142 for (auto& iter : std::filesystem::directory_iterator("/dev/block", ec)) {
143 const auto& path = iter.path();
144 if (android::base::StartsWith(path.string(), "/dev/block/dm-")) {
145 selinux_android_restorecon(path.string().c_str(), 0);
146 }
147 }
148}
149
150static std::optional<int> GetRamdiskSnapuserdFd() {
151 const char* fd_str = getenv(kSnapuserdFirstStageFdVar);
152 if (!fd_str) {
153 return {};
154 }
155
156 int fd;
157 if (!android::base::ParseInt(fd_str, &fd)) {
158 LOG(FATAL) << "Could not parse fd in environment, " << kSnapuserdFirstStageFdVar << "="
159 << fd_str;
160 }
161 return {fd};
162}
163
164void RestoreconRamdiskSnapuserd(int fd) {
165 if (fsetxattr(fd, XATTR_NAME_SELINUX, kSnapuserdLabel, strlen(kSnapuserdLabel) + 1, 0) < 0) {
166 PLOG(FATAL) << "fsetxattr snapuserd failed";
167 }
168}
169
170SnapuserdSelinuxHelper::SnapuserdSelinuxHelper(std::unique_ptr<SnapshotManager>&& sm, pid_t old_pid)
171 : sm_(std::move(sm)), old_pid_(old_pid) {
172 // Only dm-user device names change during transitions, so the other
173 // devices are expected to be present.
174 sm_->SetUeventRegenCallback([this](const std::string& device) -> bool {
175 if (android::base::StartsWith(device, "/dev/dm-user/")) {
176 return block_dev_init_.InitDmUser(android::base::Basename(device));
177 }
178 return true;
179 });
180}
181
David Anderson9fd88622021-03-05 14:10:55 -0800182static void LockAllSystemPages() {
183 bool ok = true;
184 auto callback = [&](const android::procinfo::MapInfo& map) -> void {
185 if (!ok || android::base::StartsWith(map.name, "/dev/") ||
186 !android::base::StartsWith(map.name, "/")) {
187 return;
188 }
189 auto start = reinterpret_cast<const void*>(map.start);
190 auto len = map.end - map.start;
191 if (!len) {
192 return;
193 }
194 if (mlock(start, len) < 0) {
195 LOG(ERROR) << "mlock failed, " << start << " for " << len << " bytes.";
196 ok = false;
197 }
198 };
199
200 if (!android::procinfo::ReadProcessMaps(getpid(), callback) || !ok) {
201 LOG(FATAL) << "Could not process /proc/" << getpid() << "/maps file for init, "
202 << "falling back to mlockall().";
203 if (mlockall(MCL_CURRENT) < 0) {
204 LOG(FATAL) << "mlockall failed";
205 }
206 }
207}
208
David Anderson491e4da2020-12-08 00:21:20 -0800209void SnapuserdSelinuxHelper::StartTransition() {
210 LOG(INFO) << "Starting SELinux transition of snapuserd";
211
212 // The restorecon path reads from /system etc, so make sure any reads have
213 // been cached before proceeding.
214 auto handle = selinux_android_file_context_handle();
215 if (!handle) {
216 LOG(FATAL) << "Could not create SELinux file context handle";
217 }
218 selinux_android_set_sehandle(handle);
219
220 // We cannot access /system after the transition, so make sure init is
221 // pinned in memory.
David Anderson9fd88622021-03-05 14:10:55 -0800222 LockAllSystemPages();
David Anderson491e4da2020-12-08 00:21:20 -0800223
224 argv_.emplace_back("snapuserd");
225 argv_.emplace_back("-no_socket");
226 if (!sm_->DetachSnapuserdForSelinux(&argv_)) {
227 LOG(FATAL) << "Could not perform selinux transition";
228 }
229
230 // Make sure the process is gone so we don't have any selinux audits.
231 KillFirstStageSnapuserd(old_pid_);
232}
233
234void SnapuserdSelinuxHelper::FinishTransition() {
235 RelabelLink("/dev/block/by-name/super");
236 RelabelDeviceMapper();
237
238 selinux_android_restorecon("/dev/null", 0);
239 selinux_android_restorecon("/dev/urandom", 0);
240 selinux_android_restorecon("/dev/kmsg", 0);
241 selinux_android_restorecon("/dev/dm-user", SELINUX_ANDROID_RESTORECON_RECURSE);
242
243 RelaunchFirstStageSnapuserd();
244
245 if (munlockall() < 0) {
246 PLOG(ERROR) << "munlockall failed";
247 }
248}
249
250void SnapuserdSelinuxHelper::RelaunchFirstStageSnapuserd() {
251 auto fd = GetRamdiskSnapuserdFd();
252 if (!fd) {
253 LOG(FATAL) << "Environment variable " << kSnapuserdFirstStageFdVar << " was not set!";
254 }
255 unsetenv(kSnapuserdFirstStageFdVar);
256
257 RestoreconRamdiskSnapuserd(fd.value());
258
259 pid_t pid = fork();
260 if (pid < 0) {
261 PLOG(FATAL) << "Fork to relaunch snapuserd failed";
262 }
263 if (pid > 0) {
264 // We don't need the descriptor anymore, and it should be closed to
265 // avoid leaking into subprocesses.
266 close(fd.value());
267
268 setenv(kSnapuserdFirstStagePidVar, std::to_string(pid).c_str(), 1);
269
270 LOG(INFO) << "Relaunched snapuserd with pid: " << pid;
271 return;
272 }
273
274 // Make sure the descriptor is gone after we exec.
275 if (fcntl(fd.value(), F_SETFD, FD_CLOEXEC) < 0) {
276 PLOG(FATAL) << "fcntl FD_CLOEXEC failed for snapuserd fd";
277 }
278
279 std::vector<char*> argv;
280 for (auto& arg : argv_) {
281 argv.emplace_back(arg.data());
282 }
283 argv.emplace_back(nullptr);
284
285 int rv = syscall(SYS_execveat, fd.value(), "", reinterpret_cast<char* const*>(argv.data()),
286 nullptr, AT_EMPTY_PATH);
287 if (rv < 0) {
288 PLOG(FATAL) << "Failed to execveat() snapuserd";
289 }
290}
291
292std::unique_ptr<SnapuserdSelinuxHelper> SnapuserdSelinuxHelper::CreateIfNeeded() {
293 if (IsRecoveryMode()) {
294 return nullptr;
295 }
296
297 auto old_pid = GetSnapuserdFirstStagePid();
298 if (!old_pid) {
299 return nullptr;
300 }
301
302 auto sm = SnapshotManager::NewForFirstStageMount();
303 if (!sm) {
304 LOG(FATAL) << "Unable to create SnapshotManager";
305 }
306 return std::make_unique<SnapuserdSelinuxHelper>(std::move(sm), old_pid.value());
307}
308
309void KillFirstStageSnapuserd(pid_t pid) {
310 if (kill(pid, SIGTERM) < 0 && errno != ESRCH) {
311 LOG(ERROR) << "Kill snapuserd pid failed: " << pid;
312 } else {
313 LOG(INFO) << "Sent SIGTERM to snapuserd process " << pid;
314 }
315}
316
317void CleanupSnapuserdSocket() {
318 auto socket_path = ANDROID_SOCKET_DIR "/"s + android::snapshot::kSnapuserdSocket;
319 if (access(socket_path.c_str(), F_OK) != 0) {
320 return;
321 }
322
323 // Tell the daemon to stop accepting connections and to gracefully exit
324 // once all outstanding handlers have terminated.
325 if (auto client = SnapuserdClient::Connect(android::snapshot::kSnapuserdSocket, 3s)) {
326 client->DetachSnapuserd();
327 }
328
329 // Unlink the socket so we can create it again in second-stage.
330 if (unlink(socket_path.c_str()) < 0) {
331 PLOG(FATAL) << "unlink " << socket_path << " failed";
332 }
333}
334
335void SaveRamdiskPathToSnapuserd() {
336 int fd = open(kSnapuserdPath, O_PATH);
337 if (fd < 0) {
338 PLOG(FATAL) << "Unable to open snapuserd: " << kSnapuserdPath;
339 }
340
341 auto value = std::to_string(fd);
342 if (setenv(kSnapuserdFirstStageFdVar, value.c_str(), 1) < 0) {
343 PLOG(FATAL) << "setenv failed: " << kSnapuserdFirstStageFdVar << "=" << value;
344 }
345}
346
347bool IsFirstStageSnapuserdRunning() {
348 return GetSnapuserdFirstStagePid().has_value();
349}
350
David Anderson0e5ad5a2021-07-21 21:53:28 -0700351std::vector<std::string> GetSnapuserdFirstStageInfo() {
352 const char* pid_str = getenv(kSnapuserdFirstStageInfoVar);
353 if (!pid_str) {
354 return {};
355 }
356 return android::base::Split(pid_str, ",");
357}
358
David Anderson491e4da2020-12-08 00:21:20 -0800359} // namespace init
360} // namespace android