From: Andrei Vagin <ava...@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 <ktk...@virtuozzo.com>
Signed-off-by: Andrei Vagin <ava...@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

_______________________________________________
Devel mailing list
Devel@openvz.org
https://lists.openvz.org/mailman/listinfo/devel

Reply via email to