[Devel] [PATCH 1/2] netlink: dump and restore ucred-s for netlink messages
Andrey Vagin
avagin at openvz.org
Mon Feb 13 21:59:20 PST 2017
From: Andrei Vagin <avagin at 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 at virtuozzo.com>
Signed-off-by: Andrei Vagin <avagin at 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(-)
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;
}
--
1.8.3.1
More information about the Devel
mailing list