diff options
| author | Denis Vlasenko <vda.linux@googlemail.com> | 2008-11-14 21:34:13 +0000 |
|---|---|---|
| committer | Denis Vlasenko <vda.linux@googlemail.com> | 2008-11-14 21:34:13 +0000 |
| commit | b0e5d42d4f3245cb6d7511fc03a09adb82c09783 (patch) | |
| tree | c74f488e6adb2dc6b89610fbb0dbc52957a73bac /miscutils | |
| parent | 142c5cb2a2a7bdceeebec7a55759852bb7ada066 (diff) | |
| download | busybox-w32-b0e5d42d4f3245cb6d7511fc03a09adb82c09783.tar.gz busybox-w32-b0e5d42d4f3245cb6d7511fc03a09adb82c09783.tar.bz2 busybox-w32-b0e5d42d4f3245cb6d7511fc03a09adb82c09783.zip | |
inotify: fix buffer overflow and "unreaped zombies" problem
Diffstat (limited to 'miscutils')
| -rw-r--r-- | miscutils/inotifyd.c | 51 |
1 files changed, 29 insertions, 22 deletions
diff --git a/miscutils/inotifyd.c b/miscutils/inotifyd.c index 5ac47386a..0c4b06784 100644 --- a/miscutils/inotifyd.c +++ b/miscutils/inotifyd.c | |||
| @@ -51,6 +51,7 @@ extern int inotify_add_watch(int fd, const char *path, uint32_t mask); | |||
| 51 | int inotifyd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 51 | int inotifyd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
| 52 | int inotifyd_main(int argc UNUSED_PARAM, char **argv) | 52 | int inotifyd_main(int argc UNUSED_PARAM, char **argv) |
| 53 | { | 53 | { |
| 54 | int n; | ||
| 54 | unsigned mask = IN_ALL_EVENTS; // assume we want all events | 55 | unsigned mask = IN_ALL_EVENTS; // assume we want all events |
| 55 | struct pollfd pfd; | 56 | struct pollfd pfd; |
| 56 | char **watched = ++argv; // watched name list | 57 | char **watched = ++argv; // watched name list |
| @@ -69,7 +70,6 @@ int inotifyd_main(int argc UNUSED_PARAM, char **argv) | |||
| 69 | while (*++argv) { | 70 | while (*++argv) { |
| 70 | char *path = *argv; | 71 | char *path = *argv; |
| 71 | char *masks = strchr(path, ':'); | 72 | char *masks = strchr(path, ':'); |
| 72 | int wd; // watch descriptor | ||
| 73 | // if mask is specified -> | 73 | // if mask is specified -> |
| 74 | if (masks) { | 74 | if (masks) { |
| 75 | *masks = '\0'; // split path and mask | 75 | *masks = '\0'; // split path and mask |
| @@ -83,32 +83,39 @@ int inotifyd_main(int argc UNUSED_PARAM, char **argv) | |||
| 83 | } | 83 | } |
| 84 | } | 84 | } |
| 85 | // add watch | 85 | // add watch |
| 86 | wd = inotify_add_watch(pfd.fd, path, mask); | 86 | n = inotify_add_watch(pfd.fd, path, mask); |
| 87 | if (wd < 0) { | 87 | if (n < 0) |
| 88 | bb_perror_msg_and_die("add watch (%s) failed", path); | 88 | bb_perror_msg_and_die("add watch (%s) failed", path); |
| 89 | // } else { | 89 | //bb_error_msg("added %d [%s]:%4X", n, path, mask); |
| 90 | // bb_error_msg("added %d [%s]:%4X", wd, path, mask); | ||
| 91 | } | ||
| 92 | } | 90 | } |
| 93 | 91 | ||
| 94 | // setup signals | 92 | // setup signals |
| 95 | bb_signals(0 | 93 | bb_signals(BB_FATAL_SIGS, record_signo); |
| 96 | + (1 << SIGHUP) | ||
| 97 | + (1 << SIGINT) | ||
| 98 | + (1 << SIGTERM) | ||
| 99 | + (1 << SIGPIPE) | ||
| 100 | , record_signo); | ||
| 101 | 94 | ||
| 102 | // do watch | 95 | // do watch |
| 103 | |||
| 104 | // pfd.fd = fd; | ||
| 105 | pfd.events = POLLIN; | 96 | pfd.events = POLLIN; |
| 106 | 97 | while (1) { | |
| 107 | while (!bb_got_signal && poll(&pfd, 1, -1) > 0) { | ||
| 108 | ssize_t len; | 98 | ssize_t len; |
| 109 | void *buf; | 99 | void *buf; |
| 110 | struct inotify_event *ie; | 100 | struct inotify_event *ie; |
| 111 | 101 | ||
| 102 | again: | ||
| 103 | if (bb_got_signal) | ||
| 104 | break; | ||
| 105 | n = poll(&pfd, 1, -1); | ||
| 106 | /* Signal interrupted us? */ | ||
| 107 | if (n < 0 && errno == EINTR) | ||
| 108 | goto again; | ||
| 109 | // Under Linux, above if() is not necessary. | ||
| 110 | // Non-fatal signals, e.g. SIGCHLD, when set to SIG_DFL, | ||
| 111 | // are not interrupting poll(). | ||
| 112 | // Thus we can just break if n <= 0 (see below), | ||
| 113 | // because EINTR will happen only on SIGTERM et al. | ||
| 114 | // But this might be not true under other Unixes, | ||
| 115 | // and is generally way too subtle to depend on. | ||
| 116 | if (n <= 0) // strange error? | ||
| 117 | break; | ||
| 118 | |||
| 112 | // read out all pending events | 119 | // read out all pending events |
| 113 | xioctl(pfd.fd, FIONREAD, &len); | 120 | xioctl(pfd.fd, FIONREAD, &len); |
| 114 | #define eventbuf bb_common_bufsiz1 | 121 | #define eventbuf bb_common_bufsiz1 |
| @@ -117,21 +124,21 @@ int inotifyd_main(int argc UNUSED_PARAM, char **argv) | |||
| 117 | // process events. N.B. events may vary in length | 124 | // process events. N.B. events may vary in length |
| 118 | while (len > 0) { | 125 | while (len > 0) { |
| 119 | int i; | 126 | int i; |
| 120 | char events[12]; | 127 | char events[sizeof(mask_names)]; |
| 121 | char *s = events; | 128 | char *s = events; |
| 122 | unsigned m = ie->mask; | 129 | unsigned m = ie->mask; |
| 123 | 130 | ||
| 124 | for (i = 0; i < 12; ++i, m >>= 1) { | 131 | for (i = 0; i < sizeof(mask_names)-1; ++i, m >>= 1) { |
| 125 | if (m & 1) { | 132 | if (m & 1) |
| 126 | *s++ = mask_names[i]; | 133 | *s++ = mask_names[i]; |
| 127 | } | ||
| 128 | } | 134 | } |
| 129 | *s = '\0'; | 135 | *s = '\0'; |
| 130 | // bb_error_msg("exec %s %08X\t%s\t%s\t%s", agent, ie->mask, events, watched[ie->wd], ie->len ? ie->name : ""); | 136 | //bb_error_msg("exec %s %08X\t%s\t%s\t%s", agent, |
| 137 | // ie->mask, events, watched[ie->wd], ie->len ? ie->name : ""); | ||
| 131 | args[1] = events; | 138 | args[1] = events; |
| 132 | args[2] = watched[ie->wd]; | 139 | args[2] = watched[ie->wd]; |
| 133 | args[3] = ie->len ? ie->name : NULL; | 140 | args[3] = ie->len ? ie->name : NULL; |
| 134 | xspawn((char **)args); | 141 | wait4pid(xspawn((char **)args)); |
| 135 | // next event | 142 | // next event |
| 136 | i = sizeof(struct inotify_event) + ie->len; | 143 | i = sizeof(struct inotify_event) + ie->len; |
| 137 | len -= i; | 144 | len -= i; |
