inotify: fix buffer overflow and "unreaped zombies" problem
No binary (build failed)
—
(log yok)
| @@ -51,6 +51,7 @@ extern int inotify_add_watch(int fd, const char *path, uint32_t mask); | |
| int inotifyd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | |
| int inotifyd_main(int argc UNUSED_PARAM, char **argv) | |
| { | |
| + | int n; |
| unsigned mask = IN_ALL_EVENTS; // assume we want all events | |
| struct pollfd pfd; | |
| char **watched = ++argv; // watched name list | |
| @@ -69,7 +70,6 @@ int inotifyd_main(int argc UNUSED_PARAM, char **argv) | |
| while (*++argv) { | |
| char *path = *argv; | |
| char *masks = strchr(path, ':'); | |
| - | int wd; // watch descriptor |
| // if mask is specified -> | |
| if (masks) { | |
| *masks = '\0'; // split path and mask | |
| @@ -83,32 +83,39 @@ int inotifyd_main(int argc UNUSED_PARAM, char **argv) | |
| } | |
| } | |
| // add watch | |
| - | wd = inotify_add_watch(pfd.fd, path, mask); |
| - | if (wd < 0) { |
| + | n = inotify_add_watch(pfd.fd, path, mask); |
| + | if (n < 0) |
| bb_perror_msg_and_die("add watch (%s) failed", path); | |
| - | // } else { |
| - | // bb_error_msg("added %d [%s]:%4X", wd, path, mask); |
| - | } |
| + | //bb_error_msg("added %d [%s]:%4X", n, path, mask); |
| } | |
| // setup signals | |
| - | bb_signals(0 |
| - | + (1 << SIGHUP) |
| - | + (1 << SIGINT) |
| - | + (1 << SIGTERM) |
| - | + (1 << SIGPIPE) |
| - | , record_signo); |
| + | bb_signals(BB_FATAL_SIGS, record_signo); |
| // do watch | |
| - | |
| - | // pfd.fd = fd; |
| pfd.events = POLLIN; | |
| - | |
| - | while (!bb_got_signal && poll(&pfd, 1, -1) > 0) { |
| + | while (1) { |
| ssize_t len; | |
| void *buf; | |
| struct inotify_event *ie; | |
| + | again: |
| + | if (bb_got_signal) |
| + | break; |
| + | n = poll(&pfd, 1, -1); |
| + | /* Signal interrupted us? */ |
| + | if (n < 0 && errno == EINTR) |
| + | goto again; |
| + | // Under Linux, above if() is not necessary. |
| + | // Non-fatal signals, e.g. SIGCHLD, when set to SIG_DFL, |
| + | // are not interrupting poll(). |
| + | // Thus we can just break if n <= 0 (see below), |
| + | // because EINTR will happen only on SIGTERM et al. |
| + | // But this might be not true under other Unixes, |
| + | // and is generally way too subtle to depend on. |
| + | if (n <= 0) // strange error? |
| + | break; |
| + | |
| // read out all pending events | |
| xioctl(pfd.fd, FIONREAD, &len); | |
| #define eventbuf bb_common_bufsiz1 | |
| @@ -117,21 +124,21 @@ int inotifyd_main(int argc UNUSED_PARAM, char **argv) | |
| // process events. N.B. events may vary in length | |
| while (len > 0) { | |
| int i; | |
| - | char events[12]; |
| + | char events[sizeof(mask_names)]; |
| char *s = events; | |
| unsigned m = ie->mask; | |
| - | for (i = 0; i < 12; ++i, m >>= 1) { |
| - | if (m & 1) { |
| + | for (i = 0; i < sizeof(mask_names)-1; ++i, m >>= 1) { |
| + | if (m & 1) |
| *s++ = mask_names[i]; | |
| - | } |
| } | |
| *s = '\0'; | |
| - | // bb_error_msg("exec %s %08X\t%s\t%s\t%s", agent, ie->mask, events, watched[ie->wd], ie->len ? ie->name : ""); |
| + | //bb_error_msg("exec %s %08X\t%s\t%s\t%s", agent, |
| + | // ie->mask, events, watched[ie->wd], ie->len ? ie->name : ""); |
| args[1] = events; | |
| args[2] = watched[ie->wd]; | |
| args[3] = ie->len ? ie->name : NULL; | |
| - | xspawn((char **)args); |
| + | wait4pid(xspawn((char **)args)); |
| // next event | |
| i = sizeof(struct inotify_event) + ie->len; | |
| len -= i; | |