• Linus Torvalds's avatar
    splice: teach splice pipe reading about empty pipe buffers · d1a819a2
    Linus Torvalds authored
    Tetsuo Handa reports that splice() can return 0 before the real EOF, if
    the data in the splice source pipe is an empty pipe buffer.  That empty
    pipe buffer case doesn't happen in any normal situation, but you can
    trigger it by doing a write to a pipe that fails due to a page fault.
    
    Tetsuo has a test-case to show the behavior:
    
      #define _GNU_SOURCE
      #include <sys/types.h>
      #include <sys/stat.h>
      #include <fcntl.h>
      #include <unistd.h>
    
      int main(int argc, char *argv[])
      {
    	const int fd = open("/tmp/testfile", O_WRONLY | O_CREAT, 0600);
    	int pipe_fd[2] = { -1, -1 };
    	pipe(pipe_fd);
    	write(pipe_fd[1], NULL, 4096);
    	/* This splice() should wait unless interrupted. */
    	return !splice(pipe_fd[0], NULL, fd, NULL, 65536, 0);
      }
    
    which results in
    
        write(5, NULL, 4096)                    = -1 EFAULT (Bad address)
        splice(4, NULL, 3, NULL, 65536, 0)      = 0
    
    and this can confuse splice() users into believing they have hit EOF
    prematurely.
    
    The issue was introduced when the pipe write code started pre-allocating
    the pipe buffers before copying data from user space.
    
    This is modified verion of Tetsuo's original patch.
    
    Fixes: a194dfe6 ("pipe: Rearrange sequence in pipe_write() to preallocate slot")
    Link:https://lore.kernel.org/linux-fsdevel/20201005121339.4063-1-penguin-kernel@I-love.SAKURA.ne.jp/Reported-by: default avatarTetsuo Handa <penguin-kernel@i-love.sakura.ne.jp>
    Acked-by: default avatarTetsuo Handa <penguin-kernel@i-love.sakura.ne.jp>
    Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
    d1a819a2
splice.c 41 KB