Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 961b33c2 authored by Kees Cook's avatar Kees Cook
Browse files

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: default avatarBart Massey <bart.massey@gmail.com>
Fixes: 8d2704d3 ("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: default avatarKees Cook <keescook@chromium.org>
parent 7daf201d
Loading
Loading
Loading
Loading
+7 −0
Original line number Original line Diff line number Diff line
@@ -115,6 +115,13 @@ struct dinode {
					dxd_t _dxd;	/* 16: */
					dxd_t _dxd;	/* 16: */
					union {
					union {
						__le32 _rdev;	/* 4: */
						__le32 _rdev;	/* 4: */
						/*
						 * The fast symlink area
						 * is expected to overflow
						 * into _inlineea when
						 * needed (which will clear
						 * INLINEEA).
						 */
						u8 _fastsymlink[128];
						u8 _fastsymlink[128];
					} _u;
					} _u;
					u8 _inlineea[128];
					u8 _inlineea[128];
+1 −0
Original line number Original line Diff line number Diff line
@@ -87,6 +87,7 @@ struct jfs_inode_info {
		struct {
		struct {
			unchar _unused[16];	/* 16: */
			unchar _unused[16];	/* 16: */
			dxd_t _dxd;		/* 16: */
			dxd_t _dxd;		/* 16: */
			/* _inline may overflow into _inline_ea when needed */
			unchar _inline[128];	/* 128: inline symlink */
			unchar _inline[128];	/* 128: inline symlink */
			/* _inline_ea may overlay the last part of
			/* _inline_ea may overlay the last part of
			 * file._xtroot if maxentry = XTROOTINITSLOT
			 * file._xtroot if maxentry = XTROOTINITSLOT
+1 −2
Original line number Original line Diff line number Diff line
@@ -967,8 +967,7 @@ static int __init init_jfs_fs(void)
	jfs_inode_cachep =
	jfs_inode_cachep =
	    kmem_cache_create_usercopy("jfs_ip", sizeof(struct jfs_inode_info),
	    kmem_cache_create_usercopy("jfs_ip", sizeof(struct jfs_inode_info),
			0, SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD|SLAB_ACCOUNT,
			0, SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD|SLAB_ACCOUNT,
			offsetof(struct jfs_inode_info, i_inline),
			offsetof(struct jfs_inode_info, i_inline), IDATASIZE,
			sizeof_field(struct jfs_inode_info, i_inline),
			init_once);
			init_once);
	if (jfs_inode_cachep == NULL)
	if (jfs_inode_cachep == NULL)
		return -ENOMEM;
		return -ENOMEM;