mirror of
https://github.com/checkpoint-restore/criu.git
synced 2026-07-17 16:47:50 +00:00
sk-queue: Add support of ucreds in unix sockets
Checkpoint and restore ucreds on unix sockets are not that trivial: the @pid returned by the kernel upon message fetching is mapped to current user namespace so it is not the same as it would be received inside container. So we need to map real pid returned into virtual seen from inside, but we know virtual pids only when complete process tree is built. Thus what we do -- queue such packets into own queue and when process tree is build walk over and transform former pids into virtual ones. Signed-off-by: Cyrill Gorcunov <gorcunov@virtuozzo.com> (cherry picked from commit 8f3061c360381894a97edca2ada85466f95e1d88) Signed-off-by: Ahmed Elaidy <elaidya225@gmail.com> Reviewed-by: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@futurfusion.io>
This commit is contained in:
parent
eee7477515
commit
dd11b13aab
3 changed files with 132 additions and 10 deletions
|
|
@ -55,6 +55,7 @@
|
|||
#include "tty.h"
|
||||
#include "net.h"
|
||||
#include "sk-packet.h"
|
||||
#include "sk-queue.h"
|
||||
#include "cpu.h"
|
||||
#include "elf.h"
|
||||
#include "cgroup.h"
|
||||
|
|
@ -2313,6 +2314,9 @@ int cr_dump_tasks(pid_t pid)
|
|||
if (tty_post_actions())
|
||||
goto err;
|
||||
|
||||
if (sk_queue_post_actions())
|
||||
goto err;
|
||||
|
||||
if (inventory_save_uptime(&he))
|
||||
goto err;
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ extern struct collect_image_info sk_queues_cinfo;
|
|||
|
||||
#define SK_QUEUE_REAL_PID 0x1 /* scm creds contains a real pid */
|
||||
extern int dump_sk_queue(int sock_fd, int sock_id, int flags);
|
||||
extern int sk_queue_post_actions(void);
|
||||
extern int restore_sk_queue(int fd, unsigned int peer_id);
|
||||
|
||||
#endif /* __CR_SK_QUEUE_H__ */
|
||||
|
|
|
|||
137
criu/sk-queue.c
137
criu/sk-queue.c
|
|
@ -33,7 +33,10 @@
|
|||
struct sk_packet {
|
||||
struct list_head list;
|
||||
SkPacketEntry *entry;
|
||||
char *data;
|
||||
union {
|
||||
char *data;
|
||||
size_t data_off;
|
||||
};
|
||||
unsigned scm_len;
|
||||
int *scm;
|
||||
};
|
||||
|
|
@ -136,6 +139,103 @@ static int dump_scm_rights(struct cmsghdr *ch, SkPacketEntry *pe)
|
|||
*/
|
||||
#define CMSG_MAX_SIZE 2048
|
||||
|
||||
int sk_queue_post_actions(void)
|
||||
{
|
||||
struct sk_packet *pkt, *t;
|
||||
struct cr_img *img;
|
||||
int ret = 0;
|
||||
|
||||
img = img_from_set(glob_imgset, CR_FD_SK_QUEUES);
|
||||
|
||||
list_for_each_entry_safe(pkt, t, &packets_list, list) {
|
||||
if (!pkt->entry->ucred) {
|
||||
pr_err("ucred: corruption on id_for %x\n",
|
||||
pkt->entry->id_for);
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
if (!ret) {
|
||||
struct pstree_item *item, *found = NULL;
|
||||
SkUcredEntry *ue = pkt->entry->ucred;
|
||||
|
||||
for_each_pstree_item(item) {
|
||||
if (item->pid->real == ue->pid) {
|
||||
found = item;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
pr_err("ucred: Can't lookup process with pid %d\n",
|
||||
ue->pid);
|
||||
ret = -ENOENT;
|
||||
goto next;
|
||||
} else {
|
||||
pr_debug("ucred: Fixup ucred pids %d -> %d\n",
|
||||
ue->pid, vpid(item));
|
||||
ue->pid = vpid(item);
|
||||
}
|
||||
|
||||
ret = pb_write_one(img, pkt->entry, PB_SK_QUEUES);
|
||||
if (ret < 0) {
|
||||
ret = -EIO;
|
||||
goto next;
|
||||
}
|
||||
|
||||
ret = write_img_buf(img, (char *)pkt + pkt->data_off, pkt->entry->length);
|
||||
if (ret < 0) {
|
||||
ret = -EIO;
|
||||
goto next;
|
||||
}
|
||||
}
|
||||
|
||||
next:
|
||||
list_del(&pkt->list);
|
||||
xfree(pkt);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int queue_packet_entry(SkPacketEntry *entry, void *data, size_t len)
|
||||
{
|
||||
struct sk_packet *pkt;
|
||||
size_t sum = 0;
|
||||
|
||||
sum += sizeof(*pkt);
|
||||
sum += sizeof(*pkt->entry);
|
||||
sum += sizeof(*pkt->entry->ucred);
|
||||
sum += len;
|
||||
|
||||
pkt = xmalloc(sum);
|
||||
|
||||
if (pkt) {
|
||||
SkPacketEntry *pe = (void *)pkt + sizeof(*pkt);
|
||||
SkUcredEntry *ue = (void *)pe + sizeof(*pe);
|
||||
void *p = (void *)ue + sizeof(*ue);
|
||||
|
||||
sk_packet_entry__init(pe);
|
||||
sk_ucred_entry__init(ue);
|
||||
|
||||
pkt->entry = pe;
|
||||
pkt->data_off = p - (void *)pkt;
|
||||
list_add_tail(&pkt->list, &packets_list);
|
||||
|
||||
pe->id_for = entry->id_for;
|
||||
pe->length = entry->length;
|
||||
pe->ucred = ue;
|
||||
ue->uid = entry->ucred->uid;
|
||||
ue->gid = entry->ucred->gid;
|
||||
ue->pid = entry->ucred->pid;
|
||||
|
||||
memcpy(p, data, len);
|
||||
pr_debug("ucred: Queued ucred packet id_for %x\n",
|
||||
pkt->entry->id_for);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static int dump_sk_creds(struct ucred *ucred, SkPacketEntry *pe, int flags)
|
||||
{
|
||||
SkUcredEntry *ent;
|
||||
|
|
@ -147,13 +247,22 @@ static int dump_sk_creds(struct ucred *ucred, SkPacketEntry *pe, int flags)
|
|||
sk_ucred_entry__init(ent);
|
||||
ent->uid = userns_uid(ucred->uid);
|
||||
ent->gid = userns_gid(ucred->gid);
|
||||
ent->pid = ucred->pid;
|
||||
|
||||
if (pe->ucred)
|
||||
pr_warn("ucred: ucred already assigned\n");
|
||||
pe->ucred = ent;
|
||||
|
||||
if (flags & SK_QUEUE_REAL_PID) {
|
||||
/*
|
||||
* It is impossible to convert pid from real to virt,
|
||||
* because virt pid-s are known for dumped task only
|
||||
* because virt pid-s are known for dumped task only.
|
||||
* Thus defer the image writing, we will do it at the
|
||||
* end, where all processes are collected already.
|
||||
*/
|
||||
pr_err("ucred-s for unix sockets aren't supported yet\n");
|
||||
goto out;
|
||||
pr_debug("ucred: Detected ucreds on id_for %x (uid %d gid %d pid %d)\n",
|
||||
pe->id_for, ent->uid, ent->gid, ent->pid);
|
||||
return 1;
|
||||
} else {
|
||||
int pidns = root_ns_mask & CLONE_NEWPID;
|
||||
char path[64];
|
||||
|
|
@ -173,13 +282,11 @@ static int dump_sk_creds(struct ucred *ucred, SkPacketEntry *pe, int flags)
|
|||
pr_err("Unable to dump ucred for a dead process %d\n", ucred->pid);
|
||||
goto out;
|
||||
}
|
||||
ent->pid = ucred->pid;
|
||||
}
|
||||
|
||||
pe->ucred = ent;
|
||||
|
||||
return 0;
|
||||
out:
|
||||
pe->ucred = NULL;
|
||||
xfree(ent);
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -188,6 +295,7 @@ static int dump_packet_cmsg(struct msghdr *mh, SkPacketEntry *pe, int flags)
|
|||
{
|
||||
struct cmsghdr *ch;
|
||||
int n_rights = 0;
|
||||
int ret = 0;
|
||||
|
||||
for (ch = CMSG_FIRSTHDR(mh); ch; ch = CMSG_NXTHDR(mh, ch)) {
|
||||
if (ch->cmsg_type == SCM_RIGHTS) {
|
||||
|
|
@ -212,7 +320,8 @@ static int dump_packet_cmsg(struct msghdr *mh, SkPacketEntry *pe, int flags)
|
|||
ch->cmsg_type == SCM_CREDENTIALS) {
|
||||
struct ucred *ucred = (struct ucred *)CMSG_DATA(ch);
|
||||
|
||||
if (dump_sk_creds(ucred, pe, flags))
|
||||
ret |= dump_sk_creds(ucred, pe, flags);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
continue;
|
||||
} else if (ch->cmsg_type == SCM_TIMESTAMP ||
|
||||
|
|
@ -231,7 +340,7 @@ static int dump_packet_cmsg(struct msghdr *mh, SkPacketEntry *pe, int flags)
|
|||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void release_cmsg(SkPacketEntry *pe)
|
||||
|
|
@ -342,9 +451,17 @@ int dump_sk_queue(int sock_fd, int sock_id, int flags)
|
|||
goto err_set_sock;
|
||||
}
|
||||
|
||||
if (dump_packet_cmsg(&msg, &pe, flags))
|
||||
ret = dump_packet_cmsg(&msg, &pe, flags);
|
||||
if (ret < 0)
|
||||
goto err_set_sock;
|
||||
|
||||
if (ret > 0) {
|
||||
ret = -1;
|
||||
if (queue_packet_entry(&pe, data, pe.length))
|
||||
goto err_set_sock;
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = pb_write_one(img_from_set(glob_imgset, CR_FD_SK_QUEUES), &pe, PB_SK_QUEUES);
|
||||
if (ret < 0) {
|
||||
ret = -EIO;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue