Commit cb7a95af authored by Linus Torvalds's avatar Linus Torvalds

hfs/hfsplus: avoid WARN_ON() for sanity check, use proper error handling

Commit 55d1cbbb ("hfs/hfsplus: use WARN_ON for sanity check") fixed
a build warning by turning a comment into a WARN_ON(), but it turns out
that syzbot then complains because it can trigger said warning with a
corrupted hfs image.

The warning actually does warn about a bad situation, but we are much
better off just handling it as the error it is.  So rather than warn
about us doing bad things, stop doing the bad things and return -EIO.

While at it, also fix a memory leak that was introduced by an earlier
fix for a similar syzbot warning situation, and add a check for one case
that historically wasn't handled at all (ie neither comment nor
subsequent WARN_ON).

Reported-by: syzbot+7bb7cd3595533513a9e7@syzkaller.appspotmail.com
Fixes: 55d1cbbb ("hfs/hfsplus: use WARN_ON for sanity check")
Fixes: 8d824e69 ("hfs: fix OOB Read in __hfs_brec_find")
Link: https://lore.kernel.org/lkml/000000000000dbce4e05f170f289@google.com/Tested-by: default avatarMichael Schmitz <schmitzmic@gmail.com>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Matthew Wilcox <willy@infradead.org>
Cc: Viacheslav Dubeyko <slava@dubeyko.com>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent a689b938
...@@ -458,15 +458,16 @@ int hfs_write_inode(struct inode *inode, struct writeback_control *wbc) ...@@ -458,15 +458,16 @@ int hfs_write_inode(struct inode *inode, struct writeback_control *wbc)
/* panic? */ /* panic? */
return -EIO; return -EIO;
res = -EIO;
if (HFS_I(main_inode)->cat_key.CName.len > HFS_NAMELEN) if (HFS_I(main_inode)->cat_key.CName.len > HFS_NAMELEN)
return -EIO; goto out;
fd.search_key->cat = HFS_I(main_inode)->cat_key; fd.search_key->cat = HFS_I(main_inode)->cat_key;
if (hfs_brec_find(&fd)) if (hfs_brec_find(&fd))
/* panic? */
goto out; goto out;
if (S_ISDIR(main_inode->i_mode)) { if (S_ISDIR(main_inode->i_mode)) {
WARN_ON(fd.entrylength < sizeof(struct hfs_cat_dir)); if (fd.entrylength < sizeof(struct hfs_cat_dir))
goto out;
hfs_bnode_read(fd.bnode, &rec, fd.entryoffset, hfs_bnode_read(fd.bnode, &rec, fd.entryoffset,
sizeof(struct hfs_cat_dir)); sizeof(struct hfs_cat_dir));
if (rec.type != HFS_CDR_DIR || if (rec.type != HFS_CDR_DIR ||
...@@ -479,6 +480,8 @@ int hfs_write_inode(struct inode *inode, struct writeback_control *wbc) ...@@ -479,6 +480,8 @@ int hfs_write_inode(struct inode *inode, struct writeback_control *wbc)
hfs_bnode_write(fd.bnode, &rec, fd.entryoffset, hfs_bnode_write(fd.bnode, &rec, fd.entryoffset,
sizeof(struct hfs_cat_dir)); sizeof(struct hfs_cat_dir));
} else if (HFS_IS_RSRC(inode)) { } else if (HFS_IS_RSRC(inode)) {
if (fd.entrylength < sizeof(struct hfs_cat_file))
goto out;
hfs_bnode_read(fd.bnode, &rec, fd.entryoffset, hfs_bnode_read(fd.bnode, &rec, fd.entryoffset,
sizeof(struct hfs_cat_file)); sizeof(struct hfs_cat_file));
hfs_inode_write_fork(inode, rec.file.RExtRec, hfs_inode_write_fork(inode, rec.file.RExtRec,
...@@ -486,7 +489,8 @@ int hfs_write_inode(struct inode *inode, struct writeback_control *wbc) ...@@ -486,7 +489,8 @@ int hfs_write_inode(struct inode *inode, struct writeback_control *wbc)
hfs_bnode_write(fd.bnode, &rec, fd.entryoffset, hfs_bnode_write(fd.bnode, &rec, fd.entryoffset,
sizeof(struct hfs_cat_file)); sizeof(struct hfs_cat_file));
} else { } else {
WARN_ON(fd.entrylength < sizeof(struct hfs_cat_file)); if (fd.entrylength < sizeof(struct hfs_cat_file))
goto out;
hfs_bnode_read(fd.bnode, &rec, fd.entryoffset, hfs_bnode_read(fd.bnode, &rec, fd.entryoffset,
sizeof(struct hfs_cat_file)); sizeof(struct hfs_cat_file));
if (rec.type != HFS_CDR_FIL || if (rec.type != HFS_CDR_FIL ||
...@@ -503,9 +507,10 @@ int hfs_write_inode(struct inode *inode, struct writeback_control *wbc) ...@@ -503,9 +507,10 @@ int hfs_write_inode(struct inode *inode, struct writeback_control *wbc)
hfs_bnode_write(fd.bnode, &rec, fd.entryoffset, hfs_bnode_write(fd.bnode, &rec, fd.entryoffset,
sizeof(struct hfs_cat_file)); sizeof(struct hfs_cat_file));
} }
res = 0;
out: out:
hfs_find_exit(&fd); hfs_find_exit(&fd);
return 0; return res;
} }
static struct dentry *hfs_file_lookup(struct inode *dir, struct dentry *dentry, static struct dentry *hfs_file_lookup(struct inode *dir, struct dentry *dentry,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment