criu: Add --keep-on-exec option

Submitted by Cyrill Gorcunov on May 28, 2019, 3:17 p.m.

Details

Message ID 20190528151757.22604-1-gorcunov@gmail.com
State New
Series "criu: Add --keep-on-exec option"
Headers show

Commit Message

Cyrill Gorcunov May 28, 2019, 3:17 p.m.
When we run action scripts we communicate with third-party
tools via file descriptors inherited from a criu execution
caller.

Since commit 6c8ea60491305482eb60d9b17a8635ab9248a5ab this
no longer possible, moreover it breaks API.

Thus lets provide --keep-on-exec option where we could
tell explicitly which exactly fds should be kept opened.

Signed-off-by: Cyrill Gorcunov <gorcunov@gmail.com>
---
 Documentation/criu.txt    |  7 +++++++
 criu/config.c             | 29 +++++++++++++++++++++++++++++
 criu/include/cr_options.h |  2 ++
 criu/util.c               | 23 +++++++++++++++++++++++
 4 files changed, 61 insertions(+)

Patch hide | download patch | download mbox

diff --git a/Documentation/criu.txt b/Documentation/criu.txt
index 6111c3baf0e1..5ffdd7cb1b28 100644
--- a/Documentation/criu.txt
+++ b/Documentation/criu.txt
@@ -138,6 +138,13 @@  Common options are applicable to any 'command'.
             notification message contains a file descriptor for
             the master pty
 
+*--keep-on-exec* 'fd'::
+    Keep 'fd' file descriptor when executing service programs and scripts
+    during certain stages. When *criu* is executed it inherits opened file
+    descriptors or a caller (if they are present). Sometimes it is needed
+    to pass such descriptors to the *--action-script* scripts, otherwise
+    they get closed for security reason.
+
 *-V*, *--version*::
     Print program version and exit.
 
diff --git a/criu/config.c b/criu/config.c
index 24f0b33858ad..ae2bf2070f87 100644
--- a/criu/config.c
+++ b/criu/config.c
@@ -416,6 +416,28 @@  static int parse_join_ns(const char *ptr)
 	return 0;
 }
 
+static int cmp_keep_on_exec(const void *__a, const void *__b)
+{
+	int a = ((int *)__a)[0];
+	int b = ((int *)__b)[0];
+	return a == b ? 0 : (a < b ? -1 : 1);
+}
+
+static int parse_keep_on_exec(char *optarg)
+{
+	size_t size = sizeof(opts.keep_on_exec[0]) * (opts.nr_keep_on_exec + 1);
+	int fd = atoi(optarg);
+
+	if (xrealloc_safe(&opts.keep_on_exec, size))
+		return -ENOMEM;
+
+	opts.keep_on_exec[opts.nr_keep_on_exec++] = fd;
+	qsort(opts.keep_on_exec, opts.nr_keep_on_exec,
+	      sizeof(opts.keep_on_exec[0]), cmp_keep_on_exec);
+
+	return 0;
+}
+
 /*
  * parse_options() is the point where the getopt parsing happens. The CLI
  * parsing as well as the configuration file parsing happens here.
@@ -511,6 +533,7 @@  int parse_options(int argc, char **argv, bool *usage_error,
 		BOOL_OPT("remote", &opts.remote),
 		{ "config",			required_argument,	0, 1089},
 		{ "no-default-config",		no_argument,		0, 1090},
+		{ "keep-on-exec",		required_argument,	0, 1092},
 		{ },
 	};
 
@@ -797,6 +820,12 @@  int parse_options(int argc, char **argv, bool *usage_error,
 		case 1091:
 			opts.ps_socket = atoi(optarg);
 			break;
+		case 1092:
+			if (parse_keep_on_exec(optarg)) {
+				pr_err("Unable to parse value for --keep-on-exec\n");
+				return 1;
+			}
+			break;
 		case 'V':
 			pr_msg("Version: %s\n", CRIU_VERSION);
 			if (strcmp(CRIU_GITID, "0"))
diff --git a/criu/include/cr_options.h b/criu/include/cr_options.h
index 8ddbf2341a48..2022ba12f8ec 100644
--- a/criu/include/cr_options.h
+++ b/criu/include/cr_options.h
@@ -90,6 +90,8 @@  struct cr_options {
 	struct list_head	inherit_fds;
 	struct list_head	external;
 	struct list_head	join_ns;
+	int			*keep_on_exec;
+	size_t			nr_keep_on_exec;
 	char			*libdir;
 	int			use_page_server;
 	unsigned short		port;
diff --git a/criu/util.c b/criu/util.c
index 31cdee1ff60f..d093b8669d86 100644
--- a/criu/util.c
+++ b/criu/util.c
@@ -515,6 +515,27 @@  int cr_system(int in, int out, int err, char *cmd, char *const argv[], unsigned
 	return cr_system_userns(in, out, err, cmd, argv, flags, -1);
 }
 
+static int cmp_keep_on_exec(const void *__a, const void *__b)
+{
+	int a = ((int *)__a)[0];
+	int b = ((int *)__b)[0];
+	return a == b ? 0 : (a < b ? -1 : 1);
+}
+
+static bool should_keep_on_exec(int fd)
+{
+	if (!opts.nr_keep_on_exec)
+		return false;
+
+	if (bsearch(&fd, opts.keep_on_exec,
+		    opts.nr_keep_on_exec,
+		    sizeof(opts.keep_on_exec[0]),
+		    cmp_keep_on_exec))
+	    return true;
+
+	return false;
+}
+
 static int close_fds(int minfd)
 {
 	DIR *dir;
@@ -541,6 +562,8 @@  static int close_fds(int minfd)
 			continue;
 		if (fd < minfd)
 			continue;
+		if (should_keep_on_exec(fd))
+			continue;
 		close(fd);
 	}
 	closedir(dir);