diff options
author | Kees Cook <keescook@chromium.org> | 2018-08-03 15:52:58 -0400 |
---|---|---|
committer | Kees Cook <keescook@chromium.org> | 2018-08-04 10:53:46 -0400 |
commit | 961b33c244e5ba1543ae26270a1ba29f29c2db83 (patch) | |
tree | b2e0bdb72b4e43774aa1264c9bf9f3df1e8cb2d8 | |
parent | 7daf201d7fe8334e2d2364d4e8ed3394ec9af819 (diff) |
jfs: Fix usercopy whitelist for inline inode data
Bart Massey reported what turned out to be a usercopy whitelist false
positive in JFS when symlink contents exceeded 128 bytes. The inline
inode data (i_inline) is actually designed to overflow into the "extended
area" following it (i_inline_ea) when needed. So the whitelist needed to
be expanded to include both i_inline and i_inline_ea (the whole size
of which is calculated internally using IDATASIZE, 256, instead of
sizeof(i_inline), 128).
$ cd /mnt/jfs
$ touch $(perl -e 'print "B" x 250')
$ ln -s B* b
$ ls -l >/dev/null
[ 249.436410] Bad or missing usercopy whitelist? Kernel memory exposure attempt detected from SLUB object 'jfs_ip' (offset 616, size 250)!
Reported-by: Bart Massey <bart.massey@gmail.com>
Fixes: 8d2704d382a9 ("jfs: Define usercopy region in jfs_ip slab cache")
Cc: Dave Kleikamp <shaggy@kernel.org>
Cc: jfs-discussion@lists.sourceforge.net
Cc: stable@vger.kernel.org
Signed-off-by: Kees Cook <keescook@chromium.org>
-rw-r--r-- | fs/jfs/jfs_dinode.h | 7 | ||||
-rw-r--r-- | fs/jfs/jfs_incore.h | 1 | ||||
-rw-r--r-- | fs/jfs/super.c | 3 |
3 files changed, 9 insertions, 2 deletions
diff --git a/fs/jfs/jfs_dinode.h b/fs/jfs/jfs_dinode.h index 395c4c0d0f06..1682a87c00b2 100644 --- a/fs/jfs/jfs_dinode.h +++ b/fs/jfs/jfs_dinode.h | |||
@@ -115,6 +115,13 @@ struct dinode { | |||
115 | dxd_t _dxd; /* 16: */ | 115 | dxd_t _dxd; /* 16: */ |
116 | union { | 116 | union { |
117 | __le32 _rdev; /* 4: */ | 117 | __le32 _rdev; /* 4: */ |
118 | /* | ||
119 | * The fast symlink area | ||
120 | * is expected to overflow | ||
121 | * into _inlineea when | ||
122 | * needed (which will clear | ||
123 | * INLINEEA). | ||
124 | */ | ||
118 | u8 _fastsymlink[128]; | 125 | u8 _fastsymlink[128]; |
119 | } _u; | 126 | } _u; |
120 | u8 _inlineea[128]; | 127 | u8 _inlineea[128]; |
diff --git a/fs/jfs/jfs_incore.h b/fs/jfs/jfs_incore.h index 1f26d1910409..9940a1e04cbf 100644 --- a/fs/jfs/jfs_incore.h +++ b/fs/jfs/jfs_incore.h | |||
@@ -87,6 +87,7 @@ struct jfs_inode_info { | |||
87 | struct { | 87 | struct { |
88 | unchar _unused[16]; /* 16: */ | 88 | unchar _unused[16]; /* 16: */ |
89 | dxd_t _dxd; /* 16: */ | 89 | dxd_t _dxd; /* 16: */ |
90 | /* _inline may overflow into _inline_ea when needed */ | ||
90 | unchar _inline[128]; /* 128: inline symlink */ | 91 | unchar _inline[128]; /* 128: inline symlink */ |
91 | /* _inline_ea may overlay the last part of | 92 | /* _inline_ea may overlay the last part of |
92 | * file._xtroot if maxentry = XTROOTINITSLOT | 93 | * file._xtroot if maxentry = XTROOTINITSLOT |
diff --git a/fs/jfs/super.c b/fs/jfs/super.c index 1b9264fd54b6..f08571433aba 100644 --- a/fs/jfs/super.c +++ b/fs/jfs/super.c | |||
@@ -967,8 +967,7 @@ static int __init init_jfs_fs(void) | |||
967 | jfs_inode_cachep = | 967 | jfs_inode_cachep = |
968 | kmem_cache_create_usercopy("jfs_ip", sizeof(struct jfs_inode_info), | 968 | kmem_cache_create_usercopy("jfs_ip", sizeof(struct jfs_inode_info), |
969 | 0, SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD|SLAB_ACCOUNT, | 969 | 0, SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD|SLAB_ACCOUNT, |
970 | offsetof(struct jfs_inode_info, i_inline), | 970 | offsetof(struct jfs_inode_info, i_inline), IDATASIZE, |
971 | sizeof_field(struct jfs_inode_info, i_inline), | ||
972 | init_once); | 971 | init_once); |
973 | if (jfs_inode_cachep == NULL) | 972 | if (jfs_inode_cachep == NULL) |
974 | return -ENOMEM; | 973 | return -ENOMEM; |