Subject: Re: bug#49209: coreutils: stack out-of-bounds write in tail --follow

From: Pádraig Brady <[email-masked]>
Date: Thu, 24 Jun 2021 15:50:25 +0100

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