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