blob: 5deaf31568c4639094ba3ac7f664f26e68151a83 [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>
Akilesh Kailashfd5562b2022-01-25 07:05:31 +000035#include <fs_avb/fs_avb.h>
David Anderson491e4da2020-12-08 00:21:20 -080036#include <libsnapshot/snapshot.h>
David Anderson491e4da2020-12-08 00:21:20 -080037#include <private/android_filesystem_config.h>
David Anderson9fd88622021-03-05 14:10:55 -080038#include <procinfo/process_map.h>
David Anderson491e4da2020-12-08 00:21:20 -080039#include <selinux/android.h>
Akilesh Kailash36aeeb32021-07-26 06:59:18 +000040#include <snapuserd/snapuserd_client.h>
David Anderson491e4da2020-12-08 00:21:20 -080041
42#include "block_dev_initializer.h"
43#include "service_utils.h"
44#include "util.h"
45
46namespace android {
47namespace init {
48
49using namespace std::string_literals;
50
51using android::base::unique_fd;
52using android::snapshot::SnapshotManager;
53using android::snapshot::SnapuserdClient;
54
55static constexpr char kSnapuserdPath[] = "/system/bin/snapuserd";
56static constexpr char kSnapuserdFirstStagePidVar[] = "FIRST_STAGE_SNAPUSERD_PID";
57static constexpr char kSnapuserdFirstStageFdVar[] = "FIRST_STAGE_SNAPUSERD_FD";
David Anderson0e5ad5a2021-07-21 21:53:28 -070058static constexpr char kSnapuserdFirstStageInfoVar[] = "FIRST_STAGE_SNAPUSERD_INFO";
David Anderson491e4da2020-12-08 00:21:20 -080059static constexpr char kSnapuserdLabel[] = "u:object_r:snapuserd_exec:s0";
60static constexpr char kSnapuserdSocketLabel[] = "u:object_r:snapuserd_socket:s0";
61
Akilesh Kailash3b874452021-10-03 09:41:13 +000062void LaunchFirstStageSnapuserd(SnapshotDriver driver) {
David Anderson491e4da2020-12-08 00:21:20 -080063 SocketDescriptor socket_desc;
64 socket_desc.name = android::snapshot::kSnapuserdSocket;
65 socket_desc.type = SOCK_STREAM;
66 socket_desc.perm = 0660;
67 socket_desc.uid = AID_SYSTEM;
68 socket_desc.gid = AID_SYSTEM;
69
70 // We specify a label here even though it technically is not needed. During
71 // first_stage_mount there is no sepolicy loaded. Once sepolicy is loaded,
72 // we bypass the socket entirely.
73 auto socket = socket_desc.Create(kSnapuserdSocketLabel);
74 if (!socket.ok()) {
75 LOG(FATAL) << "Could not create snapuserd socket: " << socket.error();
76 }
77
78 pid_t pid = fork();
79 if (pid < 0) {
80 PLOG(FATAL) << "Cannot launch snapuserd; fork failed";
81 }
82 if (pid == 0) {
83 socket->Publish();
Akilesh Kailash3b874452021-10-03 09:41:13 +000084
85 if (driver == SnapshotDriver::DM_USER) {
86 char arg0[] = "/system/bin/snapuserd";
87 char arg1[] = "-user_snapshot";
88 char* const argv[] = {arg0, arg1, nullptr};
89 if (execv(arg0, argv) < 0) {
90 PLOG(FATAL) << "Cannot launch snapuserd; execv failed";
91 }
92 _exit(127);
93 } else {
94 char arg0[] = "/system/bin/snapuserd";
95 char* const argv[] = {arg0, nullptr};
96 if (execv(arg0, argv) < 0) {
97 PLOG(FATAL) << "Cannot launch snapuserd; execv failed";
98 }
99 _exit(127);
David Anderson491e4da2020-12-08 00:21:20 -0800100 }
David Anderson491e4da2020-12-08 00:21:20 -0800101 }
102
David Anderson0e5ad5a2021-07-21 21:53:28 -0700103 auto client = SnapuserdClient::Connect(android::snapshot::kSnapuserdSocket, 10s);
104 if (!client) {
105 LOG(FATAL) << "Could not connect to first-stage snapuserd";
106 }
107 if (client->SupportsSecondStageSocketHandoff()) {
108 setenv(kSnapuserdFirstStageInfoVar, "socket", 1);
109 }
110
David Anderson491e4da2020-12-08 00:21:20 -0800111 setenv(kSnapuserdFirstStagePidVar, std::to_string(pid).c_str(), 1);
112
113 LOG(INFO) << "Relaunched snapuserd with pid: " << pid;
114}
115
116std::optional<pid_t> GetSnapuserdFirstStagePid() {
117 const char* pid_str = getenv(kSnapuserdFirstStagePidVar);
118 if (!pid_str) {
119 return {};
120 }
121
122 int pid = 0;
123 if (!android::base::ParseInt(pid_str, &pid)) {
124 LOG(FATAL) << "Could not parse pid in environment, " << kSnapuserdFirstStagePidVar << "="
125 << pid_str;
126 }
127 return {pid};
128}
129
130static void RelabelLink(const std::string& link) {
131 selinux_android_restorecon(link.c_str(), 0);
132
133 std::string path;
134 if (android::base::Readlink(link, &path)) {
135 selinux_android_restorecon(path.c_str(), 0);
136 }
137}
138
139static void RelabelDeviceMapper() {
140 selinux_android_restorecon("/dev/device-mapper", 0);
141
142 std::error_code ec;
143 for (auto& iter : std::filesystem::directory_iterator("/dev/block", ec)) {
144 const auto& path = iter.path();
145 if (android::base::StartsWith(path.string(), "/dev/block/dm-")) {
146 selinux_android_restorecon(path.string().c_str(), 0);
147 }
148 }
149}
150
151static std::optional<int> GetRamdiskSnapuserdFd() {
152 const char* fd_str = getenv(kSnapuserdFirstStageFdVar);
153 if (!fd_str) {
154 return {};
155 }
156
157 int fd;
158 if (!android::base::ParseInt(fd_str, &fd)) {
159 LOG(FATAL) << "Could not parse fd in environment, " << kSnapuserdFirstStageFdVar << "="
160 << fd_str;
161 }
162 return {fd};
163}
164
165void RestoreconRamdiskSnapuserd(int fd) {
166 if (fsetxattr(fd, XATTR_NAME_SELINUX, kSnapuserdLabel, strlen(kSnapuserdLabel) + 1, 0) < 0) {
167 PLOG(FATAL) << "fsetxattr snapuserd failed";
168 }
169}
170
171SnapuserdSelinuxHelper::SnapuserdSelinuxHelper(std::unique_ptr<SnapshotManager>&& sm, pid_t old_pid)
172 : sm_(std::move(sm)), old_pid_(old_pid) {
173 // Only dm-user device names change during transitions, so the other
174 // devices are expected to be present.
175 sm_->SetUeventRegenCallback([this](const std::string& device) -> bool {
176 if (android::base::StartsWith(device, "/dev/dm-user/")) {
177 return block_dev_init_.InitDmUser(android::base::Basename(device));
178 }
179 return true;
180 });
181}
182
David Anderson9fd88622021-03-05 14:10:55 -0800183static void LockAllSystemPages() {
184 bool ok = true;
185 auto callback = [&](const android::procinfo::MapInfo& map) -> void {
186 if (!ok || android::base::StartsWith(map.name, "/dev/") ||
187 !android::base::StartsWith(map.name, "/")) {
188 return;
189 }
190 auto start = reinterpret_cast<const void*>(map.start);
191 auto len = map.end - map.start;
192 if (!len) {
193 return;
194 }
195 if (mlock(start, len) < 0) {
196 LOG(ERROR) << "mlock failed, " << start << " for " << len << " bytes.";
197 ok = false;
198 }
199 };
200
201 if (!android::procinfo::ReadProcessMaps(getpid(), callback) || !ok) {
202 LOG(FATAL) << "Could not process /proc/" << getpid() << "/maps file for init, "
203 << "falling back to mlockall().";
204 if (mlockall(MCL_CURRENT) < 0) {
205 LOG(FATAL) << "mlockall failed";
206 }
207 }
208}
209
David Anderson491e4da2020-12-08 00:21:20 -0800210void SnapuserdSelinuxHelper::StartTransition() {
211 LOG(INFO) << "Starting SELinux transition of snapuserd";
212
213 // The restorecon path reads from /system etc, so make sure any reads have
214 // been cached before proceeding.
215 auto handle = selinux_android_file_context_handle();
216 if (!handle) {
217 LOG(FATAL) << "Could not create SELinux file context handle";
218 }
219 selinux_android_set_sehandle(handle);
220
221 // We cannot access /system after the transition, so make sure init is
222 // pinned in memory.
David Anderson9fd88622021-03-05 14:10:55 -0800223 LockAllSystemPages();
David Anderson491e4da2020-12-08 00:21:20 -0800224
225 argv_.emplace_back("snapuserd");
226 argv_.emplace_back("-no_socket");
227 if (!sm_->DetachSnapuserdForSelinux(&argv_)) {
228 LOG(FATAL) << "Could not perform selinux transition";
229 }
230
231 // Make sure the process is gone so we don't have any selinux audits.
232 KillFirstStageSnapuserd(old_pid_);
233}
234
235void SnapuserdSelinuxHelper::FinishTransition() {
236 RelabelLink("/dev/block/by-name/super");
237 RelabelDeviceMapper();
238
239 selinux_android_restorecon("/dev/null", 0);
240 selinux_android_restorecon("/dev/urandom", 0);
241 selinux_android_restorecon("/dev/kmsg", 0);
242 selinux_android_restorecon("/dev/dm-user", SELINUX_ANDROID_RESTORECON_RECURSE);
243
244 RelaunchFirstStageSnapuserd();
245
246 if (munlockall() < 0) {
247 PLOG(ERROR) << "munlockall failed";
248 }
249}
250
Akilesh Kailashfd5562b2022-01-25 07:05:31 +0000251/*
252 * Before starting init second stage, we will wait
253 * for snapuserd daemon to be up and running; bionic libc
254 * may read /system/etc/selinux/plat_property_contexts file
255 * before invoking main() function. This will happen if
256 * init initializes property during second stage. Any access
257 * to /system without snapuserd daemon will lead to a deadlock.
258 *
259 * Thus, we do a simple probe by reading system partition. This
260 * read will eventually be serviced by daemon confirming that
261 * daemon is up and running. Furthermore, we are still in the kernel
262 * domain and sepolicy has not been enforced yet. Thus, access
263 * to these device mapper block devices are ok even though
264 * we may see audit logs.
265 */
266bool SnapuserdSelinuxHelper::TestSnapuserdIsReady() {
267 std::string dev = "/dev/block/mapper/system"s + fs_mgr_get_slot_suffix();
268 android::base::unique_fd fd(open(dev.c_str(), O_RDONLY | O_DIRECT));
269 if (fd < 0) {
270 PLOG(ERROR) << "open " << dev << " failed";
271 return false;
272 }
273
274 void* addr;
275 ssize_t page_size = getpagesize();
276 if (posix_memalign(&addr, page_size, page_size) < 0) {
277 PLOG(ERROR) << "posix_memalign with page size " << page_size;
278 return false;
279 }
280
281 std::unique_ptr<void, decltype(&::free)> buffer(addr, ::free);
282
283 int iter = 0;
284 while (iter < 10) {
285 ssize_t n = TEMP_FAILURE_RETRY(pread(fd.get(), buffer.get(), page_size, 0));
286 if (n < 0) {
287 // Wait for sometime before retry
288 std::this_thread::sleep_for(100ms);
289 } else if (n == page_size) {
290 return true;
291 } else {
292 LOG(ERROR) << "pread returned: " << n << " from: " << dev << " expected: " << page_size;
293 }
294
295 iter += 1;
296 }
297
298 return false;
299}
300
David Anderson491e4da2020-12-08 00:21:20 -0800301void SnapuserdSelinuxHelper::RelaunchFirstStageSnapuserd() {
302 auto fd = GetRamdiskSnapuserdFd();
303 if (!fd) {
304 LOG(FATAL) << "Environment variable " << kSnapuserdFirstStageFdVar << " was not set!";
305 }
306 unsetenv(kSnapuserdFirstStageFdVar);
307
308 RestoreconRamdiskSnapuserd(fd.value());
309
310 pid_t pid = fork();
311 if (pid < 0) {
312 PLOG(FATAL) << "Fork to relaunch snapuserd failed";
313 }
314 if (pid > 0) {
315 // We don't need the descriptor anymore, and it should be closed to
316 // avoid leaking into subprocesses.
317 close(fd.value());
318
319 setenv(kSnapuserdFirstStagePidVar, std::to_string(pid).c_str(), 1);
320
321 LOG(INFO) << "Relaunched snapuserd with pid: " << pid;
Akilesh Kailashfd5562b2022-01-25 07:05:31 +0000322
323 if (!TestSnapuserdIsReady()) {
324 PLOG(FATAL) << "snapuserd daemon failed to launch";
325 } else {
326 LOG(INFO) << "snapuserd daemon is up and running";
327 }
328
David Anderson491e4da2020-12-08 00:21:20 -0800329 return;
330 }
331
332 // Make sure the descriptor is gone after we exec.
333 if (fcntl(fd.value(), F_SETFD, FD_CLOEXEC) < 0) {
334 PLOG(FATAL) << "fcntl FD_CLOEXEC failed for snapuserd fd";
335 }
336
337 std::vector<char*> argv;
338 for (auto& arg : argv_) {
339 argv.emplace_back(arg.data());
340 }
341 argv.emplace_back(nullptr);
342
343 int rv = syscall(SYS_execveat, fd.value(), "", reinterpret_cast<char* const*>(argv.data()),
344 nullptr, AT_EMPTY_PATH);
345 if (rv < 0) {
346 PLOG(FATAL) << "Failed to execveat() snapuserd";
347 }
348}
349
350std::unique_ptr<SnapuserdSelinuxHelper> SnapuserdSelinuxHelper::CreateIfNeeded() {
351 if (IsRecoveryMode()) {
352 return nullptr;
353 }
354
355 auto old_pid = GetSnapuserdFirstStagePid();
356 if (!old_pid) {
357 return nullptr;
358 }
359
360 auto sm = SnapshotManager::NewForFirstStageMount();
361 if (!sm) {
362 LOG(FATAL) << "Unable to create SnapshotManager";
363 }
364 return std::make_unique<SnapuserdSelinuxHelper>(std::move(sm), old_pid.value());
365}
366
367void KillFirstStageSnapuserd(pid_t pid) {
368 if (kill(pid, SIGTERM) < 0 && errno != ESRCH) {
369 LOG(ERROR) << "Kill snapuserd pid failed: " << pid;
370 } else {
371 LOG(INFO) << "Sent SIGTERM to snapuserd process " << pid;
372 }
373}
374
375void CleanupSnapuserdSocket() {
376 auto socket_path = ANDROID_SOCKET_DIR "/"s + android::snapshot::kSnapuserdSocket;
377 if (access(socket_path.c_str(), F_OK) != 0) {
378 return;
379 }
380
381 // Tell the daemon to stop accepting connections and to gracefully exit
382 // once all outstanding handlers have terminated.
383 if (auto client = SnapuserdClient::Connect(android::snapshot::kSnapuserdSocket, 3s)) {
384 client->DetachSnapuserd();
385 }
386
387 // Unlink the socket so we can create it again in second-stage.
388 if (unlink(socket_path.c_str()) < 0) {
389 PLOG(FATAL) << "unlink " << socket_path << " failed";
390 }
391}
392
393void SaveRamdiskPathToSnapuserd() {
394 int fd = open(kSnapuserdPath, O_PATH);
395 if (fd < 0) {
396 PLOG(FATAL) << "Unable to open snapuserd: " << kSnapuserdPath;
397 }
398
399 auto value = std::to_string(fd);
400 if (setenv(kSnapuserdFirstStageFdVar, value.c_str(), 1) < 0) {
401 PLOG(FATAL) << "setenv failed: " << kSnapuserdFirstStageFdVar << "=" << value;
402 }
403}
404
405bool IsFirstStageSnapuserdRunning() {
406 return GetSnapuserdFirstStagePid().has_value();
407}
408
David Anderson0e5ad5a2021-07-21 21:53:28 -0700409std::vector<std::string> GetSnapuserdFirstStageInfo() {
410 const char* pid_str = getenv(kSnapuserdFirstStageInfoVar);
411 if (!pid_str) {
412 return {};
413 }
414 return android::base::Split(pid_str, ",");
415}
416
David Anderson491e4da2020-12-08 00:21:20 -0800417} // namespace init
418} // namespace android