1
0
Fork 0
mirror of https://passt.top/passt synced 2025-06-09 17:15:34 +02:00

epoll: Always use epoll_ref for the epoll data variable

epoll_ref contains a variety of information useful when handling epoll
events on our sockets, and we place it in the epoll_event data field
returned by epoll.  However, for a few other things we use the 'fd' field
in the standard union of types for that data field.

This actually introduces a bug which is vanishingly unlikely to hit in
practice, but very nasty if it ever did: theoretically if we had a very
large file descriptor number for fd_tap or fd_tap_listen it could overflow
into bits that overlap with the 'proto' field in epoll_ref.  With some
very bad luck this could mean that we mistakenly think an event on a
regular socket is an event on fd_tap or fd_tap_listen.

More practically, using different (but overlapping) fields of the
epoll_data means we can't unify dispatch for the various different objects
in the epoll.  Therefore use the same epoll_ref as the data for the tap
fds and the netns quit fd, adding new fd type values to describe them.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
This commit is contained in:
David Gibson 2023-08-11 15:12:22 +10:00 committed by Stefano Brivio
parent 3401644453
commit 6a6735ece4
4 changed files with 29 additions and 12 deletions

11
passt.c
View file

@ -60,6 +60,8 @@ char *epoll_type_str[EPOLL_TYPE_MAX + 1] = {
[EPOLL_TYPE_UDP] = "UDP socket",
[EPOLL_TYPE_ICMP] = "ICMP socket",
[EPOLL_TYPE_ICMPV6] = "ICMPv6 socket",
[EPOLL_TYPE_NSQUIT] = "namespace inotify",
[EPOLL_TYPE_TAP] = "tap device",
};
/**
@ -328,12 +330,11 @@ loop:
for (i = 0; i < nfds; i++) {
union epoll_ref ref = *((union epoll_ref *)&events[i].data.u64);
int fd = events[i].data.fd;
if (fd == c.fd_tap || fd == c.fd_tap_listen)
tap_handler(&c, fd, events[i].events, &now);
else if (fd == quit_fd)
pasta_netns_quit_handler(&c, fd);
if (ref.type == EPOLL_TYPE_TAP)
tap_handler(&c, ref.fd, events[i].events, &now);
else if (ref.type == EPOLL_TYPE_NSQUIT)
pasta_netns_quit_handler(&c, quit_fd);
else
sock_handler(&c, ref, events[i].events, &now);
}