Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5222bf36 authored by Christian Wailes's avatar Christian Wailes Committed by Gerrit Code Review
Browse files

Merge "Implemented native functions and types for blastula management."

parents e22f160c 8b35ba25
Loading
Loading
Loading
Loading
+34 −13
Original line number Original line Diff line number Diff line
@@ -94,7 +94,7 @@ public final class Zygote {
    private Zygote() {}
    private Zygote() {}


    /** Called for some security initialization before any fork. */
    /** Called for some security initialization before any fork. */
    native static void nativeSecurityInit();
    static native void nativeSecurityInit();


    /**
    /**
     * Forks a new VM instance.  The current VM must have been started
     * Forks a new VM instance.  The current VM must have been started
@@ -150,14 +150,19 @@ public final class Zygote {
        return pid;
        return pid;
    }
    }


    native private static int nativeForkAndSpecialize(int uid, int gid, int[] gids,int runtimeFlags,
    private static native int nativeForkAndSpecialize(int uid, int gid, int[] gids,
          int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
            int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName,
          int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir);
            int[] fdsToClose, int[] fdsToIgnore, boolean startChildZygote, String instructionSet,
            String appDataDir);

    private static native void nativeSpecializeBlastula(int uid, int gid, int[] gids,
            int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName,
            boolean startChildZygote, String instructionSet, String appDataDir);


    /**
    /**
     * Called to do any initialization before starting an application.
     * Called to do any initialization before starting an application.
     */
     */
    native static void nativePreApplicationInit();
    static native void nativePreApplicationInit();


    /**
    /**
     * Special method to start the system server process. In addition to the
     * Special method to start the system server process. In addition to the
@@ -188,7 +193,8 @@ public final class Zygote {
        // Resets nice priority for zygote process.
        // Resets nice priority for zygote process.
        resetNicePriority();
        resetNicePriority();
        int pid = nativeForkSystemServer(
        int pid = nativeForkSystemServer(
                uid, gid, gids, runtimeFlags, rlimits, permittedCapabilities, effectiveCapabilities);
                uid, gid, gids, runtimeFlags, rlimits,
                permittedCapabilities, effectiveCapabilities);
        // Enable tracing as soon as we enter the system_server.
        // Enable tracing as soon as we enter the system_server.
        if (pid == 0) {
        if (pid == 0) {
            Trace.setTracingEnabled(true, runtimeFlags);
            Trace.setTracingEnabled(true, runtimeFlags);
@@ -197,19 +203,34 @@ public final class Zygote {
        return pid;
        return pid;
    }
    }


    native private static int nativeForkSystemServer(int uid, int gid, int[] gids, int runtimeFlags,
    private static native int nativeForkSystemServer(int uid, int gid, int[] gids, int runtimeFlags,
            int[][] rlimits, long permittedCapabilities, long effectiveCapabilities);
            int[][] rlimits, long permittedCapabilities, long effectiveCapabilities);


    /**
    /**
     * Lets children of the zygote inherit open file descriptors to this path.
     * Lets children of the zygote inherit open file descriptors to this path.
     */
     */
    native protected static void nativeAllowFileAcrossFork(String path);
    protected static native void nativeAllowFileAcrossFork(String path);


    /**
    /**
     * Zygote unmount storage space on initializing.
     * Zygote unmount storage space on initializing.
     * This method is called once.
     * This method is called once.
     */
     */
    native protected static void nativeUnmountStorageOnInit();
    protected static native void nativeUnmountStorageOnInit();

    protected static native void nativeGetSocketFDs(boolean isPrimary);

    private static native int nativeGetBlastulaPoolCount();

    private static native int nativeGetBlastulaPoolEventFD();

    private static native int nativeForkBlastula(int readPipeFD,
                                                 int writePipeFD,
                                                 int[] sessionSocketRawFDs);

    private static native int[] nativeGetBlastulaPipeFDs();

    private static native boolean nativeRemoveBlastulaTableEntry(int blastulaPID);



    private static void callPostForkSystemServerHooks() {
    private static void callPostForkSystemServerHooks() {
        // SystemServer specific post fork hooks run before child post fork hooks.
        // SystemServer specific post fork hooks run before child post fork hooks.
+667 −225

File changed.

Preview size limit exceeded, changes collapsed.

+116 −157
Original line number Original line Diff line number Diff line
@@ -131,15 +131,14 @@ FileDescriptorWhitelist* FileDescriptorWhitelist::instance_ = nullptr;
// open zygote file descriptor.
// open zygote file descriptor.
class FileDescriptorInfo {
class FileDescriptorInfo {
 public:
 public:
  // Create a FileDescriptorInfo for a given file descriptor. Returns
  // Create a FileDescriptorInfo for a given file descriptor.
  // |NULL| if an error occurred.
  static FileDescriptorInfo* CreateFromFd(int fd, fail_fn_t fail_fn);
  static FileDescriptorInfo* CreateFromFd(int fd, std::string* error_msg);


  // Checks whether the file descriptor associated with this object
  // Checks whether the file descriptor associated with this object
  // refers to the same description.
  // refers to the same description.
  bool Restat() const;
  bool RefersToSameFile() const;


  bool ReopenOrDetach(std::string* error_msg) const;
  void ReopenOrDetach(fail_fn_t fail_fn) const;


  const int fd;
  const int fd;
  const struct stat stat;
  const struct stat stat;
@@ -165,19 +164,18 @@ class FileDescriptorInfo {
  //   address).
  //   address).
  static bool GetSocketName(const int fd, std::string* result);
  static bool GetSocketName(const int fd, std::string* result);


  bool DetachSocket(std::string* error_msg) const;
  void DetachSocket(fail_fn_t fail_fn) const;


  DISALLOW_COPY_AND_ASSIGN(FileDescriptorInfo);
  DISALLOW_COPY_AND_ASSIGN(FileDescriptorInfo);
};
};


// static
// static
FileDescriptorInfo* FileDescriptorInfo::CreateFromFd(int fd, std::string* error_msg) {
FileDescriptorInfo* FileDescriptorInfo::CreateFromFd(int fd, fail_fn_t fail_fn) {
  struct stat f_stat;
  struct stat f_stat;
  // This should never happen; the zygote should always have the right set
  // This should never happen; the zygote should always have the right set
  // of permissions required to stat all its open files.
  // of permissions required to stat all its open files.
  if (TEMP_FAILURE_RETRY(fstat(fd, &f_stat)) == -1) {
  if (TEMP_FAILURE_RETRY(fstat(fd, &f_stat)) == -1) {
    *error_msg = android::base::StringPrintf("Unable to stat %d", fd);
    fail_fn(android::base::StringPrintf("Unable to stat %d", fd));
    return nullptr;
  }
  }


  const FileDescriptorWhitelist* whitelist = FileDescriptorWhitelist::Get();
  const FileDescriptorWhitelist* whitelist = FileDescriptorWhitelist::Get();
@@ -185,15 +183,13 @@ FileDescriptorInfo* FileDescriptorInfo::CreateFromFd(int fd, std::string* error_
  if (S_ISSOCK(f_stat.st_mode)) {
  if (S_ISSOCK(f_stat.st_mode)) {
    std::string socket_name;
    std::string socket_name;
    if (!GetSocketName(fd, &socket_name)) {
    if (!GetSocketName(fd, &socket_name)) {
      *error_msg = "Unable to get socket name";
      fail_fn("Unable to get socket name");
      return nullptr;
    }
    }


    if (!whitelist->IsAllowed(socket_name)) {
    if (!whitelist->IsAllowed(socket_name)) {
      *error_msg = android::base::StringPrintf("Socket name not whitelisted : %s (fd=%d)",
      fail_fn(android::base::StringPrintf("Socket name not whitelisted : %s (fd=%d)",
                                          socket_name.c_str(),
                                          socket_name.c_str(),
                                               fd);
                                          fd));
      return nullptr;
    }
    }


    return new FileDescriptorInfo(fd);
    return new FileDescriptorInfo(fd);
@@ -206,26 +202,35 @@ FileDescriptorInfo* FileDescriptorInfo::CreateFromFd(int fd, std::string* error_
  // S_ISDIR : Not supported. (We could if we wanted to, but it's unused).
  // S_ISDIR : Not supported. (We could if we wanted to, but it's unused).
  // S_ISLINK : Not supported.
  // S_ISLINK : Not supported.
  // S_ISBLK : Not supported.
  // S_ISBLK : Not supported.
  // S_ISFIFO : Not supported. Note that the zygote uses pipes to communicate
  // S_ISFIFO : Not supported. Note that the Zygote and blastulas use pipes to
  // with the child process across forks but those should have been closed
  // communicate with the child processes across forks but those should have been
  // before we got to this point.
  // added to the redirection exemption list.
  if (!S_ISCHR(f_stat.st_mode) && !S_ISREG(f_stat.st_mode)) {
  if (!S_ISCHR(f_stat.st_mode) && !S_ISREG(f_stat.st_mode)) {
    *error_msg = android::base::StringPrintf("Unsupported st_mode %u", f_stat.st_mode);
    std::string mode = "Unknown";
    return nullptr;

    if (S_ISDIR(f_stat.st_mode)) {
      mode = "DIR";
    } else if (S_ISLNK(f_stat.st_mode)) {
      mode = "LINK";
    } else if (S_ISBLK(f_stat.st_mode)) {
      mode = "BLOCK";
    } else if (S_ISFIFO(f_stat.st_mode)) {
      mode = "FIFO";
    }

    fail_fn(android::base::StringPrintf("Unsupported st_mode for FD %d:  %s", fd, mode.c_str()));
  }
  }


  std::string file_path;
  std::string file_path;
  const std::string fd_path = android::base::StringPrintf("/proc/self/fd/%d", fd);
  const std::string fd_path = android::base::StringPrintf("/proc/self/fd/%d", fd);
  if (!android::base::Readlink(fd_path, &file_path)) {
  if (!android::base::Readlink(fd_path, &file_path)) {
    *error_msg = android::base::StringPrintf("Could not read fd link %s: %s",
    fail_fn(android::base::StringPrintf("Could not read fd link %s: %s",
                                        fd_path.c_str(),
                                        fd_path.c_str(),
                                             strerror(errno));
                                        strerror(errno)));
    return nullptr;
  }
  }


  if (!whitelist->IsAllowed(file_path)) {
  if (!whitelist->IsAllowed(file_path)) {
    *error_msg = std::string("Not whitelisted : ").append(file_path);
    fail_fn(std::string("Not whitelisted : ").append(file_path));
    return nullptr;
  }
  }


  // File descriptor flags : currently on FD_CLOEXEC. We can set these
  // File descriptor flags : currently on FD_CLOEXEC. We can set these
@@ -233,11 +238,10 @@ FileDescriptorInfo* FileDescriptorInfo::CreateFromFd(int fd, std::string* error_
  // there won't be any races.
  // there won't be any races.
  const int fd_flags = TEMP_FAILURE_RETRY(fcntl(fd, F_GETFD));
  const int fd_flags = TEMP_FAILURE_RETRY(fcntl(fd, F_GETFD));
  if (fd_flags == -1) {
  if (fd_flags == -1) {
    *error_msg = android::base::StringPrintf("Failed fcntl(%d, F_GETFD) (%s): %s",
    fail_fn(android::base::StringPrintf("Failed fcntl(%d, F_GETFD) (%s): %s",
                                        fd,
                                        fd,
                                        file_path.c_str(),
                                        file_path.c_str(),
                                             strerror(errno));
                                        strerror(errno)));
    return nullptr;
  }
  }


  // File status flags :
  // File status flags :
@@ -254,11 +258,10 @@ FileDescriptorInfo* FileDescriptorInfo::CreateFromFd(int fd, std::string* error_
  //   their presence and pass them in to open().
  //   their presence and pass them in to open().
  int fs_flags = TEMP_FAILURE_RETRY(fcntl(fd, F_GETFL));
  int fs_flags = TEMP_FAILURE_RETRY(fcntl(fd, F_GETFL));
  if (fs_flags == -1) {
  if (fs_flags == -1) {
    *error_msg = android::base::StringPrintf("Failed fcntl(%d, F_GETFL) (%s): %s",
    fail_fn(android::base::StringPrintf("Failed fcntl(%d, F_GETFL) (%s): %s",
                                        fd,
                                        fd,
                                        file_path.c_str(),
                                        file_path.c_str(),
                                             strerror(errno));
                                        strerror(errno)));
    return nullptr;
  }
  }


  // File offset : Ignore the offset for non seekable files.
  // File offset : Ignore the offset for non seekable files.
@@ -273,7 +276,7 @@ FileDescriptorInfo* FileDescriptorInfo::CreateFromFd(int fd, std::string* error_
  return new FileDescriptorInfo(f_stat, file_path, fd, open_flags, fd_flags, fs_flags, offset);
  return new FileDescriptorInfo(f_stat, file_path, fd, open_flags, fd_flags, fs_flags, offset);
}
}


bool FileDescriptorInfo::Restat() const {
bool FileDescriptorInfo::RefersToSameFile() const {
  struct stat f_stat;
  struct stat f_stat;
  if (TEMP_FAILURE_RETRY(fstat(fd, &f_stat)) == -1) {
  if (TEMP_FAILURE_RETRY(fstat(fd, &f_stat)) == -1) {
    PLOG(ERROR) << "Unable to restat fd " << fd;
    PLOG(ERROR) << "Unable to restat fd " << fd;
@@ -283,9 +286,9 @@ bool FileDescriptorInfo::Restat() const {
  return f_stat.st_ino == stat.st_ino && f_stat.st_dev == stat.st_dev;
  return f_stat.st_ino == stat.st_ino && f_stat.st_dev == stat.st_dev;
}
}


bool FileDescriptorInfo::ReopenOrDetach(std::string* error_msg) const {
void FileDescriptorInfo::ReopenOrDetach(fail_fn_t fail_fn) const {
  if (is_sock) {
  if (is_sock) {
    return DetachSocket(error_msg);
    return DetachSocket(fail_fn);
  }
  }


  // NOTE: This might happen if the file was unlinked after being opened.
  // NOTE: This might happen if the file was unlinked after being opened.
@@ -294,57 +297,50 @@ bool FileDescriptorInfo::ReopenOrDetach(std::string* error_msg) const {
  const int new_fd = TEMP_FAILURE_RETRY(open(file_path.c_str(), open_flags));
  const int new_fd = TEMP_FAILURE_RETRY(open(file_path.c_str(), open_flags));


  if (new_fd == -1) {
  if (new_fd == -1) {
    *error_msg = android::base::StringPrintf("Failed open(%s, %i): %s",
    fail_fn(android::base::StringPrintf("Failed open(%s, %i): %s",
                                        file_path.c_str(),
                                        file_path.c_str(),
                                        open_flags,
                                        open_flags,
                                             strerror(errno));
                                        strerror(errno)));
    return false;
  }
  }


  if (TEMP_FAILURE_RETRY(fcntl(new_fd, F_SETFD, fd_flags)) == -1) {
  if (TEMP_FAILURE_RETRY(fcntl(new_fd, F_SETFD, fd_flags)) == -1) {
    close(new_fd);
    close(new_fd);
    *error_msg = android::base::StringPrintf("Failed fcntl(%d, F_SETFD, %d) (%s): %s",
    fail_fn(android::base::StringPrintf("Failed fcntl(%d, F_SETFD, %d) (%s): %s",
                                        new_fd,
                                        new_fd,
                                        fd_flags,
                                        fd_flags,
                                        file_path.c_str(),
                                        file_path.c_str(),
                                             strerror(errno));
                                        strerror(errno)));
    return false;
  }
  }


  if (TEMP_FAILURE_RETRY(fcntl(new_fd, F_SETFL, fs_flags)) == -1) {
  if (TEMP_FAILURE_RETRY(fcntl(new_fd, F_SETFL, fs_flags)) == -1) {
    close(new_fd);
    close(new_fd);
    *error_msg = android::base::StringPrintf("Failed fcntl(%d, F_SETFL, %d) (%s): %s",
    fail_fn(android::base::StringPrintf("Failed fcntl(%d, F_SETFL, %d) (%s): %s",
                                        new_fd,
                                        new_fd,
                                        fs_flags,
                                        fs_flags,
                                        file_path.c_str(),
                                        file_path.c_str(),
                                             strerror(errno));
                                        strerror(errno)));
    return false;
  }
  }


  if (offset != -1 && TEMP_FAILURE_RETRY(lseek64(new_fd, offset, SEEK_SET)) == -1) {
  if (offset != -1 && TEMP_FAILURE_RETRY(lseek64(new_fd, offset, SEEK_SET)) == -1) {
    close(new_fd);
    close(new_fd);
    *error_msg = android::base::StringPrintf("Failed lseek64(%d, SEEK_SET) (%s): %s",
    fail_fn(android::base::StringPrintf("Failed lseek64(%d, SEEK_SET) (%s): %s",
                                        new_fd,
                                        new_fd,
                                        file_path.c_str(),
                                        file_path.c_str(),
                                             strerror(errno));
                                        strerror(errno)));
    return false;
  }
  }


  int dupFlags = (fd_flags & FD_CLOEXEC) ? O_CLOEXEC : 0;
  int dup_flags = (fd_flags & FD_CLOEXEC) ? O_CLOEXEC : 0;
  if (TEMP_FAILURE_RETRY(dup3(new_fd, fd, dupFlags)) == -1) {
  if (TEMP_FAILURE_RETRY(dup3(new_fd, fd, dup_flags)) == -1) {
    close(new_fd);
    close(new_fd);
    *error_msg = android::base::StringPrintf("Failed dup3(%d, %d, %d) (%s): %s",
    fail_fn(android::base::StringPrintf("Failed dup3(%d, %d, %d) (%s): %s",
                                        fd,
                                        fd,
                                        new_fd,
                                        new_fd,
                                             dupFlags,
                                        dup_flags,
                                        file_path.c_str(),
                                        file_path.c_str(),
                                             strerror(errno));
                                        strerror(errno)));
    return false;
  }
  }


  close(new_fd);
  close(new_fd);

  return true;
}
}


FileDescriptorInfo::FileDescriptorInfo(int fd) :
FileDescriptorInfo::FileDescriptorInfo(int fd) :
@@ -370,7 +366,6 @@ FileDescriptorInfo::FileDescriptorInfo(struct stat stat, const std::string& file
  is_sock(false) {
  is_sock(false) {
}
}


// static
bool FileDescriptorInfo::GetSocketName(const int fd, std::string* result) {
bool FileDescriptorInfo::GetSocketName(const int fd, std::string* result) {
  sockaddr_storage ss;
  sockaddr_storage ss;
  sockaddr* addr = reinterpret_cast<sockaddr*>(&ss);
  sockaddr* addr = reinterpret_cast<sockaddr*>(&ss);
@@ -414,86 +409,75 @@ bool FileDescriptorInfo::GetSocketName(const int fd, std::string* result) {
  return true;
  return true;
}
}


bool FileDescriptorInfo::DetachSocket(std::string* error_msg) const {
void FileDescriptorInfo::DetachSocket(fail_fn_t fail_fn) const {
  const int dev_null_fd = open("/dev/null", O_RDWR);
  const int dev_null_fd = open("/dev/null", O_RDWR);
  if (dev_null_fd < 0) {
  if (dev_null_fd < 0) {
    *error_msg = std::string("Failed to open /dev/null: ").append(strerror(errno));
    fail_fn(std::string("Failed to open /dev/null: ").append(strerror(errno)));
    return false;
  }
  }


  if (dup2(dev_null_fd, fd) == -1) {
  if (dup2(dev_null_fd, fd) == -1) {
    *error_msg = android::base::StringPrintf("Failed dup2 on socket descriptor %d: %s",
    fail_fn(android::base::StringPrintf("Failed dup2 on socket descriptor %d: %s",
                                        fd,
                                        fd,
                                             strerror(errno));
                                        strerror(errno)));
    return false;
  }
  }


  if (close(dev_null_fd) == -1) {
  if (close(dev_null_fd) == -1) {
    *error_msg = android::base::StringPrintf("Failed close(%d): %s", dev_null_fd, strerror(errno));
    fail_fn(android::base::StringPrintf("Failed close(%d): %s", dev_null_fd, strerror(errno)));
    return false;
  }
  }

  return true;
}
}


// static
// static
FileDescriptorTable* FileDescriptorTable::Create(const std::vector<int>& fds_to_ignore,
FileDescriptorTable* FileDescriptorTable::Create(const std::vector<int>& fds_to_ignore,
                                                 std::string* error_msg) {
                                                 fail_fn_t fail_fn) {
  DIR* d = opendir(kFdPath);
  DIR* proc_fd_dir = opendir(kFdPath);
  if (d == nullptr) {
  if (proc_fd_dir == nullptr) {
    *error_msg = std::string("Unable to open directory ").append(kFdPath);
    fail_fn(std::string("Unable to open directory ").append(kFdPath));
    return nullptr;
  }
  }
  int dir_fd = dirfd(d);

  dirent* e;
  int dir_fd = dirfd(proc_fd_dir);
  dirent* dir_entry;


  std::unordered_map<int, FileDescriptorInfo*> open_fd_map;
  std::unordered_map<int, FileDescriptorInfo*> open_fd_map;
  while ((e = readdir(d)) != NULL) {
  while ((dir_entry = readdir(proc_fd_dir)) != nullptr) {
    const int fd = ParseFd(e, dir_fd);
    const int fd = ParseFd(dir_entry, dir_fd);
    if (fd == -1) {
    if (fd == -1) {
      continue;
      continue;
    }
    }

    if (std::find(fds_to_ignore.begin(), fds_to_ignore.end(), fd) != fds_to_ignore.end()) {
    if (std::find(fds_to_ignore.begin(), fds_to_ignore.end(), fd) != fds_to_ignore.end()) {
      LOG(INFO) << "Ignoring open file descriptor " << fd;
      LOG(INFO) << "Ignoring open file descriptor " << fd;
      continue;
      continue;
    }
    }


    FileDescriptorInfo* info = FileDescriptorInfo::CreateFromFd(fd, error_msg);
    open_fd_map[fd] = FileDescriptorInfo::CreateFromFd(fd, fail_fn);
    if (info == NULL) {
      if (closedir(d) == -1) {
        PLOG(ERROR) << "Unable to close directory";
      }
      return NULL;
    }
    open_fd_map[fd] = info;
  }
  }


  if (closedir(d) == -1) {
  if (closedir(proc_fd_dir) == -1) {
    *error_msg = "Unable to close directory";
    fail_fn("Unable to close directory");
    return nullptr;
  }
  }

  return new FileDescriptorTable(open_fd_map);
  return new FileDescriptorTable(open_fd_map);
}
}


bool FileDescriptorTable::Restat(const std::vector<int>& fds_to_ignore, std::string* error_msg) {
void FileDescriptorTable::Restat(const std::vector<int>& fds_to_ignore, fail_fn_t fail_fn) {
  std::set<int> open_fds;
  std::set<int> open_fds;


  // First get the list of open descriptors.
  // First get the list of open descriptors.
  DIR* d = opendir(kFdPath);
  DIR* proc_fd_dir = opendir(kFdPath);
  if (d == NULL) {
  if (proc_fd_dir == nullptr) {
    *error_msg = android::base::StringPrintf("Unable to open directory %s: %s",
    fail_fn(android::base::StringPrintf("Unable to open directory %s: %s",
                                        kFdPath,
                                        kFdPath,
                                             strerror(errno));
                                        strerror(errno)));
    return false;
  }
  }


  int dir_fd = dirfd(d);
  int dir_fd = dirfd(proc_fd_dir);
  dirent* e;
  dirent* dir_entry;
  while ((e = readdir(d)) != NULL) {
  while ((dir_entry = readdir(proc_fd_dir)) != nullptr) {
    const int fd = ParseFd(e, dir_fd);
    const int fd = ParseFd(dir_entry, dir_fd);
    if (fd == -1) {
    if (fd == -1) {
      continue;
      continue;
    }
    }

    if (std::find(fds_to_ignore.begin(), fds_to_ignore.end(), fd) != fds_to_ignore.end()) {
    if (std::find(fds_to_ignore.begin(), fds_to_ignore.end(), fd) != fds_to_ignore.end()) {
      LOG(INFO) << "Ignoring open file descriptor " << fd;
      LOG(INFO) << "Ignoring open file descriptor " << fd;
      continue;
      continue;
@@ -502,27 +486,24 @@ bool FileDescriptorTable::Restat(const std::vector<int>& fds_to_ignore, std::str
    open_fds.insert(fd);
    open_fds.insert(fd);
  }
  }


  if (closedir(d) == -1) {
  if (closedir(proc_fd_dir) == -1) {
    *error_msg = android::base::StringPrintf("Unable to close directory: %s", strerror(errno));
    fail_fn(android::base::StringPrintf("Unable to close directory: %s", strerror(errno)));
    return false;
  }
  }


  return RestatInternal(open_fds, error_msg);
  RestatInternal(open_fds, fail_fn);
}
}


// Reopens all file descriptors that are contained in the table. Returns true
// Reopens all file descriptors that are contained in the table.
// if all descriptors were successfully re-opened or detached, and false if an
void FileDescriptorTable::ReopenOrDetach(fail_fn_t fail_fn) {
// error occurred.
bool FileDescriptorTable::ReopenOrDetach(std::string* error_msg) {
  std::unordered_map<int, FileDescriptorInfo*>::const_iterator it;
  std::unordered_map<int, FileDescriptorInfo*>::const_iterator it;
  for (it = open_fd_map_.begin(); it != open_fd_map_.end(); ++it) {
  for (it = open_fd_map_.begin(); it != open_fd_map_.end(); ++it) {
    const FileDescriptorInfo* info = it->second;
    const FileDescriptorInfo* info = it->second;
    if (info == NULL || !info->ReopenOrDetach(error_msg)) {
    if (info == nullptr) {
      return false;
      return;
    } else {
      info->ReopenOrDetach(fail_fn);
    }
    }
  }
  }

  return true;
}
}


FileDescriptorTable::FileDescriptorTable(
FileDescriptorTable::FileDescriptorTable(
@@ -530,9 +511,7 @@ FileDescriptorTable::FileDescriptorTable(
    : open_fd_map_(map) {
    : open_fd_map_(map) {
}
}


bool FileDescriptorTable::RestatInternal(std::set<int>& open_fds, std::string* error_msg) {
void FileDescriptorTable::RestatInternal(std::set<int>& open_fds, fail_fn_t fail_fn) {
  bool error = false;

  // Iterate through the list of file descriptors we've already recorded
  // Iterate through the list of file descriptors we've already recorded
  // and check whether :
  // and check whether :
  //
  //
@@ -555,28 +534,18 @@ bool FileDescriptorTable::RestatInternal(std::set<int>& open_fds, std::string* e
    } else {
    } else {
      // The entry from the file descriptor table is still open. Restat
      // The entry from the file descriptor table is still open. Restat
      // it and check whether it refers to the same file.
      // it and check whether it refers to the same file.
      const bool same_file = it->second->Restat();
      if (!it->second->RefersToSameFile()) {
      if (!same_file) {
        // The file descriptor refers to a different description. We must
        // The file descriptor refers to a different description. We must
        // update our entry in the table.
        // update our entry in the table.
        delete it->second;
        delete it->second;
        it->second = FileDescriptorInfo::CreateFromFd(*element, error_msg);
        it->second = FileDescriptorInfo::CreateFromFd(*element, fail_fn);
        if (it->second == NULL) {
          // The descriptor no longer no longer refers to a whitelisted file.
          // We flag an error and remove it from the list of files we're
          // tracking.
          error = true;
          it = open_fd_map_.erase(it);
        } else {
          // Successfully restatted the file, move on to the next open FD.
          ++it;
        }
      } else {
      } else {
        // It's the same file. Nothing to do here. Move on to the next open
        // It's the same file. Nothing to do here. Move on to the next open
        // FD.
        // FD.
        ++it;
      }
      }


      ++it;

      // Finally, remove the FD from the set of open_fds. We do this last because
      // Finally, remove the FD from the set of open_fds. We do this last because
      // |element| will not remain valid after a call to erase.
      // |element| will not remain valid after a call to erase.
      open_fds.erase(element);
      open_fds.erase(element);
@@ -595,25 +564,15 @@ bool FileDescriptorTable::RestatInternal(std::set<int>& open_fds, std::string* e
    std::set<int>::const_iterator it;
    std::set<int>::const_iterator it;
    for (it = open_fds.begin(); it != open_fds.end(); ++it) {
    for (it = open_fds.begin(); it != open_fds.end(); ++it) {
      const int fd = (*it);
      const int fd = (*it);
      FileDescriptorInfo* info = FileDescriptorInfo::CreateFromFd(fd, error_msg);
      open_fd_map_[fd] = FileDescriptorInfo::CreateFromFd(fd, fail_fn);
      if (info == NULL) {
        // A newly opened file is not on the whitelist. Flag an error and
        // continue.
        error = true;
      } else {
        // Track the newly opened file.
        open_fd_map_[fd] = info;
    }
    }
  }
  }
}
}


  return !error;
}

// static
// static
int FileDescriptorTable::ParseFd(dirent* e, int dir_fd) {
int FileDescriptorTable::ParseFd(dirent* dir_entry, int dir_fd) {
  char* end;
  char* end;
  const int fd = strtol(e->d_name, &end, 10);
  const int fd = strtol(dir_entry->d_name, &end, 10);
  if ((*end) != '\0') {
  if ((*end) != '\0') {
    return -1;
    return -1;
  }
  }
+7 −4
Original line number Original line Diff line number Diff line
@@ -30,6 +30,9 @@


class FileDescriptorInfo;
class FileDescriptorInfo;


// This type is duplicated in com_android_internal_os_Zygote.cpp
typedef const std::function<void(std::string)>& fail_fn_t;

// Whitelist of open paths that the zygote is allowed to keep open.
// Whitelist of open paths that the zygote is allowed to keep open.
//
//
// In addition to the paths listed in kPathWhitelist in file_utils.cpp, and
// In addition to the paths listed in kPathWhitelist in file_utils.cpp, and
@@ -76,19 +79,19 @@ class FileDescriptorTable {
  // /proc/self/fd for the list of open file descriptors and collects
  // /proc/self/fd for the list of open file descriptors and collects
  // information about them. Returns NULL if an error occurs.
  // information about them. Returns NULL if an error occurs.
  static FileDescriptorTable* Create(const std::vector<int>& fds_to_ignore,
  static FileDescriptorTable* Create(const std::vector<int>& fds_to_ignore,
                                     std::string* error_msg);
                                     fail_fn_t fail_fn);


  bool Restat(const std::vector<int>& fds_to_ignore, std::string* error_msg);
  void Restat(const std::vector<int>& fds_to_ignore, fail_fn_t fail_fn);


  // Reopens all file descriptors that are contained in the table. Returns true
  // Reopens all file descriptors that are contained in the table. Returns true
  // if all descriptors were successfully re-opened or detached, and false if an
  // if all descriptors were successfully re-opened or detached, and false if an
  // error occurred.
  // error occurred.
  bool ReopenOrDetach(std::string* error_msg);
  void ReopenOrDetach(fail_fn_t fail_fn);


 private:
 private:
  explicit FileDescriptorTable(const std::unordered_map<int, FileDescriptorInfo*>& map);
  explicit FileDescriptorTable(const std::unordered_map<int, FileDescriptorInfo*>& map);


  bool RestatInternal(std::set<int>& open_fds, std::string* error_msg);
  void RestatInternal(std::set<int>& open_fds, fail_fn_t fail_fn);


  static int ParseFd(dirent* e, int dir_fd);
  static int ParseFd(dirent* e, int dir_fd);