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