mirror of
https://github.com/checkpoint-restore/criu.git
synced 2026-07-17 16:47:50 +00:00
sk-queue: fix dumping queue packets
When we have several SCM_RIGHTS packets and at least one SCM_CREDENTIALS
sent simultaneousely into same unix socket we see that SCM_RIGHTS are
dumped wrong. It happens because before this patch SkPacketEntry had
been reused when dumping consequent packets, thus when dumping
SCM_RIGHTS for non-first packet it's pe.scm also contained SCM_RIGHTS
for previous packet.
To fix this let's not reuse SkPacketEntry. Also while on it let's split
dump_sk_queue_packet() - separate function for dumping one packet, to
add more readability to the code. Also drop meaningless "ret = -E2BIG"
and staff. Note that after this change pe.ucred is also not reused as it
probably should've always been.
Fixes: e4956b0b1 ("sk-queue: Add support of ucreds in unix sockets")
Signed-off-by: Pavel Tikhomirov <ptikhomirov@virtuozzo.com>
(cherry picked from commit 6832ccd499c1bef9bc220cdf42202c468fe5a37c)
Signed-off-by: Ahmed Elaidy <elaidya225@gmail.com>
Reviewed-by: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@futurfusion.io>
This commit is contained in:
parent
fdd6c8ccc9
commit
cf89a0b7d0
1 changed files with 81 additions and 83 deletions
164
criu/sk-queue.c
164
criu/sk-queue.c
|
|
@ -398,10 +398,81 @@ static int dump_packet_cmsg(struct msghdr *mh, SkPacketEntry *pe, int flags)
|
|||
return ret;
|
||||
}
|
||||
|
||||
int dump_sk_queue(int sock_fd, int sock_id, int flags)
|
||||
static int dump_sk_queue_packet(int sock_fd, int sock_id, void *data, int size, int flags)
|
||||
{
|
||||
SkPacketEntry pe = SK_PACKET_ENTRY__INIT;
|
||||
int ret, exit_code = -1;
|
||||
char cmsg[CMSG_MAX_SIZE];
|
||||
struct iovec iov = {
|
||||
.iov_base = data,
|
||||
.iov_len = size,
|
||||
};
|
||||
struct msghdr msg = {
|
||||
.msg_iov = &iov,
|
||||
.msg_iovlen = 1,
|
||||
.msg_control = &cmsg,
|
||||
.msg_controllen = sizeof(cmsg),
|
||||
};
|
||||
|
||||
pe.id_for = sock_id;
|
||||
|
||||
ret = pe.length = recvmsg(sock_fd, &msg, MSG_DONTWAIT | MSG_PEEK);
|
||||
if (!ret) {
|
||||
/*
|
||||
* It means, that peer has performed an
|
||||
* orderly shutdown, so we're done.
|
||||
*/
|
||||
return 1;
|
||||
} else if (ret < 0) {
|
||||
if (errno == EAGAIN)
|
||||
return 1;
|
||||
|
||||
pr_perror("recvmsg fail: error");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (msg.msg_flags & MSG_TRUNC) {
|
||||
/*
|
||||
* DGRAM truncated. This should not happen. But we have
|
||||
* to check...
|
||||
*/
|
||||
pr_err("recvmsg failed: truncated\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = dump_packet_cmsg(&msg, &pe, flags);
|
||||
if (ret < 0)
|
||||
goto cleanup_packet;
|
||||
|
||||
if (ret > 0) {
|
||||
if (ret == 1) {
|
||||
if (queue_packet_entry(&pe, data, pe.length))
|
||||
goto cleanup_packet;
|
||||
}
|
||||
exit_code = 0;
|
||||
goto cleanup_packet;
|
||||
}
|
||||
|
||||
ret = pb_write_one(img_from_set(glob_imgset, CR_FD_SK_QUEUES), &pe, PB_SK_QUEUES);
|
||||
if (ret < 0)
|
||||
goto cleanup_packet;
|
||||
|
||||
ret = write_img_buf(img_from_set(glob_imgset, CR_FD_SK_QUEUES), data, pe.length);
|
||||
if (ret < 0)
|
||||
goto cleanup_packet;
|
||||
|
||||
exit_code = 0;
|
||||
cleanup_packet:
|
||||
if (pe.scm)
|
||||
release_cmsg(&pe);
|
||||
xfree(pe.ucred);
|
||||
return exit_code;
|
||||
}
|
||||
|
||||
int dump_sk_queue(int sock_fd, int sock_id, int flags)
|
||||
{
|
||||
int ret, size, orig_peek_off;
|
||||
int exit_code = -1;
|
||||
void *data;
|
||||
socklen_t tmp;
|
||||
|
||||
|
|
@ -413,7 +484,7 @@ int dump_sk_queue(int sock_fd, int sock_id, int flags)
|
|||
ret = getsockopt(sock_fd, SOL_SOCKET, SO_PEEK_OFF, &orig_peek_off, &tmp);
|
||||
if (ret < 0) {
|
||||
pr_perror("getsockopt failed");
|
||||
return ret;
|
||||
return -1;
|
||||
}
|
||||
/*
|
||||
* Discover max DGRAM size
|
||||
|
|
@ -423,7 +494,7 @@ int dump_sk_queue(int sock_fd, int sock_id, int flags)
|
|||
ret = getsockopt(sock_fd, SOL_SOCKET, SO_SNDBUF, &size, &tmp);
|
||||
if (ret < 0) {
|
||||
pr_perror("getsockopt failed");
|
||||
return ret;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Note: 32 bytes will be used by kernel for protocol header. */
|
||||
|
|
@ -442,87 +513,17 @@ int dump_sk_queue(int sock_fd, int sock_id, int flags)
|
|||
ret = setsockopt(sock_fd, SOL_SOCKET, SO_PEEK_OFF, &ret, sizeof(int));
|
||||
if (ret < 0) {
|
||||
pr_perror("setsockopt fail");
|
||||
goto err_brk;
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
pe.id_for = sock_id;
|
||||
|
||||
while (1) {
|
||||
char cmsg[CMSG_MAX_SIZE];
|
||||
struct iovec iov = {
|
||||
.iov_base = data,
|
||||
.iov_len = size,
|
||||
};
|
||||
struct msghdr msg = {
|
||||
.msg_iov = &iov,
|
||||
.msg_iovlen = 1,
|
||||
.msg_control = &cmsg,
|
||||
.msg_controllen = sizeof(cmsg),
|
||||
};
|
||||
|
||||
ret = pe.length = recvmsg(sock_fd, &msg, MSG_DONTWAIT | MSG_PEEK);
|
||||
if (!ret)
|
||||
/*
|
||||
* It means, that peer has performed an
|
||||
* orderly shutdown, so we're done.
|
||||
*/
|
||||
ret = dump_sk_queue_packet(sock_fd, sock_id, data, size, flags);
|
||||
if (ret == 1)
|
||||
break;
|
||||
else if (ret < 0) {
|
||||
if (errno == EAGAIN)
|
||||
break; /* we're done */
|
||||
pr_perror("recvmsg fail: error");
|
||||
else if (ret == -1)
|
||||
goto err_set_sock;
|
||||
}
|
||||
if (msg.msg_flags & MSG_TRUNC) {
|
||||
/*
|
||||
* DGRAM truncated. This should not happen. But we have
|
||||
* to check...
|
||||
*/
|
||||
pr_err("sys_recvmsg failed: truncated\n");
|
||||
ret = -E2BIG;
|
||||
goto err_set_sock;
|
||||
}
|
||||
if (msg.msg_flags & MSG_CTRUNC) {
|
||||
/*
|
||||
* Control data truncated. This means the cmsg
|
||||
* buffer was too small and SCM data (such as
|
||||
* passed file descriptors) has been silently
|
||||
* discarded by the kernel.
|
||||
*/
|
||||
pr_err("sys_recvmsg failed: control data truncated\n");
|
||||
ret = -E2BIG;
|
||||
goto err_set_sock;
|
||||
}
|
||||
|
||||
ret = dump_packet_cmsg(&msg, &pe, flags);
|
||||
if (ret < 0)
|
||||
goto err_set_sock;
|
||||
|
||||
if (ret > 0) {
|
||||
if (ret == 1) {
|
||||
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;
|
||||
goto err_set_sock;
|
||||
}
|
||||
|
||||
ret = write_img_buf(img_from_set(glob_imgset, CR_FD_SK_QUEUES), data, pe.length);
|
||||
if (ret < 0) {
|
||||
ret = -EIO;
|
||||
goto err_set_sock;
|
||||
}
|
||||
|
||||
if (pe.scm)
|
||||
release_cmsg(&pe);
|
||||
}
|
||||
ret = 0;
|
||||
exit_code = 0;
|
||||
|
||||
err_set_sock:
|
||||
/*
|
||||
|
|
@ -532,12 +533,9 @@ err_set_sock:
|
|||
pr_perror("setsockopt failed on restore");
|
||||
ret = -1;
|
||||
}
|
||||
if (pe.scm)
|
||||
release_cmsg(&pe);
|
||||
err_brk:
|
||||
xfree(pe.ucred);
|
||||
err_free:
|
||||
xfree(data);
|
||||
return ret;
|
||||
return exit_code;
|
||||
}
|
||||
|
||||
static int send_one_pkt(int fd, struct sk_packet *pkt)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue