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