[CRIU] [PATCH 2/4] sockets: Restore unconnected dgram sockets

Cyrill Gorcunov gorcunov at openvz.org
Sat Apr 14 04:13:22 EDT 2012


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

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

In particular this is needed for crond checkpoint/restore,
since it uses dgram socket to send messages to /dev/log.

Signed-off-by: Cyrill Gorcunov <gorcunov at openvz.org>
---
 crtools.c         |    8 +++++-
 include/crtools.h |    2 +
 sockets.c         |   64 +++++++++++++++++++++++++++++++++++++++++++++++-----
 3 files changed, 65 insertions(+), 9 deletions(-)

diff --git a/crtools.c b/crtools.c
index 9f6b415..dcee133 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[] = "dsrf:p:t:hcD:o:n:v";
 
 	BUILD_BUG_ON(PAGE_SIZE != PAGE_IMAGE_SIZE);
 
@@ -354,6 +354,9 @@ int main(int argc, char *argv[])
 		case 's':
 			opts.final_state = TASK_STOPPED;
 			break;
+		case 'r':
+			opts.resolve_peer_by_name = true;
+			break;
 		case 'p':
 			pid = atoi(optarg);
 			opts.leader_only = true;
@@ -478,6 +481,7 @@ usage:
 	pr_msg("  -s             leave tasks in stopped state after checkpoint instead of killing them\n");
 	pr_msg("  -n             checkpoint/restore namespaces - values must be separated by comma\n");
 	pr_msg("                 supported: uts, ipc\n");
+	pr_msg("  -r             resolve unconnected socket peer connection by name\n");
 
 	pr_msg("\nAdditional common parameters:\n");
 	pr_msg("  -D dir         specifis directory where checkpoint files are/to be located\n");
diff --git a/include/crtools.h b/include/crtools.h
index d79878f..764cfe1 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			resolve_peer_by_name;
 	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/sockets.c b/sockets.c
index 4428eae..09756e9 100644
--- a/sockets.c
+++ b/sockets.c
@@ -38,6 +38,8 @@ static char buf[4096];
 #define SOCKFS_MAGIC	0x534F434B
 #endif
 
+#define SOCK_STATE_INFO	255
+
 struct socket_desc {
 	unsigned int		family;
 	unsigned int		ino;
@@ -412,10 +414,32 @@ 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 %x with unreachable peer %x (%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;
+			}
+
+			struct unix_sk_entry pt = { };
+
+			/*
+			 * Socket is not connected back but have a name,
+			 * so at restore time we will find it here. Note
+			 * the id is set to impossible value by purpose.
+			 */
+
+			pt.id		= -1u;
+			pt.peer		= ue.id;
+			pt.type		= SOCK_DGRAM;
+			pt.state	= SOCK_STATE_INFO;
+			pt.namelen	= peer->namelen;
+
+			if (write_img(fdset_fd(glob_fdset, CR_FD_UNIXSK), &pt))
+				goto err;
+			if (write_img_buf(fdset_fd(glob_fdset, CR_FD_UNIXSK),
+					  peer->name, pt.namelen))
+				goto err;
 		}
 	} else if (ue.state == TCP_ESTABLISHED) {
 		const struct unix_sk_listen_icon *e;
@@ -814,6 +838,7 @@ struct unix_sk_info {
 #define USK_PAIR_SLAVE		0x2
 
 static LIST_HEAD(unix_sockets);
+static LIST_HEAD(unix_sockets_peer_names);
 
 static struct unix_sk_info *find_unix_sk(int id)
 {
@@ -825,6 +850,18 @@ static struct unix_sk_info *find_unix_sk(int id)
 	return NULL;
 }
 
+static struct unix_sk_info *find_peer_name_sk(int id)
+{
+	struct unix_sk_info *info;
+
+	list_for_each_entry(info, &unix_sockets_peer_names, list) {
+		if (info->ue.id == id)
+			return info;
+	}
+
+	return NULL;
+}
+
 struct sk_packet {
 	struct list_head list;
 	struct sk_packet_entry entry;
@@ -1076,6 +1113,8 @@ static inline char *skstate2s(u32 state)
 		return "closed";
 	else if (state == TCP_LISTEN)
 		return "listen";
+	else if (state == SOCK_STATE_INFO)
+		return "  info";
 	else
 		return unknown(state);
 }
@@ -1461,6 +1500,13 @@ int collect_unix_sockets(void)
 
 		ui->peer = NULL;
 		ui->flags = 0;
+
+		if (ui->ue.state == SOCK_STATE_INFO) {
+			pr_info(" `- Got peer name for %u\n", ui->ue.id);
+			list_add(&ui->list, &unix_sockets_peer_names);
+			continue;
+		}
+
 		pr_info(" `- Got %u peer %u\n", ui->ue.id, ui->ue.peer);
 		file_desc_add(&ui->d, FDINFO_UNIXSK, ui->ue.id,
 				&unix_desc_ops);
@@ -1485,9 +1531,13 @@ int resolve_unix_peers(void)
 
 		peer = find_unix_sk(ui->ue.peer);
 		if (!peer) {
-			pr_err("FATAL: Peer %x unresolved for %x\n",
-					ui->ue.peer, ui->ue.id);
-			return -1;
+			if (opts.resolve_peer_by_name)
+				peer = find_peer_name_sk(ui->ue.peer);
+			if (!peer) {
+				pr_err("FATAL: Peer %x unresolved for %x\n",
+				       ui->ue.peer, ui->ue.id);
+				return -1;
+			}
 		}
 
 		ui->peer = peer;
-- 
1.7.7.6



More information about the CRIU mailing list