Merge "Implemented native functions and types for blastula management." am: 5222bf368b
am: c5cc5e525c
Change-Id: I4eb03e2d0592aefa196be7f96687aa4f155c0022
This commit is contained in:
@@ -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
|
||||||
@@ -131,14 +131,14 @@ public final class Zygote {
|
|||||||
* if this is the parent, or -1 on error.
|
* if this is the parent, or -1 on error.
|
||||||
*/
|
*/
|
||||||
public static int forkAndSpecialize(int uid, int gid, int[] gids, int runtimeFlags,
|
public static int forkAndSpecialize(int uid, int gid, int[] gids, int runtimeFlags,
|
||||||
int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
|
int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
|
||||||
int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir) {
|
int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir) {
|
||||||
VM_HOOKS.preFork();
|
VM_HOOKS.preFork();
|
||||||
// Resets nice priority for zygote process.
|
// Resets nice priority for zygote process.
|
||||||
resetNicePriority();
|
resetNicePriority();
|
||||||
int pid = nativeForkAndSpecialize(
|
int pid = nativeForkAndSpecialize(
|
||||||
uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose,
|
uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose,
|
||||||
fdsToIgnore, startChildZygote, instructionSet, appDataDir);
|
fdsToIgnore, startChildZygote, instructionSet, appDataDir);
|
||||||
// Enable tracing as soon as possible for the child process.
|
// Enable tracing as soon as possible for the child process.
|
||||||
if (pid == 0) {
|
if (pid == 0) {
|
||||||
Trace.setTracingEnabled(true, runtimeFlags);
|
Trace.setTracingEnabled(true, runtimeFlags);
|
||||||
@@ -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.
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user