aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKees Cook <keescook@chromium.org>2018-08-03 15:52:58 -0400
committerKees Cook <keescook@chromium.org>2018-08-04 10:53:46 -0400
commit961b33c244e5ba1543ae26270a1ba29f29c2db83 (patch)
treeb2e0bdb72b4e43774aa1264c9bf9f3df1e8cb2d8
parent7daf201d7fe8334e2d2364d4e8ed3394ec9af819 (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.h7
-rw-r--r--fs/jfs/jfs_incore.h1
-rw-r--r--fs/jfs/super.c3
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;