From 3314ccfd985d9414e363c42d219260ec69a19e6a Mon Sep 17 00:00:00 2001 From: Alexander Mikhalitsyn Date: Mon, 2 Nov 2020 19:09:56 +0300 Subject: [PATCH] sk-queue: fix SCM restore in case when SCM_RIGHTS & SCM_CREDS in one packet If SkPacketEntry contains both SCM_CREDENTIALS and SCM_RIGHTS message then only SCM_RIGHTS will be put into socket queue. Reviewed-by: Pavel Tikhomirov Signed-off-by: Alexander Mikhalitsyn (cherry picked from commit 1aa1b1cb430e39271e7fbd44bd8609198a7f3a20) Signed-off-by: Ahmed Elaidy Reviewed-by: Alexander Mikhalitsyn --- criu/sk-queue.c | 48 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 41 insertions(+), 7 deletions(-) diff --git a/criu/sk-queue.c b/criu/sk-queue.c index b0f3b3c1c..191c9a034 100644 --- a/criu/sk-queue.c +++ b/criu/sk-queue.c @@ -545,17 +545,46 @@ static int send_one_pkt(int fd, struct sk_packet *pkt) int ret; SkPacketEntry *entry = pkt->entry; struct msghdr mh = {}; + size_t msg_controllen = 0; struct iovec iov; char cmsg[CMSG_MAX_SIZE]; + struct cmsghdr *ch = NULL; mh.msg_iov = &iov; mh.msg_iovlen = 1; iov.iov_base = pkt->data; iov.iov_len = entry->length; + /* + * We need to init msg_control, msg_controllen + * fields to make CMSG_*() helpers work correctly + * Later, just before sendmsg we have to set + * msg_controllen to actual summary length of SCMs. + */ + mh.msg_control = cmsg; + mh.msg_controllen = sizeof(cmsg); + memset(cmsg, 0, sizeof(cmsg)); + if (pkt->scm != NULL) { - mh.msg_controllen = pkt->scm_len; - mh.msg_control = pkt->scm; + ScmEntry *se; + struct cmsghdr *sch; + + BUG_ON(!entry->n_scm); + se = entry->scm[0]; + + ch = CMSG_FIRSTHDR(&mh); + BUG_ON(!ch); + + sch = (struct cmsghdr *)pkt->scm; + ch->cmsg_level = SOL_SOCKET; + ch->cmsg_type = SCM_RIGHTS; + + BUG_ON(msg_controllen + + CMSG_SPACE(se->n_rights * sizeof(int)) >= sizeof(cmsg)); + memcpy(CMSG_DATA(ch), CMSG_DATA(sch), se->n_rights * sizeof(int)); + + ch->cmsg_len = CMSG_LEN(se->n_rights * sizeof(int)); + msg_controllen += CMSG_SPACE(se->n_rights * sizeof(int)); } /* @@ -568,26 +597,31 @@ static int send_one_pkt(int fd, struct sk_packet *pkt) if (entry->ucred && entry->ucred->pid) { struct ucred *ucred; - struct cmsghdr *ch; - mh.msg_control = cmsg; - mh.msg_controllen = sizeof(cmsg); + ch = ch ? CMSG_NXTHDR(&mh, ch) : CMSG_FIRSTHDR(&mh); + BUG_ON(!ch); - ch = CMSG_FIRSTHDR(&mh); ch->cmsg_len = CMSG_LEN(sizeof(struct ucred)); ch->cmsg_level = SOL_SOCKET; ch->cmsg_type = SCM_CREDENTIALS; + + BUG_ON(msg_controllen + + CMSG_SPACE(sizeof(struct ucred)) >= sizeof(cmsg)); + ucred = (struct ucred *)CMSG_DATA(ch); ucred->pid = entry->ucred->pid; ucred->uid = entry->ucred->uid; ucred->gid = entry->ucred->gid; - mh.msg_controllen = CMSG_SPACE(sizeof(struct ucred)); + msg_controllen += CMSG_SPACE(sizeof(struct ucred)); pr_debug("\tsend creds pid %d uid %d gid %d\n", entry->ucred->pid, entry->ucred->uid, entry->ucred->gid); } + + mh.msg_controllen = msg_controllen; + ret = sendmsg(fd, &mh, 0); xfree(pkt->data); xfree(pkt->scm);