lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Fri, 28 Jul 2017 13:40:25 +0200
From:   Andreas Grünbacher <andreas.gruenbacher@...il.com>
To:     Jan Kara <jack@...e.cz>
Cc:     Ted Tso <tytso@....edu>, linux-ext4@...r.kernel.org,
        Andreas Gruenbacher <agruenba@...hat.com>,
        stable@...r.kernel.org
Subject: Re: [PATCH] ext4: Fix SEEK_HOLE/SEEK_DATA for blocksize < pagesize

2017-07-28 13:16 GMT+02:00 Jan Kara <jack@...e.cz>:
> ext4_find_unwritten_pgoff() does not properly handle a situation when
> starting index is in the middle of a page and blocksize < pagesize. The
> following command shows the bug on filesystem with 1k blocksize:
>
>   xfs_io -f -c "falloc 0 4k" \
>             -c "pwrite 1k 1k" \
>             -c "pwrite 3k 1k" \
>             -c "seek -a -r 0" foo
>
> In this example, neither lseek(fd, 1024, SEEK_HOLE) nor lseek(fd, 2048,
> SEEK_DATA) will return the correct result.
>
> Fix the problem by neglecting buffers in a page before starting offset.

This looks correct as a minimal fix for 4.13. We can later switch to
page_cache_seek_hole_data which does the same thing as
ext4_find_unwritten_pgoff, or directly to iomap_seek_{hole,data}.

> Reported-by: Andreas Gruenbacher <agruenba@...hat.com>
> CC: stable@...r.kernel.org
> Signed-off-by: Jan Kara <jack@...e.cz>
> ---
>  fs/ext4/file.c | 3 +++
>  1 file changed, 3 insertions(+)
>
> This is an easy fix for the SEEK_HOLE/SEEK_DATA bug Andreas found. Longer
> term we want to move ext4 to use page_cache_seek_hole_data() however for
> stable backporting this is more suitable.
>
> diff --git a/fs/ext4/file.c b/fs/ext4/file.c
> index b221d0b546b0..8ba34cbe8fe7 100644
> --- a/fs/ext4/file.c
> +++ b/fs/ext4/file.c
> @@ -530,6 +530,8 @@ static int ext4_find_unwritten_pgoff(struct inode *inode,
>                                 lastoff = page_offset(page);
>                                 bh = head = page_buffers(page);
>                                 do {
> +                                       if (lastoff + bh->b_size <= startoff)
> +                                               goto next;
>                                         if (buffer_uptodate(bh) ||
>                                             buffer_unwritten(bh)) {
>                                                 if (whence == SEEK_DATA)
> @@ -544,6 +546,7 @@ static int ext4_find_unwritten_pgoff(struct inode *inode,
>                                                 unlock_page(page);
>                                                 goto out;
>                                         }
> +next:
>                                         lastoff += bh->b_size;
>                                         bh = bh->b_this_page;
>                                 } while (bh != head);
> --
> 2.12.3

Thanks,
Andreas

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ