diff mbox

vfs: reject inodes with negative size to prevent kernel hang

Message ID 20161207003222.GI16807@birch.djwong.org (mailing list archive)
State New, archived
Headers show

Commit Message

Darrick J. Wong Dec. 7, 2016, 12:32 a.m. UTC
Due to insufficient input validation, various filesystem drivers can
load an inode with a negative size from a maliciously crafted fs image.
If this happens, a subsequent write-append operation can cause integer
overflows in the writeback code, causing the kernel to lock up.

Therefore, if we catch anyone trying to link a dentry to a garbage
inode, reject the whole attempt.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
---
The regression tests for this bug are {ext4,xfs}/40[01] in the patch
"xfs/ext4: check negative inode size" that I just sent to fstests@vger.

I realize it's /very/ late in the 4.9 cycle, but this seemed like the
most general way to fix this problem.

Perhaps a better fix is to strengthen the _iget verification in every
filesystem, which I'm working on for 4.10.  But we should at the very
least bonk suspicious looking activity. :)
---
 fs/dcache.c |   21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Comments

kernel test robot Dec. 7, 2016, 3:54 a.m. UTC | #1
Hi Darrick,

[auto build test WARNING on linus/master]
[also build test WARNING on v4.9-rc8 next-20161206]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Darrick-J-Wong/vfs-reject-inodes-with-negative-size-to-prevent-kernel-hang/20161207-110513
config: i386-randconfig-s1-201649 (attached as .config)
compiler: gcc-6 (Debian 6.2.0-3) 6.2.0 20160901
reproduce:
        # save the attached .config to linux build tree
        make ARCH=i386 

Note: it may well be a FALSE warning. FWIW you are at least aware of it now.
http://gcc.gnu.org/wiki/Better_Uninitialized_Warnings

All warnings (new ones prefixed by >>):

   Cyclomatic Complexity 1 fs/dcache.c:__d_rehash
   Cyclomatic Complexity 2 fs/dcache.c:prepend
   Cyclomatic Complexity 3 fs/dcache.c:path_with_deleted
   Cyclomatic Complexity 7 fs/dcache.c:__dentry_path
   Cyclomatic Complexity 1 fs/dcache.c:prepend_unreachable
   Cyclomatic Complexity 4 fs/dcache.c:d_shrink_del
   Cyclomatic Complexity 4 fs/dcache.c:d_shrink_add
   Cyclomatic Complexity 2 fs/dcache.c:__d_instantiate
   Cyclomatic Complexity 7 fs/dcache.c:d_lru_add
   Cyclomatic Complexity 2 fs/dcache.c:dentry_lru_add
   Cyclomatic Complexity 7 fs/dcache.c:d_lru_del
   Cyclomatic Complexity 7 fs/dcache.c:select_collect
   Cyclomatic Complexity 2 fs/dcache.c:detach_and_collect
   Cyclomatic Complexity 6 fs/dcache.c:dentry_unlink_inode
   Cyclomatic Complexity 1 fs/dcache.c:__d_free_external
   Cyclomatic Complexity 1 fs/dcache.c:__d_free
   Cyclomatic Complexity 5 fs/dcache.c:dentry_free
   Cyclomatic Complexity 4 fs/dcache.c:d_lru_isolate
   Cyclomatic Complexity 4 fs/dcache.c:d_lru_shrink_move
   Cyclomatic Complexity 4 fs/dcache.c:dentry_lru_isolate
   Cyclomatic Complexity 2 fs/dcache.c:dentry_lru_isolate_shrink
   Cyclomatic Complexity 16 fs/dcache.c:d_walk
   Cyclomatic Complexity 6 fs/dcache.c:umount_check
   Cyclomatic Complexity 3 fs/dcache.c:d_wait_lookup
   Cyclomatic Complexity 6 fs/dcache.c:swap_names
   Cyclomatic Complexity 6 fs/dcache.c:copy_name
   Cyclomatic Complexity 2 fs/dcache.c:set_dhash_entries
   Cyclomatic Complexity 1 fs/dcache.c:vfs_caches_init_early
   Cyclomatic Complexity 1 fs/dcache.c:vfs_caches_init
   Cyclomatic Complexity 1 fs/dcache.c:proc_nr_dentry
   Cyclomatic Complexity 3 fs/dcache.c:__d_drop
   Cyclomatic Complexity 11 fs/dcache.c:__dentry_kill
   Cyclomatic Complexity 6 fs/dcache.c:dentry_kill
   Cyclomatic Complexity 16 fs/dcache.c:shrink_dentry_list
   Cyclomatic Complexity 3 fs/dcache.c:check_and_drop
   Cyclomatic Complexity 1 fs/dcache.c:d_drop
   Cyclomatic Complexity 10 fs/dcache.c:dput
   Cyclomatic Complexity 4 fs/dcache.c:dget_parent
   Cyclomatic Complexity 2 fs/dcache.c:d_find_alias
   Cyclomatic Complexity 7 fs/dcache.c:d_prune_aliases
   Cyclomatic Complexity 1 fs/dcache.c:prune_dcache_sb
   Cyclomatic Complexity 6 fs/dcache.c:shrink_dcache_sb
   Cyclomatic Complexity 1 fs/dcache.c:have_submounts
   Cyclomatic Complexity 4 fs/dcache.c:d_set_mounted
   Cyclomatic Complexity 2 fs/dcache.c:shrink_dcache_parent
   Cyclomatic Complexity 1 fs/dcache.c:do_one_tree
   Cyclomatic Complexity 3 fs/dcache.c:shrink_dcache_for_umount
   Cyclomatic Complexity 7 fs/dcache.c:d_invalidate
   Cyclomatic Complexity 15 fs/dcache.c:d_set_d_op
   Cyclomatic Complexity 9 fs/dcache.c:__d_alloc
   Cyclomatic Complexity 2 fs/dcache.c:d_alloc
   Cyclomatic Complexity 1 fs/dcache.c:d_alloc_name
   Cyclomatic Complexity 2 fs/dcache.c:d_alloc_cursor
   Cyclomatic Complexity 1 fs/dcache.c:d_alloc_pseudo
   Cyclomatic Complexity 1 fs/dcache.c:d_set_fallthru
   Cyclomatic Complexity 2 fs/dcache.c:d_instantiate
   Cyclomatic Complexity 3 fs/dcache.c:d_instantiate_no_diralias
   Cyclomatic Complexity 3 fs/dcache.c:d_make_root
   Cyclomatic Complexity 1 fs/dcache.c:d_find_any_alias
   Cyclomatic Complexity 7 fs/dcache.c:__d_obtain_alias
   Cyclomatic Complexity 1 fs/dcache.c:d_obtain_alias
   Cyclomatic Complexity 1 fs/dcache.c:d_obtain_root
   Cyclomatic Complexity 11 fs/dcache.c:__d_lookup_rcu
   Cyclomatic Complexity 7 fs/dcache.c:__d_lookup
   Cyclomatic Complexity 3 fs/dcache.c:d_lookup
   Cyclomatic Complexity 3 fs/dcache.c:d_hash_and_lookup
   Cyclomatic Complexity 4 fs/dcache.c:d_delete
   Cyclomatic Complexity 1 fs/dcache.c:d_rehash
   Cyclomatic Complexity 18 fs/dcache.c:d_alloc_parallel
   Cyclomatic Complexity 1 fs/dcache.c:__d_lookup_done
   Cyclomatic Complexity 2 fs/dcache.c:d_add
   Cyclomatic Complexity 8 fs/dcache.c:d_exact_alias
   Cyclomatic Complexity 1 fs/dcache.c:dentry_update_name_case
   Cyclomatic Complexity 3 fs/dcache.c:d_ancestor
   Cyclomatic Complexity 5 fs/dcache.c:dentry_lock_for_move
   Cyclomatic Complexity 8 fs/dcache.c:__d_move
   Cyclomatic Complexity 1 fs/dcache.c:d_move
   Cyclomatic Complexity 5 fs/dcache.c:d_exchange
   Cyclomatic Complexity 6 fs/dcache.c:__d_unalias
   Cyclomatic Complexity 13 fs/dcache.c:d_splice_alias
   Cyclomatic Complexity 7 fs/dcache.c:d_add_ci
   Cyclomatic Complexity 3 fs/dcache.c:__d_path
   Cyclomatic Complexity 3 fs/dcache.c:d_absolute_path
   Cyclomatic Complexity 6 fs/dcache.c:d_path
   Cyclomatic Complexity 2 fs/dcache.c:dynamic_dname
   Cyclomatic Complexity 4 fs/dcache.c:simple_dname
   Cyclomatic Complexity 1 fs/dcache.c:dentry_path_raw
   Cyclomatic Complexity 5 fs/dcache.c:dentry_path
   Cyclomatic Complexity 1 fs/dcache.c:SyS_getcwd
   Cyclomatic Complexity 4 fs/dcache.c:is_subdir
   Cyclomatic Complexity 1 fs/dcache.c:d_genocide
   Cyclomatic Complexity 4 fs/dcache.c:d_tmpfile
   In file included from include/uapi/linux/stddef.h:1:0,
                    from include/linux/stddef.h:4,
                    from include/uapi/linux/posix_types.h:4,
                    from include/uapi/linux/types.h:13,
                    from include/linux/types.h:5,
                    from include/linux/syscalls.h:70,
                    from fs/dcache.c:17:
   fs/dcache.c: In function 'd_add':
>> include/linux/compiler.h:323:14: warning: 'n' may be used uninitialized in this function [-Wmaybe-uninitialized]
      { .__val = (__force typeof(x)) (val) }; \
                 ^
   fs/dcache.c:2520:11: note: 'n' was declared here
     unsigned n;
              ^
   In file included from include/uapi/linux/stddef.h:1:0,
                    from include/linux/stddef.h:4,
                    from include/uapi/linux/posix_types.h:4,
                    from include/uapi/linux/types.h:13,
                    from include/linux/types.h:5,
                    from include/linux/syscalls.h:70,
                    from fs/dcache.c:17:
   fs/dcache.c: In function 'd_splice_alias':
>> include/linux/compiler.h:323:14: warning: 'n' may be used uninitialized in this function [-Wmaybe-uninitialized]
      { .__val = (__force typeof(x)) (val) }; \
                 ^
   fs/dcache.c:2520:11: note: 'n' was declared here
     unsigned n;
              ^

vim +/n +323 include/linux/compiler.h

d976441f Andrey Ryabinin       2015-10-19  307  		__read_once_size(&(x), __u.__c, sizeof(x));		\
d976441f Andrey Ryabinin       2015-10-19  308  	else								\
d976441f Andrey Ryabinin       2015-10-19  309  		__read_once_size_nocheck(&(x), __u.__c, sizeof(x));	\
d976441f Andrey Ryabinin       2015-10-19  310  	__u.__val;							\
d976441f Andrey Ryabinin       2015-10-19  311  })
d976441f Andrey Ryabinin       2015-10-19  312  #define READ_ONCE(x) __READ_ONCE(x, 1)
d976441f Andrey Ryabinin       2015-10-19  313  
d976441f Andrey Ryabinin       2015-10-19  314  /*
d976441f Andrey Ryabinin       2015-10-19  315   * Use READ_ONCE_NOCHECK() instead of READ_ONCE() if you need
d976441f Andrey Ryabinin       2015-10-19  316   * to hide memory access from KASAN.
d976441f Andrey Ryabinin       2015-10-19  317   */
d976441f Andrey Ryabinin       2015-10-19  318  #define READ_ONCE_NOCHECK(x) __READ_ONCE(x, 0)
230fa253 Christian Borntraeger 2014-11-25  319  
43239cbe Christian Borntraeger 2015-01-13  320  #define WRITE_ONCE(x, val) \
ba33034f Christian Borntraeger 2015-08-04  321  ({							\
ba33034f Christian Borntraeger 2015-08-04  322  	union { typeof(x) __val; char __c[1]; } __u =	\
ba33034f Christian Borntraeger 2015-08-04 @323  		{ .__val = (__force typeof(x)) (val) }; \
ba33034f Christian Borntraeger 2015-08-04  324  	__write_once_size(&(x), __u.__c, sizeof(x));	\
ba33034f Christian Borntraeger 2015-08-04  325  	__u.__val;					\
ba33034f Christian Borntraeger 2015-08-04  326  })
230fa253 Christian Borntraeger 2014-11-25  327  
^1da177e Linus Torvalds        2005-04-16  328  #endif /* __KERNEL__ */
^1da177e Linus Torvalds        2005-04-16  329  
^1da177e Linus Torvalds        2005-04-16  330  #endif /* __ASSEMBLY__ */
^1da177e Linus Torvalds        2005-04-16  331  

:::::: The code at line 323 was first introduced by commit
:::::: ba33034fffc1189d95301bd865f1c799256e72a2 locking, compiler.h: Cast away attributes in the WRITE_ONCE() magic

:::::: TO: Christian Borntraeger <borntraeger@de.ibm.com>
:::::: CC: Ingo Molnar <mingo@kernel.org>

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
Darrick J. Wong Dec. 8, 2016, 6:10 a.m. UTC | #2
On Wed, Dec 07, 2016 at 11:54:52AM +0800, kbuild test robot wrote:
> Hi Darrick,
> 
> [auto build test WARNING on linus/master]
> [also build test WARNING on v4.9-rc8 next-20161206]
> [if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
> 
> url:    https://github.com/0day-ci/linux/commits/Darrick-J-Wong/vfs-reject-inodes-with-negative-size-to-prevent-kernel-hang/20161207-110513
> config: i386-randconfig-s1-201649 (attached as .config)
> compiler: gcc-6 (Debian 6.2.0-3) 6.2.0 20160901
> reproduce:
>         # save the attached .config to linux build tree
>         make ARCH=i386 
> 
> Note: it may well be a FALSE warning. FWIW you are at least aware of it now.
> http://gcc.gnu.org/wiki/Better_Uninitialized_Warnings
> 
> All warnings (new ones prefixed by >>):
> 
>    Cyclomatic Complexity 1 fs/dcache.c:__d_rehash
>    Cyclomatic Complexity 2 fs/dcache.c:prepend
>    Cyclomatic Complexity 3 fs/dcache.c:path_with_deleted
>    Cyclomatic Complexity 7 fs/dcache.c:__dentry_path
>    Cyclomatic Complexity 1 fs/dcache.c:prepend_unreachable
>    Cyclomatic Complexity 4 fs/dcache.c:d_shrink_del
>    Cyclomatic Complexity 4 fs/dcache.c:d_shrink_add
>    Cyclomatic Complexity 2 fs/dcache.c:__d_instantiate
>    Cyclomatic Complexity 7 fs/dcache.c:d_lru_add
>    Cyclomatic Complexity 2 fs/dcache.c:dentry_lru_add
>    Cyclomatic Complexity 7 fs/dcache.c:d_lru_del
>    Cyclomatic Complexity 7 fs/dcache.c:select_collect
>    Cyclomatic Complexity 2 fs/dcache.c:detach_and_collect
>    Cyclomatic Complexity 6 fs/dcache.c:dentry_unlink_inode
>    Cyclomatic Complexity 1 fs/dcache.c:__d_free_external
>    Cyclomatic Complexity 1 fs/dcache.c:__d_free
>    Cyclomatic Complexity 5 fs/dcache.c:dentry_free
>    Cyclomatic Complexity 4 fs/dcache.c:d_lru_isolate
>    Cyclomatic Complexity 4 fs/dcache.c:d_lru_shrink_move
>    Cyclomatic Complexity 4 fs/dcache.c:dentry_lru_isolate
>    Cyclomatic Complexity 2 fs/dcache.c:dentry_lru_isolate_shrink
>    Cyclomatic Complexity 16 fs/dcache.c:d_walk
>    Cyclomatic Complexity 6 fs/dcache.c:umount_check
>    Cyclomatic Complexity 3 fs/dcache.c:d_wait_lookup
>    Cyclomatic Complexity 6 fs/dcache.c:swap_names
>    Cyclomatic Complexity 6 fs/dcache.c:copy_name
>    Cyclomatic Complexity 2 fs/dcache.c:set_dhash_entries
>    Cyclomatic Complexity 1 fs/dcache.c:vfs_caches_init_early
>    Cyclomatic Complexity 1 fs/dcache.c:vfs_caches_init
>    Cyclomatic Complexity 1 fs/dcache.c:proc_nr_dentry
>    Cyclomatic Complexity 3 fs/dcache.c:__d_drop
>    Cyclomatic Complexity 11 fs/dcache.c:__dentry_kill
>    Cyclomatic Complexity 6 fs/dcache.c:dentry_kill
>    Cyclomatic Complexity 16 fs/dcache.c:shrink_dentry_list
>    Cyclomatic Complexity 3 fs/dcache.c:check_and_drop
>    Cyclomatic Complexity 1 fs/dcache.c:d_drop
>    Cyclomatic Complexity 10 fs/dcache.c:dput
>    Cyclomatic Complexity 4 fs/dcache.c:dget_parent
>    Cyclomatic Complexity 2 fs/dcache.c:d_find_alias
>    Cyclomatic Complexity 7 fs/dcache.c:d_prune_aliases
>    Cyclomatic Complexity 1 fs/dcache.c:prune_dcache_sb
>    Cyclomatic Complexity 6 fs/dcache.c:shrink_dcache_sb
>    Cyclomatic Complexity 1 fs/dcache.c:have_submounts
>    Cyclomatic Complexity 4 fs/dcache.c:d_set_mounted
>    Cyclomatic Complexity 2 fs/dcache.c:shrink_dcache_parent
>    Cyclomatic Complexity 1 fs/dcache.c:do_one_tree
>    Cyclomatic Complexity 3 fs/dcache.c:shrink_dcache_for_umount
>    Cyclomatic Complexity 7 fs/dcache.c:d_invalidate
>    Cyclomatic Complexity 15 fs/dcache.c:d_set_d_op
>    Cyclomatic Complexity 9 fs/dcache.c:__d_alloc
>    Cyclomatic Complexity 2 fs/dcache.c:d_alloc
>    Cyclomatic Complexity 1 fs/dcache.c:d_alloc_name
>    Cyclomatic Complexity 2 fs/dcache.c:d_alloc_cursor
>    Cyclomatic Complexity 1 fs/dcache.c:d_alloc_pseudo
>    Cyclomatic Complexity 1 fs/dcache.c:d_set_fallthru
>    Cyclomatic Complexity 2 fs/dcache.c:d_instantiate
>    Cyclomatic Complexity 3 fs/dcache.c:d_instantiate_no_diralias
>    Cyclomatic Complexity 3 fs/dcache.c:d_make_root
>    Cyclomatic Complexity 1 fs/dcache.c:d_find_any_alias
>    Cyclomatic Complexity 7 fs/dcache.c:__d_obtain_alias
>    Cyclomatic Complexity 1 fs/dcache.c:d_obtain_alias
>    Cyclomatic Complexity 1 fs/dcache.c:d_obtain_root
>    Cyclomatic Complexity 11 fs/dcache.c:__d_lookup_rcu
>    Cyclomatic Complexity 7 fs/dcache.c:__d_lookup
>    Cyclomatic Complexity 3 fs/dcache.c:d_lookup
>    Cyclomatic Complexity 3 fs/dcache.c:d_hash_and_lookup
>    Cyclomatic Complexity 4 fs/dcache.c:d_delete
>    Cyclomatic Complexity 1 fs/dcache.c:d_rehash
>    Cyclomatic Complexity 18 fs/dcache.c:d_alloc_parallel
>    Cyclomatic Complexity 1 fs/dcache.c:__d_lookup_done
>    Cyclomatic Complexity 2 fs/dcache.c:d_add
>    Cyclomatic Complexity 8 fs/dcache.c:d_exact_alias
>    Cyclomatic Complexity 1 fs/dcache.c:dentry_update_name_case
>    Cyclomatic Complexity 3 fs/dcache.c:d_ancestor
>    Cyclomatic Complexity 5 fs/dcache.c:dentry_lock_for_move
>    Cyclomatic Complexity 8 fs/dcache.c:__d_move
>    Cyclomatic Complexity 1 fs/dcache.c:d_move
>    Cyclomatic Complexity 5 fs/dcache.c:d_exchange
>    Cyclomatic Complexity 6 fs/dcache.c:__d_unalias
>    Cyclomatic Complexity 13 fs/dcache.c:d_splice_alias
>    Cyclomatic Complexity 7 fs/dcache.c:d_add_ci
>    Cyclomatic Complexity 3 fs/dcache.c:__d_path
>    Cyclomatic Complexity 3 fs/dcache.c:d_absolute_path
>    Cyclomatic Complexity 6 fs/dcache.c:d_path
>    Cyclomatic Complexity 2 fs/dcache.c:dynamic_dname
>    Cyclomatic Complexity 4 fs/dcache.c:simple_dname
>    Cyclomatic Complexity 1 fs/dcache.c:dentry_path_raw
>    Cyclomatic Complexity 5 fs/dcache.c:dentry_path
>    Cyclomatic Complexity 1 fs/dcache.c:SyS_getcwd
>    Cyclomatic Complexity 4 fs/dcache.c:is_subdir
>    Cyclomatic Complexity 1 fs/dcache.c:d_genocide
>    Cyclomatic Complexity 4 fs/dcache.c:d_tmpfile
>    In file included from include/uapi/linux/stddef.h:1:0,
>                     from include/linux/stddef.h:4,
>                     from include/uapi/linux/posix_types.h:4,
>                     from include/uapi/linux/types.h:13,
>                     from include/linux/types.h:5,
>                     from include/linux/syscalls.h:70,
>                     from fs/dcache.c:17:
>    fs/dcache.c: In function 'd_add':
> >> include/linux/compiler.h:323:14: warning: 'n' may be used uninitialized in this function [-Wmaybe-uninitialized]

Uh... I don't touch _n_ in this patch, and AFAICT I don't alter any of
the code paths that access _n_.

<shrugs vaguely at the robotic reply address>

--D

>       { .__val = (__force typeof(x)) (val) }; \
>                  ^
>    fs/dcache.c:2520:11: note: 'n' was declared here
>      unsigned n;
>               ^
>    In file included from include/uapi/linux/stddef.h:1:0,
>                     from include/linux/stddef.h:4,
>                     from include/uapi/linux/posix_types.h:4,
>                     from include/uapi/linux/types.h:13,
>                     from include/linux/types.h:5,
>                     from include/linux/syscalls.h:70,
>                     from fs/dcache.c:17:
>    fs/dcache.c: In function 'd_splice_alias':
> >> include/linux/compiler.h:323:14: warning: 'n' may be used uninitialized in this function [-Wmaybe-uninitialized]
>       { .__val = (__force typeof(x)) (val) }; \
>                  ^
>    fs/dcache.c:2520:11: note: 'n' was declared here
>      unsigned n;
>               ^
> 
> vim +/n +323 include/linux/compiler.h
> 
> d976441f Andrey Ryabinin       2015-10-19  307  		__read_once_size(&(x), __u.__c, sizeof(x));		\
> d976441f Andrey Ryabinin       2015-10-19  308  	else								\
> d976441f Andrey Ryabinin       2015-10-19  309  		__read_once_size_nocheck(&(x), __u.__c, sizeof(x));	\
> d976441f Andrey Ryabinin       2015-10-19  310  	__u.__val;							\
> d976441f Andrey Ryabinin       2015-10-19  311  })
> d976441f Andrey Ryabinin       2015-10-19  312  #define READ_ONCE(x) __READ_ONCE(x, 1)
> d976441f Andrey Ryabinin       2015-10-19  313  
> d976441f Andrey Ryabinin       2015-10-19  314  /*
> d976441f Andrey Ryabinin       2015-10-19  315   * Use READ_ONCE_NOCHECK() instead of READ_ONCE() if you need
> d976441f Andrey Ryabinin       2015-10-19  316   * to hide memory access from KASAN.
> d976441f Andrey Ryabinin       2015-10-19  317   */
> d976441f Andrey Ryabinin       2015-10-19  318  #define READ_ONCE_NOCHECK(x) __READ_ONCE(x, 0)
> 230fa253 Christian Borntraeger 2014-11-25  319  
> 43239cbe Christian Borntraeger 2015-01-13  320  #define WRITE_ONCE(x, val) \
> ba33034f Christian Borntraeger 2015-08-04  321  ({							\
> ba33034f Christian Borntraeger 2015-08-04  322  	union { typeof(x) __val; char __c[1]; } __u =	\
> ba33034f Christian Borntraeger 2015-08-04 @323  		{ .__val = (__force typeof(x)) (val) }; \
> ba33034f Christian Borntraeger 2015-08-04  324  	__write_once_size(&(x), __u.__c, sizeof(x));	\
> ba33034f Christian Borntraeger 2015-08-04  325  	__u.__val;					\
> ba33034f Christian Borntraeger 2015-08-04  326  })
> 230fa253 Christian Borntraeger 2014-11-25  327  
> ^1da177e Linus Torvalds        2005-04-16  328  #endif /* __KERNEL__ */
> ^1da177e Linus Torvalds        2005-04-16  329  
> ^1da177e Linus Torvalds        2005-04-16  330  #endif /* __ASSEMBLY__ */
> ^1da177e Linus Torvalds        2005-04-16  331  
> 
> :::::: The code at line 323 was first introduced by commit
> :::::: ba33034fffc1189d95301bd865f1c799256e72a2 locking, compiler.h: Cast away attributes in the WRITE_ONCE() magic
> 
> :::::: TO: Christian Borntraeger <borntraeger@de.ibm.com>
> :::::: CC: Ingo Molnar <mingo@kernel.org>
> 
> ---
> 0-DAY kernel test infrastructure                Open Source Technology Center
> https://lists.01.org/pipermail/kbuild-all                   Intel Corporation


--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Al Viro Dec. 10, 2016, 1:59 a.m. UTC | #3
On Tue, Dec 06, 2016 at 04:32:22PM -0800, Darrick J. Wong wrote:
> Due to insufficient input validation, various filesystem drivers can
> load an inode with a negative size from a maliciously crafted fs image.
> If this happens, a subsequent write-append operation can cause integer
> overflows in the writeback code, causing the kernel to lock up.
> 
> Therefore, if we catch anyone trying to link a dentry to a garbage
> inode, reject the whole attempt.

Yecchh...  This is completely wrong place for such checks.  Sorry,
NAK.  The set of spots chosen for those tests is random *and* it's
not even sufficient (consider e.g. d_obtain_alias()).  The things
go wrong when such inode is set up, not when a dentry is attached
to it.
--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/fs/dcache.c b/fs/dcache.c
index 5c7cc95..6a253a4 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -2524,6 +2524,17 @@  static inline void __d_add(struct dentry *dentry, struct inode *inode)
 		n = start_dir_add(dir);
 		__d_lookup_done(dentry);
 	}
+
+	/*
+	 * Someone fed us an inode with negative size?!  This can cause
+	 * integer overflows in other parts of the VFS, so reject this.
+	 */
+	if (inode && i_size_read(inode) < 0) {
+		WARN_ON_ONCE(1);
+		iput(inode);
+		inode = NULL;
+	}
+
 	if (inode) {
 		unsigned add_flags = d_flags_for_inode(inode);
 		hlist_add_head(&dentry->d_u.d_alias, &inode->i_dentry);
@@ -2946,6 +2957,16 @@  struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry)
 	if (!inode)
 		goto out;
 
+	/*
+	 * Someone fed us an inode with negative size?!  This can cause
+	 * integer overflows in other parts of the VFS, so reject this.
+	 */
+	if (i_size_read(inode) < 0) {
+		WARN_ON_ONCE(1);
+		iput(inode);
+		return ERR_PTR(-EUCLEAN);
+	}
+
 	security_d_instantiate(dentry, inode);
 	spin_lock(&inode->i_lock);
 	if (S_ISDIR(inode->i_mode)) {