[Devel,1/2] netlink: dump and restore ucred-s for netlink messages

Submitted by Andrei Vagin on Feb. 14, 2017, 5:59 a.m.

Details

Message ID 1487051961-9422-1-git-send-email-avagin@openvz.org
State New
Series "Series without cover letter"
Headers show

Commit Message

Andrei Vagin Feb. 14, 2017, 5:59 a.m.
From: Andrei Vagin <avagin@virtuozzo.com>

ucred in a netlink message contains the same pid and
it doesn't metter from which pidns it is read.

https://jira.sw.ru/browse/PSBM-59339

Cc: Kirill Tkhai <ktkhai@virtuozzo.com>
Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
---
 criu/include/sk-queue.h |  5 ++-
 criu/sk-netlink.c       |  2 +-
 criu/sk-queue.c         | 82 ++++++++++++++++++++++++++++++++++++++++++++++---
 criu/sk-unix.c          |  2 +-
 images/sk-packet.proto  |  7 +++++
 5 files changed, 91 insertions(+), 7 deletions(-)

Patch hide | download patch | download mbox

diff --git a/criu/include/sk-queue.h b/criu/include/sk-queue.h
index 295a227..d03eb95 100644
--- a/criu/include/sk-queue.h
+++ b/criu/include/sk-queue.h
@@ -2,7 +2,10 @@ 
 #define __CR_SK_QUEUE_H__
 
 extern struct collect_image_info sk_queues_cinfo;
-extern int dump_sk_queue(int sock_fd, int sock_id, bool dump_addr);
+
+#define SK_QUEUE_REAL_PID	0x1 /* scm creds contains a real pid */
+#define SK_QUEUE_DUMP_ADDR	0x2 /* save a sender address for messages */
+extern int dump_sk_queue(int sock_fd, int sock_id, int flags);
 extern int restore_sk_queue(int fd, unsigned int peer_id);
 
 #endif /* __CR_SK_QUEUE_H__ */
diff --git a/criu/sk-netlink.c b/criu/sk-netlink.c
index 4b8ed72..89a5d9c 100644
--- a/criu/sk-netlink.c
+++ b/criu/sk-netlink.c
@@ -178,7 +178,7 @@  static int dump_one_netlink_fd(int lfd, u32 id, const struct fd_parms *p)
 	if (dump_socket_opts(lfd, &skopts))
 		goto err;
 
-	if (kdat.has_nl_repair && dump_sk_queue(lfd, id, true))
+	if (kdat.has_nl_repair && dump_sk_queue(lfd, id, SK_QUEUE_DUMP_ADDR))
 		goto err;
 
 	if (pb_write_one(img_from_set(glob_imgset, CR_FD_NETLINK_SK), &ne, PB_NETLINK_SK))
diff --git a/criu/sk-queue.c b/criu/sk-queue.c
index e4ecf80..be33ca1 100644
--- a/criu/sk-queue.c
+++ b/criu/sk-queue.c
@@ -19,6 +19,9 @@ 
 #include "util.h"
 #include "util-pie.h"
 #include "sockets.h"
+#include "namespaces.h"
+#include "pstree.h"
+#include "util.h"
 
 #include "sk-queue.h"
 
@@ -65,11 +68,63 @@  struct collect_image_info sk_queues_cinfo = {
  * */
 #define CMSG_MAX_SIZE	1024
 
-static int dump_packet_cmsg(struct msghdr *mh, SkPacketEntry *pe)
+static int dump_sk_creds(struct ucred *ucred, SkPacketEntry *pe, int flags)
+{
+	SkUcredEntry *ent;
+
+	ent = xmalloc(sizeof(*ent));
+	if (!ent)
+		return -1;
+
+	sk_ucred_entry__init(ent);
+	ent->uid = userns_uid(ucred->uid);
+	ent->gid = userns_gid(ucred->gid);
+	if (flags & SK_QUEUE_REAL_PID) {
+		/*
+		 * It is impossible to conver pid from real to virt,
+		 * because virt pid-s are known for dumped task only
+		 */
+		pr_err("ucred-s for unix sockets aren't supported yet");
+		return -1;
+	} else {
+		int pidns = root_ns_mask & CLONE_NEWPID;
+		char path[64];
+		int ret;
+
+		/* Does a process exist? */
+		if (pidns) {
+			snprintf(path, sizeof(path), "%d", ucred->pid);
+			ret = faccessat(get_service_fd(CR_PROC_FD_OFF),
+							path, R_OK, 0);
+		} else {
+			snprintf(path, sizeof(path), "/proc/%d", ucred->pid);
+			ret = access(path, R_OK);
+		}
+		if (ret) {
+			pr_err("Unable to dump ucred for a dead process %d\n", ucred->pid);
+			return -1;
+		}
+		ent->pid = ucred->pid;
+	}
+	pe->ucred = ent;
+
+	return 0;
+}
+
+static int dump_packet_cmsg(struct msghdr *mh, SkPacketEntry *pe, int flags)
 {
 	struct cmsghdr *ch;
 
 	for (ch = CMSG_FIRSTHDR(mh); ch; ch = CMSG_NXTHDR(mh, ch)) {
+		if (ch->cmsg_len == CMSG_LEN(sizeof(struct ucred)) &&
+		    ch->cmsg_type == SCM_CREDENTIALS &&
+		    ch->cmsg_level == SOL_SOCKET) {
+			struct ucred *ucred = CMSG_DATA(ch); 
+
+			if (dump_sk_creds(ucred, pe, flags))
+				return -1;
+			continue;
+		}
 		pr_err("Control messages in queue, not supported\n");
 		return -1;
 	}
@@ -77,7 +132,7 @@  static int dump_packet_cmsg(struct msghdr *mh, SkPacketEntry *pe)
 	return 0;
 }
 
-int dump_sk_queue(int sock_fd, int sock_id, bool dump_addr)
+int dump_sk_queue(int sock_fd, int sock_id, int flags)
 {
 	SkPacketEntry pe = SK_PACKET_ENTRY__INIT;
 	int ret, size, orig_peek_off;
@@ -140,7 +195,7 @@  int dump_sk_queue(int sock_fd, int sock_id, bool dump_addr)
 			.msg_controllen	= sizeof(cmsg),
 		};
 
-		if (dump_addr) {
+		if (flags & SK_QUEUE_DUMP_ADDR) {
 			msg.msg_name	= addr;
 			msg.msg_namelen	= _K_SS_MAXSIZE;
 		}
@@ -168,7 +223,7 @@  int dump_sk_queue(int sock_fd, int sock_id, bool dump_addr)
 			goto err_set_sock;
 		}
 
-		if (dump_packet_cmsg(&msg, &pe))
+		if (dump_packet_cmsg(&msg, &pe, flags))
 			goto err_set_sock;
 
 		if (msg.msg_namelen) {
@@ -229,6 +284,7 @@  int restore_sk_queue(int fd, unsigned int peer_id)
 			.msg_iov	= &iov,
 			.msg_iovlen	= 1,
 		};
+		char cmsg[1024];
 
 		if (entry->id_for != peer_id)
 			continue;
@@ -264,6 +320,24 @@  int restore_sk_queue(int fd, unsigned int peer_id)
 			goto err;
 		}
 
+		if (entry->ucred) {
+			struct ucred *ucred;
+			struct cmsghdr *ch;
+
+			msg.msg_control = cmsg;
+			msg.msg_controllen = sizeof(cmsg);
+			
+			ch = CMSG_FIRSTHDR(&msg);
+			ch->cmsg_len = CMSG_LEN(sizeof(struct ucred));
+			ch->cmsg_level = SOL_SOCKET;
+			ch->cmsg_type = SCM_CREDENTIALS;
+			ucred = (struct ucred *) CMSG_DATA(ch);
+			ucred->pid = entry->ucred->pid;
+			ucred->uid = entry->ucred->uid;
+			ucred->gid = entry->ucred->gid;
+			msg.msg_controllen = CMSG_SPACE(sizeof(struct ucred));
+		}
+
 		ret = sendmsg(fd, &msg, 0);
 		xfree(buf);
 		if (ret < 0) {
diff --git a/criu/sk-unix.c b/criu/sk-unix.c
index edd9d0b..0cf10b0 100644
--- a/criu/sk-unix.c
+++ b/criu/sk-unix.c
@@ -464,7 +464,7 @@  dump:
 	 */
 	if (sk->rqlen != 0 && !(sk->type == SOCK_STREAM &&
 				sk->state == TCP_LISTEN))
-		if (dump_sk_queue(lfd, id, false))
+		if (dump_sk_queue(lfd, id, SK_QUEUE_REAL_PID))
 			goto err;
 
 	pr_info("Dumping unix socket at %d\n", p->fd);
diff --git a/images/sk-packet.proto b/images/sk-packet.proto
index 59c0e79..4bfc774 100644
--- a/images/sk-packet.proto
+++ b/images/sk-packet.proto
@@ -1,7 +1,14 @@ 
 syntax = "proto2";
 
+message sk_ucred_entry {
+	required uint32		uid		= 1;
+	required uint32		gid		= 2;
+	required uint32		pid		= 3;
+}
+
 message sk_packet_entry {
 	required uint32		id_for		= 1;
 	required uint32		length		= 2;
 	optional bytes		addr		= 3;
+	optional sk_ucred_entry	ucred		= 128;
 }