| From c9eb13a9105e2e418f72e46a2b6da3f49e696902 Mon Sep 17 00:00:00 2001 |
| From: Theodore Ts'o <tytso@mit.edu> |
| Date: Sat, 30 Apr 2016 00:48:54 -0400 |
| Subject: ext4: fix hang when processing corrupted orphaned inode list |
| |
| From: Theodore Ts'o <tytso@mit.edu> |
| |
| commit c9eb13a9105e2e418f72e46a2b6da3f49e696902 upstream. |
| |
| If the orphaned inode list contains inode #5, ext4_iget() returns a |
| bad inode (since the bootloader inode should never be referenced |
| directly). Because of the bad inode, we end up processing the inode |
| repeatedly and this hangs the machine. |
| |
| This can be reproduced via: |
| |
| mke2fs -t ext4 /tmp/foo.img 100 |
| debugfs -w -R "ssv last_orphan 5" /tmp/foo.img |
| mount -o loop /tmp/foo.img /mnt |
| |
| (But don't do this if you are using an unpatched kernel if you care |
| about the system staying functional. :-) |
| |
| This bug was found by the port of American Fuzzy Lop into the kernel |
| to find file system problems[1]. (Since it *only* happens if inode #5 |
| shows up on the orphan list --- 3, 7, 8, etc. won't do it, it's not |
| surprising that AFL needed two hours before it found it.) |
| |
| [1] http://events.linuxfoundation.org/sites/events/files/slides/AFL%20filesystem%20fuzzing%2C%20Vault%202016_0.pdf |
| |
| Reported by: Vegard Nossum <vegard.nossum@oracle.com> |
| Signed-off-by: Theodore Ts'o <tytso@mit.edu> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| fs/ext4/ialloc.c | 10 ++++++---- |
| 1 file changed, 6 insertions(+), 4 deletions(-) |
| |
| --- a/fs/ext4/ialloc.c |
| +++ b/fs/ext4/ialloc.c |
| @@ -1183,11 +1183,13 @@ struct inode *ext4_orphan_get(struct sup |
| goto iget_failed; |
| |
| /* |
| - * If the orphans has i_nlinks > 0 then it should be able to be |
| - * truncated, otherwise it won't be removed from the orphan list |
| - * during processing and an infinite loop will result. |
| + * If the orphans has i_nlinks > 0 then it should be able to |
| + * be truncated, otherwise it won't be removed from the orphan |
| + * list during processing and an infinite loop will result. |
| + * Similarly, it must not be a bad inode. |
| */ |
| - if (inode->i_nlink && !ext4_can_truncate(inode)) |
| + if ((inode->i_nlink && !ext4_can_truncate(inode)) || |
| + is_bad_inode(inode)) |
| goto bad_orphan; |
| |
| if (NEXT_ORPHAN(inode) > max_ino) |