aboutgitcodebugslistschat
diff options
context:
space:
mode:
authorStefano Brivio <sbrivio@redhat.com>2025-03-28 11:39:58 +1100
committerStefano Brivio <sbrivio@redhat.com>2025-03-28 13:24:44 +0100
commit42a854a52b6fa2bbd70cbc0c7657c8a49a9c3d2d (patch)
tree2d721c7b64f2267a07c522410ba3891dfe445692
parent65cca54be84ffc5d2e18fcb8229dcc9d1f229479 (diff)
downloadpasst-42a854a52b6fa2bbd70cbc0c7657c8a49a9c3d2d.tar
passt-42a854a52b6fa2bbd70cbc0c7657c8a49a9c3d2d.tar.gz
passt-42a854a52b6fa2bbd70cbc0c7657c8a49a9c3d2d.tar.bz2
passt-42a854a52b6fa2bbd70cbc0c7657c8a49a9c3d2d.tar.lz
passt-42a854a52b6fa2bbd70cbc0c7657c8a49a9c3d2d.tar.xz
passt-42a854a52b6fa2bbd70cbc0c7657c8a49a9c3d2d.tar.zst
passt-42a854a52b6fa2bbd70cbc0c7657c8a49a9c3d2d.zip
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>
-rw-r--r--passt-repair.c32
-rw-r--r--pasta.c20
2 files changed, 38 insertions, 14 deletions
diff --git a/passt-repair.c b/passt-repair.c
index 120f7aa..86f0293 100644
--- a/passt-repair.c
+++ b/passt-repair.c
@@ -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;
+ }
+
+ 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 (ev->len < REPAIR_EXT_LEN ||
- memcmp(ev->name + strlen(ev->name) - REPAIR_EXT_LEN,
- REPAIR_EXT, REPAIR_EXT_LEN));
+ } 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))) {
diff --git a/pasta.c b/pasta.c
index fa3e7de..017fa32 100644
--- a/pasta.c
+++ b/pasta.c
@@ -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);
+ }
+ }
}
/**