On 24/06/2021 15:26, Kamil Dudka wrote:
Hello,

As originally reported by Stepan Broz (CC'd), tail --follow crashes when it
is given too many files to follow, and ulimit -n is set to >1024.

FD_SET(wd, &rfd) in tail_forever_inotify() writes beyond the stack-allocated
variable in case wd >= FD_SETSIZE.  Minimal example:

# mkdir dir
# cd dir
# touch {1..1021}
# ulimit -n 1025
# tail -f *

The out-of-bound write could be fixed like this:

--- a/src/tail.c
+++ b/src/tail.c
@@ -1647,28 +1647,32 @@ tail_forever_inotify (int wd, struct File_spec *f,
size_t n_files,
                if (writer_is_dead)
                  exit (EXIT_SUCCESS);

                writer_is_dead = (kill (pid, 0) != 0 && errno != EPERM);

                if (writer_is_dead)
                  delay.tv_sec = delay.tv_usec = 0;
                else
                  {
                    delay.tv_sec = (time_t) sleep_interval;
                    delay.tv_usec = 1000000 * (sleep_interval - delay.tv_sec);
                  }
              }

+           if (FD_SETSIZE <= wd)
+             die (EXIT_FAILURE, 0,
+                  _("too many open files to wait for inotify events"));
+
             fd_set rfd;
             FD_ZERO (&rfd);
             FD_SET (wd, &rfd);
             if (monitor_output)
               FD_SET (STDOUT_FILENO, &rfd);

             int file_change = select (MAX (wd, STDOUT_FILENO) + 1,
                                       &rfd, NULL, NULL, pid ? &delay: NULL);

             if (file_change == 0)
               continue;
             else if (file_change == -1)
               die (EXIT_FAILURE, errno,
                    _("error waiting for inotify and output events"));


Alternatively, we might rewrite the code to use poll() rather than select().

Note the number of descriptors select() is waiting on in independent of the 
number of files.
We should be able to inotify_init() earlier in the process to avoid this issue.
I'll have a look.

thanks!
Pádraig



Reply via email to