• 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/strings.h>
33 #include <android-base/unique_fd.h>
34 #include <cutils/sockets.h>
35 #include <libsnapshot/snapshot.h>
36 #include <libsnapshot/snapuserd_client.h>
37 #include <private/android_filesystem_config.h>
38 #include <procinfo/process_map.h>
39 #include <selinux/android.h>
40 
41 #include "block_dev_initializer.h"
42 #include "service_utils.h"
43 #include "util.h"
44 
45 namespace android {
46 namespace init {
47 
48 using namespace std::string_literals;
49 
50 using android::base::unique_fd;
51 using android::snapshot::SnapshotManager;
52 using android::snapshot::SnapuserdClient;
53 
54 static constexpr char kSnapuserdPath[] = "/system/bin/snapuserd";
55 static constexpr char kSnapuserdFirstStagePidVar[] = "FIRST_STAGE_SNAPUSERD_PID";
56 static constexpr char kSnapuserdFirstStageFdVar[] = "FIRST_STAGE_SNAPUSERD_FD";
57 static constexpr char kSnapuserdLabel[] = "u:object_r:snapuserd_exec:s0";
58 static constexpr char kSnapuserdSocketLabel[] = "u:object_r:snapuserd_socket:s0";
59 
LaunchFirstStageSnapuserd()60 void LaunchFirstStageSnapuserd() {
61     SocketDescriptor socket_desc;
62     socket_desc.name = android::snapshot::kSnapuserdSocket;
63     socket_desc.type = SOCK_STREAM;
64     socket_desc.perm = 0660;
65     socket_desc.uid = AID_SYSTEM;
66     socket_desc.gid = AID_SYSTEM;
67 
68     // We specify a label here even though it technically is not needed. During
69     // first_stage_mount there is no sepolicy loaded. Once sepolicy is loaded,
70     // we bypass the socket entirely.
71     auto socket = socket_desc.Create(kSnapuserdSocketLabel);
72     if (!socket.ok()) {
73         LOG(FATAL) << "Could not create snapuserd socket: " << socket.error();
74     }
75 
76     pid_t pid = fork();
77     if (pid < 0) {
78         PLOG(FATAL) << "Cannot launch snapuserd; fork failed";
79     }
80     if (pid == 0) {
81         socket->Publish();
82         char arg0[] = "/system/bin/snapuserd";
83         char* const argv[] = {arg0, nullptr};
84         if (execv(arg0, argv) < 0) {
85             PLOG(FATAL) << "Cannot launch snapuserd; execv failed";
86         }
87         _exit(127);
88     }
89 
90     setenv(kSnapuserdFirstStagePidVar, std::to_string(pid).c_str(), 1);
91 
92     LOG(INFO) << "Relaunched snapuserd with pid: " << pid;
93 }
94 
GetSnapuserdFirstStagePid()95 std::optional<pid_t> GetSnapuserdFirstStagePid() {
96     const char* pid_str = getenv(kSnapuserdFirstStagePidVar);
97     if (!pid_str) {
98         return {};
99     }
100 
101     int pid = 0;
102     if (!android::base::ParseInt(pid_str, &pid)) {
103         LOG(FATAL) << "Could not parse pid in environment, " << kSnapuserdFirstStagePidVar << "="
104                    << pid_str;
105     }
106     return {pid};
107 }
108 
RelabelLink(const std::string & link)109 static void RelabelLink(const std::string& link) {
110     selinux_android_restorecon(link.c_str(), 0);
111 
112     std::string path;
113     if (android::base::Readlink(link, &path)) {
114         selinux_android_restorecon(path.c_str(), 0);
115     }
116 }
117 
RelabelDeviceMapper()118 static void RelabelDeviceMapper() {
119     selinux_android_restorecon("/dev/device-mapper", 0);
120 
121     std::error_code ec;
122     for (auto& iter : std::filesystem::directory_iterator("/dev/block", ec)) {
123         const auto& path = iter.path();
124         if (android::base::StartsWith(path.string(), "/dev/block/dm-")) {
125             selinux_android_restorecon(path.string().c_str(), 0);
126         }
127     }
128 }
129 
GetRamdiskSnapuserdFd()130 static std::optional<int> GetRamdiskSnapuserdFd() {
131     const char* fd_str = getenv(kSnapuserdFirstStageFdVar);
132     if (!fd_str) {
133         return {};
134     }
135 
136     int fd;
137     if (!android::base::ParseInt(fd_str, &fd)) {
138         LOG(FATAL) << "Could not parse fd in environment, " << kSnapuserdFirstStageFdVar << "="
139                    << fd_str;
140     }
141     return {fd};
142 }
143 
RestoreconRamdiskSnapuserd(int fd)144 void RestoreconRamdiskSnapuserd(int fd) {
145     if (fsetxattr(fd, XATTR_NAME_SELINUX, kSnapuserdLabel, strlen(kSnapuserdLabel) + 1, 0) < 0) {
146         PLOG(FATAL) << "fsetxattr snapuserd failed";
147     }
148 }
149 
SnapuserdSelinuxHelper(std::unique_ptr<SnapshotManager> && sm,pid_t old_pid)150 SnapuserdSelinuxHelper::SnapuserdSelinuxHelper(std::unique_ptr<SnapshotManager>&& sm, pid_t old_pid)
151     : sm_(std::move(sm)), old_pid_(old_pid) {
152     // Only dm-user device names change during transitions, so the other
153     // devices are expected to be present.
154     sm_->SetUeventRegenCallback([this](const std::string& device) -> bool {
155         if (android::base::StartsWith(device, "/dev/dm-user/")) {
156             return block_dev_init_.InitDmUser(android::base::Basename(device));
157         }
158         return true;
159     });
160 }
161 
LockAllSystemPages()162 static void LockAllSystemPages() {
163     bool ok = true;
164     auto callback = [&](const android::procinfo::MapInfo& map) -> void {
165         if (!ok || android::base::StartsWith(map.name, "/dev/") ||
166             !android::base::StartsWith(map.name, "/")) {
167             return;
168         }
169         auto start = reinterpret_cast<const void*>(map.start);
170         auto len = map.end - map.start;
171         if (!len) {
172             return;
173         }
174         if (mlock(start, len) < 0) {
175             LOG(ERROR) << "mlock failed, " << start << " for " << len << " bytes.";
176             ok = false;
177         }
178     };
179 
180     if (!android::procinfo::ReadProcessMaps(getpid(), callback) || !ok) {
181         LOG(FATAL) << "Could not process /proc/" << getpid() << "/maps file for init, "
182                    << "falling back to mlockall().";
183         if (mlockall(MCL_CURRENT) < 0) {
184             LOG(FATAL) << "mlockall failed";
185         }
186     }
187 }
188 
StartTransition()189 void SnapuserdSelinuxHelper::StartTransition() {
190     LOG(INFO) << "Starting SELinux transition of snapuserd";
191 
192     // The restorecon path reads from /system etc, so make sure any reads have
193     // been cached before proceeding.
194     auto handle = selinux_android_file_context_handle();
195     if (!handle) {
196         LOG(FATAL) << "Could not create SELinux file context handle";
197     }
198     selinux_android_set_sehandle(handle);
199 
200     // We cannot access /system after the transition, so make sure init is
201     // pinned in memory.
202     LockAllSystemPages();
203 
204     argv_.emplace_back("snapuserd");
205     argv_.emplace_back("-no_socket");
206     if (!sm_->DetachSnapuserdForSelinux(&argv_)) {
207         LOG(FATAL) << "Could not perform selinux transition";
208     }
209 
210     // Make sure the process is gone so we don't have any selinux audits.
211     KillFirstStageSnapuserd(old_pid_);
212 }
213 
FinishTransition()214 void SnapuserdSelinuxHelper::FinishTransition() {
215     RelabelLink("/dev/block/by-name/super");
216     RelabelDeviceMapper();
217 
218     selinux_android_restorecon("/dev/null", 0);
219     selinux_android_restorecon("/dev/urandom", 0);
220     selinux_android_restorecon("/dev/kmsg", 0);
221     selinux_android_restorecon("/dev/dm-user", SELINUX_ANDROID_RESTORECON_RECURSE);
222 
223     RelaunchFirstStageSnapuserd();
224 
225     if (munlockall() < 0) {
226         PLOG(ERROR) << "munlockall failed";
227     }
228 }
229 
RelaunchFirstStageSnapuserd()230 void SnapuserdSelinuxHelper::RelaunchFirstStageSnapuserd() {
231     auto fd = GetRamdiskSnapuserdFd();
232     if (!fd) {
233         LOG(FATAL) << "Environment variable " << kSnapuserdFirstStageFdVar << " was not set!";
234     }
235     unsetenv(kSnapuserdFirstStageFdVar);
236 
237     RestoreconRamdiskSnapuserd(fd.value());
238 
239     pid_t pid = fork();
240     if (pid < 0) {
241         PLOG(FATAL) << "Fork to relaunch snapuserd failed";
242     }
243     if (pid > 0) {
244         // We don't need the descriptor anymore, and it should be closed to
245         // avoid leaking into subprocesses.
246         close(fd.value());
247 
248         setenv(kSnapuserdFirstStagePidVar, std::to_string(pid).c_str(), 1);
249 
250         LOG(INFO) << "Relaunched snapuserd with pid: " << pid;
251         return;
252     }
253 
254     // Make sure the descriptor is gone after we exec.
255     if (fcntl(fd.value(), F_SETFD, FD_CLOEXEC) < 0) {
256         PLOG(FATAL) << "fcntl FD_CLOEXEC failed for snapuserd fd";
257     }
258 
259     std::vector<char*> argv;
260     for (auto& arg : argv_) {
261         argv.emplace_back(arg.data());
262     }
263     argv.emplace_back(nullptr);
264 
265     int rv = syscall(SYS_execveat, fd.value(), "", reinterpret_cast<char* const*>(argv.data()),
266                      nullptr, AT_EMPTY_PATH);
267     if (rv < 0) {
268         PLOG(FATAL) << "Failed to execveat() snapuserd";
269     }
270 }
271 
CreateIfNeeded()272 std::unique_ptr<SnapuserdSelinuxHelper> SnapuserdSelinuxHelper::CreateIfNeeded() {
273     if (IsRecoveryMode()) {
274         return nullptr;
275     }
276 
277     auto old_pid = GetSnapuserdFirstStagePid();
278     if (!old_pid) {
279         return nullptr;
280     }
281 
282     auto sm = SnapshotManager::NewForFirstStageMount();
283     if (!sm) {
284         LOG(FATAL) << "Unable to create SnapshotManager";
285     }
286     return std::make_unique<SnapuserdSelinuxHelper>(std::move(sm), old_pid.value());
287 }
288 
KillFirstStageSnapuserd(pid_t pid)289 void KillFirstStageSnapuserd(pid_t pid) {
290     if (kill(pid, SIGTERM) < 0 && errno != ESRCH) {
291         LOG(ERROR) << "Kill snapuserd pid failed: " << pid;
292     } else {
293         LOG(INFO) << "Sent SIGTERM to snapuserd process " << pid;
294     }
295 }
296 
CleanupSnapuserdSocket()297 void CleanupSnapuserdSocket() {
298     auto socket_path = ANDROID_SOCKET_DIR "/"s + android::snapshot::kSnapuserdSocket;
299     if (access(socket_path.c_str(), F_OK) != 0) {
300         return;
301     }
302 
303     // Tell the daemon to stop accepting connections and to gracefully exit
304     // once all outstanding handlers have terminated.
305     if (auto client = SnapuserdClient::Connect(android::snapshot::kSnapuserdSocket, 3s)) {
306         client->DetachSnapuserd();
307     }
308 
309     // Unlink the socket so we can create it again in second-stage.
310     if (unlink(socket_path.c_str()) < 0) {
311         PLOG(FATAL) << "unlink " << socket_path << " failed";
312     }
313 }
314 
SaveRamdiskPathToSnapuserd()315 void SaveRamdiskPathToSnapuserd() {
316     int fd = open(kSnapuserdPath, O_PATH);
317     if (fd < 0) {
318         PLOG(FATAL) << "Unable to open snapuserd: " << kSnapuserdPath;
319     }
320 
321     auto value = std::to_string(fd);
322     if (setenv(kSnapuserdFirstStageFdVar, value.c_str(), 1) < 0) {
323         PLOG(FATAL) << "setenv failed: " << kSnapuserdFirstStageFdVar << "=" << value;
324     }
325 }
326 
IsFirstStageSnapuserdRunning()327 bool IsFirstStageSnapuserdRunning() {
328     return GetSnapuserdFirstStagePid().has_value();
329 }
330 
331 }  // namespace init
332 }  // namespace android
333