[lvc-project] [PATCH] jfs: reject on-disk inodes of an unsupported type

Dave Kleikamp dave.kleikamp at oracle.com
Tue Dec 3 00:35:35 MSK 2024


On 11/6/24 11:42PM, Dmitry Antipov wrote:
> Syzbot has reported the following BUG:
> 
> kernel BUG at fs/inode.c:668!
> Oops: invalid opcode: 0000 [#1] PREEMPT SMP KASAN PTI
> CPU: 3 UID: 0 PID: 139 Comm: jfsCommit Not tainted 6.12.0-rc4-syzkaller-00085-g4e46774408d9 #0
> Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.16.3-3.fc41 04/01/2014
> RIP: 0010:clear_inode+0x168/0x190
> Code: 4c 89 f7 e8 ba fe e5 ff e9 61 ff ff ff 44 89 f1 80 e1 07 80 c1 03 38 c1 7c c1 4c 89 f7 e8 90 ff e5 ff eb b7
>   0b e8 01 5d 7f ff 90 0f 0b e8 f9 5c 7f ff 90 0f 0b e8 f1 5c 7f
> RSP: 0018:ffffc900027dfae8 EFLAGS: 00010093
> RAX: ffffffff82157a87 RBX: 0000000000000001 RCX: ffff888104d4b980
> RDX: 0000000000000000 RSI: 0000000000000001 RDI: 0000000000000000
> RBP: ffffc900027dfc90 R08: ffffffff82157977 R09: fffff520004fbf38
> R10: dffffc0000000000 R11: fffff520004fbf38 R12: dffffc0000000000
> R13: ffff88811315bc00 R14: ffff88811315bda8 R15: ffff88811315bb80
> FS:  0000000000000000(0000) GS:ffff888135f00000(0000) knlGS:0000000000000000
> CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> CR2: 00005565222e0578 CR3: 0000000026ef0000 CR4: 00000000000006f0
> Call Trace:
>   <TASK>
>   ? __die_body+0x5f/0xb0
>   ? die+0x9e/0xc0
>   ? do_trap+0x15a/0x3a0
>   ? clear_inode+0x168/0x190
>   ? do_error_trap+0x1dc/0x2c0
>   ? clear_inode+0x168/0x190
>   ? __pfx_do_error_trap+0x10/0x10
>   ? report_bug+0x3cd/0x500
>   ? handle_invalid_op+0x34/0x40
>   ? clear_inode+0x168/0x190
>   ? exc_invalid_op+0x38/0x50
>   ? asm_exc_invalid_op+0x1a/0x20
>   ? clear_inode+0x57/0x190
>   ? clear_inode+0x167/0x190
>   ? clear_inode+0x168/0x190
>   ? clear_inode+0x167/0x190
>   jfs_evict_inode+0xb5/0x440
>   ? __pfx_jfs_evict_inode+0x10/0x10
>   evict+0x4ea/0x9b0
>   ? __pfx_evict+0x10/0x10
>   ? iput+0x713/0xa50
>   txUpdateMap+0x931/0xb10
>   ? __pfx_txUpdateMap+0x10/0x10
>   jfs_lazycommit+0x49a/0xb80
>   ? _raw_spin_unlock_irqrestore+0x8f/0x140
>   ? lockdep_hardirqs_on+0x99/0x150
>   ? __pfx_jfs_lazycommit+0x10/0x10
>   ? __pfx_default_wake_function+0x10/0x10
>   ? __kthread_parkme+0x169/0x1d0
>   ? __pfx_jfs_lazycommit+0x10/0x10
>   kthread+0x2f2/0x390
>   ? __pfx_jfs_lazycommit+0x10/0x10
>   ? __pfx_kthread+0x10/0x10
>   ret_from_fork+0x4d/0x80
>   ? __pfx_kthread+0x10/0x10
>   ret_from_fork_asm+0x1a/0x30
>   </TASK>
> 
> This happens when 'clear_inode()' makes an attempt to finalize an underlying
> JFS inode of unknown type. According to JFS layout description from
> https://jfs.sourceforge.net/project/pub/jfslayout.pdf, inode types from 5 to
> 15 are reserved for future extensions and should not be encountered on a valid
> filesystem. So add an extra check for valid inode type in 'copy_from_dinode()'
> and fix 'jfs_lookup()' to handle possible -EINVAL.

I like the first part of this patch, but I don't see the need for the 
second part. d_splice_alias() handles IS_ERR(ip) just fine.

Would you object to me just keeping the change to jfs_imap.c?

Shaggy

> 
> Reported-by: syzbot+ac2116e48989e84a2893 at syzkaller.appspotmail.com
> Closes: https://syzkaller.appspot.com/bug?extid=ac2116e48989e84a2893
> Fixes: 79ac5a46c5c1 ("jfs_lookup(): don't bother with . or ..")
> Signed-off-by: Dmitry Antipov <dmantipov at yandex.ru>
> ---
>   fs/jfs/jfs_imap.c | 13 +++++++++++--
>   fs/jfs/namei.c    | 10 ++++++++--
>   2 files changed, 19 insertions(+), 4 deletions(-)
> 
> diff --git a/fs/jfs/jfs_imap.c b/fs/jfs/jfs_imap.c
> index a360b24ed320..debfc1389cb3 100644
> --- a/fs/jfs/jfs_imap.c
> +++ b/fs/jfs/jfs_imap.c
> @@ -3029,14 +3029,23 @@ static void duplicateIXtree(struct super_block *sb, s64 blkno,
>    *
>    * RETURN VALUES:
>    *	0	- success
> - *	-ENOMEM	- insufficient memory
> + *	-EINVAL	- unexpected inode type
>    */
>   static int copy_from_dinode(struct dinode * dip, struct inode *ip)
>   {
>   	struct jfs_inode_info *jfs_ip = JFS_IP(ip);
>   	struct jfs_sb_info *sbi = JFS_SBI(ip->i_sb);
> +	int fileset = le32_to_cpu(dip->di_fileset);
> +
> +	switch (fileset) {
> +	case AGGR_RESERVED_I: case AGGREGATE_I: case BMAP_I:
> +	case LOG_I: case BADBLOCK_I: case FILESYSTEM_I:
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
>   
> -	jfs_ip->fileset = le32_to_cpu(dip->di_fileset);
> +	jfs_ip->fileset = fileset;
>   	jfs_ip->mode2 = le32_to_cpu(dip->di_mode);
>   	jfs_set_inode_flags(ip);
>   
> diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c
> index d68a4e6ac345..845abc598334 100644
> --- a/fs/jfs/namei.c
> +++ b/fs/jfs/namei.c
> @@ -1467,8 +1467,14 @@ static struct dentry *jfs_lookup(struct inode *dip, struct dentry *dentry, unsig
>   		ip = ERR_PTR(rc);
>   	} else {
>   		ip = jfs_iget(dip->i_sb, inum);
> -		if (IS_ERR(ip))
> -			jfs_err("jfs_lookup: iget failed on inum %d", (uint)inum);
> +		if (IS_ERR(ip)) {
> +			long err = PTR_ERR(ip);
> +
> +			jfs_err("%s: iget failed on inum %d with error"
> +				" %ld, consider running 'jfs_fsck -f /dev/%s'",
> +				__func__, (uint)inum, err, dip->i_sb->s_id);
> +			return ERR_PTR(err);
> +		}
>   	}
>   
>   	return d_splice_alias(ip, dentry);



More information about the lvc-project mailing list