[CRIU] Re: [PATCH 4/4] sockets: Restore unconnected dgram sockets v4

Cyrill Gorcunov gorcunov at openvz.org
Tue Apr 17 06:18:06 EDT 2012


On Mon, Apr 16, 2012 at 08:36:34PM +0400, Cyrill Gorcunov wrote:
> In case if dgram socket peer is not connected back
> we can try to resolve peer by name.
> 
> For security reason this happens only if '-x' option
> is passed at restore time.
> 
> In particular this is needed for programs which do
> use dgram socket to send messages to /dev/log.

Here is an updated version

 - '-x' option taken into account on both stages (checkpoint and restore)
 - fixed bind call on extern sockets

I've tested it in both way -- with our zdtm suite and crond/rsyslogd
(which requires inotify).

	Cyrill
-------------- next part --------------
>From 2b64a544bd0cd410a4f3fc8ee5fff28fed5ece1a Mon Sep 17 00:00:00 2001
From: Cyrill Gorcunov <gorcunov at openvz.org>
Date: Tue, 17 Apr 2012 14:15:16 +0400
Subject: [PATCH] sockets: Restore unconnected dgram sockets v5

In case if dgram socket peer is not connected back
we can try to resolve peer by name.

For security reason this happens only if '-x' option
is passed at checkpoint and restore time.

In particular this is needed for programs which do
use dgram socket to send messages to /dev/log.

Signed-off-by: Cyrill Gorcunov <gorcunov at openvz.org>
---
 cr-dump.c         |    6 +++
 crtools.c         |    9 ++++-
 include/crtools.h |    2 +
 include/image.h   |    3 ++
 include/sockets.h |    1 +
 sockets.c         |   90 +++++++++++++++++++++++++++++++++++++++++++++++++---
 6 files changed, 103 insertions(+), 8 deletions(-)

diff --git a/cr-dump.c b/cr-dump.c
index 8c83fe8..9efcccf 100644
--- a/cr-dump.c
+++ b/cr-dump.c
@@ -1918,6 +1918,12 @@ int cr_dump_tasks(pid_t pid, const struct cr_options *opts)
 	}
 
 	ret = cr_dump_shmem();
+	if (ret)
+		goto err;
+
+	ret = dump_external_sockets();
+	if (ret)
+		goto err;
 
 	fd_id_show_tree();
 err:
diff --git a/crtools.c b/crtools.c
index 0c4bd0e..0cddcaf 100644
--- a/crtools.c
+++ b/crtools.c
@@ -23,7 +23,7 @@
 #include "uts_ns.h"
 #include "ipc_ns.h"
 
-static struct cr_options opts;
+struct cr_options opts;
 
 /*
  * The cr fd set is the set of files where the information
@@ -336,7 +336,7 @@ int main(int argc, char *argv[])
 	int log_inited = 0;
 	int log_level = 0;
 
-	static const char short_opts[] = "dsf:p:t:hcD:o:n:v";
+	static const char short_opts[] = "dsf:p:t:hcD:o:n:vx";
 
 	BUILD_BUG_ON(PAGE_SIZE != PAGE_IMAGE_SIZE);
 
@@ -359,6 +359,7 @@ int main(int argc, char *argv[])
 			{ "images-dir", required_argument, 0, 'D' },
 			{ "log-file", required_argument, 0, 'o' },
 			{ "namespaces", required_argument, 0, 'n' },
+			{ "ext-unix-sk", no_argument, 0, 'x' },
 			{ "help", no_argument, 0, 'h' },
 			{ },
 		};
@@ -371,6 +372,9 @@ int main(int argc, char *argv[])
 		case 's':
 			opts.final_state = TASK_STOPPED;
 			break;
+		case 'x':
+			opts.ext_unix_sk = true;
+			break;
 		case 'p':
 			pid = atoi(optarg);
 			opts.leader_only = true;
@@ -495,6 +499,7 @@ usage:
 	pr_msg("  -s|--leave-stopped    leave tasks in stopped state after checkpoint instead of killing them\n");
 	pr_msg("  -n|--namespaces       checkpoint/restore namespaces - values must be separated by comma\n");
 	pr_msg("                        supported: uts, ipc\n");
+	pr_msg("  -x|--ext-unix-sk      allow external unix connections\n");
 
 	pr_msg("\nAdditional common parameters:\n");
 	pr_msg("  -D|--images-dir dir   specifis directory where checkpoint files are/to be located\n");
diff --git a/include/crtools.h b/include/crtools.h
index d79878f..c17436b 100644
--- a/include/crtools.h
+++ b/include/crtools.h
@@ -67,6 +67,7 @@ struct cr_options {
 	bool			leader_only;
 	bool			show_pages_content;
 	bool			restore_detach;
+	bool			ext_unix_sk;
 	unsigned int		namespaces_flags;
 };
 
@@ -160,6 +161,7 @@ static inline int fdset_fd(const struct cr_fdset *fdset, int type)
 }
 
 extern struct cr_fdset *glob_fdset;
+extern struct cr_options opts;
 
 int cr_dump_tasks(pid_t pid, const struct cr_options *opts);
 int cr_restore_tasks(pid_t pid, struct cr_options *opts);
diff --git a/include/image.h b/include/image.h
index 9609d4e..59184b9 100644
--- a/include/image.h
+++ b/include/image.h
@@ -143,6 +143,8 @@ struct pipe_data_entry {
  */
 #define PIPE_NONALIG_DATA (15 * PAGE_SIZE)
 
+#define USK_EXTERN	(1 << 0)
+
 struct unix_sk_entry {
 	u32	id;
 	u8	type;
@@ -150,6 +152,7 @@ struct unix_sk_entry {
 	u8	namelen; /* fits UNIX_PATH_MAX */
 	u8	pad;
 	u32	flags;
+	u32	uflags;  /* own service flags */
 	u32	backlog;
 	u32	peer;
 	fown_t	fown;
diff --git a/include/sockets.h b/include/sockets.h
index 2e9a915..9d78370 100644
--- a/include/sockets.h
+++ b/include/sockets.h
@@ -14,6 +14,7 @@ struct fdinfo_list_entry;
 struct file_desc;
 struct fdinfo_entry;
 extern int collect_sockets(void);
+extern int dump_external_sockets(void);
 extern int collect_inet_sockets(void);
 extern int collect_unix_sockets(void);
 extern int resolve_unix_peers(void);
diff --git a/sockets.c b/sockets.c
index 4418121..03ed7ab 100644
--- a/sockets.c
+++ b/sockets.c
@@ -43,6 +43,7 @@ struct socket_desc {
 	unsigned int		ino;
 	struct socket_desc	*next;
 	int			already_dumped;
+	bool			external;
 };
 
 struct unix_sk_desc {
@@ -397,6 +398,7 @@ static int dump_one_unix(const struct socket_desc *_sk, struct fd_parms *p,
 	ue.backlog	= sk->wqlen;
 	ue.peer		= sk->peer_ino;
 	ue.fown		= p->fown;
+	ue.uflags	= 0;
 
 	if (ue.peer) {
 		struct unix_sk_desc *peer;
@@ -412,10 +414,18 @@ static int dump_one_unix(const struct socket_desc *_sk, struct fd_parms *p,
 		 * Peer should have us as peer or have a name by which
 		 * we can access one.
 		 */
-		if (!peer->name && (peer->peer_ino != ue.id)) {
-			pr_err("Unix socket 0x%x with unreachable peer 0x%x (0x%x/%s)\n",
-					ue.id, ue.peer, peer->peer_ino, peer->name);
-			goto err;
+		if (peer->peer_ino != ue.id) {
+			if (!peer->name) {
+				pr_err("Unix socket %x with unreachable peer %x (%x/%s)\n",
+				       ue.id, ue.peer, peer->peer_ino, peer->name);
+				goto err;
+			}
+
+			/*
+			 * It can be external socket, so we defer dumping
+			 * until all sockets the program owns are processed.
+			 */
+			peer->sd.external = true;
 		}
 	} else if (ue.state == TCP_ESTABLISHED) {
 		const struct unix_sk_listen_icon *e;
@@ -733,6 +743,61 @@ err:
 	return -1;
 }
 
+int dump_external_sockets(void)
+{
+	struct socket_desc *head, *sd;
+	int i, ret = -1;
+
+	if (!opts.ext_unix_sk)
+		return 0;
+
+	pr_debug("Dumping external sockets\n");
+
+	for (i = 0; i < SK_HASH_SIZE; i++) {
+		head = sockets[i];
+		if (!head)
+			continue;
+
+		for (sd = head; sd; sd = sd->next) {
+			struct unix_sk_entry e = { };
+			struct unix_sk_desc *sk;
+
+			if (sd->already_dumped		||
+			    sd->external == false	||
+			    sd->family != AF_UNIX)
+				continue;
+
+			sk = container_of(sd, struct unix_sk_desc, sd);
+
+			if (sk->type != SOCK_DGRAM)
+				continue;
+
+			e.id		= sd->ino;
+			e.type		= SOCK_DGRAM;
+			e.state		= TCP_LISTEN;
+			e.namelen	= sk->namelen;
+			e.uflags	= USK_EXTERN;
+			e.peer		= -1u;
+
+			show_one_unix("Dumping extern", sk);
+
+			if (write_img(fdset_fd(glob_fdset, CR_FD_UNIXSK), &e))
+				goto err;
+			if (write_img_buf(fdset_fd(glob_fdset, CR_FD_UNIXSK),
+					  sk->name, e.namelen))
+				goto err;
+
+			show_one_unix_img("Dumped extern", &e);
+
+			sd->already_dumped = 1;
+		}
+	}
+
+	return 0;
+err:
+	return -1;
+}
+
 int collect_sockets(void)
 {
 	int err = 0, tmp;
@@ -1131,9 +1196,9 @@ void show_unixsk(int fd, struct cr_options *o)
 		if (ret <= 0)
 			goto out;
 
-		pr_msg("id 0x%8x type %s state %s namelen %4d backlog %4d peer 0x%8x flags 0x%2x",
+		pr_msg("id 0x%8x type %s state %s namelen %4d backlog %4d peer 0x%8x flags 0x%2x uflags 0x%2x",
 			ue.id, sktype2s(ue.type), skstate2s(ue.state),
-			ue.namelen, ue.backlog, ue.peer, ue.flags);
+			ue.namelen, ue.backlog, ue.peer, ue.flags, ue.uflags);
 
 		if (ue.namelen) {
 			BUG_ON(ue.namelen > sizeof(buf));
@@ -1370,6 +1435,16 @@ static int open_unixsk_standalone(struct unix_sk_info *ui)
 	if (restore_fown(sk, &ui->ue.fown))
 		return -1;
 
+	/*
+	 * No connect should be done over external peers,
+	 * simply bind only to them, and that's all.
+	 */
+	if (ui->peer && ui->peer->ue.uflags & USK_EXTERN) {
+		if (bind_unix_sk(sk, ui->peer))
+			return -1;
+		return sk;
+	}
+
 	if (bind_unix_sk(sk, ui))
 		return -1;
 
@@ -1483,6 +1558,9 @@ int resolve_unix_peers(void)
 		if (!ui->ue.peer)
 			continue;
 
+		if ((ui->ue.uflags & USK_EXTERN) && opts.ext_unix_sk)
+			continue;
+
 		peer = find_unix_sk(ui->ue.peer);
 		if (!peer) {
 			pr_err("FATAL: Peer 0x%x unresolved for 0x%x\n",
-- 
1.7.7.6



More information about the CRIU mailing list