blob: dea7af97b9fd2cc312afb3012877bf2ea6f9004e [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>
Kelvin Zhangcb3cfc12023-12-11 11:14:48 -080028#include <thread>
David Anderson491e4da2020-12-08 00:21:20 -080029
30#include <android-base/file.h>
31#include <android-base/logging.h>
32#include <android-base/parseint.h>
Akilesh Kailash4ffe8a32022-06-02 08:00:39 +000033#include <android-base/stringprintf.h>
David Anderson491e4da2020-12-08 00:21:20 -080034#include <android-base/strings.h>
35#include <android-base/unique_fd.h>
36#include <cutils/sockets.h>
Akilesh Kailashfd5562b2022-01-25 07:05:31 +000037#include <fs_avb/fs_avb.h>
David Anderson491e4da2020-12-08 00:21:20 -080038#include <libsnapshot/snapshot.h>
David Anderson491e4da2020-12-08 00:21:20 -080039#include <private/android_filesystem_config.h>
David Anderson9fd88622021-03-05 14:10:55 -080040#include <procinfo/process_map.h>
David Anderson491e4da2020-12-08 00:21:20 -080041#include <selinux/android.h>
Akilesh Kailash36aeeb32021-07-26 06:59:18 +000042#include <snapuserd/snapuserd_client.h>
David Anderson491e4da2020-12-08 00:21:20 -080043
44#include "block_dev_initializer.h"
Akilesh Kailash4ffe8a32022-06-02 08:00:39 +000045#include "lmkd_service.h"
David Anderson491e4da2020-12-08 00:21:20 -080046#include "service_utils.h"
47#include "util.h"
48
49namespace android {
50namespace init {
51
52using namespace std::string_literals;
53
54using android::base::unique_fd;
55using android::snapshot::SnapshotManager;
56using android::snapshot::SnapuserdClient;
57
58static constexpr char kSnapuserdPath[] = "/system/bin/snapuserd";
59static constexpr char kSnapuserdFirstStagePidVar[] = "FIRST_STAGE_SNAPUSERD_PID";
60static constexpr char kSnapuserdFirstStageFdVar[] = "FIRST_STAGE_SNAPUSERD_FD";
David Anderson0e5ad5a2021-07-21 21:53:28 -070061static constexpr char kSnapuserdFirstStageInfoVar[] = "FIRST_STAGE_SNAPUSERD_INFO";
David Anderson491e4da2020-12-08 00:21:20 -080062static constexpr char kSnapuserdLabel[] = "u:object_r:snapuserd_exec:s0";
63static constexpr char kSnapuserdSocketLabel[] = "u:object_r:snapuserd_socket:s0";
64
Akilesh Kailash3b874452021-10-03 09:41:13 +000065void LaunchFirstStageSnapuserd(SnapshotDriver driver) {
David Anderson491e4da2020-12-08 00:21:20 -080066 SocketDescriptor socket_desc;
67 socket_desc.name = android::snapshot::kSnapuserdSocket;
68 socket_desc.type = SOCK_STREAM;
69 socket_desc.perm = 0660;
70 socket_desc.uid = AID_SYSTEM;
71 socket_desc.gid = AID_SYSTEM;
72
73 // We specify a label here even though it technically is not needed. During
74 // first_stage_mount there is no sepolicy loaded. Once sepolicy is loaded,
75 // we bypass the socket entirely.
76 auto socket = socket_desc.Create(kSnapuserdSocketLabel);
77 if (!socket.ok()) {
78 LOG(FATAL) << "Could not create snapuserd socket: " << socket.error();
79 }
80
81 pid_t pid = fork();
82 if (pid < 0) {
83 PLOG(FATAL) << "Cannot launch snapuserd; fork failed";
84 }
85 if (pid == 0) {
86 socket->Publish();
Akilesh Kailash3b874452021-10-03 09:41:13 +000087
88 if (driver == SnapshotDriver::DM_USER) {
89 char arg0[] = "/system/bin/snapuserd";
90 char arg1[] = "-user_snapshot";
91 char* const argv[] = {arg0, arg1, nullptr};
92 if (execv(arg0, argv) < 0) {
93 PLOG(FATAL) << "Cannot launch snapuserd; execv failed";
94 }
95 _exit(127);
96 } else {
97 char arg0[] = "/system/bin/snapuserd";
98 char* const argv[] = {arg0, nullptr};
99 if (execv(arg0, argv) < 0) {
100 PLOG(FATAL) << "Cannot launch snapuserd; execv failed";
101 }
102 _exit(127);
David Anderson491e4da2020-12-08 00:21:20 -0800103 }
David Anderson491e4da2020-12-08 00:21:20 -0800104 }
105
David Anderson0e5ad5a2021-07-21 21:53:28 -0700106 auto client = SnapuserdClient::Connect(android::snapshot::kSnapuserdSocket, 10s);
107 if (!client) {
108 LOG(FATAL) << "Could not connect to first-stage snapuserd";
109 }
110 if (client->SupportsSecondStageSocketHandoff()) {
111 setenv(kSnapuserdFirstStageInfoVar, "socket", 1);
112 }
113
David Anderson491e4da2020-12-08 00:21:20 -0800114 setenv(kSnapuserdFirstStagePidVar, std::to_string(pid).c_str(), 1);
115
Akilesh Kailash5140f3a2023-01-02 21:11:13 -0800116 if (!client->RemoveTransitionedDaemonIndicator()) {
117 LOG(ERROR) << "RemoveTransitionedDaemonIndicator failed";
118 }
119
David Anderson491e4da2020-12-08 00:21:20 -0800120 LOG(INFO) << "Relaunched snapuserd with pid: " << pid;
121}
122
123std::optional<pid_t> GetSnapuserdFirstStagePid() {
124 const char* pid_str = getenv(kSnapuserdFirstStagePidVar);
125 if (!pid_str) {
126 return {};
127 }
128
129 int pid = 0;
130 if (!android::base::ParseInt(pid_str, &pid)) {
131 LOG(FATAL) << "Could not parse pid in environment, " << kSnapuserdFirstStagePidVar << "="
132 << pid_str;
133 }
134 return {pid};
135}
136
137static void RelabelLink(const std::string& link) {
138 selinux_android_restorecon(link.c_str(), 0);
139
140 std::string path;
141 if (android::base::Readlink(link, &path)) {
142 selinux_android_restorecon(path.c_str(), 0);
143 }
144}
145
146static void RelabelDeviceMapper() {
147 selinux_android_restorecon("/dev/device-mapper", 0);
148
149 std::error_code ec;
150 for (auto& iter : std::filesystem::directory_iterator("/dev/block", ec)) {
151 const auto& path = iter.path();
152 if (android::base::StartsWith(path.string(), "/dev/block/dm-")) {
153 selinux_android_restorecon(path.string().c_str(), 0);
154 }
155 }
156}
157
158static std::optional<int> GetRamdiskSnapuserdFd() {
159 const char* fd_str = getenv(kSnapuserdFirstStageFdVar);
160 if (!fd_str) {
161 return {};
162 }
163
164 int fd;
165 if (!android::base::ParseInt(fd_str, &fd)) {
166 LOG(FATAL) << "Could not parse fd in environment, " << kSnapuserdFirstStageFdVar << "="
167 << fd_str;
168 }
169 return {fd};
170}
171
172void RestoreconRamdiskSnapuserd(int fd) {
173 if (fsetxattr(fd, XATTR_NAME_SELINUX, kSnapuserdLabel, strlen(kSnapuserdLabel) + 1, 0) < 0) {
174 PLOG(FATAL) << "fsetxattr snapuserd failed";
175 }
176}
177
178SnapuserdSelinuxHelper::SnapuserdSelinuxHelper(std::unique_ptr<SnapshotManager>&& sm, pid_t old_pid)
179 : sm_(std::move(sm)), old_pid_(old_pid) {
180 // Only dm-user device names change during transitions, so the other
181 // devices are expected to be present.
182 sm_->SetUeventRegenCallback([this](const std::string& device) -> bool {
183 if (android::base::StartsWith(device, "/dev/dm-user/")) {
184 return block_dev_init_.InitDmUser(android::base::Basename(device));
185 }
186 return true;
187 });
188}
189
David Anderson9fd88622021-03-05 14:10:55 -0800190static void LockAllSystemPages() {
191 bool ok = true;
192 auto callback = [&](const android::procinfo::MapInfo& map) -> void {
193 if (!ok || android::base::StartsWith(map.name, "/dev/") ||
194 !android::base::StartsWith(map.name, "/")) {
195 return;
196 }
197 auto start = reinterpret_cast<const void*>(map.start);
Kalesh Singhf90de492024-02-14 17:03:01 -0800198 uint64_t len = android::procinfo::MappedFileSize(map);
David Anderson9fd88622021-03-05 14:10:55 -0800199 if (!len) {
200 return;
201 }
Kalesh Singhf90de492024-02-14 17:03:01 -0800202
David Anderson9fd88622021-03-05 14:10:55 -0800203 if (mlock(start, len) < 0) {
Kalesh Singhf90de492024-02-14 17:03:01 -0800204 PLOG(ERROR) << "\"" << map.name << "\": mlock(" << start << ", " << len
205 << ") failed: pgoff = " << map.pgoff;
David Anderson9fd88622021-03-05 14:10:55 -0800206 ok = false;
207 }
208 };
209
210 if (!android::procinfo::ReadProcessMaps(getpid(), callback) || !ok) {
Kalesh Singhf90de492024-02-14 17:03:01 -0800211 LOG(FATAL) << "Could not process /proc/" << getpid() << "/maps file for init";
David Anderson9fd88622021-03-05 14:10:55 -0800212 }
213}
214
David Anderson491e4da2020-12-08 00:21:20 -0800215void SnapuserdSelinuxHelper::StartTransition() {
216 LOG(INFO) << "Starting SELinux transition of snapuserd";
217
218 // The restorecon path reads from /system etc, so make sure any reads have
219 // been cached before proceeding.
220 auto handle = selinux_android_file_context_handle();
221 if (!handle) {
222 LOG(FATAL) << "Could not create SELinux file context handle";
223 }
224 selinux_android_set_sehandle(handle);
225
226 // We cannot access /system after the transition, so make sure init is
227 // pinned in memory.
David Anderson9fd88622021-03-05 14:10:55 -0800228 LockAllSystemPages();
David Anderson491e4da2020-12-08 00:21:20 -0800229
230 argv_.emplace_back("snapuserd");
231 argv_.emplace_back("-no_socket");
Akilesh Kailash035e5572022-07-15 18:40:07 +0000232 if (!sm_->PrepareSnapuserdArgsForSelinux(&argv_)) {
David Anderson491e4da2020-12-08 00:21:20 -0800233 LOG(FATAL) << "Could not perform selinux transition";
234 }
David Anderson491e4da2020-12-08 00:21:20 -0800235}
236
237void SnapuserdSelinuxHelper::FinishTransition() {
238 RelabelLink("/dev/block/by-name/super");
239 RelabelDeviceMapper();
240
241 selinux_android_restorecon("/dev/null", 0);
242 selinux_android_restorecon("/dev/urandom", 0);
243 selinux_android_restorecon("/dev/kmsg", 0);
244 selinux_android_restorecon("/dev/dm-user", SELINUX_ANDROID_RESTORECON_RECURSE);
245
246 RelaunchFirstStageSnapuserd();
247
248 if (munlockall() < 0) {
249 PLOG(ERROR) << "munlockall failed";
250 }
251}
252
Akilesh Kailashfd5562b2022-01-25 07:05:31 +0000253/*
254 * Before starting init second stage, we will wait
255 * for snapuserd daemon to be up and running; bionic libc
256 * may read /system/etc/selinux/plat_property_contexts file
257 * before invoking main() function. This will happen if
258 * init initializes property during second stage. Any access
259 * to /system without snapuserd daemon will lead to a deadlock.
260 *
261 * Thus, we do a simple probe by reading system partition. This
262 * read will eventually be serviced by daemon confirming that
263 * daemon is up and running. Furthermore, we are still in the kernel
264 * domain and sepolicy has not been enforced yet. Thus, access
265 * to these device mapper block devices are ok even though
266 * we may see audit logs.
267 */
268bool SnapuserdSelinuxHelper::TestSnapuserdIsReady() {
Akilesh Kailash5140f3a2023-01-02 21:11:13 -0800269 // Wait for the daemon to be fully up. Daemon will write to path
270 // /metadata/ota/daemon-alive-indicator only when all the threads
271 // are ready and attached to dm-user.
272 //
273 // This check will fail for GRF devices with vendor on Android S.
274 // snapuserd binary from Android S won't be able to communicate
275 // and hence, we will fallback and issue I/O to verify
276 // the presence of daemon.
277 auto client = std::make_unique<SnapuserdClient>();
278 if (!client->IsTransitionedDaemonReady()) {
279 LOG(ERROR) << "IsTransitionedDaemonReady failed";
280 }
281
Akilesh Kailashfd5562b2022-01-25 07:05:31 +0000282 std::string dev = "/dev/block/mapper/system"s + fs_mgr_get_slot_suffix();
283 android::base::unique_fd fd(open(dev.c_str(), O_RDONLY | O_DIRECT));
284 if (fd < 0) {
285 PLOG(ERROR) << "open " << dev << " failed";
286 return false;
287 }
288
289 void* addr;
290 ssize_t page_size = getpagesize();
291 if (posix_memalign(&addr, page_size, page_size) < 0) {
292 PLOG(ERROR) << "posix_memalign with page size " << page_size;
293 return false;
294 }
295
296 std::unique_ptr<void, decltype(&::free)> buffer(addr, ::free);
297
298 int iter = 0;
299 while (iter < 10) {
300 ssize_t n = TEMP_FAILURE_RETRY(pread(fd.get(), buffer.get(), page_size, 0));
301 if (n < 0) {
302 // Wait for sometime before retry
303 std::this_thread::sleep_for(100ms);
304 } else if (n == page_size) {
305 return true;
306 } else {
307 LOG(ERROR) << "pread returned: " << n << " from: " << dev << " expected: " << page_size;
308 }
309
310 iter += 1;
311 }
312
313 return false;
314}
315
David Anderson491e4da2020-12-08 00:21:20 -0800316void SnapuserdSelinuxHelper::RelaunchFirstStageSnapuserd() {
Akilesh Kailash035e5572022-07-15 18:40:07 +0000317 if (!sm_->DetachFirstStageSnapuserdForSelinux()) {
318 LOG(FATAL) << "Could not perform selinux transition";
319 }
320
321 KillFirstStageSnapuserd(old_pid_);
322
David Anderson491e4da2020-12-08 00:21:20 -0800323 auto fd = GetRamdiskSnapuserdFd();
324 if (!fd) {
325 LOG(FATAL) << "Environment variable " << kSnapuserdFirstStageFdVar << " was not set!";
326 }
327 unsetenv(kSnapuserdFirstStageFdVar);
328
329 RestoreconRamdiskSnapuserd(fd.value());
330
331 pid_t pid = fork();
332 if (pid < 0) {
333 PLOG(FATAL) << "Fork to relaunch snapuserd failed";
334 }
335 if (pid > 0) {
336 // We don't need the descriptor anymore, and it should be closed to
337 // avoid leaking into subprocesses.
338 close(fd.value());
339
340 setenv(kSnapuserdFirstStagePidVar, std::to_string(pid).c_str(), 1);
341
342 LOG(INFO) << "Relaunched snapuserd with pid: " << pid;
Akilesh Kailashfd5562b2022-01-25 07:05:31 +0000343
Akilesh Kailash4ffe8a32022-06-02 08:00:39 +0000344 // Since daemon is not started as a service, we have
345 // to explicitly set the OOM score to default which is unkillable
346 std::string oom_str = std::to_string(DEFAULT_OOM_SCORE_ADJUST);
347 std::string oom_file = android::base::StringPrintf("/proc/%d/oom_score_adj", pid);
348 if (!android::base::WriteStringToFile(oom_str, oom_file)) {
349 PLOG(ERROR) << "couldn't write oom_score_adj to snapuserd daemon with pid: " << pid;
350 }
351
Akilesh Kailashfd5562b2022-01-25 07:05:31 +0000352 if (!TestSnapuserdIsReady()) {
353 PLOG(FATAL) << "snapuserd daemon failed to launch";
354 } else {
355 LOG(INFO) << "snapuserd daemon is up and running";
356 }
357
David Anderson491e4da2020-12-08 00:21:20 -0800358 return;
359 }
360
361 // Make sure the descriptor is gone after we exec.
362 if (fcntl(fd.value(), F_SETFD, FD_CLOEXEC) < 0) {
363 PLOG(FATAL) << "fcntl FD_CLOEXEC failed for snapuserd fd";
364 }
365
366 std::vector<char*> argv;
367 for (auto& arg : argv_) {
368 argv.emplace_back(arg.data());
369 }
370 argv.emplace_back(nullptr);
371
372 int rv = syscall(SYS_execveat, fd.value(), "", reinterpret_cast<char* const*>(argv.data()),
373 nullptr, AT_EMPTY_PATH);
374 if (rv < 0) {
375 PLOG(FATAL) << "Failed to execveat() snapuserd";
376 }
377}
378
379std::unique_ptr<SnapuserdSelinuxHelper> SnapuserdSelinuxHelper::CreateIfNeeded() {
380 if (IsRecoveryMode()) {
381 return nullptr;
382 }
383
384 auto old_pid = GetSnapuserdFirstStagePid();
385 if (!old_pid) {
386 return nullptr;
387 }
388
389 auto sm = SnapshotManager::NewForFirstStageMount();
390 if (!sm) {
391 LOG(FATAL) << "Unable to create SnapshotManager";
392 }
393 return std::make_unique<SnapuserdSelinuxHelper>(std::move(sm), old_pid.value());
394}
395
396void KillFirstStageSnapuserd(pid_t pid) {
397 if (kill(pid, SIGTERM) < 0 && errno != ESRCH) {
398 LOG(ERROR) << "Kill snapuserd pid failed: " << pid;
399 } else {
400 LOG(INFO) << "Sent SIGTERM to snapuserd process " << pid;
401 }
402}
403
404void CleanupSnapuserdSocket() {
405 auto socket_path = ANDROID_SOCKET_DIR "/"s + android::snapshot::kSnapuserdSocket;
406 if (access(socket_path.c_str(), F_OK) != 0) {
407 return;
408 }
409
410 // Tell the daemon to stop accepting connections and to gracefully exit
411 // once all outstanding handlers have terminated.
412 if (auto client = SnapuserdClient::Connect(android::snapshot::kSnapuserdSocket, 3s)) {
413 client->DetachSnapuserd();
414 }
415
416 // Unlink the socket so we can create it again in second-stage.
417 if (unlink(socket_path.c_str()) < 0) {
418 PLOG(FATAL) << "unlink " << socket_path << " failed";
419 }
420}
421
422void SaveRamdiskPathToSnapuserd() {
423 int fd = open(kSnapuserdPath, O_PATH);
424 if (fd < 0) {
425 PLOG(FATAL) << "Unable to open snapuserd: " << kSnapuserdPath;
426 }
427
428 auto value = std::to_string(fd);
429 if (setenv(kSnapuserdFirstStageFdVar, value.c_str(), 1) < 0) {
430 PLOG(FATAL) << "setenv failed: " << kSnapuserdFirstStageFdVar << "=" << value;
431 }
432}
433
434bool IsFirstStageSnapuserdRunning() {
435 return GetSnapuserdFirstStagePid().has_value();
436}
437
David Anderson0e5ad5a2021-07-21 21:53:28 -0700438std::vector<std::string> GetSnapuserdFirstStageInfo() {
439 const char* pid_str = getenv(kSnapuserdFirstStageInfoVar);
440 if (!pid_str) {
441 return {};
442 }
443 return android::base::Split(pid_str, ",");
444}
445
David Anderson491e4da2020-12-08 00:21:20 -0800446} // namespace init
447} // namespace android