blob: d23e18275ccfaa095ad5f20265e1e9733fccd042 [file] [log] [blame]
Jeff Sharkeydeb24052015-03-02 21:01:40 -08001/*
2 * Copyright (C) 2015 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
Jeff Sharkeydeb24052015-03-02 21:01:40 -080017#include "sehandle.h"
18#include "Utils.h"
19#include "Process.h"
20
Jeff Sharkey36801cc2015-03-13 16:09:20 -070021#include <base/logging.h>
Jeff Sharkey9c484982015-03-31 10:35:33 -070022#include <base/stringprintf.h>
Jeff Sharkeydeb24052015-03-02 21:01:40 -080023#include <cutils/fs.h>
Jeff Sharkeydeb24052015-03-02 21:01:40 -080024#include <private/android_filesystem_config.h>
Jeff Sharkey9c484982015-03-31 10:35:33 -070025#include <logwrap/logwrap.h>
Jeff Sharkeydeb24052015-03-02 21:01:40 -080026
Jeff Sharkeyce6a9132015-04-08 21:07:21 -070027#include <mutex>
Jeff Sharkeydeb24052015-03-02 21:01:40 -080028#include <fcntl.h>
29#include <linux/fs.h>
30#include <stdlib.h>
31#include <sys/mount.h>
32#include <sys/types.h>
33#include <sys/stat.h>
34#include <sys/wait.h>
35
36#ifndef UMOUNT_NOFOLLOW
37#define UMOUNT_NOFOLLOW 0x00000008 /* Don't follow symlink on umount */
38#endif
39
Jeff Sharkey9c484982015-03-31 10:35:33 -070040using android::base::StringPrintf;
41
Jeff Sharkeydeb24052015-03-02 21:01:40 -080042namespace android {
43namespace vold {
44
Jeff Sharkeyce6a9132015-04-08 21:07:21 -070045/* Since we use setexeccon(), we need to carefully lock around any
46 * code that calls exec() to avoid crossing the streams. */
47static std::mutex sExecLock;
48
Jeff Sharkey95c87cc2015-04-01 11:54:32 -070049security_context_t sBlkidContext = nullptr;
50security_context_t sBlkidUntrustedContext = nullptr;
51security_context_t sFsckContext = nullptr;
52security_context_t sFsckUntrustedContext = nullptr;
53
Jeff Sharkey9c484982015-03-31 10:35:33 -070054static const char* kBlkidPath = "/system/bin/blkid";
55
Jeff Sharkeydeb24052015-03-02 21:01:40 -080056status_t CreateDeviceNode(const std::string& path, dev_t dev) {
57 const char* cpath = path.c_str();
58 status_t res = 0;
59
60 char* secontext = nullptr;
61 if (sehandle) {
62 if (!selabel_lookup(sehandle, &secontext, cpath, S_IFBLK)) {
63 setfscreatecon(secontext);
64 }
65 }
66
67 mode_t mode = 0660 | S_IFBLK;
68 if (mknod(cpath, mode, dev) < 0) {
69 if (errno != EEXIST) {
Jeff Sharkey36801cc2015-03-13 16:09:20 -070070 PLOG(ERROR) << "Failed to create device node for " << major(dev)
71 << ":" << minor(dev) << " at " << path;
Jeff Sharkeydeb24052015-03-02 21:01:40 -080072 res = -errno;
73 }
74 }
75
76 if (secontext) {
77 setfscreatecon(nullptr);
78 freecon(secontext);
79 }
80
81 return res;
82}
83
84status_t DestroyDeviceNode(const std::string& path) {
85 const char* cpath = path.c_str();
86 if (TEMP_FAILURE_RETRY(unlink(cpath))) {
87 return -errno;
88 } else {
89 return OK;
90 }
91}
92
Jeff Sharkeyf0121c52015-04-06 14:08:45 -070093status_t PrepareDir(const std::string& path, mode_t mode, uid_t uid, gid_t gid) {
94 const char* cpath = path.c_str();
95
96 char* secontext = nullptr;
97 if (sehandle) {
98 if (!selabel_lookup(sehandle, &secontext, cpath, S_IFDIR)) {
99 setfscreatecon(secontext);
100 }
101 }
102
103 int res = fs_prepare_dir(cpath, mode, uid, gid);
104
105 if (secontext) {
106 setfscreatecon(nullptr);
107 freecon(secontext);
108 }
109
110 if (res == 0) {
111 return OK;
112 } else {
113 return -errno;
114 }
115}
116
Jeff Sharkeydeb24052015-03-02 21:01:40 -0800117status_t ForceUnmount(const std::string& path) {
118 const char* cpath = path.c_str();
119 if (!umount2(cpath, UMOUNT_NOFOLLOW) || errno == EINVAL || errno == ENOENT) {
120 return OK;
121 }
Jeff Sharkeyf0121c52015-04-06 14:08:45 -0700122 PLOG(WARNING) << "Failed to unmount " << path;
123
124 sleep(5);
Jeff Sharkeyce6a9132015-04-08 21:07:21 -0700125 Process::killProcessesWithOpenFiles(cpath, SIGINT);
126
127 if (!umount2(cpath, UMOUNT_NOFOLLOW) || errno == EINVAL || errno == ENOENT) {
128 return OK;
129 }
130 PLOG(WARNING) << "Failed to unmount " << path;
131
132 sleep(5);
Jeff Sharkeydeb24052015-03-02 21:01:40 -0800133 Process::killProcessesWithOpenFiles(cpath, SIGTERM);
Jeff Sharkeydeb24052015-03-02 21:01:40 -0800134
135 if (!umount2(cpath, UMOUNT_NOFOLLOW) || errno == EINVAL || errno == ENOENT) {
136 return OK;
137 }
Jeff Sharkeyf0121c52015-04-06 14:08:45 -0700138 PLOG(WARNING) << "Failed to unmount " << path;
139
140 sleep(5);
Jeff Sharkeydeb24052015-03-02 21:01:40 -0800141 Process::killProcessesWithOpenFiles(cpath, SIGKILL);
Jeff Sharkeydeb24052015-03-02 21:01:40 -0800142
143 if (!umount2(cpath, UMOUNT_NOFOLLOW) || errno == EINVAL || errno == ENOENT) {
144 return OK;
145 }
Jeff Sharkeyf0121c52015-04-06 14:08:45 -0700146 PLOG(ERROR) << "Failed to unmount " << path;
147
Jeff Sharkeydeb24052015-03-02 21:01:40 -0800148 return -errno;
149}
150
Jeff Sharkey36801cc2015-03-13 16:09:20 -0700151status_t BindMount(const std::string& source, const std::string& target) {
152 if (::mount(source.c_str(), target.c_str(), "", MS_BIND, NULL)) {
153 PLOG(ERROR) << "Failed to bind mount " << source << " to " << target;
154 return -errno;
155 }
156 return OK;
157}
158
Jeff Sharkey95c87cc2015-04-01 11:54:32 -0700159static status_t readMetadata(const std::string& path, std::string& fsType,
160 std::string& fsUuid, std::string& fsLabel, bool untrusted) {
Jeff Sharkey9c484982015-03-31 10:35:33 -0700161 fsType.clear();
162 fsUuid.clear();
163 fsLabel.clear();
164
Jeff Sharkeyce6a9132015-04-08 21:07:21 -0700165 std::vector<std::string> cmd;
166 cmd.push_back(kBlkidPath);
167 cmd.push_back("-c");
168 cmd.push_back("/dev/null");
169 cmd.push_back(path);
170
171 std::vector<std::string> output;
172 status_t res = ForkExecvp(cmd, output, untrusted ? sBlkidUntrustedContext : sBlkidContext);
173 if (res != OK) {
174 LOG(WARNING) << "blkid failed to identify " << path;
175 return res;
Jeff Sharkey9c484982015-03-31 10:35:33 -0700176 }
177
Jeff Sharkey9c484982015-03-31 10:35:33 -0700178 char value[128];
Jeff Sharkeyce6a9132015-04-08 21:07:21 -0700179 for (auto line : output) {
Jeff Sharkey9c484982015-03-31 10:35:33 -0700180 // Extract values from blkid output, if defined
Jeff Sharkeyce6a9132015-04-08 21:07:21 -0700181 const char* cline = line.c_str();
182 char* start = strstr(cline, "TYPE=");
Jeff Sharkey9c484982015-03-31 10:35:33 -0700183 if (start != nullptr && sscanf(start + 5, "\"%127[^\"]\"", value) == 1) {
184 fsType = value;
185 }
186
Jeff Sharkeyce6a9132015-04-08 21:07:21 -0700187 start = strstr(cline, "UUID=");
Jeff Sharkey9c484982015-03-31 10:35:33 -0700188 if (start != nullptr && sscanf(start + 5, "\"%127[^\"]\"", value) == 1) {
189 fsUuid = value;
190 }
191
Jeff Sharkeyce6a9132015-04-08 21:07:21 -0700192 start = strstr(cline, "LABEL=");
Jeff Sharkey9c484982015-03-31 10:35:33 -0700193 if (start != nullptr && sscanf(start + 6, "\"%127[^\"]\"", value) == 1) {
194 fsLabel = value;
195 }
Jeff Sharkey9c484982015-03-31 10:35:33 -0700196 }
197
Jeff Sharkeyce6a9132015-04-08 21:07:21 -0700198 return OK;
Jeff Sharkey9c484982015-03-31 10:35:33 -0700199}
200
Jeff Sharkey95c87cc2015-04-01 11:54:32 -0700201status_t ReadMetadata(const std::string& path, std::string& fsType,
202 std::string& fsUuid, std::string& fsLabel) {
203 return readMetadata(path, fsType, fsUuid, fsLabel, false);
204}
205
206status_t ReadMetadataUntrusted(const std::string& path, std::string& fsType,
207 std::string& fsUuid, std::string& fsLabel) {
208 return readMetadata(path, fsType, fsUuid, fsLabel, true);
209}
210
Jeff Sharkeyce6a9132015-04-08 21:07:21 -0700211status_t ForkExecvp(const std::vector<std::string>& args) {
212 return ForkExecvp(args, nullptr);
213}
214
215status_t ForkExecvp(const std::vector<std::string>& args, security_context_t context) {
216 size_t argc = args.size();
Jeff Sharkey9c484982015-03-31 10:35:33 -0700217 char** argv = (char**) calloc(argc, sizeof(char*));
Jeff Sharkeyce6a9132015-04-08 21:07:21 -0700218 for (size_t i = 0; i < argc; i++) {
Jeff Sharkey9c484982015-03-31 10:35:33 -0700219 argv[i] = (char*) args[i].c_str();
220 if (i == 0) {
221 LOG(VERBOSE) << args[i];
222 } else {
223 LOG(VERBOSE) << " " << args[i];
224 }
225 }
Jeff Sharkeyce6a9132015-04-08 21:07:21 -0700226
227 status_t res = OK;
228 {
229 std::lock_guard<std::mutex> lock(sExecLock);
230 if (setexeccon(context)) {
231 LOG(ERROR) << "Failed to setexeccon";
232 abort();
233 }
234 res = android_fork_execvp(argc, argv, NULL, false, true);
235 if (setexeccon(nullptr)) {
236 LOG(ERROR) << "Failed to setexeccon";
237 abort();
238 }
239 }
Jeff Sharkey9c484982015-03-31 10:35:33 -0700240 free(argv);
241 return res;
242}
243
Jeff Sharkeyce6a9132015-04-08 21:07:21 -0700244status_t ForkExecvp(const std::vector<std::string>& args,
245 std::vector<std::string>& output) {
246 return ForkExecvp(args, output, nullptr);
247}
248
249status_t ForkExecvp(const std::vector<std::string>& args,
250 std::vector<std::string>& output, security_context_t context) {
251 std::string cmd;
252 for (size_t i = 0; i < args.size(); i++) {
253 cmd += args[i] + " ";
254 if (i == 0) {
255 LOG(VERBOSE) << args[i];
256 } else {
257 LOG(VERBOSE) << " " << args[i];
258 }
259 }
260 output.clear();
261
262 FILE* fp = nullptr;
263 {
264 std::lock_guard<std::mutex> lock(sExecLock);
265 if (setexeccon(context)) {
266 LOG(ERROR) << "Failed to setexeccon";
267 abort();
268 }
269 fp = popen(cmd.c_str(), "r");
270 if (setexeccon(nullptr)) {
271 LOG(ERROR) << "Failed to setexeccon";
272 abort();
273 }
274 }
275
276 if (!fp) {
277 PLOG(ERROR) << "Failed to popen " << cmd;
278 return -errno;
279 }
280 char line[1024];
281 while (fgets(line, sizeof(line), fp) != nullptr) {
282 LOG(VERBOSE) << line;
283 output.push_back(std::string(line));
284 }
285 if (pclose(fp) != 0) {
286 PLOG(ERROR) << "Failed to pclose " << cmd;
287 return -errno;
288 }
289
290 return OK;
291}
292
Jeff Sharkey9c484982015-03-31 10:35:33 -0700293status_t ReadRandomBytes(size_t bytes, std::string& out) {
294 out.clear();
295
296 int fd = TEMP_FAILURE_RETRY(open("/dev/urandom", O_RDONLY | O_CLOEXEC | O_NOFOLLOW));
297 if (fd == -1) {
298 return -errno;
299 }
300
301 char buf[BUFSIZ];
302 size_t n;
303 while ((n = TEMP_FAILURE_RETRY(read(fd, &buf[0], std::min(sizeof(buf), bytes)))) > 0) {
304 out.append(buf, n);
305 bytes -= n;
306 }
307 TEMP_FAILURE_RETRY(close(fd));
308
309 if (bytes == 0) {
310 return OK;
311 } else {
312 return -EIO;
313 }
314}
315
316status_t HexToStr(const std::string& hex, std::string& str) {
317 str.clear();
318 bool even = true;
319 char cur = 0;
320 for (size_t i = 0; i < hex.size(); i++) {
321 int val = 0;
322 switch (hex[i]) {
323 case ' ': case '-': case ':': continue;
324 case 'f': case 'F': val = 15; break;
325 case 'e': case 'E': val = 14; break;
326 case 'd': case 'D': val = 13; break;
327 case 'c': case 'C': val = 12; break;
328 case 'b': case 'B': val = 11; break;
329 case 'a': case 'A': val = 10; break;
330 case '9': val = 9; break;
331 case '8': val = 8; break;
332 case '7': val = 7; break;
333 case '6': val = 6; break;
334 case '5': val = 5; break;
335 case '4': val = 4; break;
336 case '3': val = 3; break;
337 case '2': val = 2; break;
338 case '1': val = 1; break;
339 case '0': val = 0; break;
340 default: return -EINVAL;
341 }
342
343 if (even) {
344 cur = val << 4;
345 } else {
346 cur += val;
347 str.push_back(cur);
348 cur = 0;
349 }
350 even = !even;
351 }
352 return even ? OK : -EINVAL;
353}
354
355static const char* kLookup = "0123456789abcdef";
356
357status_t StrToHex(const std::string& str, std::string& hex) {
358 hex.clear();
359 for (size_t i = 0; i < str.size(); i++) {
360 hex.push_back(kLookup[str[i] >> 4]);
361 hex.push_back(kLookup[str[i] & 0x0F]);
362 }
363 return OK;
364}
365
Jeff Sharkeydeb24052015-03-02 21:01:40 -0800366} // namespace vold
367} // namespace android