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