vfs-6.19-rc1.minix

-----BEGIN PGP SIGNATURE-----
 
 iHUEABYKAB0WIQRAhzRXHqcMeLMyaSiRxhvAZXjcogUCaSmOZgAKCRCRxhvAZXjc
 olEcAP4qG313oT/tm4W3nC4g2k8S//KqET97B80pSX0K3DvQEwD+LSCf1Th3RnsV
 EAMHczmCtRlbcFPqYOFVAMS8VxOyVg0=
 =7Ca4
 -----END PGP SIGNATURE-----

Merge tag 'vfs-6.19-rc1.minix' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs

Pull minix fixes from Christian Brauner:
 "Fix two syzbot corruption bugs in the minix filesystem.

  Syzbot fuzzes filesystems by trying to mount and manipulate
  deliberately corrupted images. This should not lead to BUG_ONs and
  WARN_ONs for easy to detect corruptions.

   - Add error handling to minix filesystem for inode corruption
     detection, enabling the filesystem to report such corruptions
     cleanly.

   - Fix a drop_nlink warning in minix_rmdir() triggered by corrupted
     directory link counts.

   - Fix a drop_nlink warning in minix_rename() triggered by corrupted
     inode link counts"

* tag 'vfs-6.19-rc1.minix' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs:
  Fix a drop_nlink warning in minix_rename
  Fix a drop_nlink warning in minix_rmdir
  Add error handling to minix filesystem for inode corruption detection
This commit is contained in:
Linus Torvalds 2025-12-01 15:22:40 -08:00
commit 4664fb427c
3 changed files with 57 additions and 7 deletions

View File

@ -26,6 +26,22 @@ static int minix_write_inode(struct inode *inode,
struct writeback_control *wbc); struct writeback_control *wbc);
static int minix_statfs(struct dentry *dentry, struct kstatfs *buf); static int minix_statfs(struct dentry *dentry, struct kstatfs *buf);
void __minix_error_inode(struct inode *inode, const char *function,
unsigned int line, const char *fmt, ...)
{
struct va_format vaf;
va_list args;
va_start(args, fmt);
vaf.fmt = fmt;
vaf.va = &args;
printk(KERN_CRIT "minix-fs error (device %s): %s:%d: "
"inode #%lu: comm %s: %pV\n",
inode->i_sb->s_id, function, line, inode->i_ino,
current->comm, &vaf);
va_end(args);
}
static void minix_evict_inode(struct inode *inode) static void minix_evict_inode(struct inode *inode)
{ {
truncate_inode_pages_final(&inode->i_data); truncate_inode_pages_final(&inode->i_data);

View File

@ -42,6 +42,9 @@ struct minix_sb_info {
unsigned short s_version; unsigned short s_version;
}; };
void __minix_error_inode(struct inode *inode, const char *function,
unsigned int line, const char *fmt, ...);
struct inode *minix_iget(struct super_block *, unsigned long); struct inode *minix_iget(struct super_block *, unsigned long);
struct minix_inode *minix_V1_raw_inode(struct super_block *, ino_t, struct buffer_head **); struct minix_inode *minix_V1_raw_inode(struct super_block *, ino_t, struct buffer_head **);
struct minix2_inode *minix_V2_raw_inode(struct super_block *, ino_t, struct buffer_head **); struct minix2_inode *minix_V2_raw_inode(struct super_block *, ino_t, struct buffer_head **);
@ -168,4 +171,10 @@ static inline int minix_test_bit(int nr, const void *vaddr)
#endif #endif
#define minix_error_inode(inode, fmt, ...) \
__minix_error_inode((inode), __func__, __LINE__, \
(fmt), ##__VA_ARGS__)
#define EFSCORRUPTED EUCLEAN /* Filesystem is corrupted */
#endif /* FS_MINIX_H */ #endif /* FS_MINIX_H */

View File

@ -145,6 +145,11 @@ static int minix_unlink(struct inode * dir, struct dentry *dentry)
struct minix_dir_entry * de; struct minix_dir_entry * de;
int err; int err;
if (inode->i_nlink == 0) {
minix_error_inode(inode, "inode has corrupted nlink");
return -EFSCORRUPTED;
}
de = minix_find_entry(dentry, &folio); de = minix_find_entry(dentry, &folio);
if (!de) if (!de)
return -ENOENT; return -ENOENT;
@ -161,15 +166,24 @@ static int minix_unlink(struct inode * dir, struct dentry *dentry)
static int minix_rmdir(struct inode * dir, struct dentry *dentry) static int minix_rmdir(struct inode * dir, struct dentry *dentry)
{ {
struct inode * inode = d_inode(dentry); struct inode * inode = d_inode(dentry);
int err = -ENOTEMPTY; int err = -EFSCORRUPTED;
if (minix_empty_dir(inode)) { if (dir->i_nlink <= 2) {
err = minix_unlink(dir, dentry); minix_error_inode(dir, "inode has corrupted nlink");
if (!err) { goto out;
inode_dec_link_count(dir);
inode_dec_link_count(inode);
}
} }
err = -ENOTEMPTY;
if (!minix_empty_dir(inode))
goto out;
err = minix_unlink(dir, dentry);
if (!err) {
inode_dec_link_count(dir);
inode_dec_link_count(inode);
}
out:
return err; return err;
} }
@ -208,6 +222,17 @@ static int minix_rename(struct mnt_idmap *idmap,
if (dir_de && !minix_empty_dir(new_inode)) if (dir_de && !minix_empty_dir(new_inode))
goto out_dir; goto out_dir;
err = -EFSCORRUPTED;
if (new_inode->i_nlink == 0 || (dir_de && new_inode->i_nlink != 2)) {
minix_error_inode(new_inode, "inode has corrupted nlink");
goto out_dir;
}
if (dir_de && old_dir->i_nlink <= 2) {
minix_error_inode(old_dir, "inode has corrupted nlink");
goto out_dir;
}
err = -ENOENT; err = -ENOENT;
new_de = minix_find_entry(new_dentry, &new_folio); new_de = minix_find_entry(new_dentry, &new_folio);
if (!new_de) if (!new_de)