From 624758e9ac4f12ca979791ec997cac55a8626d1c Mon Sep 17 00:00:00 2001 From: Alexander Mikhalitsyn Date: Wed, 8 Jul 2026 22:31:01 +0300 Subject: [PATCH] sk-queue: fix lost ScmEntries during SkPacketEntry copy When unix socket contains SCM with SCM_CREDENTIALS cmsg_type we have to postpone saving this packet to CR_FD_SK_QUEUES image because we need to have information about process which creds was transfered in this message. But if this SkPacketEntry already contains data from SCM_RIGHTS messages (file descriptors was transfered through unix socket) we will lose this data because of incorrect queue_packet_entry function implementation. This problem tends to inconsistent CRIU dump and on restore we will get: Error (criu/files.c:230): Empty list on file desc id 13(5) Error (criu/files.c:232): BUG at criu/files.c:232 Reviewed-by: Pavel Tikhomirov Signed-off-by: Alexander Mikhalitsyn (cherry picked from commit e6a9ce32ad14d18ff3160e5339e4582885d740fe) Signed-off-by: Ahmed Elaidy Reviewed-by: Alexander Mikhalitsyn --- criu/sk-queue.c | 105 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 74 insertions(+), 31 deletions(-) diff --git a/criu/sk-queue.c b/criu/sk-queue.c index 27049d5a4..b0f3b3c1c 100644 --- a/criu/sk-queue.c +++ b/criu/sk-queue.c @@ -124,6 +124,18 @@ static int dump_scm_rights(struct cmsghdr *ch, SkPacketEntry *pe) return 0; } +static void release_cmsg(SkPacketEntry *pe) +{ + int i; + + for (i = 0; i < pe->n_scm; i++) + xfree(pe->scm[i]); + xfree(pe->scm); + + pe->n_scm = 0; + pe->scm = NULL; +} + /* * Maximum size of the control messages. XXX -- is there any * way to get this value out of the kernel? @@ -190,6 +202,8 @@ int sk_queue_post_actions(void) next: list_del(&pkt->list); + if (pkt->entry) + release_cmsg(pkt->entry); xfree(pkt); } return ret; @@ -197,8 +211,12 @@ next: static int queue_packet_entry(SkPacketEntry *entry, void *data, size_t len) { + SkPacketEntry *pe; + SkUcredEntry *ue; + void *p; struct sk_packet *pkt; size_t sum = 0; + int i, j; sum += sizeof(*pkt); sum += sizeof(*pkt->entry); @@ -206,32 +224,69 @@ static int queue_packet_entry(SkPacketEntry *entry, void *data, size_t len) sum += len; pkt = xmalloc(sum); + if (!pkt) + return -ENOMEM; - if (pkt) { - SkPacketEntry *pe = (void *)pkt + sizeof(*pkt); - SkUcredEntry *ue = (void *)pe + sizeof(*pe); - void *p = (void *)ue + sizeof(*ue); + pe = (void *)pkt + sizeof(*pkt); + ue = (void *)pe + sizeof(*pe); + p = (void *)ue + sizeof(*ue); - sk_packet_entry__init(pe); - sk_ucred_entry__init(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); + pkt->entry = pe; + pkt->data_off = p - (void *)pkt; - 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; + 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; + pe->n_scm = entry->n_scm; + + pe->scm = xmalloc(pe->n_scm * sizeof(ScmEntry *)); + if (!pe->scm) { + xfree(pkt); + return -1; } + for (i = 0; i < entry->n_scm; i++) { + void *buf; + ScmEntry *scme; + + buf = xmalloc(sizeof(ScmEntry) + entry->scm[i]->n_rights * sizeof(uint32_t)); + if (!buf) + goto err_free; + + scme = xptr_pull(&buf, ScmEntry); + scm_entry__init(scme); + scme->type = entry->scm[i]->type; + scme->n_rights = entry->scm[i]->n_rights; + scme->rights = xptr_pull_s(&buf, scme->n_rights * sizeof(uint32_t)); + + for (j = 0; j < scme->n_rights; j++) + scme->rights[j] = entry->scm[i]->rights[j]; + + pe->scm[i] = scme; + } + + + memcpy(p, data, len); + pr_debug("ucred: Queued ucred packet id_for %x\n", + pkt->entry->id_for); + + list_add_tail(&pkt->list, &packets_list); + + return 0; + +err_free: + for (j = 0; j < i; j++) + xfree(pe->scm[j]); + xfree(pe->scm); + xfree(pkt); + return -ENOMEM; } @@ -343,18 +398,6 @@ static int dump_packet_cmsg(struct msghdr *mh, SkPacketEntry *pe, int flags) return ret; } -static void release_cmsg(SkPacketEntry *pe) -{ - int i; - - for (i = 0; i < pe->n_scm; i++) - xfree(pe->scm[i]); - xfree(pe->scm); - - pe->n_scm = 0; - pe->scm = NULL; -} - int dump_sk_queue(int sock_fd, int sock_id, int flags) { SkPacketEntry pe = SK_PACKET_ENTRY__INIT;