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