diff mbox series

fs: hfsplus: remove WARN_ON() from hfsplus_cat_{read,write}_inode()

Message ID 15308173-5252-d6a3-ae3b-e96d46cb6f41@I-love.SAKURA.ne.jp (mailing list archive)
State Mainlined, archived
Headers show
Series fs: hfsplus: remove WARN_ON() from hfsplus_cat_{read,write}_inode() | expand

Commit Message

Tetsuo Handa April 11, 2023, 10:57 a.m. UTC
syzbot is hitting WARN_ON() in hfsplus_cat_{read,write}_inode(), for
crafted filesystem image can contain bogus length. There conditions are
not kernel bugs that can justify kernel to panic.

Reported-by: syzbot <syzbot+e2787430e752a92b8750@syzkaller.appspotmail.com>
Link: https://syzkaller.appspot.com/bug?extid=e2787430e752a92b8750
Reported-by: syzbot <syzbot+4913dca2ea6e4d43f3f1@syzkaller.appspotmail.com>
Link: https://syzkaller.appspot.com/bug?extid=4913dca2ea6e4d43f3f1
Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
---
 fs/hfsplus/inode.c | 28 +++++++++++++++++++++++-----
 1 file changed, 23 insertions(+), 5 deletions(-)

Comments

Viacheslav Dubeyko April 11, 2023, 6:44 p.m. UTC | #1
> On Apr 11, 2023, at 3:57 AM, Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> wrote:
> 
> syzbot is hitting WARN_ON() in hfsplus_cat_{read,write}_inode(), for
> crafted filesystem image can contain bogus length. There conditions are
> not kernel bugs that can justify kernel to panic.
> 
> Reported-by: syzbot <syzbot+e2787430e752a92b8750@syzkaller.appspotmail.com>
> Link: https://syzkaller.appspot.com/bug?extid=e2787430e752a92b8750
> Reported-by: syzbot <syzbot+4913dca2ea6e4d43f3f1@syzkaller.appspotmail.com>
> Link: https://syzkaller.appspot.com/bug?extid=4913dca2ea6e4d43f3f1
> Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
> ---
> fs/hfsplus/inode.c | 28 +++++++++++++++++++++++-----
> 1 file changed, 23 insertions(+), 5 deletions(-)
> 
> diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c
> index abb91f5fae92..b21660475ac1 100644
> --- a/fs/hfsplus/inode.c
> +++ b/fs/hfsplus/inode.c
> @@ -511,7 +511,11 @@ int hfsplus_cat_read_inode(struct inode *inode, struct hfs_find_data *fd)
> 	if (type == HFSPLUS_FOLDER) {
> 		struct hfsplus_cat_folder *folder = &entry.folder;
> 
> -		WARN_ON(fd->entrylength < sizeof(struct hfsplus_cat_folder));
> +		if (fd->entrylength < sizeof(struct hfsplus_cat_folder)) {
> +			pr_err("bad catalog folder entry\n");
> +			res = -EIO;
> +			goto out;
> +		}
> 		hfs_bnode_read(fd->bnode, &entry, fd->entryoffset,
> 					sizeof(struct hfsplus_cat_folder));
> 		hfsplus_get_perms(inode, &folder->permissions, 1);
> @@ -531,7 +535,11 @@ int hfsplus_cat_read_inode(struct inode *inode, struct hfs_find_data *fd)
> 	} else if (type == HFSPLUS_FILE) {
> 		struct hfsplus_cat_file *file = &entry.file;
> 
> -		WARN_ON(fd->entrylength < sizeof(struct hfsplus_cat_file));
> +		if (fd->entrylength < sizeof(struct hfsplus_cat_file)) {
> +			pr_err("bad catalog file entry\n");
> +			res = -EIO;
> +			goto out;
> +		}
> 		hfs_bnode_read(fd->bnode, &entry, fd->entryoffset,
> 					sizeof(struct hfsplus_cat_file));
> 
> @@ -562,6 +570,7 @@ int hfsplus_cat_read_inode(struct inode *inode, struct hfs_find_data *fd)
> 		pr_err("bad catalog entry used to create inode\n");
> 		res = -EIO;
> 	}
> +out:
> 	return res;
> }
> 
> @@ -570,6 +579,7 @@ int hfsplus_cat_write_inode(struct inode *inode)
> 	struct inode *main_inode = inode;
> 	struct hfs_find_data fd;
> 	hfsplus_cat_entry entry;
> +	int res = 0;
> 
> 	if (HFSPLUS_IS_RSRC(inode))
> 		main_inode = HFSPLUS_I(inode)->rsrc_inode;
> @@ -588,7 +598,11 @@ int hfsplus_cat_write_inode(struct inode *inode)
> 	if (S_ISDIR(main_inode->i_mode)) {
> 		struct hfsplus_cat_folder *folder = &entry.folder;
> 
> -		WARN_ON(fd.entrylength < sizeof(struct hfsplus_cat_folder));
> +		if (fd.entrylength < sizeof(struct hfsplus_cat_folder)) {
> +			pr_err("bad catalog folder entry\n");
> +			res = -EIO;
> +			goto out;
> +		}
> 		hfs_bnode_read(fd.bnode, &entry, fd.entryoffset,
> 					sizeof(struct hfsplus_cat_folder));
> 		/* simple node checks? */
> @@ -613,7 +627,11 @@ int hfsplus_cat_write_inode(struct inode *inode)
> 	} else {
> 		struct hfsplus_cat_file *file = &entry.file;
> 
> -		WARN_ON(fd.entrylength < sizeof(struct hfsplus_cat_file));
> +		if (fd.entrylength < sizeof(struct hfsplus_cat_file)) {
> +			pr_err("bad catalog file entry\n");
> +			res = -EIO;
> +			goto out;
> +		}
> 		hfs_bnode_read(fd.bnode, &entry, fd.entryoffset,
> 					sizeof(struct hfsplus_cat_file));
> 		hfsplus_inode_write_fork(inode, &file->data_fork);
> @@ -634,7 +652,7 @@ int hfsplus_cat_write_inode(struct inode *inode)
> 	set_bit(HFSPLUS_I_CAT_DIRTY, &HFSPLUS_I(inode)->flags);
> out:
> 	hfs_find_exit(&fd);
> -	return 0;
> +	return res;
> }
> 

Looks reasonable to me. Maybe, WARN_ON() provided the opportunity to see
the call stack of the issue. It could be useful for the issue’s environment
analysis. But returning error from the function(s) makes the execution flow
much better.

Reviewed-by: Viacheslav Dubeyko <slava@dubeyko.com>

Thanks,
Slava.


> int hfsplus_fileattr_get(struct dentry *dentry, struct fileattr *fa)
> -- 
> 2.34.1
>
Christian Brauner April 12, 2023, 9:38 a.m. UTC | #2
On Tue, 11 Apr 2023 19:57:33 +0900, Tetsuo Handa wrote:
> syzbot is hitting WARN_ON() in hfsplus_cat_{read,write}_inode(), for
> crafted filesystem image can contain bogus length. There conditions are
> not kernel bugs that can justify kernel to panic.
> 
> 

Seems fine as a follow-up fix to Arnd's in
55d1cbbbb29e ("hfs/hfsplus: use WARN_ON for sanity check").
Filesystems is orphaned so taking this through one of our vfs trees,

branch: fs.misc
[1/1] fs: hfsplus: remove WARN_ON() from hfsplus_cat_{read,write}_inode()
      commit: 81b21c0f0138ff5a499eafc3eb0578ad2a99622c
diff mbox series

Patch

diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c
index abb91f5fae92..b21660475ac1 100644
--- a/fs/hfsplus/inode.c
+++ b/fs/hfsplus/inode.c
@@ -511,7 +511,11 @@  int hfsplus_cat_read_inode(struct inode *inode, struct hfs_find_data *fd)
 	if (type == HFSPLUS_FOLDER) {
 		struct hfsplus_cat_folder *folder = &entry.folder;
 
-		WARN_ON(fd->entrylength < sizeof(struct hfsplus_cat_folder));
+		if (fd->entrylength < sizeof(struct hfsplus_cat_folder)) {
+			pr_err("bad catalog folder entry\n");
+			res = -EIO;
+			goto out;
+		}
 		hfs_bnode_read(fd->bnode, &entry, fd->entryoffset,
 					sizeof(struct hfsplus_cat_folder));
 		hfsplus_get_perms(inode, &folder->permissions, 1);
@@ -531,7 +535,11 @@  int hfsplus_cat_read_inode(struct inode *inode, struct hfs_find_data *fd)
 	} else if (type == HFSPLUS_FILE) {
 		struct hfsplus_cat_file *file = &entry.file;
 
-		WARN_ON(fd->entrylength < sizeof(struct hfsplus_cat_file));
+		if (fd->entrylength < sizeof(struct hfsplus_cat_file)) {
+			pr_err("bad catalog file entry\n");
+			res = -EIO;
+			goto out;
+		}
 		hfs_bnode_read(fd->bnode, &entry, fd->entryoffset,
 					sizeof(struct hfsplus_cat_file));
 
@@ -562,6 +570,7 @@  int hfsplus_cat_read_inode(struct inode *inode, struct hfs_find_data *fd)
 		pr_err("bad catalog entry used to create inode\n");
 		res = -EIO;
 	}
+out:
 	return res;
 }
 
@@ -570,6 +579,7 @@  int hfsplus_cat_write_inode(struct inode *inode)
 	struct inode *main_inode = inode;
 	struct hfs_find_data fd;
 	hfsplus_cat_entry entry;
+	int res = 0;
 
 	if (HFSPLUS_IS_RSRC(inode))
 		main_inode = HFSPLUS_I(inode)->rsrc_inode;
@@ -588,7 +598,11 @@  int hfsplus_cat_write_inode(struct inode *inode)
 	if (S_ISDIR(main_inode->i_mode)) {
 		struct hfsplus_cat_folder *folder = &entry.folder;
 
-		WARN_ON(fd.entrylength < sizeof(struct hfsplus_cat_folder));
+		if (fd.entrylength < sizeof(struct hfsplus_cat_folder)) {
+			pr_err("bad catalog folder entry\n");
+			res = -EIO;
+			goto out;
+		}
 		hfs_bnode_read(fd.bnode, &entry, fd.entryoffset,
 					sizeof(struct hfsplus_cat_folder));
 		/* simple node checks? */
@@ -613,7 +627,11 @@  int hfsplus_cat_write_inode(struct inode *inode)
 	} else {
 		struct hfsplus_cat_file *file = &entry.file;
 
-		WARN_ON(fd.entrylength < sizeof(struct hfsplus_cat_file));
+		if (fd.entrylength < sizeof(struct hfsplus_cat_file)) {
+			pr_err("bad catalog file entry\n");
+			res = -EIO;
+			goto out;
+		}
 		hfs_bnode_read(fd.bnode, &entry, fd.entryoffset,
 					sizeof(struct hfsplus_cat_file));
 		hfsplus_inode_write_fork(inode, &file->data_fork);
@@ -634,7 +652,7 @@  int hfsplus_cat_write_inode(struct inode *inode)
 	set_bit(HFSPLUS_I_CAT_DIRTY, &HFSPLUS_I(inode)->flags);
 out:
 	hfs_find_exit(&fd);
-	return 0;
+	return res;
 }
 
 int hfsplus_fileattr_get(struct dentry *dentry, struct fileattr *fa)