lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite for Android: free password hash cracker in your pocket
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Date:   Mon, 26 Mar 2018 20:38:00 -0700
From:   Eric Biggers <ebiggers3@...il.com>
To:     linux-ext4@...r.kernel.org, Theodore Ts'o <tytso@....edu>
Cc:     Andreas Dilger <adilger.kernel@...ger.ca>,
        Wen Xu <wen.xu@...ech.edu>, Eric Biggers <ebiggers@...gle.com>
Subject: [PATCH] ext4: limit external inode xattrs to XATTR_SIZE_MAX

From: Eric Biggers <ebiggers@...gle.com>

This is a replacement for the broken patch "ext4: add better range
checking for e_value_size in xattrs" currently in ext4/dev.

-----8<-----

ext4 isn't validating the sizes of xattrs that are stored in external
inodes.  This is problematic because ->e_value_size is a u32, but
ext4_xattr_get() returns an int.  A very large size is misinterpreted as
an error code, which ext4_get_acl() translates into a bogus ERR_PTR()
for which IS_ERR() returns false, causing a crash.

Fix this by validating that all xattrs are <= XATTR_SIZE_MAX bytes.
(It's not strictly needed for non-EA-inode xattrs, but it doesn't hurt.)

https://bugzilla.kernel.org/show_bug.cgi?id=199185

Reported-by: Wen Xu <wen.xu@...ech.edu>
Fixes: e50e5129f384 ("ext4: xattr-in-inode support")
Cc: <stable@...r.kernel.org> # v4.13+
Signed-off-by: Eric Biggers <ebiggers@...gle.com>
---
 fs/ext4/xattr.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c
index 63656dbafdc45..8c9ade64aea2a 100644
--- a/fs/ext4/xattr.c
+++ b/fs/ext4/xattr.c
@@ -195,10 +195,13 @@ ext4_xattr_check_entries(struct ext4_xattr_entry *entry, void *end,
 
 	/* Check the values */
 	while (!IS_LAST_ENTRY(entry)) {
-		if (entry->e_value_size != 0 &&
-		    entry->e_value_inum == 0) {
+		u32 size = le32_to_cpu(entry->e_value_size);
+
+		if (size > XATTR_SIZE_MAX)
+			return -EFSCORRUPTED;
+
+		if (size != 0 && entry->e_value_inum == 0) {
 			u16 offs = le16_to_cpu(entry->e_value_offs);
-			u32 size = le32_to_cpu(entry->e_value_size);
 			void *value;
 
 			/*
-- 
2.16.2

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ