* Re: [syzbot] [serial?] INFO: task hung in vcs_open (8)
[not found] <66f59678.050a0220.46d20.0001.GAE@google.com>
@ 2024-09-28 3:53 ` Ryusuke Konishi
2024-10-04 3:35 ` [PATCH] nilfs2: propagate directory read errors from nilfs_find_entry() Ryusuke Konishi
1 sibling, 0 replies; 2+ messages in thread
From: Ryusuke Konishi @ 2024-09-28 3:53 UTC (permalink / raw)
To: syzbot; +Cc: Lizhi Xu, linux-nilfs, linux-kernel, syzkaller-bugs, linux-serial
On Fri, Sep 27, 2024 at 2:36 AM syzbot
<syzbot+8a192e8d090fa9a31135@syzkaller.appspotmail.com> wrote:
>
> Hello,
>
> syzbot found the following issue on:
>
> HEAD commit: 88264981f208 Merge tag 'sched_ext-for-6.12' of git://git.k..
> git tree: upstream
> console+strace: https://syzkaller.appspot.com/x/log.txt?x=1187c19f980000
> kernel config: https://syzkaller.appspot.com/x/.config?x=74ffdb3b3fad1a43
> dashboard link: https://syzkaller.appspot.com/bug?extid=8a192e8d090fa9a31135
> compiler: Debian clang version 15.0.6, GNU ld (GNU Binutils for Debian) 2.40
> syz repro: https://syzkaller.appspot.com/x/repro.syz?x=16aa3ca9980000
> C reproducer: https://syzkaller.appspot.com/x/repro.c?x=1587c19f980000
>
> Downloadable assets:
> disk image: https://storage.googleapis.com/syzbot-assets/87eaf0ad6d60/disk-88264981.raw.xz
> vmlinux: https://storage.googleapis.com/syzbot-assets/30c01cf8bc82/vmlinux-88264981.xz
> kernel image: https://storage.googleapis.com/syzbot-assets/a1407424ea54/bzImage-88264981.xz
> mounted in repro: https://storage.googleapis.com/syzbot-assets/a8a56914d1d8/mount_6.gz
>
> Bisection is inconclusive: the issue happens on the oldest tested release.
>
> bisection log: https://syzkaller.appspot.com/x/bisect.txt?x=16154c80580000
> final oops: https://syzkaller.appspot.com/x/report.txt?x=15154c80580000
> console output: https://syzkaller.appspot.com/x/log.txt?x=11154c80580000
>
> IMPORTANT: if you fix the issue, please add the following tag to the commit:
> Reported-by: syzbot+8a192e8d090fa9a31135@syzkaller.appspotmail.com
>
> INFO: task syz-executor199:5270 blocked for more than 147 seconds.
> Not tainted 6.11.0-syzkaller-08481-g88264981f208 #0
> "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
> task:syz-executor199 state:D stack:27360 pid:5270 tgid:5255 ppid:5233 flags:0x00004006
> Call Trace:
> <TASK>
> context_switch kernel/sched/core.c:5315 [inline]
> __schedule+0x1843/0x4ae0 kernel/sched/core.c:6674
> __schedule_loop kernel/sched/core.c:6751 [inline]
> schedule+0x14b/0x320 kernel/sched/core.c:6766
> schedule_timeout+0xb0/0x310 kernel/time/timer.c:2591
> ___down_common kernel/locking/semaphore.c:225 [inline]
> __down_common+0x346/0x7f0 kernel/locking/semaphore.c:246
> down+0x84/0xc0 kernel/locking/semaphore.c:63
> console_lock+0x145/0x1b0 kernel/printk/printk.c:2808
> vcs_open+0x5d/0xd0 drivers/tty/vt/vc_screen.c:763
> chrdev_open+0x521/0x600 fs/char_dev.c:414
> do_dentry_open+0x978/0x1460 fs/open.c:958
> vfs_open+0x3e/0x330 fs/open.c:1088
> do_open fs/namei.c:3774 [inline]
> path_openat+0x2c84/0x3590 fs/namei.c:3933
> do_filp_open+0x235/0x490 fs/namei.c:3960
>
>
> ---
> This report is generated by a bot. It may contain errors.
> See https://goo.gl/tpsmEJ for more information about syzbot.
> syzbot engineers can be reached at syzkaller@googlegroups.com.
>
> syzbot will keep track of this issue. See:
> https://goo.gl/tpsmEJ#status for how to communicate with syzbot.
> For information about bisection process see: https://goo.gl/tpsmEJ#bisection
>
> If the report is already addressed, let syzbot know by replying with:
> #syz fix: exact-commit-title
>
> If you want syzbot to run the reproducer, reply with:
> #syz test: git://repo/address.git branch-or-commit-hash
> If you attach or paste a git patch, syzbot will apply it before testing.
>
> If you want to overwrite report's subsystems, reply with:
> #syz set subsystems: new-subsystem
> (See the list of subsystem names on the web dashboard)
>
> If the report is a duplicate of another one, reply with:
> #syz dup: exact-subject-of-another-report
>
> If you want to undo deduplication, reply with:
> #syz undup
>
The problem caused by this reproducer seems to be an issue on the
nilfs side based on testing with Lizhi's patch (not all logs recorded
are like that), so I will add a nilfs tag:
#syz set subsystems: nilfs, serial
Ryusuke Konishi
^ permalink raw reply [flat|nested] 2+ messages in thread
* [PATCH] nilfs2: propagate directory read errors from nilfs_find_entry()
[not found] <66f59678.050a0220.46d20.0001.GAE@google.com>
2024-09-28 3:53 ` [syzbot] [serial?] INFO: task hung in vcs_open (8) Ryusuke Konishi
@ 2024-10-04 3:35 ` Ryusuke Konishi
1 sibling, 0 replies; 2+ messages in thread
From: Ryusuke Konishi @ 2024-10-04 3:35 UTC (permalink / raw)
To: Andrew Morton; +Cc: linux-nilfs, syzbot, syzkaller-bugs, LKML, Lizhi Xu
Syzbot reported that a task hang occurs in vcs_open() during a fuzzing
test for nilfs2.
The root cause of this problem is that in nilfs_find_entry(), which
searches for directory entries, ignores errors when loading a
directory page/folio via nilfs_get_folio() fails.
If the filesystem images is corrupted, and the i_size of the directory
inode is large, and the directory page/folio is successfully read but
fails the sanity check, for example when it is zero-filled,
nilfs_check_folio() may continue to spit out error messages in bursts.
Fix this issue by propagating the error to the callers when loading a
page/folio fails in nilfs_find_entry().
The current interface of nilfs_find_entry() and its callers is
outdated and cannot propagate error codes such as -EIO and -ENOMEM
returned via nilfs_find_entry(), so fix it together.
Signed-off-by: Ryusuke Konishi <konishi.ryusuke@gmail.com>
Reported-by: Lizhi Xu <lizhi.xu@windriver.com>
Closes: https://lkml.kernel.org/r/20240927013806.3577931-1-lizhi.xu@windriver.com
Reported-by: syzbot+8a192e8d090fa9a31135@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=8a192e8d090fa9a31135
Fixes: 2ba466d74ed7 ("nilfs2: directory entry operations")
Cc: stable@vger.kernel.org
---
Hi Andrew, please apply this as a bug fix.
This fixes a flaw in nilfs2's directory lookup error handling that was
the root cause of the vcs hang issue recently reported by syzbot.
Thanks,
Ryusuke Konishi
fs/nilfs2/dir.c | 48 ++++++++++++++++++++++++-----------------------
fs/nilfs2/namei.c | 39 +++++++++++++++++++++++++-------------
fs/nilfs2/nilfs.h | 2 +-
3 files changed, 52 insertions(+), 37 deletions(-)
diff --git a/fs/nilfs2/dir.c b/fs/nilfs2/dir.c
index fe5b1a30c509..a8602729586a 100644
--- a/fs/nilfs2/dir.c
+++ b/fs/nilfs2/dir.c
@@ -289,7 +289,7 @@ static int nilfs_readdir(struct file *file, struct dir_context *ctx)
* The folio is mapped and unlocked. When the caller is finished with
* the entry, it should call folio_release_kmap().
*
- * On failure, returns NULL and the caller should ignore foliop.
+ * On failure, returns an error pointer and the caller should ignore foliop.
*/
struct nilfs_dir_entry *nilfs_find_entry(struct inode *dir,
const struct qstr *qstr, struct folio **foliop)
@@ -312,22 +312,24 @@ struct nilfs_dir_entry *nilfs_find_entry(struct inode *dir,
do {
char *kaddr = nilfs_get_folio(dir, n, foliop);
- if (!IS_ERR(kaddr)) {
- de = (struct nilfs_dir_entry *)kaddr;
- kaddr += nilfs_last_byte(dir, n) - reclen;
- while ((char *) de <= kaddr) {
- if (de->rec_len == 0) {
- nilfs_error(dir->i_sb,
- "zero-length directory entry");
- folio_release_kmap(*foliop, kaddr);
- goto out;
- }
- if (nilfs_match(namelen, name, de))
- goto found;
- de = nilfs_next_entry(de);
+ if (IS_ERR(kaddr))
+ return ERR_CAST(kaddr);
+
+ de = (struct nilfs_dir_entry *)kaddr;
+ kaddr += nilfs_last_byte(dir, n) - reclen;
+ while ((char *)de <= kaddr) {
+ if (de->rec_len == 0) {
+ nilfs_error(dir->i_sb,
+ "zero-length directory entry");
+ folio_release_kmap(*foliop, kaddr);
+ goto out;
}
- folio_release_kmap(*foliop, kaddr);
+ if (nilfs_match(namelen, name, de))
+ goto found;
+ de = nilfs_next_entry(de);
}
+ folio_release_kmap(*foliop, kaddr);
+
if (++n >= npages)
n = 0;
/* next folio is past the blocks we've got */
@@ -340,7 +342,7 @@ struct nilfs_dir_entry *nilfs_find_entry(struct inode *dir,
}
} while (n != start);
out:
- return NULL;
+ return ERR_PTR(-ENOENT);
found:
ei->i_dir_start_lookup = n;
@@ -384,18 +386,18 @@ struct nilfs_dir_entry *nilfs_dotdot(struct inode *dir, struct folio **foliop)
return NULL;
}
-ino_t nilfs_inode_by_name(struct inode *dir, const struct qstr *qstr)
+int nilfs_inode_by_name(struct inode *dir, const struct qstr *qstr, ino_t *ino)
{
- ino_t res = 0;
struct nilfs_dir_entry *de;
struct folio *folio;
de = nilfs_find_entry(dir, qstr, &folio);
- if (de) {
- res = le64_to_cpu(de->inode);
- folio_release_kmap(folio, de);
- }
- return res;
+ if (IS_ERR(de))
+ return PTR_ERR(de);
+
+ *ino = le64_to_cpu(de->inode);
+ folio_release_kmap(folio, de);
+ return 0;
}
void nilfs_set_link(struct inode *dir, struct nilfs_dir_entry *de,
diff --git a/fs/nilfs2/namei.c b/fs/nilfs2/namei.c
index c950139db6ef..4905063790c5 100644
--- a/fs/nilfs2/namei.c
+++ b/fs/nilfs2/namei.c
@@ -55,12 +55,20 @@ nilfs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
{
struct inode *inode;
ino_t ino;
+ int res;
if (dentry->d_name.len > NILFS_NAME_LEN)
return ERR_PTR(-ENAMETOOLONG);
- ino = nilfs_inode_by_name(dir, &dentry->d_name);
- inode = ino ? nilfs_iget(dir->i_sb, NILFS_I(dir)->i_root, ino) : NULL;
+ res = nilfs_inode_by_name(dir, &dentry->d_name, &ino);
+ if (res) {
+ if (res != -ENOENT)
+ return ERR_PTR(res);
+ inode = NULL;
+ } else {
+ inode = nilfs_iget(dir->i_sb, NILFS_I(dir)->i_root, ino);
+ }
+
return d_splice_alias(inode, dentry);
}
@@ -263,10 +271,11 @@ static int nilfs_do_unlink(struct inode *dir, struct dentry *dentry)
struct folio *folio;
int err;
- err = -ENOENT;
de = nilfs_find_entry(dir, &dentry->d_name, &folio);
- if (!de)
+ if (IS_ERR(de)) {
+ err = PTR_ERR(de);
goto out;
+ }
inode = d_inode(dentry);
err = -EIO;
@@ -362,10 +371,11 @@ static int nilfs_rename(struct mnt_idmap *idmap,
if (unlikely(err))
return err;
- err = -ENOENT;
old_de = nilfs_find_entry(old_dir, &old_dentry->d_name, &old_folio);
- if (!old_de)
+ if (IS_ERR(old_de)) {
+ err = PTR_ERR(old_de);
goto out;
+ }
if (S_ISDIR(old_inode->i_mode)) {
err = -EIO;
@@ -382,10 +392,12 @@ static int nilfs_rename(struct mnt_idmap *idmap,
if (dir_de && !nilfs_empty_dir(new_inode))
goto out_dir;
- err = -ENOENT;
- new_de = nilfs_find_entry(new_dir, &new_dentry->d_name, &new_folio);
- if (!new_de)
+ new_de = nilfs_find_entry(new_dir, &new_dentry->d_name,
+ &new_folio);
+ if (IS_ERR(new_de)) {
+ err = PTR_ERR(new_de);
goto out_dir;
+ }
nilfs_set_link(new_dir, new_de, new_folio, old_inode);
folio_release_kmap(new_folio, new_de);
nilfs_mark_inode_dirty(new_dir);
@@ -440,12 +452,13 @@ static int nilfs_rename(struct mnt_idmap *idmap,
*/
static struct dentry *nilfs_get_parent(struct dentry *child)
{
- unsigned long ino;
+ ino_t ino;
+ int res;
struct nilfs_root *root;
- ino = nilfs_inode_by_name(d_inode(child), &dotdot_name);
- if (!ino)
- return ERR_PTR(-ENOENT);
+ res = nilfs_inode_by_name(d_inode(child), &dotdot_name, &ino);
+ if (res)
+ return ERR_PTR(res);
root = NILFS_I(d_inode(child))->i_root;
diff --git a/fs/nilfs2/nilfs.h b/fs/nilfs2/nilfs.h
index fb1c4c5bae7c..45d03826eaf1 100644
--- a/fs/nilfs2/nilfs.h
+++ b/fs/nilfs2/nilfs.h
@@ -254,7 +254,7 @@ static inline __u32 nilfs_mask_flags(umode_t mode, __u32 flags)
/* dir.c */
int nilfs_add_link(struct dentry *, struct inode *);
-ino_t nilfs_inode_by_name(struct inode *, const struct qstr *);
+int nilfs_inode_by_name(struct inode *dir, const struct qstr *qstr, ino_t *ino);
int nilfs_make_empty(struct inode *, struct inode *);
struct nilfs_dir_entry *nilfs_find_entry(struct inode *, const struct qstr *,
struct folio **);
--
2.43.0
^ permalink raw reply related [flat|nested] 2+ messages in thread
end of thread, other threads:[~2024-10-04 3:37 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <66f59678.050a0220.46d20.0001.GAE@google.com>
2024-09-28 3:53 ` [syzbot] [serial?] INFO: task hung in vcs_open (8) Ryusuke Konishi
2024-10-04 3:35 ` [PATCH] nilfs2: propagate directory read errors from nilfs_find_entry() Ryusuke Konishi
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).