1
0
Fork 0
mirror of https://passt.top/passt synced 2025-05-21 00:35:34 +02:00

pasta, passt-repair: Support multiple events per read() in inotify handlers

The current code assumes that we'll get one event per read() on
inotify descriptors, but that's not the case, not from documentation,
and not from reports.

Add loops in the two inotify handlers we have, in pasta-specific code
and passt-repair, to go through all the events we receive.

Link: https://bugs.passt.top/show_bug.cgi?id=119
[dwg: Remove unnecessary buffer expansion, use strnlen instead of strlen
 to make Coverity happier]
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
[sbrivio: Add additional check on ev->name and ev->len in passt-repair]
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
This commit is contained in:
Stefano Brivio 2025-03-28 11:39:58 +11:00 committed by David Gibson
parent 37550961ea
commit d9a7f1b008
2 changed files with 38 additions and 14 deletions

View file

@ -111,14 +111,14 @@ int main(int argc, char **argv)
}
if ((sb.st_mode & S_IFMT) == S_IFDIR) {
char buf[sizeof(struct inotify_event) + NAME_MAX + 1];
char buf[sizeof(struct inotify_event) + NAME_MAX + 1]
__attribute__ ((aligned(__alignof__(struct inotify_event))));
const struct inotify_event *ev;
char path[PATH_MAX + 1];
bool found = false;
ssize_t n;
int fd;
ev = (struct inotify_event *)buf;
if ((fd = inotify_init1(IN_CLOEXEC)) < 0) {
fprintf(stderr, "inotify_init1: %i\n", errno);
_exit(1);
@ -130,6 +130,8 @@ int main(int argc, char **argv)
}
do {
char *p;
n = read(fd, buf, sizeof(buf));
if (n < 0) {
fprintf(stderr, "inotify read: %i", errno);
@ -138,11 +140,27 @@ int main(int argc, char **argv)
if (n < (ssize_t)sizeof(*ev)) {
fprintf(stderr, "Short inotify read: %zi", n);
_exit(1);
continue;
}
} while (ev->len < REPAIR_EXT_LEN ||
memcmp(ev->name + strlen(ev->name) - REPAIR_EXT_LEN,
REPAIR_EXT, REPAIR_EXT_LEN));
for (p = buf; p < buf + n; p += sizeof(*ev) + ev->len) {
ev = (const struct inotify_event *)p;
if (ev->len >= REPAIR_EXT_LEN &&
!memcmp(ev->name +
strnlen(ev->name, ev->len) -
REPAIR_EXT_LEN,
REPAIR_EXT, REPAIR_EXT_LEN)) {
found = true;
break;
}
}
} while (!found);
if (ev->len > NAME_MAX + 1 || ev->name[ev->len] != '\0') {
fprintf(stderr, "Invalid filename from inotify\n");
_exit(1);
}
snprintf(path, sizeof(path), "%s/%s", argv[1], ev->name);
if ((stat(path, &sb))) {

20
pasta.c
View file

@ -498,17 +498,23 @@ void pasta_netns_quit_init(const struct ctx *c)
*/
void pasta_netns_quit_inotify_handler(struct ctx *c, int inotify_fd)
{
char buf[sizeof(struct inotify_event) + NAME_MAX + 1];
const struct inotify_event *in_ev = (struct inotify_event *)buf;
char buf[sizeof(struct inotify_event) + NAME_MAX + 1]
__attribute__ ((aligned(__alignof__(struct inotify_event))));
const struct inotify_event *ev;
ssize_t n;
char *p;
if (read(inotify_fd, buf, sizeof(buf)) < (ssize_t)sizeof(*in_ev))
if ((n = read(inotify_fd, buf, sizeof(buf))) < (ssize_t)sizeof(*ev))
return;
if (strncmp(in_ev->name, c->netns_base, sizeof(c->netns_base)))
return;
for (p = buf; p < buf + n; p += sizeof(*ev) + ev->len) {
ev = (const struct inotify_event *)p;
info("Namespace %s is gone, exiting", c->netns_base);
_exit(EXIT_SUCCESS);
if (!strncmp(ev->name, c->netns_base, sizeof(c->netns_base))) {
info("Namespace %s is gone, exiting", c->netns_base);
_exit(EXIT_SUCCESS);
}
}
}
/**