[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: Are there still machines with PAGE_SHIFT 16 or larger ?



Hi,

Anatoly Pugachev wrote:
> mator@chubaka:~$ md5sum /tmp/half_sparse /mnt/iso/half_sparse
> 3e98c342558c453b379cf7699f98a108  /tmp/half_sparse
> Segmentation fault

Hah ! The obvious bug about all-zero blocks has bitten.
I would not have expected a memory fault, though. Rather some false
output and maybe an i/o error at the end.


> mator@chubaka:~$ md5sum /tmp/full_random /mnt/iso/full_random
> 9014e927951d25e01aa89858ebb82ce6  /tmp/full_random
> 9014e927951d25e01aa89858ebb82ce6  /mnt/iso/full_random

I don't understand how this can work. If i am not totally mistaken,
the code omits a pair of zlib_inflateEnd zlib_inflateInit when
decompressing 2 consequtive zisofs blocks as one.
If page size is <= 32 KiB, the code does for the two zisofs blocks:
  zlib_inflateInit zlib_inflate ... zlib_inflate zlib_inflateEnd
  zlib_inflateInit zlib_inflate ... zlib_inflate zlib_inflateEnd
But with 64 KiB the same data get processed by a single:
  zlib_inflateInit zlib_inflate ... zlib_inflate zlib_inflateEnd

Either zlib tolerates this by design or my assessment of this case in the
code is wrong. (I prepare myself for more embarrassment ...)


At least i have the triumph of the zero block bug.
But i should better try to understand why it leads to a memory error.

> Nov 12 19:28:50 chubaka kernel: NIP [c0000000000ad4b0] .memset+0x68/0x104
> [...] .zisofs_readpage+0x470/0xd90 [isofs] (unreliable)
> [...] .read_pages+0x2f8/0x390
> [...] .page_cache_readahead_unbounded+0x224/0x2f0
> [...] .generic_file_buffered_read+0x704/0xcf0
> [...] .new_sync_read+0x13c/0x1e0
> [...] .vfs_read+0x1a0/0x210

There are two occasions of memset() underneath zisofs_readpage().
One of them, in zisofs_fill_pages(), already cought my attention because
it plays with a potentially invalid memory pointer.

                ret = zisofs_uncompress_block(inode, block_start, block_end,
                                              pcount, pages, poffset, &err);
                poffset += ret;
                pages += poffset >> PAGE_SHIFT;
                ...
                poffset &= ~PAGE_MASK;

ret is supposed to be 65366. PAGE_SHIFT is 16. PAGE_MASK is 65365.
So "pages" gets altered.
Later comes:

        if (poffset && *pages) {
                memset(page_address(*pages) + poffset, 0,
                       PAGE_SIZE - poffset);
                flush_dcache_page(*pages);
                SetPageUptodate(*pages);
        }

I could not imagine how poffset would be non-0 here. But if it is, and if
the "pages" array has only one member, then memset() is the first to read
the bytes after the kmalloc'ed "pages" and to perform a write operation
to a location that depends on their value.

Now the question is how poffset became unaligned to 64 KiB.
The best chance for that is at the very end of the file.

Does dd, after umount and mount, yield bytes before the memory fault
happens ? If so, how many.


Have a nice day :)

Thomas


Reply to: