fd_utils.cpp revision 54e387ddbe6a0462bc8e9e15c7c7b3463adfcb24
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/strings.h>
30#include <cutils/log.h>
31
32// Static whitelist of open paths that the zygote is allowed to keep open.
33static 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
48FileDescriptorWhitelist* 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
135FileDescriptorInfo* 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
144  const FileDescriptorWhitelist* whitelist = FileDescriptorWhitelist::Get();
145
146  if (S_ISSOCK(f_stat.st_mode)) {
147    std::string socket_name;
148    if (!GetSocketName(fd, &socket_name)) {
149      return NULL;
150    }
151
152    if (!whitelist->IsAllowed(socket_name)) {
153      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
180  if (!whitelist->IsAllowed(file_path)) {
181    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
300// 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
384FileDescriptorTable* FileDescriptorTable::Create() {
385  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    }
399
400    FileDescriptorInfo* info = FileDescriptorInfo::CreateFromFd(fd);
401    if (info == NULL) {
402      if (closedir(d) == -1) {
403        ALOGE("Unable to close directory : %s", strerror(errno));
404      }
405      return NULL;
406    }
407    open_fd_map[fd] = info;
408  }
409
410  if (closedir(d) == -1) {
411    ALOGE("Unable to close directory : %s", strerror(errno));
412    return NULL;
413  }
414  return new FileDescriptorTable(open_fd_map);
415}
416
417bool FileDescriptorTable::Restat() {
418  std::set<int> open_fds;
419
420  // First get the list of open descriptors.
421  DIR* d = opendir(kFdPath);
422  if (d == NULL) {
423    ALOGE("Unable to open directory %s: %s", kFdPath, strerror(errno));
424    return false;
425  }
426
427  int dir_fd = dirfd(d);
428  dirent* e;
429  while ((e = readdir(d)) != NULL) {
430    const int fd = ParseFd(e, dir_fd);
431    if (fd == -1) {
432      continue;
433    }
434
435    open_fds.insert(fd);
436  }
437
438  if (closedir(d) == -1) {
439    ALOGE("Unable to close directory : %s", strerror(errno));
440    return false;
441  }
442
443  return RestatInternal(open_fds);
444}
445
446// Reopens all file descriptors that are contained in the table. Returns true
447// if all descriptors were successfully re-opened or detached, and false if an
448// error occurred.
449bool FileDescriptorTable::ReopenOrDetach() {
450  std::unordered_map<int, FileDescriptorInfo*>::const_iterator it;
451  for (it = open_fd_map_.begin(); it != open_fd_map_.end(); ++it) {
452    const FileDescriptorInfo* info = it->second;
453    if (info == NULL || !info->ReopenOrDetach()) {
454      return false;
455    }
456  }
457
458  return true;
459}
460
461FileDescriptorTable::FileDescriptorTable(
462    const std::unordered_map<int, FileDescriptorInfo*>& map)
463    : open_fd_map_(map) {
464}
465
466bool FileDescriptorTable::RestatInternal(std::set<int>& open_fds) {
467  bool error = false;
468
469  // Iterate through the list of file descriptors we've already recorded
470  // and check whether :
471  //
472  // (a) they continue to be open.
473  // (b) they refer to the same file.
474  std::unordered_map<int, FileDescriptorInfo*>::iterator it = open_fd_map_.begin();
475  while (it != open_fd_map_.end()) {
476    std::set<int>::const_iterator element = open_fds.find(it->first);
477    if (element == open_fds.end()) {
478      // The entry from the file descriptor table is no longer in the list
479      // of open files. We warn about this condition and remove it from
480      // the list of FDs under consideration.
481      //
482      // TODO(narayan): This will be an error in a future android release.
483      // error = true;
484      // ALOGW("Zygote closed file descriptor %d.", it->first);
485      it = open_fd_map_.erase(it);
486    } else {
487      // The entry from the file descriptor table is still open. Restat
488      // it and check whether it refers to the same file.
489      const bool same_file = it->second->Restat();
490      if (!same_file) {
491        // The file descriptor refers to a different description. We must
492        // update our entry in the table.
493        delete it->second;
494        it->second = FileDescriptorInfo::CreateFromFd(*element);
495        if (it->second == NULL) {
496          // The descriptor no longer no longer refers to a whitelisted file.
497          // We flag an error and remove it from the list of files we're
498          // tracking.
499          error = true;
500          it = open_fd_map_.erase(it);
501        } else {
502          // Successfully restatted the file, move on to the next open FD.
503          ++it;
504        }
505      } else {
506        // It's the same file. Nothing to do here. Move on to the next open
507        // FD.
508        ++it;
509      }
510
511      // Finally, remove the FD from the set of open_fds. We do this last because
512      // |element| will not remain valid after a call to erase.
513      open_fds.erase(element);
514    }
515  }
516
517  if (open_fds.size() > 0) {
518    // The zygote has opened new file descriptors since our last inspection.
519    // We warn about this condition and add them to our table.
520    //
521    // TODO(narayan): This will be an error in a future android release.
522    // error = true;
523    // ALOGW("Zygote opened %zd new file descriptor(s).", open_fds.size());
524
525    // TODO(narayan): This code will be removed in a future android release.
526    std::set<int>::const_iterator it;
527    for (it = open_fds.begin(); it != open_fds.end(); ++it) {
528      const int fd = (*it);
529      FileDescriptorInfo* info = FileDescriptorInfo::CreateFromFd(fd);
530      if (info == NULL) {
531        // A newly opened file is not on the whitelist. Flag an error and
532        // continue.
533        error = true;
534      } else {
535        // Track the newly opened file.
536        open_fd_map_[fd] = info;
537      }
538    }
539  }
540
541  return !error;
542}
543
544// static
545int FileDescriptorTable::ParseFd(dirent* e, int dir_fd) {
546  char* end;
547  const int fd = strtol(e->d_name, &end, 10);
548  if ((*end) != '\0') {
549    return -1;
550  }
551
552  // Don't bother with the standard input/output/error, they're handled
553  // specially post-fork anyway.
554  if (fd <= STDERR_FILENO || fd == dir_fd) {
555    return -1;
556  }
557
558  return fd;
559}
560