From: Edward Adam Davis <eadavis@qq.com>
To: phillip@squashfs.org.uk
Cc: akpm@linux-foundation.org, eadavis@qq.com,
linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org,
squashfs-devel@lists.sourceforge.net,
syzbot+604424eb051c2f696163@syzkaller.appspotmail.com,
syzkaller-bugs@googlegroups.com
Subject: Re: [PATCH] squashfs: fix oob in squashfs_readahead
Date: Sat, 18 Nov 2023 10:12:24 +0800 [thread overview]
Message-ID: <tencent_C893AEDDAED20C8F27DD46FB92C9066E0906@qq.com> (raw)
In-Reply-To: <20231116151424.23597-1-phillip@squashfs.org.uk>
On Thu, 16 Nov 2023 15:14:24 +0000, Phillip Lougher wrote:
> > [Bug]
> > path_openat() called open_last_lookups() before calling do_open() and
> > open_last_lookups() will eventually call squashfs_read_inode() to set
> > inode->i_size, but before setting i_size, it is necessary to obtain file_size
> > from the disk.
> >
> > However, during the value retrieval process, the length of the value retrieved
> > from the disk was greater than output->length, resulting(-EIO) in the failure of
> > squashfs_read_data(), further leading to i_size has not been initialized,
> > i.e. its value is 0.
> >
>
> NACK
>
> This analysis is completely *wrong*. First, if there was I/O error reading
> the inode it would never be created, and squasfs_readahead() would
> never be called on it, because it will never exist.
>
> Second i_size isn't unintialised and it isn't 0 in value. Where
> you got this bogus information from is because in your test patches,
> i.e.
[There is my debuging patch]
diff --git a/fs/squashfs/block.c b/fs/squashfs/block.c
index 581ce9519339..1c7c5500206b 100644
--- a/fs/squashfs/block.c
+++ b/fs/squashfs/block.c
@@ -314,9 +314,11 @@ int squashfs_read_data(struct super_block *sb, u64 index, int length,
bio_uninit(bio);
kfree(bio);
+ printk("datal: %d \n", length);
compressed = SQUASHFS_COMPRESSED(length);
length = SQUASHFS_COMPRESSED_SIZE(length);
index += 2;
+ printk("datal2: %d, c:%d, i:%d \n", length, compressed, index);
TRACE("Block @ 0x%llx, %scompressed size %d\n", index - 2,
compressed ? "" : "un", length);
@@ -324,6 +326,7 @@ int squashfs_read_data(struct super_block *sb, u64 index, int length,
if (length < 0 || length > output->length ||
(index + length) > msblk->bytes_used) {
res = -EIO;
+ printk("srd: l:%d, ol: %d, bu: %d \n", length, output->length, msblk->bytes_used);
goto out;
}
patch link: https://syzkaller.appspot.com/text?tag=Patch&x=1142f82f680000
[There is my test log]
[ 457.030754][ T8879] datal: 65473
[ 457.034334][ T8879] datal2: 32705, c:0, i:1788
[ 457.039253][ T8879] srd: l:32705, ol: 8192, bu: 1870
[ 457.044513][ T8879] SQUASHFS error: Failed to read block 0x6fc: -5
[ 457.052034][ T8879] SQUASHFS error: Unable to read metadata cache entry [6fa]
log link: https://syzkaller.appspot.com/x/log.txt?x=137b0270e80000
[Answer your doubts]
Based on the above test, it can be clearly determined that length=32705 is
greater than the maximum metadata size of 8192, resulting in squashfs_read_data() failed.
This will further lead to squashfs_cache_get() returns "entry->error=entry->length=-EIO",
followed by squashfs_read_metadata() failed, which will ultimately result in i_size not
being initialized in squashfs_read_inode().
The following are the relevant call stacks:
23 const struct inode_operations squashfs_dir_inode_ops = {
24 .lookup = squashfs_lookup,
25 .listxattr = squashfs_listxattr
26 };
NORMAL +0 ~0 -0 fs/squashfs/namei.c
path_openat()->open_last_lookups()->lookup_open()
1 if (d_in_lookup(dentry)) {
3455 struct dentry *res = dir_inode->i_op->lookup(dir_inode, dentry, 1 nd->flags);
squashfs_lookup()->
squashfs_iget()->
squashfs_read_inode()->
init inode->i_size, example: inode->i_size = sqsh_ino->file_size;
>
> https://lore.kernel.org/all/000000000000bb74b9060a14717c@google.com/
>
> You have
>
> + if (!file_end) {
> + printk("i:%p, is:%d, %s\n", inode, i_size_read(inode), __func__);
> + res = -EINVAL;
> + goto out;
> + }
> +
>
> You have used %d, and the result of i_size_read(inode) overflows, giving the
> bogus 0 value.
>
> The actual value is 1407374883553280, or 0x5000000000000, which is
> too big to fit into an unsigned int.
>
> > This resulted in the failure of squashfs_read_data(), where "SQUASHFS error:
> > Failed to read block 0x6fc: -5" was output in the syz log.
> > This also resulted in the failure of squashfs_cache_get(), outputting "SQUASHFS
> > error: Unable to read metadata cache entry [6fa]" in the syz log.
> >
>
> NO, *that* is caused by the failure to read some other inodes which
> as a result are correctly not created. Nothing to do with the oops here.
>
> > [Fix]
> > Before performing a read ahead operation in squashfs_read_folio() and
> > squashfs_readahead(), check if i_size is not 0 before continuing.
> >
>
> A third NO, it is only 0 because the variable overflowed.
>
> Additionally, let's look at your "fix" here.
>
> > @@ -461,6 +461,11 @@ static int squashfs_read_folio(struct file *file, struct folio *folio)
> > TRACE("Entered squashfs_readpage, page index %lx, start block %llx\n",
> > page->index, squashfs_i(inode)->start);
> >
> > + if (!file_end) {
> > + res = -EINVAL;
> > + goto out;
> > + }
> > +
>
> file_end is computed by
>
> int file_end = i_size_read(inode) >> msblk->block_log;
>
> So your "fix" will reject *any* file less than msblk->block_log in
> size as invalid, including perfectly valid zero size files (empty
> files are valid too).
edward
next prev parent reply other threads:[~2023-11-18 2:12 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-11-12 5:32 [syzbot] [squashfs?] KASAN: slab-out-of-bounds Write in squashfs_readahead (2) syzbot
2023-11-13 15:27 ` Phillip Lougher
2023-11-15 4:05 ` [PATCH] squashfs: fix oob in squashfs_readahead Edward Adam Davis
2023-11-15 22:39 ` Andrew Morton
2023-11-16 15:14 ` Phillip Lougher
2023-11-18 2:12 ` Edward Adam Davis [this message]
[not found] ` <CGME20231117131718eucas1p13328b32942cce99a99197eb28e14a981@eucas1p1.samsung.com>
2023-11-17 13:17 ` Marek Szyprowski
2023-11-17 15:48 ` Andrew Morton
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=tencent_C893AEDDAED20C8F27DD46FB92C9066E0906@qq.com \
--to=eadavis@qq.com \
--cc=akpm@linux-foundation.org \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=phillip@squashfs.org.uk \
--cc=squashfs-devel@lists.sourceforge.net \
--cc=syzbot+604424eb051c2f696163@syzkaller.appspotmail.com \
--cc=syzkaller-bugs@googlegroups.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).