summaryrefslogtreecommitdiff
path: root/core/jni/fd_utils.cpp
diff options
context:
space:
mode:
authorChris Wailes <chriswailes@google.com>2019-01-10 16:55:32 -0800
committerChris Wailes <chriswailes@google.com>2019-01-23 13:34:40 -0800
commit8b35ba25a9663264e6e50867f124f9100953299a (patch)
treeabf86737b0eb7ec947a9ea906ea1687367dd5295 /core/jni/fd_utils.cpp
parentc0db63f6ac6cf6b784ea6633b037764452c52c91 (diff)
Implemented native functions and types for blastula management.
This patch adds native support for spawning and managing blastula pools, as well as several code cleanups and modernizations. Changes includes: * A function to fork blastulas * A table for managing blastula-related data * Functions for adding and removing blastula data from the aforementioned table * Switching from NULL to nullptr * Replacing string-passing error handling with a curried failure function * Utility functions for handling managed objects * JNI functions for blastula pool management Topic: zygot-prefork Test: make & flash & launch apps & check log for messages Bug: 68253328 Change-Id: I12cd9f2c87a2e3c00d64b683edf3631e29a51551 Merged-In: I12cd9f2c87a2e3c00d64b683edf3631e29a51551
Diffstat (limited to 'core/jni/fd_utils.cpp')
-rw-r--r--core/jni/fd_utils.cpp273
1 files changed, 116 insertions, 157 deletions
diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp
index 9e7ccfd1f4c0..0ed8c0c97738 100644
--- a/core/jni/fd_utils.cpp
+++ b/core/jni/fd_utils.cpp
@@ -131,15 +131,14 @@ FileDescriptorWhitelist* FileDescriptorWhitelist::instance_ = nullptr;
// open zygote file descriptor.
class FileDescriptorInfo {
public:
- // Create a FileDescriptorInfo for a given file descriptor. Returns
- // |NULL| if an error occurred.
- static FileDescriptorInfo* CreateFromFd(int fd, std::string* error_msg);
+ // Create a FileDescriptorInfo for a given file descriptor.
+ static FileDescriptorInfo* CreateFromFd(int fd, fail_fn_t fail_fn);
// Checks whether the file descriptor associated with this object
// 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 struct stat stat;
@@ -165,19 +164,18 @@ class FileDescriptorInfo {
// address).
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);
};
// static
-FileDescriptorInfo* FileDescriptorInfo::CreateFromFd(int fd, std::string* error_msg) {
+FileDescriptorInfo* FileDescriptorInfo::CreateFromFd(int fd, fail_fn_t fail_fn) {
struct stat f_stat;
// This should never happen; the zygote should always have the right set
// of permissions required to stat all its open files.
if (TEMP_FAILURE_RETRY(fstat(fd, &f_stat)) == -1) {
- *error_msg = android::base::StringPrintf("Unable to stat %d", fd);
- return nullptr;
+ fail_fn(android::base::StringPrintf("Unable to stat %d", fd));
}
const FileDescriptorWhitelist* whitelist = FileDescriptorWhitelist::Get();
@@ -185,15 +183,13 @@ FileDescriptorInfo* FileDescriptorInfo::CreateFromFd(int fd, std::string* error_
if (S_ISSOCK(f_stat.st_mode)) {
std::string socket_name;
if (!GetSocketName(fd, &socket_name)) {
- *error_msg = "Unable to get socket name";
- return nullptr;
+ fail_fn("Unable to get socket name");
}
if (!whitelist->IsAllowed(socket_name)) {
- *error_msg = android::base::StringPrintf("Socket name not whitelisted : %s (fd=%d)",
- socket_name.c_str(),
- fd);
- return nullptr;
+ fail_fn(android::base::StringPrintf("Socket name not whitelisted : %s (fd=%d)",
+ socket_name.c_str(),
+ 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_ISLINK : Not supported.
// S_ISBLK : Not supported.
- // S_ISFIFO : Not supported. Note that the zygote uses pipes to communicate
- // with the child process across forks but those should have been closed
- // before we got to this point.
+ // S_ISFIFO : Not supported. Note that the Zygote and blastulas use pipes to
+ // communicate with the child processes across forks but those should have been
+ // added to the redirection exemption list.
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);
- return nullptr;
+ std::string mode = "Unknown";
+
+ 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;
const std::string fd_path = android::base::StringPrintf("/proc/self/fd/%d", fd);
if (!android::base::Readlink(fd_path, &file_path)) {
- *error_msg = android::base::StringPrintf("Could not read fd link %s: %s",
- fd_path.c_str(),
- strerror(errno));
- return nullptr;
+ fail_fn(android::base::StringPrintf("Could not read fd link %s: %s",
+ fd_path.c_str(),
+ strerror(errno)));
}
if (!whitelist->IsAllowed(file_path)) {
- *error_msg = std::string("Not whitelisted : ").append(file_path);
- return nullptr;
+ fail_fn(std::string("Not whitelisted : ").append(file_path));
}
// 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.
const int fd_flags = TEMP_FAILURE_RETRY(fcntl(fd, F_GETFD));
if (fd_flags == -1) {
- *error_msg = android::base::StringPrintf("Failed fcntl(%d, F_GETFD) (%s): %s",
- fd,
- file_path.c_str(),
- strerror(errno));
- return nullptr;
+ fail_fn(android::base::StringPrintf("Failed fcntl(%d, F_GETFD) (%s): %s",
+ fd,
+ file_path.c_str(),
+ strerror(errno)));
}
// File status flags :
@@ -254,11 +258,10 @@ FileDescriptorInfo* FileDescriptorInfo::CreateFromFd(int fd, std::string* error_
// their presence and pass them in to open().
int fs_flags = TEMP_FAILURE_RETRY(fcntl(fd, F_GETFL));
if (fs_flags == -1) {
- *error_msg = android::base::StringPrintf("Failed fcntl(%d, F_GETFL) (%s): %s",
- fd,
- file_path.c_str(),
- strerror(errno));
- return nullptr;
+ fail_fn(android::base::StringPrintf("Failed fcntl(%d, F_GETFL) (%s): %s",
+ fd,
+ file_path.c_str(),
+ strerror(errno)));
}
// 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);
}
-bool FileDescriptorInfo::Restat() const {
+bool FileDescriptorInfo::RefersToSameFile() const {
struct stat f_stat;
if (TEMP_FAILURE_RETRY(fstat(fd, &f_stat)) == -1) {
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;
}
-bool FileDescriptorInfo::ReopenOrDetach(std::string* error_msg) const {
+void FileDescriptorInfo::ReopenOrDetach(fail_fn_t fail_fn) const {
if (is_sock) {
- return DetachSocket(error_msg);
+ return DetachSocket(fail_fn);
}
// 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));
if (new_fd == -1) {
- *error_msg = android::base::StringPrintf("Failed open(%s, %i): %s",
- file_path.c_str(),
- open_flags,
- strerror(errno));
- return false;
+ fail_fn(android::base::StringPrintf("Failed open(%s, %i): %s",
+ file_path.c_str(),
+ open_flags,
+ strerror(errno)));
}
if (TEMP_FAILURE_RETRY(fcntl(new_fd, F_SETFD, fd_flags)) == -1) {
close(new_fd);
- *error_msg = android::base::StringPrintf("Failed fcntl(%d, F_SETFD, %d) (%s): %s",
- new_fd,
- fd_flags,
- file_path.c_str(),
- strerror(errno));
- return false;
+ fail_fn(android::base::StringPrintf("Failed fcntl(%d, F_SETFD, %d) (%s): %s",
+ new_fd,
+ fd_flags,
+ file_path.c_str(),
+ strerror(errno)));
}
if (TEMP_FAILURE_RETRY(fcntl(new_fd, F_SETFL, fs_flags)) == -1) {
close(new_fd);
- *error_msg = android::base::StringPrintf("Failed fcntl(%d, F_SETFL, %d) (%s): %s",
- new_fd,
- fs_flags,
- file_path.c_str(),
- strerror(errno));
- return false;
+ fail_fn(android::base::StringPrintf("Failed fcntl(%d, F_SETFL, %d) (%s): %s",
+ new_fd,
+ fs_flags,
+ file_path.c_str(),
+ strerror(errno)));
}
if (offset != -1 && TEMP_FAILURE_RETRY(lseek64(new_fd, offset, SEEK_SET)) == -1) {
close(new_fd);
- *error_msg = android::base::StringPrintf("Failed lseek64(%d, SEEK_SET) (%s): %s",
- new_fd,
- file_path.c_str(),
- strerror(errno));
- return false;
+ fail_fn(android::base::StringPrintf("Failed lseek64(%d, SEEK_SET) (%s): %s",
+ new_fd,
+ file_path.c_str(),
+ strerror(errno)));
}
- int dupFlags = (fd_flags & FD_CLOEXEC) ? O_CLOEXEC : 0;
- if (TEMP_FAILURE_RETRY(dup3(new_fd, fd, dupFlags)) == -1) {
+ int dup_flags = (fd_flags & FD_CLOEXEC) ? O_CLOEXEC : 0;
+ if (TEMP_FAILURE_RETRY(dup3(new_fd, fd, dup_flags)) == -1) {
close(new_fd);
- *error_msg = android::base::StringPrintf("Failed dup3(%d, %d, %d) (%s): %s",
- fd,
- new_fd,
- dupFlags,
- file_path.c_str(),
- strerror(errno));
- return false;
+ fail_fn(android::base::StringPrintf("Failed dup3(%d, %d, %d) (%s): %s",
+ fd,
+ new_fd,
+ dup_flags,
+ file_path.c_str(),
+ strerror(errno)));
}
close(new_fd);
-
- return true;
}
FileDescriptorInfo::FileDescriptorInfo(int fd) :
@@ -370,7 +366,6 @@ FileDescriptorInfo::FileDescriptorInfo(struct stat stat, const std::string& file
is_sock(false) {
}
-// static
bool FileDescriptorInfo::GetSocketName(const int fd, std::string* result) {
sockaddr_storage ss;
sockaddr* addr = reinterpret_cast<sockaddr*>(&ss);
@@ -414,86 +409,75 @@ bool FileDescriptorInfo::GetSocketName(const int fd, std::string* result) {
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);
if (dev_null_fd < 0) {
- *error_msg = std::string("Failed to open /dev/null: ").append(strerror(errno));
- return false;
+ fail_fn(std::string("Failed to open /dev/null: ").append(strerror(errno)));
}
if (dup2(dev_null_fd, fd) == -1) {
- *error_msg = android::base::StringPrintf("Failed dup2 on socket descriptor %d: %s",
- fd,
- strerror(errno));
- return false;
+ fail_fn(android::base::StringPrintf("Failed dup2 on socket descriptor %d: %s",
+ fd,
+ strerror(errno)));
}
if (close(dev_null_fd) == -1) {
- *error_msg = android::base::StringPrintf("Failed close(%d): %s", dev_null_fd, strerror(errno));
- return false;
+ fail_fn(android::base::StringPrintf("Failed close(%d): %s", dev_null_fd, strerror(errno)));
}
-
- return true;
}
// static
FileDescriptorTable* FileDescriptorTable::Create(const std::vector<int>& fds_to_ignore,
- std::string* error_msg) {
- DIR* d = opendir(kFdPath);
- if (d == nullptr) {
- *error_msg = std::string("Unable to open directory ").append(kFdPath);
- return nullptr;
+ fail_fn_t fail_fn) {
+ DIR* proc_fd_dir = opendir(kFdPath);
+ if (proc_fd_dir == nullptr) {
+ fail_fn(std::string("Unable to open directory ").append(kFdPath));
}
- 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;
- while ((e = readdir(d)) != NULL) {
- const int fd = ParseFd(e, dir_fd);
+ while ((dir_entry = readdir(proc_fd_dir)) != nullptr) {
+ const int fd = ParseFd(dir_entry, dir_fd);
if (fd == -1) {
continue;
}
+
if (std::find(fds_to_ignore.begin(), fds_to_ignore.end(), fd) != fds_to_ignore.end()) {
LOG(INFO) << "Ignoring open file descriptor " << fd;
continue;
}
- FileDescriptorInfo* info = FileDescriptorInfo::CreateFromFd(fd, error_msg);
- if (info == NULL) {
- if (closedir(d) == -1) {
- PLOG(ERROR) << "Unable to close directory";
- }
- return NULL;
- }
- open_fd_map[fd] = info;
+ open_fd_map[fd] = FileDescriptorInfo::CreateFromFd(fd, fail_fn);
}
- if (closedir(d) == -1) {
- *error_msg = "Unable to close directory";
- return nullptr;
+ if (closedir(proc_fd_dir) == -1) {
+ fail_fn("Unable to close directory");
}
+
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;
// First get the list of open descriptors.
- DIR* d = opendir(kFdPath);
- if (d == NULL) {
- *error_msg = android::base::StringPrintf("Unable to open directory %s: %s",
- kFdPath,
- strerror(errno));
- return false;
+ DIR* proc_fd_dir = opendir(kFdPath);
+ if (proc_fd_dir == nullptr) {
+ fail_fn(android::base::StringPrintf("Unable to open directory %s: %s",
+ kFdPath,
+ strerror(errno)));
}
- int dir_fd = dirfd(d);
- dirent* e;
- while ((e = readdir(d)) != NULL) {
- const int fd = ParseFd(e, dir_fd);
+ int dir_fd = dirfd(proc_fd_dir);
+ dirent* dir_entry;
+ while ((dir_entry = readdir(proc_fd_dir)) != nullptr) {
+ const int fd = ParseFd(dir_entry, dir_fd);
if (fd == -1) {
continue;
}
+
if (std::find(fds_to_ignore.begin(), fds_to_ignore.end(), fd) != fds_to_ignore.end()) {
LOG(INFO) << "Ignoring open file descriptor " << fd;
continue;
@@ -502,27 +486,24 @@ bool FileDescriptorTable::Restat(const std::vector<int>& fds_to_ignore, std::str
open_fds.insert(fd);
}
- if (closedir(d) == -1) {
- *error_msg = android::base::StringPrintf("Unable to close directory: %s", strerror(errno));
- return false;
+ if (closedir(proc_fd_dir) == -1) {
+ fail_fn(android::base::StringPrintf("Unable to close directory: %s", strerror(errno)));
}
- return RestatInternal(open_fds, error_msg);
+ RestatInternal(open_fds, fail_fn);
}
-// 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
-// error occurred.
-bool FileDescriptorTable::ReopenOrDetach(std::string* error_msg) {
+// Reopens all file descriptors that are contained in the table.
+void FileDescriptorTable::ReopenOrDetach(fail_fn_t fail_fn) {
std::unordered_map<int, FileDescriptorInfo*>::const_iterator it;
for (it = open_fd_map_.begin(); it != open_fd_map_.end(); ++it) {
const FileDescriptorInfo* info = it->second;
- if (info == NULL || !info->ReopenOrDetach(error_msg)) {
- return false;
+ if (info == nullptr) {
+ return;
+ } else {
+ info->ReopenOrDetach(fail_fn);
}
}
-
- return true;
}
FileDescriptorTable::FileDescriptorTable(
@@ -530,9 +511,7 @@ FileDescriptorTable::FileDescriptorTable(
: open_fd_map_(map) {
}
-bool FileDescriptorTable::RestatInternal(std::set<int>& open_fds, std::string* error_msg) {
- bool error = false;
-
+void FileDescriptorTable::RestatInternal(std::set<int>& open_fds, fail_fn_t fail_fn) {
// Iterate through the list of file descriptors we've already recorded
// and check whether :
//
@@ -555,28 +534,18 @@ bool FileDescriptorTable::RestatInternal(std::set<int>& open_fds, std::string* e
} else {
// The entry from the file descriptor table is still open. Restat
// it and check whether it refers to the same file.
- const bool same_file = it->second->Restat();
- if (!same_file) {
+ if (!it->second->RefersToSameFile()) {
// The file descriptor refers to a different description. We must
// update our entry in the table.
delete it->second;
- it->second = FileDescriptorInfo::CreateFromFd(*element, error_msg);
- 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;
- }
+ it->second = FileDescriptorInfo::CreateFromFd(*element, fail_fn);
} else {
// It's the same file. Nothing to do here. Move on to the next open
// FD.
- ++it;
}
+ ++it;
+
// 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.
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;
for (it = open_fds.begin(); it != open_fds.end(); ++it) {
const int fd = (*it);
- FileDescriptorInfo* info = FileDescriptorInfo::CreateFromFd(fd, error_msg);
- 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;
- }
+ open_fd_map_[fd] = FileDescriptorInfo::CreateFromFd(fd, fail_fn);
}
}
-
- return !error;
}
// static
-int FileDescriptorTable::ParseFd(dirent* e, int dir_fd) {
+int FileDescriptorTable::ParseFd(dirent* dir_entry, int dir_fd) {
char* end;
- const int fd = strtol(e->d_name, &end, 10);
+ const int fd = strtol(dir_entry->d_name, &end, 10);
if ((*end) != '\0') {
return -1;
}