Add an option to close all open file descriptors
This adds the minijail_close_open_fds() API to close all open file
descriptors (except the pipes that are internally set up to communicate
with the jailed process).
Bug: 32005517
Test: libminijail_unittest
Change-Id: Ia392f14c080716297c5766ad31af983ee6c5ead3
diff --git a/libminijail.c b/libminijail.c
index e837414..a44c5d2 100644
--- a/libminijail.c
+++ b/libminijail.c
@@ -9,6 +9,7 @@
#include <asm/unistd.h>
#include <ctype.h>
+#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <grp.h>
@@ -148,6 +149,7 @@
int cgroups:1;
int alt_syscall:1;
int reset_signal_mask:1;
+ int close_open_fds:1;
} flags;
uid_t uid;
gid_t gid;
@@ -461,6 +463,11 @@
j->flags.ns_cgroups = 1;
}
+void API minijail_close_open_fds(struct minijail *j)
+{
+ j->flags.close_open_fds = 1;
+}
+
void API minijail_remount_proc_readonly(struct minijail *j)
{
j->flags.vfs = 1;
@@ -1796,6 +1803,43 @@
return dup2(fds[index], fd);
}
+int close_open_fds(int *inheritable_fds, size_t size)
+{
+ const char *kFdPath = "/proc/self/fd";
+
+ DIR *d = opendir(kFdPath);
+ struct dirent *dir_entry;
+
+ if (d == NULL)
+ return -1;
+ int dir_fd = dirfd(d);
+ while ((dir_entry = readdir(d)) != NULL) {
+ size_t i;
+ char *end;
+ bool should_close = true;
+ const int fd = strtol(dir_entry->d_name, &end, 10);
+
+ if ((*end) != '\0') {
+ continue;
+ }
+ /*
+ * We might have set up some pipes that we want to share with
+ * the parent process, and should not be closed.
+ */
+ for (i = 0; i < size; ++i) {
+ if (fd == inheritable_fds[i]) {
+ should_close = false;
+ break;
+ }
+ }
+ /* Also avoid closing the directory fd. */
+ if (should_close && fd != dir_fd)
+ close(fd);
+ }
+ closedir(d);
+ return 0;
+}
+
int minijail_run_internal(struct minijail *j, const char *filename,
char *const argv[], pid_t *pchild_pid,
int *pstdin_fd, int *pstdout_fd, int *pstderr_fd,
@@ -2077,6 +2121,35 @@
pdie("sigprocmask failed");
}
+ if (j->flags.close_open_fds) {
+ const size_t kMaxInheritableFdsSize = 10;
+ int inheritable_fds[kMaxInheritableFdsSize];
+ size_t size = 0;
+ if (use_preload) {
+ inheritable_fds[size++] = pipe_fds[0];
+ inheritable_fds[size++] = pipe_fds[1];
+ }
+ if (sync_child) {
+ inheritable_fds[size++] = child_sync_pipe_fds[0];
+ inheritable_fds[size++] = child_sync_pipe_fds[1];
+ }
+ if (pstdin_fd) {
+ inheritable_fds[size++] = stdin_fds[0];
+ inheritable_fds[size++] = stdin_fds[1];
+ }
+ if (pstdout_fd) {
+ inheritable_fds[size++] = stdout_fds[0];
+ inheritable_fds[size++] = stdout_fds[1];
+ }
+ if (pstderr_fd) {
+ inheritable_fds[size++] = stderr_fds[0];
+ inheritable_fds[size++] = stderr_fds[1];
+ }
+
+ if (close_open_fds(inheritable_fds, size) < 0)
+ die("failed to close open file descriptors");
+ }
+
if (sync_child)
wait_for_parent_setup(child_sync_pipe_fds);