blob: 59a536b1b001640a8dcf6a78937df6e09fb98ef5 [file] [log] [blame]
Robert Sesek8225b7c2016-12-16 14:02:31 -05001/*
2 * Copyright (C) 2016 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 "fd_utils.h"
18
19#include <algorithm>
20
21#include <fcntl.h>
22#include <grp.h>
23#include <stdlib.h>
24#include <sys/socket.h>
25#include <sys/types.h>
26#include <sys/un.h>
27#include <unistd.h>
28
29#include <android-base/strings.h>
30#include <cutils/log.h>
31
Robert Sesek54e387d2016-12-02 17:27:50 -050032// Static whitelist of open paths that the zygote is allowed to keep open.
Robert Sesek8225b7c2016-12-16 14:02:31 -050033static const char* kPathWhitelist[] = {
34 "/dev/null",
35 "/dev/socket/zygote",
36 "/dev/socket/zygote_secondary",
37 "/dev/socket/webview_zygote",
38 "/sys/kernel/debug/tracing/trace_marker",
39 "/system/framework/framework-res.apk",
40 "/dev/urandom",
41 "/dev/ion",
42 "/dev/dri/renderD129", // Fixes b/31172436
43};
44
45static const char kFdPath[] = "/proc/self/fd";
46
47// static
Robert Sesek54e387d2016-12-02 17:27:50 -050048FileDescriptorWhitelist* FileDescriptorWhitelist::Get() {
49 if (instance_ == nullptr) {
50 instance_ = new FileDescriptorWhitelist();
51 }
52 return instance_;
53}
54
55bool FileDescriptorWhitelist::IsAllowed(const std::string& path) const {
56 // Check the static whitelist path.
57 for (const auto& whitelist_path : kPathWhitelist) {
58 if (path == whitelist_path)
59 return true;
60 }
61
62 // Check any paths added to the dynamic whitelist.
63 for (const auto& whitelist_path : whitelist_) {
64 if (path == whitelist_path)
65 return true;
66 }
67
68 static const std::string kFrameworksPrefix = "/system/framework/";
69 static const std::string kJarSuffix = ".jar";
70 if (StartsWith(path, kFrameworksPrefix) && EndsWith(path, kJarSuffix)) {
71 return true;
72 }
73
74 // Whitelist files needed for Runtime Resource Overlay, like these:
75 // /system/vendor/overlay/framework-res.apk
76 // /system/vendor/overlay-subdir/pg/framework-res.apk
77 // /vendor/overlay/framework-res.apk
78 // /vendor/overlay/PG/android-framework-runtime-resource-overlay.apk
79 // /data/resource-cache/system@vendor@overlay@framework-res.apk@idmap
80 // /data/resource-cache/system@vendor@overlay-subdir@pg@framework-res.apk@idmap
81 // See AssetManager.cpp for more details on overlay-subdir.
82 static const std::string kOverlayDir = "/system/vendor/overlay/";
83 static const std::string kVendorOverlayDir = "/vendor/overlay";
84 static const std::string kOverlaySubdir = "/system/vendor/overlay-subdir/";
85 static const std::string kApkSuffix = ".apk";
86
87 if ((StartsWith(path, kOverlayDir) || StartsWith(path, kOverlaySubdir)
88 || StartsWith(path, kVendorOverlayDir))
89 && EndsWith(path, kApkSuffix)
90 && path.find("/../") == std::string::npos) {
91 return true;
92 }
93
94 static const std::string kOverlayIdmapPrefix = "/data/resource-cache/";
95 static const std::string kOverlayIdmapSuffix = ".apk@idmap";
96 if (StartsWith(path, kOverlayIdmapPrefix) && EndsWith(path, kOverlayIdmapSuffix)
97 && path.find("/../") == std::string::npos) {
98 return true;
99 }
100
101 // All regular files that are placed under this path are whitelisted automatically.
102 static const std::string kZygoteWhitelistPath = "/vendor/zygote_whitelist/";
103 if (StartsWith(path, kZygoteWhitelistPath) && path.find("/../") == std::string::npos) {
104 return true;
105 }
106
107 return false;
108}
109
110FileDescriptorWhitelist::FileDescriptorWhitelist()
111 : whitelist_() {
112}
113
114// TODO: Call android::base::StartsWith instead of copying the code here.
115// static
116bool FileDescriptorWhitelist::StartsWith(const std::string& str,
117 const std::string& prefix) {
118 return str.compare(0, prefix.size(), prefix) == 0;
119}
120
121// TODO: Call android::base::EndsWith instead of copying the code here.
122// static
123bool FileDescriptorWhitelist::EndsWith(const std::string& str,
124 const std::string& suffix) {
125 if (suffix.size() > str.size()) {
126 return false;
127 }
128
129 return str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0;
130}
131
132FileDescriptorWhitelist* FileDescriptorWhitelist::instance_ = nullptr;
133
134// static
Robert Sesek8225b7c2016-12-16 14:02:31 -0500135FileDescriptorInfo* FileDescriptorInfo::CreateFromFd(int fd) {
136 struct stat f_stat;
137 // This should never happen; the zygote should always have the right set
138 // of permissions required to stat all its open files.
139 if (TEMP_FAILURE_RETRY(fstat(fd, &f_stat)) == -1) {
140 ALOGE("Unable to stat fd %d : %s", fd, strerror(errno));
141 return NULL;
142 }
143
Robert Sesek54e387d2016-12-02 17:27:50 -0500144 const FileDescriptorWhitelist* whitelist = FileDescriptorWhitelist::Get();
145
Robert Sesek8225b7c2016-12-16 14:02:31 -0500146 if (S_ISSOCK(f_stat.st_mode)) {
147 std::string socket_name;
148 if (!GetSocketName(fd, &socket_name)) {
149 return NULL;
150 }
151
Robert Sesek54e387d2016-12-02 17:27:50 -0500152 if (!whitelist->IsAllowed(socket_name)) {
Robert Sesek8225b7c2016-12-16 14:02:31 -0500153 ALOGE("Socket name not whitelisted : %s (fd=%d)", socket_name.c_str(), fd);
154 return NULL;
155 }
156
157 return new FileDescriptorInfo(fd);
158 }
159
160 // We only handle whitelisted regular files and character devices. Whitelisted
161 // character devices must provide a guarantee of sensible behaviour when
162 // reopened.
163 //
164 // S_ISDIR : Not supported. (We could if we wanted to, but it's unused).
165 // S_ISLINK : Not supported.
166 // S_ISBLK : Not supported.
167 // S_ISFIFO : Not supported. Note that the zygote uses pipes to communicate
168 // with the child process across forks but those should have been closed
169 // before we got to this point.
170 if (!S_ISCHR(f_stat.st_mode) && !S_ISREG(f_stat.st_mode)) {
171 ALOGE("Unsupported st_mode %d", f_stat.st_mode);
172 return NULL;
173 }
174
175 std::string file_path;
176 if (!Readlink(fd, &file_path)) {
177 return NULL;
178 }
179
Robert Sesek54e387d2016-12-02 17:27:50 -0500180 if (!whitelist->IsAllowed(file_path)) {
Robert Sesek8225b7c2016-12-16 14:02:31 -0500181 ALOGE("Not whitelisted : %s", file_path.c_str());
182 return NULL;
183 }
184
185 // File descriptor flags : currently on FD_CLOEXEC. We can set these
186 // using F_SETFD - we're single threaded at this point of execution so
187 // there won't be any races.
188 const int fd_flags = TEMP_FAILURE_RETRY(fcntl(fd, F_GETFD));
189 if (fd_flags == -1) {
190 ALOGE("Failed fcntl(%d, F_GETFD) : %s", fd, strerror(errno));
191 return NULL;
192 }
193
194 // File status flags :
195 // - File access mode : (O_RDONLY, O_WRONLY...) we'll pass these through
196 // to the open() call.
197 //
198 // - File creation flags : (O_CREAT, O_EXCL...) - there's not much we can
199 // do about these, since the file has already been created. We shall ignore
200 // them here.
201 //
202 // - Other flags : We'll have to set these via F_SETFL. On linux, F_SETFL
203 // can only set O_APPEND, O_ASYNC, O_DIRECT, O_NOATIME, and O_NONBLOCK.
204 // In particular, it can't set O_SYNC and O_DSYNC. We'll have to test for
205 // their presence and pass them in to open().
206 int fs_flags = TEMP_FAILURE_RETRY(fcntl(fd, F_GETFL));
207 if (fs_flags == -1) {
208 ALOGE("Failed fcntl(%d, F_GETFL) : %s", fd, strerror(errno));
209 return NULL;
210 }
211
212 // File offset : Ignore the offset for non seekable files.
213 const off_t offset = TEMP_FAILURE_RETRY(lseek64(fd, 0, SEEK_CUR));
214
215 // We pass the flags that open accepts to open, and use F_SETFL for
216 // the rest of them.
217 static const int kOpenFlags = (O_RDONLY | O_WRONLY | O_RDWR | O_DSYNC | O_SYNC);
218 int open_flags = fs_flags & (kOpenFlags);
219 fs_flags = fs_flags & (~(kOpenFlags));
220
221 return new FileDescriptorInfo(f_stat, file_path, fd, open_flags, fd_flags, fs_flags, offset);
222}
223
224bool FileDescriptorInfo::Restat() const {
225 struct stat f_stat;
226 if (TEMP_FAILURE_RETRY(fstat(fd, &f_stat)) == -1) {
227 return false;
228 }
229
230 return f_stat.st_ino == stat.st_ino && f_stat.st_dev == stat.st_dev;
231}
232
233bool FileDescriptorInfo::ReopenOrDetach() const {
234 if (is_sock) {
235 return DetachSocket();
236 }
237
238 // NOTE: This might happen if the file was unlinked after being opened.
239 // It's a common pattern in the case of temporary files and the like but
240 // we should not allow such usage from the zygote.
241 const int new_fd = TEMP_FAILURE_RETRY(open(file_path.c_str(), open_flags));
242
243 if (new_fd == -1) {
244 ALOGE("Failed open(%s, %d) : %s", file_path.c_str(), open_flags, strerror(errno));
245 return false;
246 }
247
248 if (TEMP_FAILURE_RETRY(fcntl(new_fd, F_SETFD, fd_flags)) == -1) {
249 close(new_fd);
250 ALOGE("Failed fcntl(%d, F_SETFD, %x) : %s", new_fd, fd_flags, strerror(errno));
251 return false;
252 }
253
254 if (TEMP_FAILURE_RETRY(fcntl(new_fd, F_SETFL, fs_flags)) == -1) {
255 close(new_fd);
256 ALOGE("Failed fcntl(%d, F_SETFL, %x) : %s", new_fd, fs_flags, strerror(errno));
257 return false;
258 }
259
260 if (offset != -1 && TEMP_FAILURE_RETRY(lseek64(new_fd, offset, SEEK_SET)) == -1) {
261 close(new_fd);
262 ALOGE("Failed lseek64(%d, SEEK_SET) : %s", new_fd, strerror(errno));
263 return false;
264 }
265
266 if (TEMP_FAILURE_RETRY(dup2(new_fd, fd)) == -1) {
267 close(new_fd);
268 ALOGE("Failed dup2(%d, %d) : %s", fd, new_fd, strerror(errno));
269 return false;
270 }
271
272 close(new_fd);
273
274 return true;
275}
276
277FileDescriptorInfo::FileDescriptorInfo(int fd) :
278 fd(fd),
279 stat(),
280 open_flags(0),
281 fd_flags(0),
282 fs_flags(0),
283 offset(0),
284 is_sock(true) {
285}
286
287FileDescriptorInfo::FileDescriptorInfo(struct stat stat, const std::string& file_path,
288 int fd, int open_flags, int fd_flags, int fs_flags,
289 off_t offset) :
290 fd(fd),
291 stat(stat),
292 file_path(file_path),
293 open_flags(open_flags),
294 fd_flags(fd_flags),
295 fs_flags(fs_flags),
296 offset(offset),
297 is_sock(false) {
298}
299
Robert Sesek8225b7c2016-12-16 14:02:31 -0500300// TODO: Call android::base::Readlink instead of copying the code here.
301// static
302bool FileDescriptorInfo::Readlink(const int fd, std::string* result) {
303 char path[64];
304 snprintf(path, sizeof(path), "/proc/self/fd/%d", fd);
305
306 // Code copied from android::base::Readlink starts here :
307
308 // Annoyingly, the readlink system call returns EINVAL for a zero-sized buffer,
309 // and truncates to whatever size you do supply, so it can't be used to query.
310 // We could call lstat first, but that would introduce a race condition that
311 // we couldn't detect.
312 // ext2 and ext4 both have PAGE_SIZE limitations, so we assume that here.
313 char buf[4096];
314 ssize_t len = readlink(path, buf, sizeof(buf));
315 if (len == -1) return false;
316
317 result->assign(buf, len);
318 return true;
319}
320
321// static
322bool FileDescriptorInfo::GetSocketName(const int fd, std::string* result) {
323 sockaddr_storage ss;
324 sockaddr* addr = reinterpret_cast<sockaddr*>(&ss);
325 socklen_t addr_len = sizeof(ss);
326
327 if (TEMP_FAILURE_RETRY(getsockname(fd, addr, &addr_len)) == -1) {
328 ALOGE("Failed getsockname(%d) : %s", fd, strerror(errno));
329 return false;
330 }
331
332 if (addr->sa_family != AF_UNIX) {
333 ALOGE("Unsupported socket (fd=%d) with family %d", fd, addr->sa_family);
334 return false;
335 }
336
337 const sockaddr_un* unix_addr = reinterpret_cast<const sockaddr_un*>(&ss);
338
339 size_t path_len = addr_len - offsetof(struct sockaddr_un, sun_path);
340 // This is an unnamed local socket, we do not accept it.
341 if (path_len == 0) {
342 ALOGE("Unsupported AF_UNIX socket (fd=%d) with empty path.", fd);
343 return false;
344 }
345
346 // This is a local socket with an abstract address, we do not accept it.
347 if (unix_addr->sun_path[0] == '\0') {
348 ALOGE("Unsupported AF_UNIX socket (fd=%d) with abstract address.", fd);
349 return false;
350 }
351
352 // If we're here, sun_path must refer to a null terminated filesystem
353 // pathname (man 7 unix). Remove the terminator before assigning it to an
354 // std::string.
355 if (unix_addr->sun_path[path_len - 1] == '\0') {
356 --path_len;
357 }
358
359 result->assign(unix_addr->sun_path, path_len);
360 return true;
361}
362
363bool FileDescriptorInfo::DetachSocket() const {
364 const int dev_null_fd = open("/dev/null", O_RDWR);
365 if (dev_null_fd < 0) {
366 ALOGE("Failed to open /dev/null : %s", strerror(errno));
367 return false;
368 }
369
370 if (dup2(dev_null_fd, fd) == -1) {
371 ALOGE("Failed dup2 on socket descriptor %d : %s", fd, strerror(errno));
372 return false;
373 }
374
375 if (close(dev_null_fd) == -1) {
376 ALOGE("Failed close(%d) : %s", dev_null_fd, strerror(errno));
377 return false;
378 }
379
380 return true;
381}
382
383// static
Andreas Gampe8dfa1782017-01-05 12:45:58 -0800384FileDescriptorTable* FileDescriptorTable::Create(const std::vector<int>& fds_to_ignore) {
Robert Sesek8225b7c2016-12-16 14:02:31 -0500385 DIR* d = opendir(kFdPath);
386 if (d == NULL) {
387 ALOGE("Unable to open directory %s: %s", kFdPath, strerror(errno));
388 return NULL;
389 }
390 int dir_fd = dirfd(d);
391 dirent* e;
392
393 std::unordered_map<int, FileDescriptorInfo*> open_fd_map;
394 while ((e = readdir(d)) != NULL) {
395 const int fd = ParseFd(e, dir_fd);
396 if (fd == -1) {
397 continue;
398 }
Andreas Gampe8dfa1782017-01-05 12:45:58 -0800399 if (std::find(fds_to_ignore.begin(), fds_to_ignore.end(), fd) != fds_to_ignore.end()) {
400 ALOGI("Ignoring open file descriptor %d", fd);
401 continue;
402 }
Robert Sesek8225b7c2016-12-16 14:02:31 -0500403
404 FileDescriptorInfo* info = FileDescriptorInfo::CreateFromFd(fd);
405 if (info == NULL) {
406 if (closedir(d) == -1) {
407 ALOGE("Unable to close directory : %s", strerror(errno));
408 }
409 return NULL;
410 }
411 open_fd_map[fd] = info;
412 }
413
414 if (closedir(d) == -1) {
415 ALOGE("Unable to close directory : %s", strerror(errno));
416 return NULL;
417 }
418 return new FileDescriptorTable(open_fd_map);
419}
420
Andreas Gampe8dfa1782017-01-05 12:45:58 -0800421bool FileDescriptorTable::Restat(const std::vector<int>& fds_to_ignore) {
Robert Sesek8225b7c2016-12-16 14:02:31 -0500422 std::set<int> open_fds;
423
424 // First get the list of open descriptors.
425 DIR* d = opendir(kFdPath);
426 if (d == NULL) {
427 ALOGE("Unable to open directory %s: %s", kFdPath, strerror(errno));
428 return false;
429 }
430
431 int dir_fd = dirfd(d);
432 dirent* e;
433 while ((e = readdir(d)) != NULL) {
434 const int fd = ParseFd(e, dir_fd);
435 if (fd == -1) {
436 continue;
437 }
Andreas Gampe8dfa1782017-01-05 12:45:58 -0800438 if (std::find(fds_to_ignore.begin(), fds_to_ignore.end(), fd) != fds_to_ignore.end()) {
439 ALOGI("Ignoring open file descriptor %d", fd);
440 continue;
441 }
Robert Sesek8225b7c2016-12-16 14:02:31 -0500442
443 open_fds.insert(fd);
444 }
445
446 if (closedir(d) == -1) {
447 ALOGE("Unable to close directory : %s", strerror(errno));
448 return false;
449 }
450
451 return RestatInternal(open_fds);
452}
453
454// Reopens all file descriptors that are contained in the table. Returns true
455// if all descriptors were successfully re-opened or detached, and false if an
456// error occurred.
457bool FileDescriptorTable::ReopenOrDetach() {
458 std::unordered_map<int, FileDescriptorInfo*>::const_iterator it;
459 for (it = open_fd_map_.begin(); it != open_fd_map_.end(); ++it) {
460 const FileDescriptorInfo* info = it->second;
461 if (info == NULL || !info->ReopenOrDetach()) {
462 return false;
463 }
464 }
465
466 return true;
467}
468
469FileDescriptorTable::FileDescriptorTable(
470 const std::unordered_map<int, FileDescriptorInfo*>& map)
471 : open_fd_map_(map) {
472}
473
474bool FileDescriptorTable::RestatInternal(std::set<int>& open_fds) {
475 bool error = false;
476
477 // Iterate through the list of file descriptors we've already recorded
478 // and check whether :
479 //
480 // (a) they continue to be open.
481 // (b) they refer to the same file.
482 std::unordered_map<int, FileDescriptorInfo*>::iterator it = open_fd_map_.begin();
483 while (it != open_fd_map_.end()) {
484 std::set<int>::const_iterator element = open_fds.find(it->first);
485 if (element == open_fds.end()) {
486 // The entry from the file descriptor table is no longer in the list
487 // of open files. We warn about this condition and remove it from
488 // the list of FDs under consideration.
489 //
490 // TODO(narayan): This will be an error in a future android release.
491 // error = true;
492 // ALOGW("Zygote closed file descriptor %d.", it->first);
493 it = open_fd_map_.erase(it);
494 } else {
495 // The entry from the file descriptor table is still open. Restat
496 // it and check whether it refers to the same file.
497 const bool same_file = it->second->Restat();
498 if (!same_file) {
499 // The file descriptor refers to a different description. We must
500 // update our entry in the table.
501 delete it->second;
502 it->second = FileDescriptorInfo::CreateFromFd(*element);
503 if (it->second == NULL) {
504 // The descriptor no longer no longer refers to a whitelisted file.
505 // We flag an error and remove it from the list of files we're
506 // tracking.
507 error = true;
508 it = open_fd_map_.erase(it);
509 } else {
510 // Successfully restatted the file, move on to the next open FD.
511 ++it;
512 }
513 } else {
514 // It's the same file. Nothing to do here. Move on to the next open
515 // FD.
516 ++it;
517 }
518
519 // Finally, remove the FD from the set of open_fds. We do this last because
520 // |element| will not remain valid after a call to erase.
521 open_fds.erase(element);
522 }
523 }
524
525 if (open_fds.size() > 0) {
526 // The zygote has opened new file descriptors since our last inspection.
527 // We warn about this condition and add them to our table.
528 //
529 // TODO(narayan): This will be an error in a future android release.
530 // error = true;
531 // ALOGW("Zygote opened %zd new file descriptor(s).", open_fds.size());
532
533 // TODO(narayan): This code will be removed in a future android release.
534 std::set<int>::const_iterator it;
535 for (it = open_fds.begin(); it != open_fds.end(); ++it) {
536 const int fd = (*it);
537 FileDescriptorInfo* info = FileDescriptorInfo::CreateFromFd(fd);
538 if (info == NULL) {
539 // A newly opened file is not on the whitelist. Flag an error and
540 // continue.
541 error = true;
542 } else {
543 // Track the newly opened file.
544 open_fd_map_[fd] = info;
545 }
546 }
547 }
548
549 return !error;
550}
551
552// static
553int FileDescriptorTable::ParseFd(dirent* e, int dir_fd) {
554 char* end;
555 const int fd = strtol(e->d_name, &end, 10);
556 if ((*end) != '\0') {
557 return -1;
558 }
559
560 // Don't bother with the standard input/output/error, they're handled
561 // specially post-fork anyway.
562 if (fd <= STDERR_FILENO || fd == dir_fd) {
563 return -1;
564 }
565
566 return fd;
567}